diff options
| author | Stephan Herrmann | 2014-07-14 10:40:07 +0000 |
|---|---|---|
| committer | Stephan Herrmann | 2014-07-22 12:37:56 +0000 |
| commit | 63231f253dc3aaae18caf57a7f77da85f8cefe96 (patch) | |
| tree | 732498dc8eac297112c1c4960944922be823d6b9 | |
| parent | b1c69f20f23ddb575225e5b5cb5d470714f41aad (diff) | |
| download | eclipse.jdt.core-63231f253dc3aaae18caf57a7f77da85f8cefe96.tar.gz eclipse.jdt.core-63231f253dc3aaae18caf57a7f77da85f8cefe96.tar.xz eclipse.jdt.core-63231f253dc3aaae18caf57a7f77da85f8cefe96.zip | |
Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit
type bound of binary type
5 files changed, 64 insertions, 23 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java index 376b52deb0..ae505e794e 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java @@ -5383,6 +5383,31 @@ public void testTypeVariable7err() { "Null type safety (type annotations): The expression of type \'String\' needs unchecked conversion to conform to \'@NonNull String\'\n" + "----------\n"); } +// Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type +public void testTypeVariable10() { + runConformTestWithLibs( + new String[] { + "X.java", + "@org.eclipse.jdt.annotation.NonNullByDefault\n" + + "public class X<T> {\n" + + " void test(T t) {}\n" + + "}\n" + }, + getCompilerOptions(), + ""); + runConformTestWithLibs( + false, + new String[] { + "Y.java", + "public class Y {\n" + + " void foo(X<@org.eclipse.jdt.annotation.Nullable String> xs) {\n" + + " xs.test(null);\n" + + " }\n" + + "}\n" + }, + getCompilerOptions(), + ""); +} public void testBug434600() { runConformTestWithLibs( new String[] { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java index fd8105b6b2..cac02c8e7c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java @@ -16,6 +16,7 @@ import org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair; import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; /** * A type annotation walker that adds missing NonNull annotations according to the current default. @@ -25,6 +26,8 @@ public class NonNullDefaultAwareTypeAnnotationWalker extends TypeAnnotationWalke private int defaultNullness; private boolean atDefaultLocation; private boolean nextIsDefaultLocation; + private boolean atTypeBound; + private boolean nextIsTypeBound; private boolean isEmpty; IBinaryAnnotation nonNullAnnotation; @@ -38,24 +41,26 @@ public class NonNullDefaultAwareTypeAnnotationWalker extends TypeAnnotationWalke /** Create an initial walker without 'real' type annotations, but with a nonnull default. */ public NonNullDefaultAwareTypeAnnotationWalker(int defaultNullness, LookupEnvironment environment) { - this(defaultNullness, getNonNullAnnotation(environment), false); + this(defaultNullness, getNonNullAnnotation(environment), false, false); } /** Get restricted walker, still with non-empty type annotations. */ NonNullDefaultAwareTypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations, long newMatches, int newPathPtr, - int defaultNullness, IBinaryAnnotation nonNullAnnotation, boolean atDefaultLocation) { + int defaultNullness, IBinaryAnnotation nonNullAnnotation, boolean atDefaultLocation, boolean atTypeBound) { super(typeAnnotations, newMatches, newPathPtr); this.defaultNullness = defaultNullness; this.nonNullAnnotation = nonNullAnnotation; this.atDefaultLocation = atDefaultLocation; + this.atTypeBound = atTypeBound; } /** Create a restricted walker without 'real' type annotations, but with a nonnull default. */ - NonNullDefaultAwareTypeAnnotationWalker(int defaultNullness, IBinaryAnnotation nonNullAnnotation, boolean atDefaultLocation) { + NonNullDefaultAwareTypeAnnotationWalker(int defaultNullness, IBinaryAnnotation nonNullAnnotation, boolean atDefaultLocation, boolean atTypeBound) { super(null, 0, 0); this.nonNullAnnotation = nonNullAnnotation; this.defaultNullness = defaultNullness; this.atDefaultLocation = atDefaultLocation; + this.atTypeBound = atTypeBound; this.isEmpty = true; } @@ -79,16 +84,19 @@ public class NonNullDefaultAwareTypeAnnotationWalker extends TypeAnnotationWalke // considers nextIsDefaultLocation as the new atDefaultLocation try { // do we have any change at all? - if (this.matches == newMatches && this.pathPtr == newPathPtr && this.atDefaultLocation == this.nextIsDefaultLocation) + if (this.matches == newMatches && this.pathPtr == newPathPtr + && this.atDefaultLocation == this.nextIsDefaultLocation && this.atTypeBound == this.nextIsTypeBound) return this; // are we running out of real type annotations? if (newMatches == 0 || this.typeAnnotations == null || this.typeAnnotations.length == 0) - return new NonNullDefaultAwareTypeAnnotationWalker(this.defaultNullness, this.nonNullAnnotation, this.nextIsDefaultLocation); + return new NonNullDefaultAwareTypeAnnotationWalker(this.defaultNullness, this.nonNullAnnotation, + this.nextIsDefaultLocation, this.nextIsTypeBound); // proceed as normal, but pass on our specific fields, too: return new NonNullDefaultAwareTypeAnnotationWalker(this.typeAnnotations, newMatches, newPathPtr, - this.defaultNullness, this.nonNullAnnotation, this.nextIsDefaultLocation); + this.defaultNullness, this.nonNullAnnotation, this.nextIsDefaultLocation, this.nextIsTypeBound); } finally { this.nextIsDefaultLocation = false; // expire + this.nextIsTypeBound = false; } } @@ -109,6 +117,7 @@ public class NonNullDefaultAwareTypeAnnotationWalker extends TypeAnnotationWalke @Override public TypeAnnotationWalker toTypeBound(short boundIndex) { this.nextIsDefaultLocation = (this.defaultNullness & Binding.DefaultLocationTypeBound) != 0; + this.nextIsTypeBound = true; if (this.isEmpty) return restrict(this.matches, this.pathPtr); return super.toTypeBound(boundIndex); } @@ -116,6 +125,7 @@ public class NonNullDefaultAwareTypeAnnotationWalker extends TypeAnnotationWalke @Override public TypeAnnotationWalker toTypeParameterBounds(boolean isClassTypeParameter, int parameterRank) { this.nextIsDefaultLocation = (this.defaultNullness & Binding.DefaultLocationTypeBound) != 0; + this.nextIsTypeBound = true; if (this.isEmpty) return restrict(this.matches, this.pathPtr); return super.toTypeParameterBounds(isClassTypeParameter, parameterRank); } @@ -123,6 +133,7 @@ public class NonNullDefaultAwareTypeAnnotationWalker extends TypeAnnotationWalke @Override public TypeAnnotationWalker toTypeArgument(int rank) { this.nextIsDefaultLocation = (this.defaultNullness & Binding.DefaultLocationTypeArgument) != 0; + this.nextIsTypeBound = false; if (this.isEmpty) return restrict(this.matches, this.pathPtr); return super.toTypeArgument(rank); } @@ -130,14 +141,17 @@ public class NonNullDefaultAwareTypeAnnotationWalker extends TypeAnnotationWalke @Override public TypeAnnotationWalker toTypeParameter(boolean isClassTypeParameter, int rank) { this.nextIsDefaultLocation = (this.defaultNullness & Binding.DefaultLocationTypeParameter) != 0; + this.nextIsTypeBound = false; if (this.isEmpty) return restrict(this.matches, this.pathPtr); return super.toTypeParameter(isClassTypeParameter, rank); } @Override - public IBinaryAnnotation[] getAnnotationsAtCursor() { - IBinaryAnnotation[] normalAnnotations = this.isEmpty ? null : super.getAnnotationsAtCursor(); - if (this.atDefaultLocation) { + public IBinaryAnnotation[] getAnnotationsAtCursor(int currentTypeId) { + IBinaryAnnotation[] normalAnnotations = this.isEmpty ? null : super.getAnnotationsAtCursor(currentTypeId); + if (this.atDefaultLocation && + !(this.atTypeBound && currentTypeId == TypeIds.T_JavaLangObject)) // for CLIMB-to-top consider a j.l.Object type bound as no explicit type bound + { if (normalAnnotations == null || normalAnnotations.length == 0) return new IBinaryAnnotation[] { this.nonNullAnnotation }; int len = normalAnnotations.length; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java index 9f189b7cf4..3e525b7879 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java @@ -41,7 +41,7 @@ public class TypeAnnotationWalker { public TypeAnnotationWalker toTypeBound(short boundIndex) { return this; } public TypeAnnotationWalker toTypeParameter(boolean isClassTypeParameter, int rank) { return this; } public TypeAnnotationWalker toNextDetail(int detailKind) { return this; } - public IBinaryAnnotation[] getAnnotationsAtCursor() { return NO_ANNOTATIONS; } + public IBinaryAnnotation[] getAnnotationsAtCursor(int currentTypeId) { return NO_ANNOTATIONS; } }; final protected IBinaryTypeAnnotation[] typeAnnotations; // the actual material we're managing here @@ -298,7 +298,7 @@ public class TypeAnnotationWalker { * Retrieve the type annotations at the current position * reached by invocations of toXYZ() methods. */ - public IBinaryAnnotation[] getAnnotationsAtCursor() { + public IBinaryAnnotation[] getAnnotationsAtCursor(int currentTypeId) { int length = this.typeAnnotations.length; IBinaryAnnotation[] filtered = new IBinaryAnnotation[length]; long ptr = 1; 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 bfe7fcb74d..b6ed2c8c94 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 @@ -27,6 +27,7 @@ * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault * Bug 390889 - [1.8][compiler] Evaluate options to support 1.7- projects against 1.8 JRE. * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables + * Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type * Jesper Steen Moller - Contributions for * Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable @@ -744,7 +745,7 @@ private MethodBinding createMethod(IBinaryMethod method, long sourceLevel, char[ ? new MethodBinding(methodModifiers, parameters, exceptions, this) : new MethodBinding(methodModifiers, method.getSelector(), returnType, parameters, exceptions, this); - IBinaryAnnotation[] receiverAnnotations = walker.toReceiver().getAnnotationsAtCursor(); + IBinaryAnnotation[] receiverAnnotations = walker.toReceiver().getAnnotationsAtCursor(0); if (receiverAnnotations != null && receiverAnnotations.length > 0) { result.receiver = this.environment.createAnnotatedType(this, createAnnotations(receiverAnnotations, this.environment, missingTypeNames)); } @@ -753,7 +754,7 @@ private MethodBinding createMethod(IBinaryMethod method, long sourceLevel, char[ IBinaryAnnotation[] annotations = method.getAnnotations(); if (annotations == null || annotations.length == 0) if (method.isConstructor()) - annotations = walker.toMethodReturn().getAnnotationsAtCursor(); // FIXME: When both exist, order could become an issue. + annotations = walker.toMethodReturn().getAnnotationsAtCursor(0); // FIXME: When both exist, order could become an issue. result.setAnnotations( createAnnotations(annotations, this.environment, missingTypeNames), paramAnnotations, @@ -865,7 +866,7 @@ private TypeVariableBinding[] createTypeVariables(SignatureWrapper wrapper, bool int colon = CharOperation.indexOf(Util.C_COLON, typeSignature, i); char[] variableName = CharOperation.subarray(typeSignature, i, colon); TypeVariableBinding typeVariable = new TypeVariableBinding(variableName, this, rank, this.environment); - AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.toTypeParameter(isClassTypeParameter, rank++).getAnnotationsAtCursor(), + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.toTypeParameter(isClassTypeParameter, rank++).getAnnotationsAtCursor(0), this.environment, missingTypeNames); if (annotations != null && annotations != Binding.NO_ANNOTATIONS) typeVariable.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); 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 a2420003ea..5fe450c9c5 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 @@ -25,6 +25,7 @@ * Bug 416190 - [1.8][null] detect incompatible overrides due to null type annotations * Bug 424624 - [1.8][null] if a static-object with annotation @NonNull is used, a warning is shown * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables + * Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -1257,7 +1258,7 @@ TypeBinding getTypeFromSignature(char[] signature, int start, int end, boolean i AnnotationBinding [][] annotationsOnDimensions = null; if (dimension > 0 && walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { for (int i = 0; i < dimension; i++) { - AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0), this, missingTypeNames); if (annotations != Binding.NO_ANNOTATIONS) { if (annotationsOnDimensions == null) annotationsOnDimensions = new AnnotationBinding[dimension][]; @@ -1342,7 +1343,7 @@ private TypeBinding annotateType(TypeBinding binding, TypeAnnotationWalker walke } AnnotationBinding [][] annotations = null; for (int i = 0; i < depth; i++) { - AnnotationBinding[] annots = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + AnnotationBinding[] annots = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(binding.id), this, missingTypeNames); if (annots != null && annots.length > 0) { if (annotations == null) annotations = new AnnotationBinding[depth][]; @@ -1387,7 +1388,7 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab AnnotationBinding [][] annotationsOnDimensions = null; if (dimension > 0 && walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { for (int i = 0; i < dimension; i++) { - AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0), this, missingTypeNames); if (annotations != Binding.NO_ANNOTATIONS) { if (annotationsOnDimensions == null) annotationsOnDimensions = new AnnotationBinding[dimension][]; @@ -1432,7 +1433,7 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab if (actualEnclosing != null) { // convert needed if read some static member type actualEnclosing = (ReferenceBinding) convertToRawType(actualEnclosing, false /*do not force conversion of enclosing types*/); } - AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(actualType.id), this, missingTypeNames); TypeBinding[] typeArguments = getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, actualType, missingTypeNames, walker); ParameterizedTypeBinding parameterizedType = createParameterizedType(actualType, typeArguments, actualEnclosing, annotations); @@ -1446,7 +1447,7 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab if (memberType == null) this.problemReporter.corruptedSignature(parameterizedType, wrapper.signature, memberStart); // aborts walker = walker.toNextNestedType(); - annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(memberType.id), this, missingTypeNames); if (wrapper.signature[wrapper.start] == '<') { wrapper.start++; // skip '<' typeArguments = getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, memberType, missingTypeNames, walker); @@ -1460,7 +1461,7 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab } private TypeBinding getTypeFromTypeVariable(TypeVariableBinding typeVariableBinding, int dimension, AnnotationBinding [][] annotationsOnDimensions, TypeAnnotationWalker walker, char [][][] missingTypeNames) { - AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0), this, missingTypeNames); if (annotations != null && annotations != Binding.NO_ANNOTATIONS) typeVariableBinding = (TypeVariableBinding) createAnnotatedType(typeVariableBinding, new AnnotationBinding [][] { annotations }); @@ -1487,18 +1488,18 @@ TypeBinding getTypeFromVariantTypeSignature( // ? super aType wrapper.start++; TypeBinding bound = getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames, walker.toWildcardBound()); - AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0), this, missingTypeNames); return this.typeSystem.getWildcard(genericType, rank, bound, null /*no extra bound*/, Wildcard.SUPER, annotations); case '+' : // ? extends aType wrapper.start++; bound = getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames, walker.toWildcardBound()); - annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0), this, missingTypeNames); return this.typeSystem.getWildcard(genericType, rank, bound, null /*no extra bound*/, Wildcard.EXTENDS, annotations); case '*' : // ? wrapper.start++; - annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0), this, missingTypeNames); return this.typeSystem.getWildcard(genericType, rank, null, null /*no extra bound*/, Wildcard.UNBOUND, annotations); default : return getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames, walker); |
