diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
index fc21f6d..fc4d329 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
@@ -1915,7 +1915,7 @@
"Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" +
"----------\n");
}
-// package level default is consumed from package-info.class
+// package level default is consumed from package-info.class, similarly for type level default
public void test_default_nullness_003a() {
Map customOptions = getCompilerOptions();
// customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR);
@@ -1972,6 +1972,69 @@
"Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" +
"----------\n");
}
+// same as test_default_nullness_003b, but default-induced annotations are combined with explicit ones (not null related)
+public void test_default_nullness_003b() {
+ Map customOptions = getCompilerOptions();
+ runConformTestWithLibs(
+ new String[] {
+ "p1/Annot.java",
+ "package p1;\n" +
+ "import static java.lang.annotation.ElementType.*;\n" +
+ "import java.lang.annotation.*;\n" +
+ "@Retention(RetentionPolicy.CLASS)\n" +
+ "@Target({METHOD,PARAMETER})\n" +
+ "public @interface Annot {}\n",
+ "p1/X.java",
+ "package p1;\n" +
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "@NonNullByDefault\n" +
+ "public class X {\n" +
+ " protected @Annot Object getObject(@Annot @Nullable Object o) {\n" +
+ " return new Object();\n" +
+ " }\n" +
+ " protected @Annot void bar(@Annot Object o2) { }\n" + // parameter is nonnull per type default
+ "}\n",
+ "p2/package-info.java",
+ "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "package p2;\n",
+ },
+ customOptions,
+ "");
+ // check if default is visible from package-info.class.
+ runNegativeTestWithLibs(
+ false, // don't flush
+ new String[] {
+ "p2/Y.java",
+ "package p2;\n" +
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "public class Y extends p1.X {\n" +
+ " @Override\n" +
+ " protected @Nullable Object getObject(@Nullable Object o) {\n" + // can't override inherited default nonnull
+ " bar(o);\n" + // parameter is nonnull in super class's .class file
+ " accept(o);\n" +
+ " return o;\n" +
+ " }\n" +
+ " void accept(@p1.Annot Object a) {}\n" + // governed by package level default
+ "}\n"
+ },
+ customOptions,
+ "----------\n" +
+ "1. ERROR in p2\\Y.java (at line 5)\n" +
+ " protected @Nullable Object getObject(@Nullable Object o) {\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "The return type is incompatible with the @NonNull return from X.getObject(Object)\n" +
+ "----------\n" +
+ "2. ERROR in p2\\Y.java (at line 6)\n" +
+ " bar(o);\n" +
+ " ^\n" +
+ "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" +
+ "----------\n" +
+ "3. ERROR in p2\\Y.java (at line 7)\n" +
+ " accept(o);\n" +
+ " ^\n" +
+ "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" +
+ "----------\n");
+}
// don't apply type-level default to non-reference type
public void test_default_nullness_004() {
Map customOptions = getCompilerOptions();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
index 5035d83..9deaade 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
@@ -53,6 +53,7 @@
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.StringConstant;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
@@ -324,7 +325,7 @@
if (typeDeclaration != null) {
final Annotation[] annotations = typeDeclaration.annotations;
if (annotations != null) {
- attributesNumber += generateRuntimeAnnotations(annotations);
+ attributesNumber += generateRuntimeAnnotations(annotations, 0);
}
}
}
@@ -413,7 +414,7 @@
if (fieldDeclaration != null) {
Annotation[] annotations = fieldDeclaration.annotations;
if (annotations != null) {
- attributesNumber += generateRuntimeAnnotations(annotations);
+ attributesNumber += generateRuntimeAnnotations(annotations, 0);
}
}
}
@@ -2683,8 +2684,9 @@
AbstractMethodDeclaration methodDeclaration = methodBinding.sourceMethod();
if (methodDeclaration != null) {
Annotation[] annotations = methodDeclaration.annotations;
- if (annotations != null) {
- attributesNumber += generateRuntimeAnnotations(annotations);
+ int modifiers = methodBinding.modifiers;
+ if (annotations != null || (modifiers & ExtraCompilerModifiers.AccImplicitlyNonNull) != 0) {
+ attributesNumber += generateRuntimeAnnotations(annotations, methodBinding.modifiers);
}
if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) {
Argument[] arguments = methodDeclaration.arguments;
@@ -2868,23 +2870,53 @@
}
}
+ private int generateNonNullAttribute() {
+ TypeBinding nonNullAnnotation;
+ try {
+ nonNullAnnotation = this.referenceBinding.fPackage.environment.getNullAnnotationBinding(TagBits.AnnotationNonNull, true);
+ } catch (NullPointerException npe) {
+ return 0; // above chain of dereferencing is quite long, difficult to analyse if all are safe
+ }
+ int localContentsOffset = this.contentsOffset;
+ if (localContentsOffset + 6 >= this.contents.length) {
+ resizeContents(6);
+ }
+ int nonNullAttributeNameIndex = this.constantPool.literalIndex(nonNullAnnotation);
+ this.contents[localContentsOffset++] = (byte) (nonNullAttributeNameIndex >> 8);
+ this.contents[localContentsOffset++] = (byte) nonNullAttributeNameIndex;
+ // the length of a nonNull attribute is equals to 0
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contents[localContentsOffset++] = 0;
+ this.contentsOffset = localContentsOffset;
+ return 1;
+ }
+
/**
* @param annotations
+ * @param modifiers modifiers that could trigger generating an implicit annotation
* @return the number of attributes created while dumping the annotations in the .class file
*/
- private int generateRuntimeAnnotations(final Annotation[] annotations) {
+ private int generateRuntimeAnnotations(final Annotation[] annotations, int modifiers) {
int attributesNumber = 0;
- final int length = annotations.length;
int visibleAnnotationsCounter = 0;
int invisibleAnnotationsCounter = 0;
-
- for (int i = 0; i < length; i++) {
- Annotation annotation = annotations[i];
- if (annotation.isRuntimeInvisible()) {
- invisibleAnnotationsCounter++;
- } else if (annotation.isRuntimeVisible()) {
- visibleAnnotationsCounter++;
+
+ if (annotations != null) {
+ final int length = annotations.length;
+ for (int i = 0; i < length; i++) {
+ Annotation annotation = annotations[i];
+ if (annotation.isRuntimeInvisible()) {
+ invisibleAnnotationsCounter++;
+ } else if (annotation.isRuntimeVisible()) {
+ visibleAnnotationsCounter++;
+ }
}
+ }
+ boolean isImplicitlyNonNull = (modifiers & ExtraCompilerModifiers.AccImplicitlyNonNull) != 0;
+ if (isImplicitlyNonNull) {
+ visibleAnnotationsCounter++;
}
int annotationAttributeOffset = this.contentsOffset;
@@ -2905,15 +2937,18 @@
this.contentsOffset += 2; // leave space for the annotations length
int counter = 0;
- loop: for (int i = 0; i < length; i++) {
- if (invisibleAnnotationsCounter == 0) break loop;
- Annotation annotation = annotations[i];
- if (annotation.isRuntimeInvisible()) {
- int currentAnnotationOffset = this.contentsOffset;
- generateAnnotation(annotation, currentAnnotationOffset);
- invisibleAnnotationsCounter--;
- if (this.contentsOffset != currentAnnotationOffset) {
- counter++;
+ if (annotations != null) {
+ final int length = annotations.length;
+ loop: for (int i = 0; i < length; i++) {
+ if (invisibleAnnotationsCounter == 0) break loop;
+ Annotation annotation = annotations[i];
+ if (annotation.isRuntimeInvisible()) {
+ int currentAnnotationOffset = this.contentsOffset;
+ generateAnnotation(annotation, currentAnnotationOffset);
+ invisibleAnnotationsCounter--;
+ if (this.contentsOffset != currentAnnotationOffset) {
+ counter++;
+ }
}
}
}
@@ -2952,15 +2987,22 @@
this.contentsOffset += 2; // leave space for the annotations length
int counter = 0;
- loop: for (int i = 0; i < length; i++) {
- if (visibleAnnotationsCounter == 0) break loop;
- Annotation annotation = annotations[i];
- if (annotation.isRuntimeVisible()) {
- visibleAnnotationsCounter--;
- int currentAnnotationOffset = this.contentsOffset;
- generateAnnotation(annotation, currentAnnotationOffset);
- if (this.contentsOffset != currentAnnotationOffset) {
- counter++;
+ if (isImplicitlyNonNull) {
+ counter += generateNonNullAttribute();
+ visibleAnnotationsCounter--;
+ }
+ if (annotations != null) {
+ final int length = annotations.length;
+ loop: for (int i = 0; i < length; i++) {
+ if (visibleAnnotationsCounter == 0) break loop;
+ Annotation annotation = annotations[i];
+ if (annotation.isRuntimeVisible()) {
+ visibleAnnotationsCounter--;
+ int currentAnnotationOffset = this.contentsOffset;
+ generateAnnotation(annotation, currentAnnotationOffset);
+ if (this.contentsOffset != currentAnnotationOffset) {
+ counter++;
+ }
}
}
}
@@ -3002,6 +3044,9 @@
visibleParametersAnnotationsCounter++;
}
}
+ }
+ if ((argument.binding.modifiers & ExtraCompilerModifiers.AccImplicitlyNonNull) != 0) {
+ visibleParametersAnnotationsCounter++;
}
}
int attributesNumber = 0;
@@ -3085,13 +3130,13 @@
this.contents[this.contentsOffset++] = (byte) 0;
this.contents[this.contentsOffset++] = (byte) 0;
} else {
+ Argument argument = arguments[i];
final int numberOfVisibleAnnotations = annotationsCounters[i][VISIBLE_INDEX];
int visibleAnnotationsOffset = this.contentsOffset;
// leave space for number of annotations
this.contentsOffset += 2;
int counter = 0;
if (numberOfVisibleAnnotations != 0) {
- Argument argument = arguments[i];
Annotation[] annotations = argument.annotations;
for (int j = 0, max = annotations.length; j < max; j++) {
Annotation annotation = annotations[j];
@@ -3106,6 +3151,12 @@
}
}
}
+ if ((argument.binding.modifiers & ExtraCompilerModifiers.AccImplicitlyNonNull) != 0) {
+ int generated = generateNonNullAttribute();
+ counter+=generated;
+ globalCounter+=generated;
+ visibleParametersAnnotationsCounter--;
+ }
this.contents[visibleAnnotationsOffset++] = (byte) (counter >> 8);
this.contents[visibleAnnotationsOffset] = (byte) counter;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index 4cedddc..0795ad6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -256,8 +256,6 @@
// this is only used for method invocation as the expression inside an expression statement
public static final int InsideExpressionStatement = Bit5;
- // for annotation reference, signal if annotation was created from a default:
- public static final int IsSynthetic = ASTNode.Bit7;
// for name reference within a memberValuePair of an annotation:
public static final int IsMemberValueReference = ASTNode.Bit15;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
index f6d98fd..7af8bbd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
@@ -11,8 +11,6 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
-import java.util.Arrays;
-
import org.eclipse.jdt.core.compiler.*;
import org.eclipse.jdt.internal.compiler.*;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
@@ -69,42 +67,6 @@
default :
throw new AbortMethod(this.compilationResult, problem);
}
- }
-
- /**
- * Materialize a null annotation that has been added from the current default,
- * in order to ensure that this annotation will be generated into the .class file, too.
- */
- public void addNullnessAnnotation(ReferenceBinding annotationBinding) {
- this.annotations = addAnnotation(this, this.annotations, annotationBinding);
- }
-
- /**
- * Materialize a null parameter annotation that has been added from the current default,
- * in order to ensure that this annotation will be generated into the .class file, too.
- */
- public void addParameterNonNullAnnotation(int i, ReferenceBinding annotationBinding) {
- Argument argument = this.arguments[i];
- if (argument.type != null) // null happens for constructors of anonymous classes
- argument.annotations = addAnnotation(argument.type, argument.annotations, annotationBinding);
- }
-
- private Annotation[] addAnnotation(ASTNode location, Annotation[] oldAnnotations, ReferenceBinding annotationBinding) {
- long pos = ((long)location.sourceStart<<32) + location.sourceEnd;
- long[] poss = new long[annotationBinding.compoundName.length];
- Arrays.fill(poss, pos);
- MarkerAnnotation annotation = new MarkerAnnotation(new QualifiedTypeReference(annotationBinding.compoundName, poss), location.sourceStart);
- annotation.declarationSourceEnd = location.sourceEnd;
- annotation.resolvedType = annotationBinding;
- annotation.bits = IsSynthetic;
- if (oldAnnotations == null) {
- oldAnnotations = new Annotation[] {annotation};
- } else {
- int len = oldAnnotations.length;
- System.arraycopy(oldAnnotations, 0, oldAnnotations=new Annotation[len+1], 1, len);
- oldAnnotations[0] = annotation;
- }
- return oldAnnotations;
}
/**
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 4a1bad4..125a30c 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
@@ -1218,7 +1218,7 @@
IBinaryAnnotation[] annotations = binaryType.getAnnotations();
if (annotations != null) {
long annotationBit = 0L;
- TypeBinding defaultNullness = null;
+ int defaultNullness = NO_NULL_DEFAULT;
for (int i = 0; i < annotations.length; i++) {
char[] annotationTypeName = annotations[i].getTypeName();
if (annotationTypeName[0] != Util.C_RESOLVED)
@@ -1233,19 +1233,19 @@
{
// parameter is 'false': this means we cancel defaults from outer scopes:
annotationBit = TagBits.AnnotationNullUnspecifiedByDefault;
- defaultNullness = ReferenceBinding.NULL_UNSPECIFIED;
+ defaultNullness = NULL_UNSPECIFIED_BY_DEFAULT;
break;
}
}
annotationBit = TagBits.AnnotationNonNullByDefault;
- defaultNullness = this.environment.getNullAnnotationBinding(TagBits.AnnotationNonNull, false/*resolve*/);
+ defaultNullness = NONNULL_BY_DEFAULT;
break;
}
}
if (annotationBit != 0L) {
this.tagBits |= annotationBit;
if (CharOperation.equals(this.sourceName(), TypeConstants.PACKAGE_INFO_NAME))
- this.getPackage().nullnessDefaultAnnotation = defaultNullness;
+ this.getPackage().defaultNullness = defaultNullness;
}
}
}
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 d0e769e..3c32855 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
@@ -48,6 +48,11 @@
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/ExtraCompilerModifiers.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java
index 9927aaa..d2d4fe0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java
@@ -41,4 +41,5 @@
final int AccOverriding = ASTNode.Bit29; // record fact a method overrides another one
final int AccImplementing = ASTNode.Bit30; // record fact a method implements another one (it is concrete and overrides an abstract one)
final int AccGenericSignature = ASTNode.Bit31; // record fact a type/method/field involves generics in its signature (and need special signature attr)
+ final int AccImplicitlyNonNull = ASTNode.Bit32; // record fact that a method/argument should be seen as NonNull due to an applicable default
}
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 659ef81..b2a3ccf 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
@@ -1113,21 +1113,6 @@
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 (@NonNull
or @Nullable
)
- * or null
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;
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 0e1140d..84ca7ce 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
@@ -444,35 +444,30 @@
}
/**
- * 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();
for (int i = 0; i < this.parameterNonNullness.length; i++) {
if (this.parameters[i].isBaseType())
continue;
- boolean added = false;
if (this.parameterNonNullness[i] == null) {
- added = true;
this.parameterNonNullness[i] = Boolean.TRUE;
if (sourceMethod != null)
- sourceMethod.addParameterNonNullAnnotation(i, (ReferenceBinding)annotationBinding);
+ sourceMethod.arguments[i].binding.modifiers |= ExtraCompilerModifiers.AccImplicitlyNonNull;
+ this.tagBits |= TagBits.HasParameterAnnotations;
} else if (this.parameterNonNullness[i].booleanValue()) {
sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, i);
}
- if (added)
- this.tagBits |= TagBits.HasParameterAnnotations;
}
if ( this.returnType != null
&& !this.returnType.isBaseType()
&& (this.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0)
{
this.tagBits |= TagBits.AnnotationNonNull;
- if (sourceMethod != null)
- sourceMethod.addNullnessAnnotation((ReferenceBinding)annotationBinding);
+ this.modifiers |= ExtraCompilerModifiers.AccImplicitlyNonNull;
} 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 8d7c02d..965878b 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
@@ -24,8 +24,9 @@
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
@@ -267,22 +268,19 @@
if (this.environment.nullableAnnotationPackage == this
&& CharOperation.equals(type.compoundName, this.environment.getNullableAnnotationName())) {
type.id = TypeIds.T_ConfiguredAnnotationNullable;
- this.environment.nullableAnnotationPackage = null; // don't check again
+ if (!(type instanceof UnresolvedReferenceBinding)) // unresolved type will come back here
+ this.environment.nullableAnnotationPackage = null; // don't check again
} else if (this.environment.nonnullAnnotationPackage == this
&& CharOperation.equals(type.compoundName, this.environment.getNonNullAnnotationName())) {
type.id = TypeIds.T_ConfiguredAnnotationNonNull;
- this.environment.nonnullAnnotationPackage = null; // don't check again
+ if (!(type instanceof UnresolvedReferenceBinding)) // unresolved type will come back here
+ this.environment.nonnullAnnotationPackage = null; // don't check again
} else if (this.environment.nonnullByDefaultAnnotationPackage == this
&& CharOperation.equals(type.compoundName, this.environment.getNonNullByDefaultAnnotationName())) {
type.id = TypeIds.T_ConfiguredAnnotationNonNullByDefault;
- this.environment.nonnullByDefaultAnnotationPackage = null; // don't check again
+ if (!(type instanceof UnresolvedReferenceBinding)) // unresolved type will come back here
+ this.environment.nonnullByDefaultAnnotationPackage = null; // don't check again
}
-}
-
-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*/ {
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 75de854..5116382 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
@@ -50,14 +50,6 @@
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 094c155..faa5a51 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
@@ -56,7 +56,7 @@
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) {
@@ -1618,9 +1618,9 @@
if (methodDecl != null) {
if (method.parameters != Binding.NO_PARAMETERS)
methodDecl.createArgumentBindings();
- TypeBinding annotationBinding = findDefaultNullness(method, methodDecl.scope.environment());
- if (annotationBinding != null && annotationBinding.id == TypeIds.T_ConfiguredAnnotationNonNull)
- method.fillInDefaultNonNullness(annotationBinding);
+ if (hasNonNullDefault(method, methodDecl.scope.environment())) {
+ method.fillInDefaultNonNullness();
+ }
}
}
private void evaluateNullAnnotations(long annotationTagBits) {
@@ -1628,69 +1628,66 @@
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;
+ getPackage().defaultNullness = newDefaultNullness;
} else {
- this.nullnessDefaultAnnotation = defaultAnnotation;
+ this.defaultNullness = newDefaultNullness;
}
}
}
-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: