Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Clement2013-08-23 05:08:16 +0000
committerssankaran2013-08-23 05:08:16 +0000
commite002812d8385bfcab83bbcee92fbb80489aadeb5 (patch)
tree3dc0c1ff9f3d21de83ed8e6445d75fbadc9d0109
parent5c94036938fe400e122792407c5c35d8914790e5 (diff)
downloadeclipse.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>
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java145
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java25
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;

Back to the top