diff options
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup')
11 files changed, 150 insertions, 205 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; } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java index ea41433e6..f4c04c2ff 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java @@ -10,6 +10,8 @@ * IBM Corporation - initial API and implementation * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation + * Stephan Herrmann - Contribution for + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -68,6 +70,11 @@ public abstract class Binding { public static final MethodBinding[] UNINITIALIZED_METHODS = new MethodBinding[0]; public static final ReferenceBinding[] UNINITIALIZED_REFERENCE_TYPES = new ReferenceBinding[0]; + // Nullness defaults: + public static final int NO_NULL_DEFAULT = 0; + public static final int NULL_UNSPECIFIED_BY_DEFAULT = 1; + public static final int NONNULL_BY_DEFAULT = 2; + /* * Answer the receiver's binding type from Binding.BindingID. */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java index ba128f166..5df6a31d1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java @@ -14,6 +14,8 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points * bug 358903 - Filter practically unimportant resource leak warnings + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -28,6 +30,7 @@ import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.WrapperKind; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; @@ -1156,11 +1159,12 @@ public void pruneWrapperTrackingVar(FakedTrackingVariable trackingVariable) { * At the end of a block check the closing-status of all tracked closeables that are declared in this block. * Also invoked when entering unreachable code. */ -public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location, BlockScope locationScope) { +public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext, ASTNode location, BlockScope locationScope) { + if (!compilerOptions().analyseResourceLeaks) return; if (this.trackingVariables == null) { // at a method return we also consider enclosing scopes if (location != null && this.parent instanceof BlockScope) - ((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, location, locationScope); + ((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, flowContext, location, locationScope); return; } if (location != null && flowInfo.reachMode() != 0) return; @@ -1177,9 +1181,14 @@ public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location, BlockSc continue; } - if (location != null && trackingVar.originalBinding != null && flowInfo.isDefinitelyNull(trackingVar.originalBinding)) - continue; // reporting against a specific location, resource is null at this flow, don't complain - + if (location != null && trackingVar.hasDefinitelyNoResource(flowInfo)) { + continue; // reporting against a specific location, there is no resource at this flow, don't complain + } + + if (location != null && flowContext != null && flowContext.recordExitAgainstResource(this, flowInfo, trackingVar, location)) { + continue; // handled by the flow context + } + // compute the most specific null status for this resource, int status = trackingVar.findMostSpecificStatus(flowInfo, this, locationScope); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index b82025b21..f8ec700ab 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -139,6 +139,7 @@ public class ClassScope extends Scope { public TypeDeclaration referenceContext; public TypeReference superTypeReference; java.util.ArrayList deferredBoundChecks; + public ClassScope(Scope parent, TypeDeclaration context) { super(Scope.CLASS_SCOPE, parent); this.referenceContext = context; @@ -179,7 +180,6 @@ public class ClassScope extends Scope { } } } - this.referenceContext.binding.cumulativeFieldCount += outerMostMethodScope().analysisIndex; connectMemberTypes(); buildFieldsAndMethods(); //{ObjectTeams: catchup also in OT-specific process (see class comment concerning local types in Dependencies): @@ -271,7 +271,6 @@ public class ClassScope extends Scope { // remove duplicate fields if (count != fieldBindings.length) System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count); - sourceType.cumulativeFieldCount += count; sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type sourceType.setFields(fieldBindings); } @@ -412,7 +411,6 @@ public class ClassScope extends Scope { checkParameterizedTypeBounds(); checkParameterizedSuperTypeCollisions(); } - this.referenceContext.binding.cumulativeFieldCount += outerMostMethodScope().analysisIndex; buildFieldsAndMethods(); //{ObjectTeams: catchup also in OT-specific process (see class comment concerning local types in Dependencies). if (this.referenceContext.isRole()) { @@ -842,8 +840,6 @@ public class ClassScope extends Scope { fieldDeclaration, null, fieldDeclaration.modifiers|ExtraCompilerModifiers.AccUnresolved, sourceType); sourceType.addField(fieldBinding); - sourceType.cumulativeFieldCount++; - this.referenceContext.updateMaxFieldCount(); checkAndSetModifiersForField(fieldBinding, fieldDeclaration); // FIXME(SH): does this improve robustness? diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java index 5d20c1d42..28818d76a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -351,13 +351,6 @@ public long getAnnotationTagBits() { return originalField.tagBits; } -public int getAnalysisId(int maxFieldCount) { - TypeBinding original = this.declaringClass.original(); - if (original instanceof SourceTypeBinding) - return ((SourceTypeBinding)original).fieldAnalysisOffset + this.id; - return this.id; -} - public final boolean isDefault() { return !isPublic() && !isProtected() && !isPrivate(); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index 8951528e0..8e8fa9446 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,6 +12,7 @@ * Stephan Herrmann - contributions for * bug 337868 - [compiler][model] incomplete support for package-info.java when using SearchableEnvironment * bug 186342 - [compiler][null] Using annotations for null checking + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -1301,59 +1302,6 @@ public char[][] getNonNullByDefaultAnnotationName() { return this.globalOptions.nonNullByDefaultAnnotationName; } -/** - * Answer the type binding representing the null-annotation identified by the given tag bits. - * @param annotationTagBit tag bits potentially denoting a null-annotation - * @param resolve should the resulting type binding be resolved? - * @return the corresponding annotation type binding - * or <code>null</code> if no annotation bits are contained in the given tag bits. - */ -public TypeBinding getNullAnnotationBinding(long annotationTagBit, boolean resolve) { - char[][] name = null; - if (annotationTagBit == TagBits.AnnotationNonNull) - name = getNonNullAnnotationName(); - else if (annotationTagBit == TagBits.AnnotationNullable) - name = getNullableAnnotationName(); - else - return null; - if (resolve) - return getType(name); - else - return getTypeFromCompoundName(name, false, false); -} - -/** - * Inspect the given tag bits and answer a corresponding null annotation type binding - * @param defaultTagBit tag bits representing the default applicable at the current code location - * @param resolve should the resulting type binding be resolved? - * @return the corresponding concrete annotation type binding (<code>@NonNull</code> or <code>@Nullable</code>) - * or <code>null</code> if no bits of a default-annotation are contained in the given tag bits. - */ -public TypeBinding getNullAnnotationBindingFromDefault(long defaultTagBit, boolean resolve) { - if ((defaultTagBit & TagBits.AnnotationNullUnspecifiedByDefault) != 0) - return ReferenceBinding.NULL_UNSPECIFIED; - if ((defaultTagBit & TagBits.AnnotationNonNullByDefault) != 0) - return getNullAnnotationBinding(TagBits.AnnotationNonNull, resolve); - return null; -} - -TypeBinding getNullAnnotationResolved(TypeBinding nullAnnotation, Scope scope) { - // avoid unspecific error "The type in.valid cannot be resolved. It is indirectly referenced from required .class files" - boolean tolerateMissing = this.mayTolerateMissingType; - this.mayTolerateMissingType = true; - try { - nullAnnotation = BinaryTypeBinding.resolveType(nullAnnotation, this, false); - } finally { - this.mayTolerateMissingType = tolerateMissing; - } - if (nullAnnotation instanceof MissingTypeBinding) { - // convert error into a specific one: - scope.problemReporter().missingNullAnnotationType(((MissingTypeBinding)nullAnnotation).compoundName); - return null; - } - return nullAnnotation; -} - /* Answer the top level package named name if it exists in the cache. * Answer theNotFoundPackage if it could not be resolved the first time * it was looked up, otherwise answer null. diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java index d49b3039e..da2f17577 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java @@ -14,6 +14,7 @@ * bug 367203 - [compiler][null] detect assigning null to nonnull argument * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * bug 365662 - [compiler][null] warn on contradictory and redundant null annotations + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -854,10 +855,9 @@ public final char[] constantPoolName() { } /** - * After method verifier has finished, fill in missing nullness values from the applicable default. - * @param annotationBinding the null annotation specified to be the default at the current code location. + * After method verifier has finished, fill in missing @NonNull specification from the applicable default. */ -protected void fillInDefaultNonNullness(TypeBinding annotationBinding) { +protected void fillInDefaultNonNullness() { if (this.parameterNonNullness == null) this.parameterNonNullness = new Boolean[this.parameters.length]; AbstractMethodDeclaration sourceMethod = sourceMethod(); @@ -870,9 +870,7 @@ protected void fillInDefaultNonNullness(TypeBinding annotationBinding) { added = true; this.parameterNonNullness[i] = Boolean.TRUE; if (sourceMethod != null) { - Argument argument = sourceMethod.arguments[i]; - sourceMethod.addParameterNonNullAnnotation(argument, (ReferenceBinding)annotationBinding); - argument.binding.tagBits |= TagBits.AnnotationNonNull; + sourceMethod.arguments[i].binding.tagBits |= TagBits.AnnotationNonNull; } } else if (this.parameterNonNullness[i].booleanValue()) { sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, i); @@ -885,8 +883,6 @@ protected void fillInDefaultNonNullness(TypeBinding annotationBinding) { && (this.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0) { this.tagBits |= TagBits.AnnotationNonNull; - if (sourceMethod != null) - sourceMethod.addNonNullAnnotation((ReferenceBinding)annotationBinding); } else if ((this.tagBits & TagBits.AnnotationNonNull) != 0) { sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, -1/*signifies method return*/); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java index a7cc75a7b..0c6cd255e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java @@ -13,6 +13,7 @@ * Stephan Herrmann - Contributions for * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -35,8 +36,9 @@ public class PackageBinding extends Binding implements TypeConstants { HashtableOfType knownTypes; HashtableOfPackage knownPackages; - // annotation type binding representing the default that has been defined for this package (using @NonNullByDefault) - protected TypeBinding nullnessDefaultAnnotation; + // code representing the default that has been defined for this package (using @NonNullByDefault) + // one of Binding.{NO_NULL_DEFAULT,NULL_UNSPECIFIED_BY_DEFAULT,NONNULL_BY_DEFAULT} + protected int defaultNullness = NO_NULL_DEFAULT; protected PackageBinding() { // for creating problem package @@ -297,12 +299,6 @@ void checkIfNullAnnotationType(ReferenceBinding type) { } } -public TypeBinding getNullnessDefaultAnnotation(Scope scope) { - if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding) - return this.nullnessDefaultAnnotation = this.environment.getNullAnnotationResolved(this.nullnessDefaultAnnotation, scope); - return this.nullnessDefaultAnnotation; -} - public char[] readableName() /*java.lang*/ { return CharOperation.concatWith(this.compoundName, '.'); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java index 22e8ec920..fe876d5c6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java @@ -14,6 +14,7 @@ * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * 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; @@ -101,14 +102,6 @@ abstract public class ReferenceBinding extends AbstractOTReferenceBinding { public boolean hasTypeBit(int bit) { return false; } }; - /** - * This faked annotation type binding marks types with unspecified nullness. - * For use in {@link PackageBinding#nullnessDefaultAnnotation} and SourceTypeBinding#nullnessDefaultAnnotation - */ - final static ReferenceBinding NULL_UNSPECIFIED = new ReferenceBinding() { /* faked type binding */ - public boolean hasTypeBit(int bit) { return false; } - }; - private static final Comparator FIELD_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { char[] n1 = ((FieldBinding) o1).name; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java index 07d1434a1..dc57ce771 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -16,6 +16,8 @@ * bug 365836 - [compiler][null] Incomplete propagation of null defaults. * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * bug 365662 - [compiler][null] warn on contradictory and redundant null annotations + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults + * bug 366063 - Compiler should not add synthetic @NonNull annotations *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -107,8 +109,6 @@ public class SourceTypeBinding extends ReferenceBinding { // SH} public ClassScope scope; - public int fieldAnalysisOffset; // an offset for ids of fields of this class (id to be used for flow analysis) - public int cumulativeFieldCount; // cumulative field count from all enclosing types, used to build unique field id's for member types. // Synthetics are separated into 4 categories: methods, super methods, fields, class literals and bridge methods // if a new category is added, also increment MAX_SYNTHETICS @@ -139,7 +139,7 @@ public class SourceTypeBinding extends ReferenceBinding { private SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder - private TypeBinding nullnessDefaultAnnotation; + private int defaultNullness; private int nullnessDefaultInitialized = 0; // 0: nothing; 1: type; 2: package public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) { @@ -158,7 +158,6 @@ public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassSc // SH} this.sourceName = scope.referenceContext.name; this.scope = scope; - this.cumulativeFieldCount = 0; //{ObjectTeams: ROFI create a package binding for our role files (if any): maybeSetTeamPackage(compoundName, fPackage, scope.environment()); // SH} @@ -2376,9 +2375,9 @@ private void createArgumentBindings(MethodBinding method) { if (methodDecl != null) { if (method.parameters != Binding.NO_PARAMETERS) methodDecl.createArgumentBindings(); - TypeBinding annotationBinding = findDefaultNullness(methodDecl.scope, methodDecl.scope.environment()); - if (annotationBinding != null && annotationBinding.id == TypeIds.T_ConfiguredAnnotationNonNull) - method.fillInDefaultNonNullness(annotationBinding); + if ((findNonNullDefault(methodDecl.scope, methodDecl.scope.environment()) == NONNULL_BY_DEFAULT)) { + method.fillInDefaultNonNullness(); + } } } private void evaluateNullAnnotations(long annotationTagBits) { @@ -2386,18 +2385,16 @@ private void evaluateNullAnnotations(long annotationTagBits) { return; this.nullnessDefaultInitialized = 1; // transfer nullness info from tagBits to this.nullnessDefaultAnnotation - TypeBinding defaultAnnotation = getPackage().environment - .getNullAnnotationBindingFromDefault(annotationTagBits, false/*resolve*/); - if (defaultAnnotation != null) { + int newDefaultNullness = NO_NULL_DEFAULT; + if ((annotationTagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0) + newDefaultNullness = NULL_UNSPECIFIED_BY_DEFAULT; + else if ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0) + newDefaultNullness = NONNULL_BY_DEFAULT; + if (newDefaultNullness != NO_NULL_DEFAULT) { if (CharOperation.equals(this.sourceName, TypeConstants.PACKAGE_INFO_NAME)) { - getPackage().nullnessDefaultAnnotation = defaultAnnotation; - long globalDefault = this.scope.compilerOptions().defaultNonNullness; - if (globalDefault == TagBits.AnnotationNonNull && (annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0) { - TypeDeclaration typeDecl = this.scope.referenceContext; - this.scope.problemReporter().nullDefaultAnnotationIsRedundant(typeDecl, typeDecl.annotations, null); - } + getPackage().defaultNullness = newDefaultNullness; } else { - this.nullnessDefaultAnnotation = defaultAnnotation; + this.defaultNullness = newDefaultNullness; TypeDeclaration typeDecl = this.scope.referenceContext; long nullDefaultBits = annotationTagBits & (TagBits.AnnotationNullUnspecifiedByDefault|TagBits.AnnotationNonNullByDefault); checkRedundantNullnessDefaultRecurse(typeDecl, typeDecl.annotations, nullDefaultBits); @@ -2406,25 +2403,20 @@ private void evaluateNullAnnotations(long annotationTagBits) { } protected void checkRedundantNullnessDefaultRecurse(ASTNode location, Annotation[] annotations, long annotationTagBits) { - if (this.fPackage.nullnessDefaultAnnotation != null) { - if ((this.fPackage.nullnessDefaultAnnotation.id == TypeIds.T_ConfiguredAnnotationNonNull + if (this.fPackage.defaultNullness != NO_NULL_DEFAULT) { + if ((this.fPackage.defaultNullness == NONNULL_BY_DEFAULT && ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0))) { this.scope.problemReporter().nullDefaultAnnotationIsRedundant(location, annotations, this.fPackage); } return; } - long globalDefault = this.scope.compilerOptions().defaultNonNullness; - if (globalDefault == TagBits.AnnotationNonNull && annotationTagBits == TagBits.AnnotationNonNullByDefault) { - this.scope.problemReporter().nullDefaultAnnotationIsRedundant(location, annotations, null); - } } // return: should caller continue searching? protected boolean checkRedundantNullnessDefaultOne(ASTNode location, Annotation[] annotations, long annotationTagBits) { - TypeBinding thisDefault = this.nullnessDefaultAnnotation; - if (thisDefault != null) { - if (thisDefault.id == TypeIds.T_ConfiguredAnnotationNonNull - && ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0)) { + int thisDefault = this.defaultNullness; + if (thisDefault == NONNULL_BY_DEFAULT) { + if ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0) { this.scope.problemReporter().nullDefaultAnnotationIsRedundant(location, annotations, this); } return false; // different default means inner default is not redundant -> we're done @@ -2432,42 +2424,35 @@ protected boolean checkRedundantNullnessDefaultOne(ASTNode location, Annotation[ return true; } -private TypeBinding getNullnessDefaultAnnotation() { - if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding) - this.nullnessDefaultAnnotation = this.scope.environment().getNullAnnotationResolved(this.nullnessDefaultAnnotation, this.scope); - return this.nullnessDefaultAnnotation; -} /** * Answer the nullness default applicable at the given method binding. - * Possible values:<ul> - * <li>the type binding for @NonNulByDefault</li> - * <li>the synthetic type {@link ReferenceBinding#NULL_UNSPECIFIED} if a default from outer scope has been canceled</li> - * <li>null if no default has been defined</li> - * </ul> + * Possible values: {@link Binding#NO_NULL_DEFAULT}, {@link Binding#NULL_UNSPECIFIED_BY_DEFAULT}, {@link Binding#NONNULL_BY_DEFAULT}. * @param currentScope where to start search for lexically enclosing default - * @param environment gateway to options and configured annotation types + * @param environment gateway to options */ -private TypeBinding findDefaultNullness(Scope currentScope, LookupEnvironment environment) { +private int findNonNullDefault(Scope currentScope, LookupEnvironment environment) { // find the applicable default inside->out: SourceTypeBinding currentType = null; - TypeBinding annotationBinding; while (currentScope != null) { switch (currentScope.kind) { case Scope.METHOD_SCOPE: AbstractMethodDeclaration referenceMethod = ((MethodScope)currentScope).referenceMethod(); if (referenceMethod != null && referenceMethod.binding != null) { - annotationBinding = environment.getNullAnnotationBindingFromDefault(referenceMethod.binding.tagBits, true/*resolve*/); - if (annotationBinding != null) - return annotationBinding; + long methodTagBits = referenceMethod.binding.tagBits; + if ((methodTagBits & TagBits.AnnotationNonNullByDefault) != 0) + return NONNULL_BY_DEFAULT; + if ((methodTagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0) + return NULL_UNSPECIFIED_BY_DEFAULT; } break; case Scope.CLASS_SCOPE: currentType = ((ClassScope)currentScope).referenceContext.binding; if (currentType != null) { - annotationBinding = currentType.getNullnessDefaultAnnotation(); - if (annotationBinding != null) - return annotationBinding; + int foundDefaultNullness = currentType.defaultNullness; + if (foundDefaultNullness != NO_NULL_DEFAULT) { + return foundDefaultNullness; + } } break; } @@ -2476,28 +2461,13 @@ private TypeBinding findDefaultNullness(Scope currentScope, LookupEnvironment en // package if (currentType != null) { - annotationBinding = currentType.getPackage().getNullnessDefaultAnnotation(this.scope); - if (annotationBinding != null) - return annotationBinding; - } - - // global - long defaultNullness = environment.globalOptions.defaultNonNullness; - if (defaultNullness != 0) { - // we have a default, so we need an annotation type to record this during compile and in the byte code - annotationBinding = environment.getNullAnnotationBinding(defaultNullness, true/*resolve*/); - if (annotationBinding != null) - return annotationBinding; - - // on this branch default was not defined using an annotation, thus annotation type can still be missing - if (defaultNullness == TagBits.AnnotationNonNull) - this.scope.problemReporter().missingNullAnnotationType(environment.getNonNullAnnotationName()); - else - this.scope.problemReporter().abortDueToInternalError("Illegal default nullness value: "+defaultNullness); //$NON-NLS-1$ - // reset default to avoid duplicate errors: - environment.globalOptions.defaultNonNullness = 0; + int foundDefaultNullness = currentType.getPackage().defaultNullness; + if (foundDefaultNullness != NO_NULL_DEFAULT) { + return foundDefaultNullness; + } } - return null; + + return NO_NULL_DEFAULT; } //{ObjectTeams: helper to find args allowing baseclass decapsulation: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java index ae9a80904..d11f88d6c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java @@ -60,10 +60,6 @@ public abstract class VariableBinding return this.constant; } - public int getAnalysisId(int maxFieldCount) { - return this.id + maxFieldCount; - } - public abstract AnnotationBinding[] getAnnotations(); public final boolean isBlankFinal(){ |