diff options
| author | Andrew Clement | 2013-08-23 05:08:16 +0000 |
|---|---|---|
| committer | ssankaran | 2013-08-23 05:08:16 +0000 |
| commit | e002812d8385bfcab83bbcee92fbb80489aadeb5 (patch) | |
| tree | 3dc0c1ff9f3d21de83ed8e6445d75fbadc9d0109 | |
| parent | 5c94036938fe400e122792407c5c35d8914790e5 (diff) | |
| download | eclipse.jdt.core-e002812d8385bfcab83bbcee92fbb80489aadeb5.tar.gz eclipse.jdt.core-e002812d8385bfcab83bbcee92fbb80489aadeb5.tar.xz eclipse.jdt.core-e002812d8385bfcab83bbcee92fbb80489aadeb5.zip | |
Fixed Bug 415470 - [1.8][compiler] Type annotations on class declaration
go vanishing
Signed-off-by: Andrew Clement <aclement@gopivotal.com>
2 files changed, 161 insertions, 9 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java index 00cc01ff7e..dce6dc12e1 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java @@ -16,6 +16,7 @@ * Bug 415543 - [1.8][compiler] Incorrect bound index in RuntimeInvisibleTypeAnnotations attribute * Bug 415397 - [1.8][compiler] Type Annotations on wildcard type argument dropped * Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator + * Bug 415470 - [1.8][compiler] Type annotations on class declaration go vanishing *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -1424,7 +1425,7 @@ public class JSR308SpecSnippetTests extends AbstractRegressionTest { "The annotation @MAnno is disallowed for this location\n" + "----------\n"); } - public void test030() throws Exception { // WILL FAIL WHEN https://bugs.eclipse.org/bugs/show_bug.cgi?id=415470 IS FIXED. + public void test030() throws Exception { this.runConformTest( new String[] { "X.java", @@ -1436,6 +1437,10 @@ public class JSR308SpecSnippetTests extends AbstractRegressionTest { "}\n", }, ""); + // javac b100 produces: + // RuntimeInvisibleAnnotations: + // 0: #11() LAnnotation; + // 1: #12() LTypeAnnotation; String expectedOutput = "// Compiled from X.java (version 1.8 : 52.0, super bit)\n" + "class X {\n" + @@ -1457,6 +1462,7 @@ public class JSR308SpecSnippetTests extends AbstractRegressionTest { " constant #15 utf8: \"X.java\"\n" + " constant #16 utf8: \"RuntimeInvisibleAnnotations\"\n" + " constant #17 utf8: \"LAnnotation;\"\n" + + " constant #18 utf8: \"LTypeAnnotation;\"\n" + " \n" + " // Method descriptor #6 ()V\n" + " // Stack: 1, Locals: 1\n" + @@ -1472,6 +1478,143 @@ public class JSR308SpecSnippetTests extends AbstractRegressionTest { " RuntimeInvisibleAnnotations: \n" + " #17 @Annotation(\n" + " )\n" + + " #18 @TypeAnnotation(\n" + + " )\n" + + "}"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput, ClassFileBytesDisassembler.SYSTEM); + } + + public void test030a() throws Exception { + this.runConformTest( + new String[] { + "X.java", + "import java.lang.annotation.*;\n" + + "import static java.lang.annotation.ElementType.*; \n" + + "@Retention(RetentionPolicy.RUNTIME)\n" + + "@Target({TYPE_USE}) @interface TypeAnnotation { }\n" + + "@Retention(RetentionPolicy.RUNTIME)\n" + + "@Target({TYPE}) @interface Annotation { }\n" + + "@Annotation @TypeAnnotation class X {\n" + + "}\n", + }, + ""); + String expectedOutput = + "// Compiled from X.java (version 1.8 : 52.0, super bit)\n" + + "class X {\n" + + " Constant pool:\n" + + " constant #1 class: #2 X\n" + + " constant #2 utf8: \"X\"\n" + + " constant #3 class: #4 java/lang/Object\n" + + " constant #4 utf8: \"java/lang/Object\"\n" + + " constant #5 utf8: \"<init>\"\n" + + " constant #6 utf8: \"()V\"\n" + + " constant #7 utf8: \"Code\"\n" + + " constant #8 method_ref: #3.#9 java/lang/Object.<init> ()V\n" + + " constant #9 name_and_type: #5.#6 <init> ()V\n" + + " constant #10 utf8: \"LineNumberTable\"\n" + + " constant #11 utf8: \"LocalVariableTable\"\n" + + " constant #12 utf8: \"this\"\n" + + " constant #13 utf8: \"LX;\"\n" + + " constant #14 utf8: \"SourceFile\"\n" + + " constant #15 utf8: \"X.java\"\n" + + " constant #16 utf8: \"RuntimeVisibleAnnotations\"\n" + + " constant #17 utf8: \"LAnnotation;\"\n" + + " constant #18 utf8: \"LTypeAnnotation;\"\n" + + " \n" + + " // Method descriptor #6 ()V\n" + + " // Stack: 1, Locals: 1\n" + + " X();\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [8]\n" + + " 4 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 7]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 5] local: this index: 0 type: X\n" + + "\n" + + " RuntimeVisibleAnnotations: \n" + + " #17 @Annotation(\n" + + " )\n" + + " #18 @TypeAnnotation(\n" + + " )\n" + + "}"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput, ClassFileBytesDisassembler.SYSTEM); + } + + public void test030b() throws Exception { + this.runNegativeTest( + new String[] { + "X.java", + "import java.lang.annotation.*;\n" + + "import static java.lang.annotation.ElementType.*; \n" + + "@Retention(RetentionPolicy.RUNTIME)\n" + + // Only TYPE_USE annotations get this special treatment + "@Target({TYPE_PARAMETER}) @interface TypeAnnotation { }\n" + + "@Retention(RetentionPolicy.RUNTIME)\n" + + "@Target({TYPE}) @interface Annotation { }\n" + + "@Annotation @TypeAnnotation class X {\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in X.java (at line 7)\n" + + " @Annotation @TypeAnnotation class X {\n" + + " ^^^^^^^^^^^^^^^\n" + + "The annotation @TypeAnnotation is disallowed for this location\n" + + "----------\n"); + } + public void test030c() throws Exception { + this.runConformTest( + new String[] { + "X.java", + "import java.lang.annotation.*;\n" + + "import static java.lang.annotation.ElementType.*; \n" + + "@Retention(RetentionPolicy.RUNTIME)\n" + + "@Target({TYPE_USE,TYPE_PARAMETER}) @interface TypeAnnotation { }\n" + + "@Retention(RetentionPolicy.RUNTIME)\n" + + "@Target({TYPE}) @interface Annotation { }\n" + + "@Annotation @TypeAnnotation class X {\n" + + "}\n", + }, + ""); + String expectedOutput = + "// Compiled from X.java (version 1.8 : 52.0, super bit)\n" + + "class X {\n" + + " Constant pool:\n" + + " constant #1 class: #2 X\n" + + " constant #2 utf8: \"X\"\n" + + " constant #3 class: #4 java/lang/Object\n" + + " constant #4 utf8: \"java/lang/Object\"\n" + + " constant #5 utf8: \"<init>\"\n" + + " constant #6 utf8: \"()V\"\n" + + " constant #7 utf8: \"Code\"\n" + + " constant #8 method_ref: #3.#9 java/lang/Object.<init> ()V\n" + + " constant #9 name_and_type: #5.#6 <init> ()V\n" + + " constant #10 utf8: \"LineNumberTable\"\n" + + " constant #11 utf8: \"LocalVariableTable\"\n" + + " constant #12 utf8: \"this\"\n" + + " constant #13 utf8: \"LX;\"\n" + + " constant #14 utf8: \"SourceFile\"\n" + + " constant #15 utf8: \"X.java\"\n" + + " constant #16 utf8: \"RuntimeVisibleAnnotations\"\n" + + " constant #17 utf8: \"LAnnotation;\"\n" + + " constant #18 utf8: \"LTypeAnnotation;\"\n" + + " \n" + + " // Method descriptor #6 ()V\n" + + " // Stack: 1, Locals: 1\n" + + " X();\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [8]\n" + + " 4 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 7]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 5] local: this index: 0 type: X\n" + + "\n" + + " RuntimeVisibleAnnotations: \n" + + " #17 @Annotation(\n" + + " )\n" + + " #18 @TypeAnnotation(\n" + + " )\n" + "}"; checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput, ClassFileBytesDisassembler.SYSTEM); } 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 e8b2c90ee9..25cdbab62b 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 @@ -19,6 +19,7 @@ * Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly * Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped * Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator + * Bug 415470 - [1.8][compiler] Type annotations on class declaration go vanishing *******************************************************************************/ package org.eclipse.jdt.internal.compiler; @@ -354,7 +355,7 @@ public class ClassFile implements TypeConstants, TypeIds { if (typeDeclaration != null) { final Annotation[] annotations = typeDeclaration.annotations; if (annotations != null) { - attributesNumber += generateRuntimeAnnotations(annotations); + attributesNumber += generateRuntimeAnnotations(annotations, true); } } } @@ -450,7 +451,7 @@ public class ClassFile implements TypeConstants, TypeIds { if (fieldDeclaration != null) { Annotation[] annotations = fieldDeclaration.annotations; if (annotations != null) { - attributesNumber += generateRuntimeAnnotations(annotations); + attributesNumber += generateRuntimeAnnotations(annotations, false); } if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { @@ -3180,7 +3181,7 @@ public class ClassFile implements TypeConstants, TypeIds { if (methodDeclaration != null) { Annotation[] annotations = methodDeclaration.annotations; if (annotations != null) { - attributesNumber += generateRuntimeAnnotations(annotations); + attributesNumber += generateRuntimeAnnotations(annotations, false); } if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) { Argument[] arguments = methodDeclaration.arguments; @@ -3384,9 +3385,10 @@ public class ClassFile implements TypeConstants, TypeIds { /** * @param annotations + * @param includeTypeUseAnnotations Used to support JSR308 Section 2.3 special allowance for TYPE_USE annotation used on a type declaration * @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, final boolean includeTypeUseAnnotations) { int attributesNumber = 0; final int length = annotations.length; int visibleAnnotationsCounter = 0; @@ -3394,9 +3396,9 @@ public class ClassFile implements TypeConstants, TypeIds { for (int i = 0; i < length; i++) { Annotation annotation = annotations[i]; - if (annotation.isRuntimeInvisible()) { + if (annotation.isRuntimeInvisible() || (includeTypeUseAnnotations && annotation.isRuntimeTypeInvisible())) { invisibleAnnotationsCounter++; - } else if (annotation.isRuntimeVisible()) { + } else if (annotation.isRuntimeVisible() || (includeTypeUseAnnotations && annotation.isRuntimeTypeVisible())) { visibleAnnotationsCounter++; } } @@ -3422,7 +3424,10 @@ public class ClassFile implements TypeConstants, TypeIds { loop: for (int i = 0; i < length; i++) { if (invisibleAnnotationsCounter == 0) break loop; Annotation annotation = annotations[i]; - if (annotation.isRuntimeInvisible()) { + if (annotation.isRuntimeInvisible() || + // No need to explicitly check it is type_use and not type_parameter, + // that will already have been checked + (includeTypeUseAnnotations && annotation.isRuntimeTypeInvisible())) { int currentAnnotationOffset = this.contentsOffset; generateAnnotation(annotation, currentAnnotationOffset); invisibleAnnotationsCounter--; @@ -3469,7 +3474,10 @@ public class ClassFile implements TypeConstants, TypeIds { loop: for (int i = 0; i < length; i++) { if (visibleAnnotationsCounter == 0) break loop; Annotation annotation = annotations[i]; - if (annotation.isRuntimeVisible()) { + if (annotation.isRuntimeVisible() || + // No need to explicitly check it is type_use and not type_parameter, + // that will already have been checked + (includeTypeUseAnnotations && annotation.isRuntimeTypeVisible())) { visibleAnnotationsCounter--; int currentAnnotationOffset = this.contentsOffset; generateAnnotation(annotation, currentAnnotationOffset); @@ -3495,6 +3503,7 @@ public class ClassFile implements TypeConstants, TypeIds { } return attributesNumber; } + private int generateRuntimeAnnotationsForParameters(Argument[] arguments) { final int argumentsLength = arguments.length; final int VISIBLE_INDEX = 0; |
