diff options
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java')
-rw-r--r-- | org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java | 117 |
1 files changed, 79 insertions, 38 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java index 1648cff86..4af69a35d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -15,6 +15,7 @@ * bug 364890 - BinaryTypeBinding should use char constants from Util * bug 365387 - [compiler][null] bug 186342: Issues to follow up post review and verification. * bug 358903 - Filter practically unimportant resource leak warnings + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -552,6 +553,11 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { } } + // need type annotations before processing methods (for @NonNullByDefault) + if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { + scanTypeForNullDefaultAnnotation(binaryType); + } + if (needFieldsAndMethods) { createFields(binaryType.getFields(), sourceLevel, missingTypeNames); createMethods(binaryType.getMethods(), sourceLevel, missingTypeNames); @@ -581,14 +587,6 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { // SH} if (this.environment.globalOptions.storeAnnotations) setAnnotations(createAnnotations(binaryType.getAnnotations(), this.environment, missingTypeNames)); - - if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled - && CharOperation.equals(TypeConstants.PACKAGE_INFO_NAME, binaryType.getSourceName())) - { - // only for package-info.java can type-level null-annotations (i.e., @NonNullByDefault) - // on a binary type influence the compilation - scanPackageInfoForNullDefaultAnnotation(binaryType); - } } finally { // protect against incorrect use of the needFieldsAndMethods flag, see 48459 if (this.fields == null) @@ -1586,65 +1584,93 @@ void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding methodBindi return; char[][] nullableAnnotationName = this.environment.getNullableAnnotationName(); char[][] nonNullAnnotationName = this.environment.getNonNullAnnotationName(); - if (nullableAnnotationName == null || nonNullAnnotationName == null) + char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName(); + if (nullableAnnotationName == null || nonNullAnnotationName == null || nonNullByDefaultAnnotationName == null) return; // not well-configured to use null annotations + int currentDefault = NO_NULL_DEFAULT; + if ((this.tagBits & TagBits.AnnotationNonNullByDefault) != 0) { + currentDefault = NONNULL_BY_DEFAULT; + } else if ((this.tagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0) { + currentDefault = NULL_UNSPECIFIED_BY_DEFAULT; + } + // return: IBinaryAnnotation[] annotations = method.getAnnotations(); + boolean explicitNullness = false; if (annotations != null) { for (int i = 0; i < annotations.length; i++) { char[] annotationTypeName = annotations[i].getTypeName(); if (annotationTypeName[0] != Util.C_RESOLVED) continue; char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' - if (CharOperation.equals(typeName, nonNullAnnotationName)) { + if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName)) { + methodBinding.tagBits |= TagBits.AnnotationNonNullByDefault; + currentDefault = NONNULL_BY_DEFAULT; + } + if (!explicitNullness && CharOperation.equals(typeName, nonNullAnnotationName)) { methodBinding.tagBits |= TagBits.AnnotationNonNull; - break; + explicitNullness = true; } - if (CharOperation.equals(typeName, nullableAnnotationName)) { + if (!explicitNullness && CharOperation.equals(typeName, nullableAnnotationName)) { methodBinding.tagBits |= TagBits.AnnotationNullable; - break; + explicitNullness = true; } } } + if (!explicitNullness && currentDefault == NONNULL_BY_DEFAULT) { + methodBinding.tagBits |= TagBits.AnnotationNonNull; + } // parameters: TypeBinding[] parameters = methodBinding.parameters; int numVisibleParams = parameters.length; int numParamAnnotations = method.getAnnotatedParametersCount(); - if (numParamAnnotations > 0) { - int startIndex = numParamAnnotations - numVisibleParams; + if (numParamAnnotations > 0 || currentDefault == NONNULL_BY_DEFAULT) { for (int j = 0; j < numVisibleParams; j++) { - IBinaryAnnotation[] paramAnnotations = method.getParameterAnnotations(j+startIndex); - if (paramAnnotations != null) { - for (int i = 0; i < paramAnnotations.length; i++) { - char[] annotationTypeName = paramAnnotations[i].getTypeName(); - if (annotationTypeName[0] != Util.C_RESOLVED) - continue; - char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' - if (CharOperation.equals(typeName, nonNullAnnotationName)) { - if (methodBinding.parameterNonNullness == null) - methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; - methodBinding.parameterNonNullness[j] = Boolean.TRUE; - break; - } else if (CharOperation.equals(typeName, nullableAnnotationName)) { - if (methodBinding.parameterNonNullness == null) - methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; - methodBinding.parameterNonNullness[j] = Boolean.FALSE; - break; + explicitNullness = false; + if (numParamAnnotations > 0) { + int startIndex = numParamAnnotations - numVisibleParams; + IBinaryAnnotation[] paramAnnotations = method.getParameterAnnotations(j+startIndex); + if (paramAnnotations != null) { + for (int i = 0; i < paramAnnotations.length; i++) { + char[] annotationTypeName = paramAnnotations[i].getTypeName(); + if (annotationTypeName[0] != Util.C_RESOLVED) + continue; + char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' + if (CharOperation.equals(typeName, nonNullAnnotationName)) { + if (methodBinding.parameterNonNullness == null) + methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; + methodBinding.parameterNonNullness[j] = Boolean.TRUE; + explicitNullness = true; + break; + } else if (CharOperation.equals(typeName, nullableAnnotationName)) { + if (methodBinding.parameterNonNullness == null) + methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; + methodBinding.parameterNonNullness[j] = Boolean.FALSE; + explicitNullness = true; + break; + } } } } + if (!explicitNullness && currentDefault == NONNULL_BY_DEFAULT) { + if (methodBinding.parameterNonNullness == null) + methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; + methodBinding.parameterNonNullness[j] = Boolean.TRUE; + } } } } -void scanPackageInfoForNullDefaultAnnotation(IBinaryType binaryType) { +void scanTypeForNullDefaultAnnotation(IBinaryType binaryType) { char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName(); if (nonNullByDefaultAnnotationName == null) return; // not well-configured to use null annotations IBinaryAnnotation[] annotations = binaryType.getAnnotations(); if (annotations != null) { + long annotationBit = 0L; + int nullness = NO_NULL_DEFAULT; int length = annotations.length; for (int i = 0; i < length; i++) { char[] annotationTypeName = annotations[i].getTypeName(); @@ -1659,13 +1685,28 @@ void scanPackageInfoForNullDefaultAnnotation(IBinaryType binaryType) { && !((BooleanConstant)value).booleanValue()) { // parameter is 'false': this means we cancel defaults from outer scopes: - this.getPackage().nullnessDefaultAnnotation = ReferenceBinding.NULL_UNSPECIFIED; - return; + annotationBit = TagBits.AnnotationNullUnspecifiedByDefault; + nullness = NULL_UNSPECIFIED_BY_DEFAULT; + break; } } - this.getPackage().nullnessDefaultAnnotation = - this.environment.getNullAnnotationBinding(TagBits.AnnotationNonNull, false/*resolve*/); - return; + annotationBit = TagBits.AnnotationNonNullByDefault; + nullness = NONNULL_BY_DEFAULT; + break; + } + } + if (annotationBit != 0L) { + this.tagBits |= annotationBit; + if (CharOperation.equals(this.sourceName(), TypeConstants.PACKAGE_INFO_NAME)) + this.getPackage().defaultNullness = nullness; + } else { + switch (this.getPackage().defaultNullness) { + case NONNULL_BY_DEFAULT : + this.tagBits |= TagBits.AnnotationNonNullByDefault; + break; + case NULL_UNSPECIFIED_BY_DEFAULT : + this.tagBits |= TagBits.AnnotationNullUnspecifiedByDefault; + break; } } } |