changeset 60122:d6d5d422e8b8

8242529: javac defines type annotations incorrectly for record members (constructor and property accessor) Reviewed-by: psandoz, jlahoda
author vromero
date Thu, 09 Jul 2020 17:37:53 -0400
parents 8b852eea3cc0
children f5196c0828a7 eafd23945cc2
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java test/langtools/tools/javac/diags/examples/KindnameRecord.java test/langtools/tools/javac/processing/model/element/RecordNotPreservingNestedTypeAnnotationsTest.java
diffstat 3 files changed, 83 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Thu Jul 09 17:04:06 2020 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Thu Jul 09 17:37:53 2020 -0400
@@ -1087,9 +1087,11 @@
                  * it could be that some of those annotations are not applicable to the accessor, they will be striped
                  * away later at Check::validateAnnotation
                  */
+                TreeCopier<JCTree> tc = new TreeCopier<JCTree>(make.at(tree.pos));
                 List<JCAnnotation> originalAnnos = rec.getOriginalAnnos().isEmpty() ?
                         rec.getOriginalAnnos() :
-                        new TreeCopier<JCTree>(make.at(tree.pos)).copy(rec.getOriginalAnnos());
+                        tc.copy(rec.getOriginalAnnos());
+                JCVariableDecl recordField = TreeInfo.recordFields((JCClassDecl) env.tree).stream().filter(rf -> rf.name == tree.name).findAny().get();
                 JCMethodDecl getter = make.at(tree.pos).
                         MethodDef(
                                 make.Modifiers(PUBLIC | Flags.GENERATED_MEMBER, originalAnnos),
@@ -1099,7 +1101,7 @@
                            * return type: javac issues an error if a type annotation is applied to java.lang.String
                            * but applying a type annotation to String is kosher
                            */
-                          tree.vartype.hasTag(IDENT) ? make.Ident(tree.vartype.type.tsym) : make.Type(tree.sym.type),
+                          tc.copy(recordField.vartype),
                           List.nil(),
                           List.nil(),
                           List.nil(), // thrown
@@ -1404,10 +1406,11 @@
                  * parameter in the constructor.
                  */
                 RecordComponent rc = ((ClassSymbol) owner).getRecordComponent(arg.sym);
+                TreeCopier<JCTree> tc = new TreeCopier<JCTree>(make.at(arg.pos));
                 arg.mods.annotations = rc.getOriginalAnnos().isEmpty() ?
                         List.nil() :
-                        new TreeCopier<JCTree>(make.at(arg.pos)).copy(rc.getOriginalAnnos());
-                arg.vartype = tmpRecordFieldDecls.head.vartype;
+                        tc.copy(rc.getOriginalAnnos());
+                arg.vartype = tc.copy(tmpRecordFieldDecls.head.vartype);
                 tmpRecordFieldDecls = tmpRecordFieldDecls.tail;
             }
             return md;
--- a/test/langtools/tools/javac/diags/examples/KindnameRecord.java	Thu Jul 09 17:04:06 2020 +0000
+++ b/test/langtools/tools/javac/diags/examples/KindnameRecord.java	Thu Jul 09 17:37:53 2020 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,8 @@
 
 // key: compiler.misc.kindname.record.component
 // key: compiler.misc.kindname.record
-// key: compiler.misc.count.error
+// key: compiler.misc.count.error.plural
+// key: compiler.misc.kindname.method
 // key: compiler.err.already.defined
 // key: compiler.err.error
 // key: compiler.note.preview.filename
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/processing/model/element/RecordNotPreservingNestedTypeAnnotationsTest.java	Thu Jul 09 17:37:53 2020 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test 8242529
+ * @summary javac defines type annotations incorrectly for record members (constructor and property accessor)
+ * @modules
+ *      jdk.compiler/com.sun.tools.javac.util
+ * @compile --enable-preview -source ${jdk.version} RecordNotPreservingNestedTypeAnnotationsTest.java
+ * @run main/othervm --enable-preview RecordNotPreservingNestedTypeAnnotationsTest
+ */
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.*;
+import java.util.concurrent.Callable;
+import com.sun.tools.javac.util.Assert;
+
+public record RecordNotPreservingNestedTypeAnnotationsTest(@RegularAnnotation @TypeAnnotation Callable<@TypeAnnotation ?> foo) {
+    public static void main(String[] args) throws Exception {
+        RecordComponent recordComponent = RecordNotPreservingNestedTypeAnnotationsTest.class.getRecordComponents()[0];
+        checkAnnotations(recordComponent.getAnnotations(), recordComponent.getAnnotatedType());
+
+        Method accessor = recordComponent.getAccessor();
+        checkAnnotations(accessor.getAnnotations(), accessor.getAnnotatedReturnType());
+
+        Constructor<?> constructor = RecordNotPreservingNestedTypeAnnotationsTest.class.getConstructor(Callable.class);
+        checkAnnotations(constructor.getParameterAnnotations()[0], constructor.getAnnotatedParameterTypes()[0]);
+
+        Field field = RecordNotPreservingNestedTypeAnnotationsTest.class.getDeclaredField(recordComponent.getName());
+        checkAnnotations(field.getAnnotations(), field.getAnnotatedType());
+    }
+
+    static void checkAnnotations(Annotation[] decAnnotations, AnnotatedType annoType) {
+        Assert.check(decAnnotations.length == 1);
+        Assert.check(decAnnotations[0] instanceof RegularAnnotation);
+
+        Assert.check(annoType.getAnnotations()[0] instanceof TypeAnnotation);
+        var annoTypeArgs = ((AnnotatedParameterizedType) annoType).getAnnotatedActualTypeArguments();
+        Assert.check(annoTypeArgs.length == 1);
+        Assert.check(annoTypeArgs[0].getAnnotations()[0] instanceof TypeAnnotation);
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE_USE})
+    @interface TypeAnnotation {}
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface RegularAnnotation {}
+}