diff options
author | Stephan Herrmann | 2014-03-09 23:20:50 +0000 |
---|---|---|
committer | Stephan Herrmann | 2014-03-11 16:17:32 +0000 |
commit | dc444b8320482476925f9f5e1514794476164a28 (patch) | |
tree | 168bdca960fd7c53bcbf37a275ca95498324f4b3 | |
parent | c92099fc5b6f140409692775e015990a59416465 (diff) | |
download | eclipse.jdt.core-dc444b8320482476925f9f5e1514794476164a28.tar.gz eclipse.jdt.core-dc444b8320482476925f9f5e1514794476164a28.tar.xz eclipse.jdt.core-dc444b8320482476925f9f5e1514794476164a28.zip |
Bug 424624 - [1.8][null] if a static-object with annotation @NonNull is
used, a warning is shown
3 files changed, 278 insertions, 26 deletions
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 ba135b7e6b..44f66afb74 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 @@ -6821,4 +6821,172 @@ public void testBug420313() { "Missing non-null annotation: inherited method from UntypedBase specifies this parameter as @NonNull\n" + "----------\n"); } +// original test +public void testBug424624() { + runConformTestWithLibs( + new String[] { + "Test3.java", + "import org.eclipse.jdt.annotation.NonNull;\n" + + "\n" + + "public class Test3 {\n" + + "\n" + + " public Test3() {\n" + + " }\n" + + "\n" + + " static public class Test3aa extends Object {}\n" + + " static public final @NonNull Test3aa Test3a = new Test3aa();\n" + + "\n" + + "}\n", + }, + getCompilerOptions(), + ""); + runConformTestWithLibs( + new String[] { + "Test4.java", + "import org.eclipse.jdt.annotation.NonNull;\n" + + "\n" + + "public class Test4 {\n" + + "\n" + + " public Test4() {\n" + + " }\n" + + " \n" + + " public void test() {\n" + + " test1( Test3.Test3a);\n" + + " }\n" + + " \n" + + " public void test1( @NonNull Object object) {\n" + + " }\n" + + "\n" + + "}\n" + }, + getCompilerOptions(), + ""); +} +// other nesting levels, binary case +public void testBug424624a() { + runConformTestWithLibs( + new String[] { + "test/Test3.java", + "package test;\n" + + "import org.eclipse.jdt.annotation.NonNull;\n" + + (this.complianceLevel >= ClassFileConstants.JDK1_8 ? + "import java.lang.annotation.*;\n" + + "@Target(ElementType.TYPE_USE) @interface Marker {}\n" + : + "" + )+ + "\n" + + "public class Test3 {\n" + + "\n" + + " public Test3() {\n" + + " }\n" + + "\n" + + " public class Inner extends Object {\n" + + " class DeepInner {}\n" + + " }\n" + + " public static class Nested extends Object {\n" + + " class InnerInNested {}\n" + + " static class DeepNested {}\n" + + " }\n" + + " static public final @NonNull Inner field1 = new Test3().new Inner();\n" + + (this.complianceLevel < ClassFileConstants.JDK1_8 ? + " static public final @NonNull Inner.DeepInner field2 = field1.new DeepInner();\n" + + " static public final @NonNull Nested.InnerInNested field3 = new Nested().new InnerInNested();\n" + + " static public final @NonNull Nested.DeepNested field4 = new Nested.DeepNested();\n" + : + " static public final @Marker Inner.@NonNull DeepInner field2 = field1.new DeepInner();\n" + + " static public final Nested.@NonNull InnerInNested field3 = new Nested().new InnerInNested();\n" + + " static public final Nested.@NonNull DeepNested field4 = new Nested.DeepNested();\n" + ) + + "\n" + + "}\n", + }, + getCompilerOptions(), + ""); + runConformTestWithLibs( + new String[] { + "Test4.java", + "import org.eclipse.jdt.annotation.NonNull;\n" + + "import test.Test3;\n" + + "\n" + + "public class Test4 {\n" + + "\n" + + " public Test4() {\n" + + " }\n" + + " \n" + + " public void test() {\n" + + " test1( Test3.field1);\n" + + " test1( Test3.field2);\n" + + " test1( Test3.field3);\n" + + " test1( Test3.field4);\n" + + " }\n" + + " \n" + + " public void test1( @NonNull Object object) {\n" + + " }\n" + + "\n" + + "}\n" + }, + getCompilerOptions(), + ""); +} +// same as previous, source case for reference +public void testBug424624b() { + runConformTestWithLibs( + new String[] { + "Test3.java", + "import org.eclipse.jdt.annotation.NonNull;\n" + + (this.complianceLevel >= ClassFileConstants.JDK1_8 ? + "import java.lang.annotation.*;\n" + + "@Target(ElementType.TYPE_USE) @interface Marker {}\n" + : + "" + )+ + "\n" + + "public class Test3 {\n" + + "\n" + + " public Test3() {\n" + + " }\n" + + "\n" + + " public class Inner extends Object {\n" + + " class DeepInner {}\n" + + " }\n" + + " public static class Nested extends Object {\n" + + " class InnerInNested {}\n" + + " static class DeepNested {}\n" + + " }\n" + + " static public final @NonNull Inner field1 = new Test3().new Inner();\n" + + (this.complianceLevel < ClassFileConstants.JDK1_8 ? + " static public final @NonNull Inner.DeepInner field2 = field1.new DeepInner();\n" + + " static public final @NonNull Nested.InnerInNested field3 = new Nested().new InnerInNested();\n" + + " static public final @NonNull Nested.DeepNested field4 = new Nested.DeepNested();\n" + : + " static public final @Marker Inner.@NonNull DeepInner field2 = field1.new DeepInner();\n" + + " static public final Nested.@NonNull InnerInNested field3 = new Nested().new InnerInNested();\n" + + " static public final Nested.@NonNull DeepNested field4 = new Nested.DeepNested();\n" + ) + + "\n" + + "}\n", + "Test4.java", + "import org.eclipse.jdt.annotation.NonNull;\n" + + "\n" + + "public class Test4 {\n" + + "\n" + + " public Test4() {\n" + + " }\n" + + " \n" + + " public void test() {\n" + + " test1( Test3.field1);\n" + + " test1( Test3.field2);\n" + + " test1( Test3.field3);\n" + + " test1( Test3.field4);\n" + + " }\n" + + " \n" + + " public void test1( @NonNull Object object) {\n" + + " }\n" + + "\n" + + "}\n" + }, + getCompilerOptions(), + ""); +} } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java index 555c4dadfc..e7571a89af 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java @@ -2078,6 +2078,83 @@ public class TypeBindingTests308 extends ConverterTestSetup { removeLibrary(javaProject, jarName, srcName);
}
}
+ // Variants where superclass in binary is an annotated inner/nested class
+ public void testBinaryWithoutGenericSignature_b() throws CoreException, IOException {
+ String jarName = "TypeBindingTests308.jar";
+ String srcName = "TypeBindingTests308_src.zip";
+ final IJavaProject javaProject = getJavaProject("Converter18");
+ try {
+ String[] pathAndContents = new String[] {
+ "Superclass.java",
+ "import java.lang.annotation.ElementType;\n" +
+ "import java.lang.annotation.Target;\n" +
+ "@Target(ElementType.TYPE_USE)\n" +
+ "@interface T {\n" +
+ " int value() default 0;\n" +
+ "}\n" +
+ "@T(1)\n" +
+ "public abstract class Superclass extends @T(2) Object implements @T(3) Runnable {\n" +
+ " @T(9)\n" +
+ " Superclass () {}\n" +
+ " @T(10)\n" +
+ " class Inner {}\n" +
+ " @T(11)\n" +
+ " class SubInner extends @T(12) Inner {}\n" +
+ " @T(13)\n" +
+ " static class Nested {}\n" +
+ " @T(14)\n" +
+ " static class SubNested extends @T(15) Nested {}\n" +
+ "}\n"
+ };
+
+ HashMap libraryOptions = new HashMap(javaProject.getOptions(true));
+ libraryOptions.put(CompilerOptions.OPTION_Store_Annotations, CompilerOptions.ENABLED);
+ addLibrary(javaProject, jarName, srcName, pathAndContents, JavaCore.VERSION_1_8, libraryOptions);
+
+ String contents =
+ "@T(21)\n" +
+ "public abstract class X extends @T(22) Superclass implements @T(23) Runnable {\n" +
+ "}\n";
+
+ this.workingCopy = getWorkingCopy("/Converter18/src/X.java", true);
+ ASTNode node = buildAST(contents, this.workingCopy);
+ assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
+ CompilationUnit compilationUnit = (CompilationUnit) node;
+ assertProblemsSize(compilationUnit, 0);
+ List types = compilationUnit.types();
+ assertEquals("Incorrect no of types", 1, types.size());
+ TypeDeclaration typeDecl = (TypeDeclaration) types.get(0);
+ ITypeBinding typeBinding = typeDecl.resolveBinding();
+ IAnnotationBinding[] annotations = typeBinding.getAnnotations();
+ assertTrue("Should be 1", annotations.length == 1);
+ assertEquals("Annotation mismatch", "@T(value = 21)", annotations[0].toString());
+
+ ITypeBinding superclass = typeBinding.getSuperclass();
+ ITypeBinding[] inners = superclass.getDeclaredTypes();
+ assertTrue("Should be 2", inners.length == 4);
+
+ ITypeBinding subInner = inners[2];
+ assertEquals("Type name mismatch", "SubInner", subInner.getName());
+ annotations = subInner.getAnnotations();
+ assertTrue("Should be 1", annotations.length == 1);
+ assertEquals("Annotation mismatch", "@T(value = 11)", annotations[0].toString());
+
+ annotations = subInner.getSuperclass().getTypeAnnotations();
+ assertTrue("Should be 1", annotations.length == 1);
+ assertEquals("Annotation mismatch", "@T(value = 12)", annotations[0].toString());
+
+ ITypeBinding subNested = inners[3];
+ annotations = subNested.getAnnotations();
+ assertTrue("Should be 1", annotations.length == 1);
+ assertEquals("Annotation mismatch", "@T(value = 14)", annotations[0].toString());
+
+ annotations = subNested.getSuperclass().getTypeAnnotations();
+ assertTrue("Should be 1", annotations.length == 1);
+ assertEquals("Annotation mismatch", "@T(value = 15)", annotations[0].toString());
+ } finally {
+ removeLibrary(javaProject, jarName, srcName);
+ }
+ }
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=419918, [1.8][compiler] Annotations are not restored from class files in a few situations.
public void testBinaryAnnotationType() throws CoreException, IOException {
String jarName = "TypeBindingTests308.jar";
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 d3c68a02f8..6ff5e28ce3 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 @@ -27,6 +27,7 @@ * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * 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 *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -1228,19 +1229,7 @@ ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start, int en } ReferenceBinding binding = getTypeFromCompoundName(compoundName, isParameterized, wasMissingType); if (walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { - final int depth = binding.depth(); - AnnotationBinding [][] annotations = null; - for (int i = 0; i <= depth; i++) { - AnnotationBinding[] annots = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); - if (annots != null && annots.length > 0) { - if (annotations == null) - annotations = new AnnotationBinding[depth + 1][]; - annotations[i] = annots; - } - walker = walker.toNextNestedType(); - } - if (annotations != null) - binding = (ReferenceBinding) createAnnotatedType(binding, annotations); + binding = (ReferenceBinding) annotateType(binding, walker, missingTypeNames); } return binding; } @@ -1326,19 +1315,7 @@ TypeBinding getTypeFromSignature(char[] signature, int start, int end, boolean i } if (walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { - final int depth = binding.depth(); - AnnotationBinding [][] annotations = null; - for (int i = 0; i <= depth; i++) { - AnnotationBinding[] annots = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); - if (annots != null && annots.length > 0) { - if (annotations == null) - annotations = new AnnotationBinding[depth + 1][]; - annotations[i] = annots; - } - walker = walker.toNextNestedType(); - } - if (annotations != null) - binding = createAnnotatedType(binding, annotations); + binding = annotateType(binding, walker, missingTypeNames); } if (dimension != 0) @@ -1347,6 +1324,36 @@ TypeBinding getTypeFromSignature(char[] signature, int start, int end, boolean i return binding; } +private TypeBinding annotateType(TypeBinding binding, TypeAnnotationWalker walker, char[][][] missingTypeNames) { + int depth = binding.depth() + 1; + if (depth > 1) { + // need to count non-static nesting levels, resolved binding required for precision + if (binding.isUnresolvedType()) + binding = ((UnresolvedReferenceBinding) binding).resolve(this, true); + TypeBinding currentBinding = binding; + depth = 0; + while (currentBinding != null) { + depth++; + if (currentBinding.isStatic()) + break; + currentBinding = currentBinding.enclosingType(); + } + } + AnnotationBinding [][] annotations = null; + for (int i = 0; i < depth; i++) { + AnnotationBinding[] annots = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + if (annots != null && annots.length > 0) { + if (annotations == null) + annotations = new AnnotationBinding[depth][]; + annotations[i] = annots; + } + walker = walker.toNextNestedType(); + } + if (annotations != null) + binding = createAnnotatedType(binding, annotations); + return binding; +} + boolean qualifiedNameMatchesSignature(char[][] name, char[] signature) { int s = 1; // skip 'L' for (int i = 0; i < name.length; i++) { |