8044196: Incorrect applying of repeatable annotations with incompatible target to type parameter

Additional applicability checks added.

Reviewed-by: jlahoda
This commit is contained in:
Andreas Lundblad 2015-04-30 12:21:50 +02:00
parent 8c93ae0560
commit bd17f06ead
18 changed files with 275 additions and 19 deletions

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,2 @@
InvalidClsTypeParamTarget.java:19:16: compiler.err.invalid.repeatable.annotation.not.applicable: InvalidClsTypeParamTarget.TC, InvalidClsTypeParamTarget.Test
1 error

View File

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

View File

@ -0,0 +1,2 @@
InvalidMethodTypeParamTarget.java:19:13: compiler.err.invalid.repeatable.annotation.not.applicable: InvalidMethodTypeParamTarget.TC, <N>method()
1 error

View File

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

View File

@ -0,0 +1,2 @@
InvalidMethodTypeUse.java:20:15: compiler.err.invalid.repeatable.annotation.not.applicable.in.context: InvalidMethodTypeUse.TC
1 error

View File

@ -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();
}

View File

@ -0,0 +1,2 @@
InvalidRepAnnoOnCast.java:19:17: compiler.err.invalid.repeatable.annotation.not.applicable.in.context: InvalidRepAnnoOnCast.TC
1 error

View File

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

View File

@ -0,0 +1,2 @@
BrokenTypeAnnoContainer.java:12:20: compiler.err.duplicate.annotation.invalid.repeated: T
1 error

View File

@ -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(); }

View File

@ -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();
}

View File

@ -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();
}

View File

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