protected void resolveAnnotations(Scope scope, int location) { Annotation[][] annotationsOnDimensions = getAnnotationsOnDimensions(); if (this.annotations != null || annotationsOnDimensions != null) { BlockScope resolutionScope = Scope.typeAnnotationsResolutionScope(scope); if (resolutionScope != null) { int dimensions = this.dimensions(); if (this.annotations != null) { TypeBinding leafComponentType = this.resolvedType.leafComponentType(); leafComponentType = resolveAnnotations(resolutionScope, this.annotations, leafComponentType); this.resolvedType = dimensions > 0 ? scope.environment().createArrayType(leafComponentType, dimensions) : leafComponentType; // contradictory null annotations on the type are already detected in // Annotation.resolveType() (SE7 treatment) } if (annotationsOnDimensions != null) { this.resolvedType = resolveAnnotations(resolutionScope, annotationsOnDimensions, this.resolvedType); if (this.resolvedType instanceof ArrayBinding) { long[] nullTagBitsPerDimension = ((ArrayBinding) this.resolvedType).nullTagBitsPerDimension; if (nullTagBitsPerDimension != null) { for (int i = 0; i < dimensions; i++) { // skip last annotations at [dimensions] (concerns the leaf type) if ((nullTagBitsPerDimension[i] & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { scope.problemReporter().contradictoryNullAnnotations(annotationsOnDimensions[i]); nullTagBitsPerDimension[i] = 0; } } } } } } } if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled && this.resolvedType != null && (this.resolvedType.tagBits & TagBits.AnnotationNullMASK) == 0 && !this.resolvedType.isTypeVariable() && !this.resolvedType.isWildcard() && location != 0 && scope.hasDefaultNullnessFor(location)) { if (location == Binding.DefaultLocationTypeBound && this.resolvedType.id == TypeIds.T_JavaLangObject) { scope.problemReporter().implicitObjectBoundNoNullDefault(this); } else { LookupEnvironment environment = scope.environment(); AnnotationBinding[] annots = new AnnotationBinding[] {environment.getNonNullAnnotation()}; this.resolvedType = environment.createAnnotatedType(this.resolvedType, annots); } } }
void recordArgNonNullness18( MethodBinding method, int paramIdx, Argument currentArgument, Boolean nonNullNess, LookupEnvironment env) { AnnotationBinding annotationBinding = nonNullNess.booleanValue() ? env.getNonNullAnnotation() : env.getNullableAnnotation(); method.parameters[paramIdx] = env.createAnnotatedType( method.parameters[paramIdx], new AnnotationBinding[] {annotationBinding}); if (currentArgument != null) { currentArgument.binding.type = method.parameters[paramIdx]; } }
/** * Check and fill in implicit annotations from overridden methods and from default. Precondition: * caller has checked whether annotation-based null analysis is enabled. */ public void checkImplicitNullAnnotations( MethodBinding currentMethod, AbstractMethodDeclaration srcMethod, boolean complain, Scope scope) { // check inherited nullness from superclass and superInterfaces try { ReferenceBinding currentType = currentMethod.declaringClass; if (currentType.id == TypeIds.T_JavaLangObject) { return; } boolean usesTypeAnnotations = scope.environment().usesNullTypeAnnotations(); boolean needToApplyReturnNonNullDefault = currentMethod.hasNonNullDefaultFor( Binding.DefaultLocationReturnType, usesTypeAnnotations); boolean needToApplyParameterNonNullDefault = currentMethod.hasNonNullDefaultFor(Binding.DefaultLocationParameter, usesTypeAnnotations); boolean needToApplyNonNullDefault = needToApplyReturnNonNullDefault | needToApplyParameterNonNullDefault; // compatibility & inheritance do not consider constructors / static methods: boolean isInstanceMethod = !currentMethod.isConstructor() && !currentMethod.isStatic(); complain &= isInstanceMethod; if (!needToApplyNonNullDefault && !complain && !(this.inheritNullAnnotations && isInstanceMethod)) { return; // short cut, no work to be done } if (isInstanceMethod) { List superMethodList = new ArrayList(); // need super types connected: if (currentType instanceof SourceTypeBinding && !currentType.isHierarchyConnected() && !currentType.isAnonymousType()) { ((SourceTypeBinding) currentType).scope.connectTypeHierarchy(); } int paramLen = currentMethod.parameters.length; findAllOverriddenMethods( currentMethod.original(), currentMethod.selector, paramLen, currentType, new HashSet(), superMethodList); // prepare interim storage for nullness info so we don't pollute currentMethod before we // know its conflict-free: InheritedNonNullnessInfo[] inheritedNonNullnessInfos = new InheritedNonNullnessInfo[paramLen + 1]; // index 0 is for the return type for (int i = 0; i < paramLen + 1; i++) inheritedNonNullnessInfos[i] = new InheritedNonNullnessInfo(); int length = superMethodList.size(); for (int i = length; --i >= 0; ) { MethodBinding currentSuper = (MethodBinding) superMethodList.get(i); if ((currentSuper.tagBits & TagBits.IsNullnessKnown) == 0) { // recurse to prepare currentSuper checkImplicitNullAnnotations( currentSuper, null, false, scope); // TODO (stephan) complain=true if currentSuper is source method?? } checkNullSpecInheritance( currentMethod, srcMethod, needToApplyReturnNonNullDefault, needToApplyParameterNonNullDefault, complain, currentSuper, null, scope, inheritedNonNullnessInfos); needToApplyNonNullDefault = false; } // transfer collected information into currentMethod: InheritedNonNullnessInfo info = inheritedNonNullnessInfos[0]; if (!info.complained) { long tagBits = 0; if (info.inheritedNonNullness == Boolean.TRUE) { tagBits = TagBits.AnnotationNonNull; } else if (info.inheritedNonNullness == Boolean.FALSE) { tagBits = TagBits.AnnotationNullable; } if (tagBits != 0) { if (!usesTypeAnnotations) { currentMethod.tagBits |= tagBits; } else { if (!currentMethod.returnType.isBaseType()) { LookupEnvironment env = scope.environment(); currentMethod.returnType = env.createAnnotatedType( currentMethod.returnType, env.nullAnnotationsFromTagBits(tagBits)); } } } } for (int i = 0; i < paramLen; i++) { info = inheritedNonNullnessInfos[i + 1]; if (!info.complained && info.inheritedNonNullness != null) { Argument currentArg = srcMethod == null ? null : srcMethod.arguments[i]; if (!usesTypeAnnotations) recordArgNonNullness( currentMethod, paramLen, i, currentArg, info.inheritedNonNullness); else recordArgNonNullness18( currentMethod, i, currentArg, info.inheritedNonNullness, scope.environment()); } } } if (needToApplyNonNullDefault) { if (!usesTypeAnnotations) currentMethod.fillInDefaultNonNullness(srcMethod); else currentMethod.fillInDefaultNonNullness18(srcMethod, scope.environment()); } } finally { currentMethod.tagBits |= TagBits.IsNullnessKnown; } }
public TypeBinding resolveType(BlockScope scope) { this.constant = Constant.NotAConstant; if ((this.targetType = this.type.resolveType(scope, true /* check bounds*/)) == null) return null; /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=320463 https://bugs.eclipse.org/bugs/show_bug.cgi?id=312076 JLS3 15.8.2 forbids the type named in the class literal expression from being a parameterized type. And the grammar in 18.1 disallows (where X and Y are some concrete types) constructs of the form Outer<X>.class, Outer<X>.Inner.class, Outer.Inner<X>.class, Outer<X>.Inner<Y>.class etc. Corollary wise, we should resolve the type of the class literal expression to be a raw type as class literals exist only for the raw underlying type. */ LookupEnvironment environment = scope.environment(); this.targetType = environment.convertToRawType( this.targetType, true /* force conversion of enclosing types*/); if (this.targetType.isArrayType()) { ArrayBinding arrayBinding = (ArrayBinding) this.targetType; TypeBinding leafComponentType = arrayBinding.leafComponentType; if (leafComponentType == TypeBinding.VOID) { scope.problemReporter().cannotAllocateVoidArray(this); return null; } else if (leafComponentType.isTypeVariable()) { scope .problemReporter() .illegalClassLiteralForTypeVariable((TypeVariableBinding) leafComponentType, this); } } else if (this.targetType.isTypeVariable()) { scope .problemReporter() .illegalClassLiteralForTypeVariable((TypeVariableBinding) this.targetType, this); } // {ObjectTeams: do we need a RoleClassLiteralAccess? if (this.targetType instanceof ReferenceBinding) { ReferenceBinding targetRef = (ReferenceBinding) this.targetType; if (targetRef.isRole()) { if (this.verbatim) { this.targetType = RoleTypeCreator.maybeWrapUnqualifiedRoleType(scope, this.targetType, this); } else { SourceTypeBinding site = scope.enclosingSourceType(); if (scope.methodScope().isStatic // role class literal needs team instance && !site.isRole() // static role method are OK. && !RoleTypeBinding.isRoleWithExplicitAnchor(this.targetType)) // t.R.class? { scope.problemReporter().roleClassLiteralLacksTeamInstance(this, targetRef); return null; } ReferenceBinding teamBinding; if (RoleTypeBinding.isRoleWithExplicitAnchor(targetRef)) teamBinding = targetRef.enclosingType(); else teamBinding = TeamModel.findEnclosingTeamContainingRole(site, targetRef); if (teamBinding == null) scope.problemReporter().externalizedRoleClassLiteral(this, targetRef); else { TypeBinding methodType = RoleClassLiteralAccess.ensureGetClassMethod( teamBinding.getTeamModel(), targetRef.roleModel); // not affected by visibility check (for resilience) this.roleClassLiteralAccess = new RoleClassLiteralAccess(this, methodType); this.resolvedType = this.roleClassLiteralAccess.resolveType(scope); } return this.resolvedType; } } } // SH} ReferenceBinding classType = scope.getJavaLangClass(); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328689 if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { // Integer.class --> Class<Integer>, perform boxing of base types (int.class --> // Class<Integer>) TypeBinding boxedType = null; if (this.targetType.id == T_void) { boxedType = environment.getResolvedType(JAVA_LANG_VOID, scope); } else { boxedType = scope.boxing(this.targetType); } if (environment.usesNullTypeAnnotations()) boxedType = environment.createAnnotatedType( boxedType, new AnnotationBinding[] {environment.getNonNullAnnotation()}); this.resolvedType = environment.createParameterizedType( classType, new TypeBinding[] {boxedType}, null /*not a member*/); } else { this.resolvedType = classType; } return this.resolvedType; }