8242529: javac defines type annotations incorrectly for record members (constructor and property accessor)

Reviewed-by: psandoz, jlahoda
This commit is contained in:
Vicente Romero 2020-07-09 17:37:53 -04:00
parent 1b1fb08000
commit 37880ba60d
3 changed files with 83 additions and 6 deletions

View File

@ -1087,9 +1087,11 @@ public class TypeEnter implements Completer {
* 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 @@ public class TypeEnter implements Completer {
* 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 @@ public class TypeEnter implements Completer {
* 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;

View File

@ -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

View File

@ -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 {}
}