8044196: Incorrect applying of repeatable annotations with incompatible target to type parameter
Additional applicability checks added. Reviewed-by: jlahoda
This commit is contained in:
parent
8c93ae0560
commit
bd17f06ead
@ -28,11 +28,11 @@ package com.sun.tools.javac.code;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import com.sun.tools.javac.code.Attribute.Array;
|
||||
import com.sun.tools.javac.code.Attribute.TypeCompound;
|
||||
import com.sun.tools.javac.code.Symbol.TypeSymbol;
|
||||
import com.sun.tools.javac.code.Type.ArrayType;
|
||||
import com.sun.tools.javac.code.Type.CapturedType;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
@ -153,8 +153,8 @@ public class TypeAnnotations {
|
||||
|
||||
public enum AnnotationType { DECLARATION, TYPE, NONE, BOTH }
|
||||
|
||||
public List<Attribute> annotationTargets(Attribute.Compound anno) {
|
||||
Attribute.Compound atTarget = anno.type.tsym.getAnnotationTypeMetadata().getTarget();
|
||||
public List<Attribute> annotationTargets(TypeSymbol tsym) {
|
||||
Attribute.Compound atTarget = tsym.getAnnotationTypeMetadata().getTarget();
|
||||
if (atTarget == null) {
|
||||
return null;
|
||||
}
|
||||
@ -177,7 +177,7 @@ public class TypeAnnotations {
|
||||
* a type annotation, or both.
|
||||
*/
|
||||
public AnnotationType annotationTargetType(Attribute.Compound a, Symbol s) {
|
||||
List<Attribute> targets = annotationTargets(a);
|
||||
List<Attribute> targets = annotationTargets(a.type.tsym);
|
||||
return (targets == null) ?
|
||||
AnnotationType.DECLARATION :
|
||||
targets.stream()
|
||||
|
@ -243,7 +243,10 @@ public class Annotate {
|
||||
log.error(annotations.head.pos, "already.annotated", Kinds.kindName(s), s);
|
||||
|
||||
Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
|
||||
annotateNow(s, annotations, localEnv, false);
|
||||
|
||||
// false is passed as fifth parameter since annotateLater is
|
||||
// never called for a type parameter
|
||||
annotateNow(s, annotations, localEnv, false, false);
|
||||
} finally {
|
||||
if (prevLint != null)
|
||||
chk.setLint(prevLint);
|
||||
@ -327,7 +330,8 @@ public class Annotate {
|
||||
* then continue on with repeating annotations processing.
|
||||
*/
|
||||
private <T extends Attribute.Compound> void annotateNow(Symbol toAnnotate,
|
||||
List<JCAnnotation> withAnnotations, Env<AttrContext> env, boolean typeAnnotations)
|
||||
List<JCAnnotation> withAnnotations, Env<AttrContext> env, boolean typeAnnotations,
|
||||
boolean isTypeParam)
|
||||
{
|
||||
Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
|
||||
Map<T, DiagnosticPosition> pos = new HashMap<>();
|
||||
@ -377,7 +381,7 @@ public class Annotate {
|
||||
buf = buf.prepend(lb.first());
|
||||
} else {
|
||||
AnnotationContext<T> ctx = new AnnotationContext<>(env, annotated, pos, typeAnnotations);
|
||||
T res = makeContainerAnnotation(lb.toList(), ctx, toAnnotate);
|
||||
T res = makeContainerAnnotation(lb.toList(), ctx, toAnnotate, isTypeParam);
|
||||
if (res != null)
|
||||
buf = buf.prepend(res);
|
||||
}
|
||||
@ -698,7 +702,7 @@ public class Annotate {
|
||||
* annotation are invalid. This method reports errors/warnings.
|
||||
*/
|
||||
private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
|
||||
AnnotationContext<T> ctx, Symbol on)
|
||||
AnnotationContext<T> ctx, Symbol on, boolean isTypeParam)
|
||||
{
|
||||
T firstOccurrence = annotations.head;
|
||||
List<Attribute> repeated = List.nil();
|
||||
@ -752,7 +756,8 @@ public class Annotate {
|
||||
|
||||
if (!repeated.isEmpty()) {
|
||||
repeated = repeated.reverse();
|
||||
TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
|
||||
DiagnosticPosition pos = ctx.pos.get(firstOccurrence);
|
||||
TreeMaker m = make.at(pos);
|
||||
Pair<MethodSymbol, Attribute> p =
|
||||
new Pair<MethodSymbol, Attribute>(containerValueSymbol,
|
||||
new Attribute.Array(arrayOfOrigAnnoType, repeated));
|
||||
@ -768,7 +773,14 @@ public class Annotate {
|
||||
Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
|
||||
((Attribute.TypeCompound)annotations.head).position);
|
||||
|
||||
// TODO: annotation applicability checks from below?
|
||||
JCAnnotation annoTree = m.TypeAnnotation(at);
|
||||
if (!chk.validateAnnotationDeferErrors(annoTree))
|
||||
log.error(annoTree.pos(), Errors.DuplicateAnnotationInvalidRepeated(origAnnoType));
|
||||
|
||||
if (!chk.isTypeAnnotation(annoTree, isTypeParam)) {
|
||||
log.error(pos, isTypeParam ? Errors.InvalidRepeatableAnnotationNotApplicable(targetContainerType, on)
|
||||
: Errors.InvalidRepeatableAnnotationNotApplicableInContext(targetContainerType));
|
||||
}
|
||||
|
||||
at.setSynthesized(true);
|
||||
|
||||
@ -925,11 +937,11 @@ public class Annotate {
|
||||
}
|
||||
|
||||
private <T extends Attribute.Compound> T makeContainerAnnotation(List<T> toBeReplaced,
|
||||
AnnotationContext<T> ctx, Symbol sym)
|
||||
AnnotationContext<T> ctx, Symbol sym, boolean isTypeParam)
|
||||
{
|
||||
// Process repeated annotations
|
||||
T validRepeated =
|
||||
processRepeatedAnnotations(toBeReplaced, ctx, sym);
|
||||
processRepeatedAnnotations(toBeReplaced, ctx, sym, isTypeParam);
|
||||
|
||||
if (validRepeated != null) {
|
||||
// Check that the container isn't manually
|
||||
@ -955,7 +967,7 @@ public class Annotate {
|
||||
* Attribute the list of annotations and enter them onto s.
|
||||
*/
|
||||
public void enterTypeAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env,
|
||||
Symbol s, DiagnosticPosition deferPos)
|
||||
Symbol s, DiagnosticPosition deferPos, boolean isTypeParam)
|
||||
{
|
||||
Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
|
||||
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
|
||||
@ -965,7 +977,7 @@ public class Annotate {
|
||||
prevLintPos = deferredLintHandler.setPos(deferPos);
|
||||
}
|
||||
try {
|
||||
annotateNow(s, annotations, env, true);
|
||||
annotateNow(s, annotations, env, true, isTypeParam);
|
||||
} finally {
|
||||
if (prevLintPos != null)
|
||||
deferredLintHandler.setPos(prevLintPos);
|
||||
@ -1048,21 +1060,21 @@ public class Annotate {
|
||||
|
||||
@Override
|
||||
public void visitAnnotatedType(JCAnnotatedType tree) {
|
||||
enterTypeAnnotations(tree.annotations, env, sym, deferPos);
|
||||
enterTypeAnnotations(tree.annotations, env, sym, deferPos, false);
|
||||
scan(tree.underlyingType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeParameter(JCTypeParameter tree) {
|
||||
enterTypeAnnotations(tree.annotations, env, sym, deferPos);
|
||||
enterTypeAnnotations(tree.annotations, env, sym, deferPos, true);
|
||||
scan(tree.bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNewArray(JCNewArray tree) {
|
||||
enterTypeAnnotations(tree.annotations, env, sym, deferPos);
|
||||
enterTypeAnnotations(tree.annotations, env, sym, deferPos, false);
|
||||
for (List<JCAnnotation> dimAnnos : tree.dimAnnotations)
|
||||
enterTypeAnnotations(dimAnnos, env, sym, deferPos);
|
||||
enterTypeAnnotations(dimAnnos, env, sym, deferPos, false);
|
||||
scan(tree.elemtype);
|
||||
scan(tree.elems);
|
||||
}
|
||||
|
@ -2999,7 +2999,7 @@ public class Check {
|
||||
|
||||
/** Is the annotation applicable to types? */
|
||||
protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) {
|
||||
List<Attribute> targets = typeAnnotations.annotationTargets(a.attribute);
|
||||
List<Attribute> targets = typeAnnotations.annotationTargets(a.annotationType.type.tsym);
|
||||
return (targets == null) ?
|
||||
false :
|
||||
targets.stream()
|
||||
|
@ -414,6 +414,10 @@ compiler.err.invalid.repeatable.annotation.repeated.and.container.present=\
|
||||
compiler.err.invalid.repeatable.annotation.not.applicable=\
|
||||
container {0} is not applicable to element {1}
|
||||
|
||||
# 0: type
|
||||
compiler.err.invalid.repeatable.annotation.not.applicable.in.context=\
|
||||
container {0} is not applicable in this type context
|
||||
|
||||
# 0: name
|
||||
compiler.err.duplicate.class=\
|
||||
duplicate class: {0}
|
||||
|
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8044196
|
||||
* @summary Ensure that containers with target FIELD can't be applied to type parameters.
|
||||
* @compile/fail/ref=InvalidClsTypeParamTarget.out -XDrawDiagnostics InvalidClsTypeParamTarget.java
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class InvalidClsTypeParamTarget {
|
||||
|
||||
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE, ElementType.FIELD})
|
||||
@Repeatable(TC.class)
|
||||
@interface T { int value(); }
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@interface TC { T[] value(); }
|
||||
|
||||
class Test<@T(1) @T(2) N> {
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
InvalidClsTypeParamTarget.java:19:16: compiler.err.invalid.repeatable.annotation.not.applicable: InvalidClsTypeParamTarget.TC, InvalidClsTypeParamTarget.Test
|
||||
1 error
|
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8044196
|
||||
* @summary Ensure that containers with target METHOD can't be applied to type parameters.
|
||||
* @compile/fail/ref=InvalidMethodTypeParamTarget.out -XDrawDiagnostics InvalidMethodTypeParamTarget.java
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class InvalidMethodTypeParamTarget {
|
||||
|
||||
@Target({ElementType.TYPE_PARAMETER, ElementType.METHOD})
|
||||
@Repeatable(TC.class)
|
||||
@interface T { int value(); }
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@interface TC { T[] value(); }
|
||||
|
||||
public <@T(1) @T(2) N> void method() { }
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
InvalidMethodTypeParamTarget.java:19:13: compiler.err.invalid.repeatable.annotation.not.applicable: InvalidMethodTypeParamTarget.TC, <N>method()
|
||||
1 error
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8044196
|
||||
* @summary Make sure repeatable annotations can't be erroneously applied to type arguments.
|
||||
* @compile/fail/ref=InvalidMethodTypeUse.out -XDrawDiagnostics InvalidMethodTypeUse.java
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class InvalidMethodTypeUse {
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.TYPE_PARAMETER})
|
||||
@Repeatable(TC.class)
|
||||
@interface T { int value(); }
|
||||
|
||||
@Target({ElementType.METHOD, ElementType.TYPE_PARAMETER})
|
||||
@interface TC { T[] value(); }
|
||||
|
||||
void method() {
|
||||
this.<@T(1) @T(2) String>method2();
|
||||
}
|
||||
|
||||
<@T(3) S> void method2() { }
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
InvalidMethodTypeUse.java:20:15: compiler.err.invalid.repeatable.annotation.not.applicable.in.context: InvalidMethodTypeUse.TC
|
||||
1 error
|
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8044196
|
||||
* @summary Make sure repeatable annotations can't be erroneously applied to a cast type
|
||||
* @compile/fail/ref=InvalidRepAnnoOnCast.out -XDrawDiagnostics InvalidRepAnnoOnCast.java
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class InvalidRepAnnoOnCast {
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
|
||||
@Repeatable(TC.class)
|
||||
@interface T { int value(); }
|
||||
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
@interface TC { T[] value(); }
|
||||
|
||||
String s = (@T(1) @T(2) String) new Object();
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
InvalidRepAnnoOnCast.java:19:17: compiler.err.invalid.repeatable.annotation.not.applicable.in.context: InvalidRepAnnoOnCast.TC
|
||||
1 error
|
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8044196
|
||||
* @summary Ensure that a broken type annotation container generates a correct error message.
|
||||
* @compile T.java TC.java
|
||||
* @compile TCBroken.java
|
||||
* @compile/fail/ref=BrokenTypeAnnoContainer.out -XDrawDiagnostics BrokenTypeAnnoContainer.java
|
||||
*/
|
||||
|
||||
class BrokenTypeAnnoContainer {
|
||||
void method() {
|
||||
int ll2 = (@T(1) @T(2) int) 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
BrokenTypeAnnoContainer.java:12:20: compiler.err.duplicate.annotation.invalid.repeated: T
|
||||
1 error
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Repeatable(TC.class)
|
||||
@interface T { int value(); }
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TC {
|
||||
T[] value();
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TC {
|
||||
T[] value();
|
||||
int foo();
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
// key: compiler.err.invalid.repeatable.annotation.not.applicable.in.context
|
||||
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.TYPE_PARAMETER})
|
||||
@Repeatable(TC.class)
|
||||
@interface T { int value(); }
|
||||
|
||||
@Target({ElementType.METHOD, ElementType.TYPE_PARAMETER})
|
||||
@interface TC { T[] value(); }
|
||||
|
||||
public class InvalidTypeContextRepeatableAnnotation {
|
||||
void method() {
|
||||
this.<@T(1) @T(2) String>method2();
|
||||
}
|
||||
|
||||
<@T(3) S> void method2() {
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user