6993978: Project Coin: Compiler support of annotation to reduce varargs warnings
Reviewed-by: jjg, darcy
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Mon Dec 13 15:11:00 2010 -0800
@@ -177,6 +177,9 @@
public boolean allowStringsInSwitch() {
return compareTo(JDK1_7) >= 0;
}
+ public boolean allowSimplifiedVarargs() {
+ return compareTo(JDK1_7) >= 0;
+ }
public static SourceVersion toSourceVersion(Source source) {
switch(source) {
case JDK1_2:
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Mon Dec 13 15:11:00 2010 -0800
@@ -154,6 +154,7 @@
public final Type proprietaryType;
public final Type systemType;
public final Type autoCloseableType;
+ public final Type trustMeType;
/** The symbol representing the length field of an array.
*/
@@ -461,6 +462,7 @@
new MethodType(List.<Type>nil(), voidType,
List.of(exceptionType), methodClass),
autoCloseableType.tsym);
+ trustMeType = enterClass("java.lang.SafeVarargs");
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Mon Dec 13 15:11:00 2010 -0800
@@ -754,6 +754,10 @@
return (ARRAY << 5) + elemtype.hashCode();
}
+ public boolean isVarargs() {
+ return false;
+ }
+
public List<Type> allparams() { return elemtype.allparams(); }
public boolean isErroneous() {
@@ -768,6 +772,15 @@
return elemtype.isRaw();
}
+ public ArrayType makeVarargs() {
+ return new ArrayType(elemtype, tsym) {
+ @Override
+ public boolean isVarargs() {
+ return true;
+ }
+ };
+ }
+
public Type map(Mapping f) {
Type elemtype1 = f.apply(elemtype);
if (elemtype1 == elemtype) return this;
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Mon Dec 13 15:11:00 2010 -0800
@@ -33,6 +33,7 @@
import com.sun.tools.javac.jvm.ClassReader;
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
+import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.comp.Check;
import static com.sun.tools.javac.code.Type.*;
@@ -272,13 +273,36 @@
public boolean isConvertible(Type t, Type s, Warner warn) {
boolean tPrimitive = t.isPrimitive();
boolean sPrimitive = s.isPrimitive();
- if (tPrimitive == sPrimitive)
+ if (tPrimitive == sPrimitive) {
+ checkUnsafeVarargsConversion(t, s, warn);
return isSubtypeUnchecked(t, s, warn);
+ }
if (!allowBoxing) return false;
return tPrimitive
? isSubtype(boxedClass(t).type, s)
: isSubtype(unboxedType(t), s);
}
+ //where
+ private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) {
+ if (t.tag != ARRAY || isReifiable(t)) return;
+ ArrayType from = (ArrayType)t;
+ boolean shouldWarn = false;
+ switch (s.tag) {
+ case ARRAY:
+ ArrayType to = (ArrayType)s;
+ shouldWarn = from.isVarargs() &&
+ !to.isVarargs() &&
+ !isReifiable(from);
+ break;
+ case CLASS:
+ shouldWarn = from.isVarargs() &&
+ isSubtype(from, s);
+ break;
+ }
+ if (shouldWarn) {
+ warn.warn(LintCategory.VARARGS);
+ }
+ }
/**
* Is t a subtype of or convertiable via boxing/unboxing
@@ -301,9 +325,18 @@
*/
public boolean isSubtypeUnchecked(Type t, Type s, Warner warn) {
if (t.tag == ARRAY && s.tag == ARRAY) {
- return (((ArrayType)t).elemtype.tag <= lastBaseTag)
- ? isSameType(elemtype(t), elemtype(s))
- : isSubtypeUnchecked(elemtype(t), elemtype(s), warn);
+ if (((ArrayType)t).elemtype.tag <= lastBaseTag) {
+ return isSameType(elemtype(t), elemtype(s));
+ } else {
+ ArrayType from = (ArrayType)t;
+ ArrayType to = (ArrayType)s;
+ if (from.isVarargs() &&
+ !to.isVarargs() &&
+ !isReifiable(from)) {
+ warn.warn(LintCategory.VARARGS);
+ }
+ return isSubtypeUnchecked(elemtype(t), elemtype(s), warn);
+ }
} else if (isSubtype(t, s)) {
return true;
}
@@ -319,9 +352,9 @@
Type t2 = asSuper(t, s.tsym);
if (t2 != null && t2.isRaw()) {
if (isReifiable(s))
- warn.silentUnchecked();
+ warn.silentWarn(LintCategory.UNCHECKED);
else
- warn.warnUnchecked();
+ warn.warn(LintCategory.UNCHECKED);
return true;
}
}
@@ -922,6 +955,7 @@
if (warn != warnStack.head) {
try {
warnStack = warnStack.prepend(warn);
+ checkUnsafeVarargsConversion(t, s, warn);
return isCastable.visit(t,s);
} finally {
warnStack = warnStack.tail;
@@ -964,7 +998,7 @@
if (s.tag == TYPEVAR) {
if (isCastable(t, s.getUpperBound(), Warner.noWarnings)) {
- warnStack.head.warnUnchecked();
+ warnStack.head.warn(LintCategory.UNCHECKED);
return true;
} else {
return false;
@@ -980,8 +1014,8 @@
if (!visit(intf, s))
return false;
}
- if (warnStack.head.unchecked == true)
- oldWarner.warnUnchecked();
+ if (warnStack.head.hasLint(LintCategory.UNCHECKED))
+ oldWarner.warn(LintCategory.UNCHECKED);
return true;
}
@@ -996,13 +1030,13 @@
|| isSubtype(erasure(s), erasure(t))) {
if (!upcast && s.tag == ARRAY) {
if (!isReifiable(s))
- warnStack.head.warnUnchecked();
+ warnStack.head.warn(LintCategory.UNCHECKED);
return true;
} else if (s.isRaw()) {
return true;
} else if (t.isRaw()) {
if (!isUnbounded(s))
- warnStack.head.warnUnchecked();
+ warnStack.head.warn(LintCategory.UNCHECKED);
return true;
}
// Assume |a| <: |b|
@@ -1035,7 +1069,7 @@
&& !disjointTypes(aLow.allparams(), lowSub.allparams())) {
if (upcast ? giveWarning(a, b) :
giveWarning(b, a))
- warnStack.head.warnUnchecked();
+ warnStack.head.warn(LintCategory.UNCHECKED);
return true;
}
}
@@ -1072,7 +1106,7 @@
return true;
case TYPEVAR:
if (isCastable(s, t, Warner.noWarnings)) {
- warnStack.head.warnUnchecked();
+ warnStack.head.warn(LintCategory.UNCHECKED);
return true;
} else {
return false;
@@ -1101,7 +1135,7 @@
if (isSubtype(t, s)) {
return true;
} else if (isCastable(t.bound, s, Warner.noWarnings)) {
- warnStack.head.warnUnchecked();
+ warnStack.head.warn(LintCategory.UNCHECKED);
return true;
} else {
return false;
@@ -2906,7 +2940,7 @@
return true;
if (!isSubtype(r1.getReturnType(), erasure(r2res)))
return false;
- warner.warnUnchecked();
+ warner.warn(LintCategory.UNCHECKED);
return true;
}
@@ -3122,7 +3156,7 @@
commonSupers = commonSupers.tail;
}
if (giveWarning && !isReifiable(reverse ? from : to))
- warn.warnUnchecked();
+ warn.warn(LintCategory.UNCHECKED);
if (!source.allowCovariantReturns())
// reject if there is a common method signature with
// incompatible return types.
@@ -3156,7 +3190,7 @@
chk.checkCompatibleAbstracts(warn.pos(), from, to);
if (!isReifiable(target) &&
(reverse ? giveWarning(t2, t1) : giveWarning(t1, t2)))
- warn.warnUnchecked();
+ warn.warn(LintCategory.UNCHECKED);
return true;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Dec 13 15:11:00 2010 -0800
@@ -38,6 +38,7 @@
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.code.Type.*;
@@ -669,6 +670,7 @@
Lint lint = env.info.lint.augment(m.attributes_field, m.flags());
Lint prevLint = chk.setLint(lint);
+ MethodSymbol prevMethod = chk.setMethod(m);
try {
chk.checkDeprecatedAnnotation(tree.pos(), m);
@@ -700,7 +702,7 @@
attribStat(l.head, localEnv);
}
- chk.checkVarargMethodDecl(tree);
+ chk.checkVarargsMethodDecl(localEnv, tree);
// Check that type parameters are well-formed.
chk.validate(tree.typarams, localEnv);
@@ -789,6 +791,7 @@
}
finally {
chk.setLint(prevLint);
+ chk.setMethod(prevMethod);
}
}
@@ -2272,8 +2275,8 @@
((VarSymbol)sitesym).isResourceVariable() &&
sym.kind == MTH &&
sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true) &&
- env.info.lint.isEnabled(Lint.LintCategory.TRY)) {
- log.warning(Lint.LintCategory.TRY, tree, "try.explicit.close.call");
+ env.info.lint.isEnabled(LintCategory.TRY)) {
+ log.warning(LintCategory.TRY, tree, "try.explicit.close.call");
}
// Disallow selecting a type from an expression
@@ -2700,7 +2703,7 @@
// For methods, we need to compute the instance type by
// Resolve.instantiate from the symbol's type as well as
// any type arguments and value arguments.
- noteWarner.warned = false;
+ noteWarner.clear();
Type owntype = rs.instantiate(env,
site,
sym,
@@ -2709,7 +2712,7 @@
true,
useVarargs,
noteWarner);
- boolean warned = noteWarner.warned;
+ boolean warned = noteWarner.hasNonSilentLint(LintCategory.UNCHECKED);
// If this fails, something went wrong; we should not have
// found the identifier in the first place.
@@ -2734,7 +2737,7 @@
JCTree arg = args.head;
Warner warn = chk.convertWarner(arg.pos(), arg.type, formals.head);
assertConvertible(arg, arg.type, formals.head, warn);
- warned |= warn.warned;
+ warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
args = args.tail;
formals = formals.tail;
}
@@ -2744,7 +2747,7 @@
JCTree arg = args.head;
Warner warn = chk.convertWarner(arg.pos(), arg.type, varArg);
assertConvertible(arg, arg.type, varArg, warn);
- warned |= warn.warned;
+ warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
args = args.tail;
}
} else if ((sym.flags() & VARARGS) != 0 && allowVarargs) {
@@ -2776,7 +2779,7 @@
JCTree tree = env.tree;
Type argtype = owntype.getParameterTypes().last();
if (owntype.getReturnType().tag != FORALL || warned) {
- chk.checkVararg(env.tree.pos(), owntype.getParameterTypes(), sym, env);
+ chk.checkVararg(env.tree.pos(), owntype.getParameterTypes(), sym);
}
Type elemtype = types.elemtype(argtype);
switch (tree.getTag()) {
@@ -3175,7 +3178,7 @@
chk.checkNonCyclicElements(tree);
// Check for proper use of serialVersionUID
- if (env.info.lint.isEnabled(Lint.LintCategory.SERIAL) &&
+ if (env.info.lint.isEnabled(LintCategory.SERIAL) &&
isSerializable(c) &&
(c.flags() & Flags.ENUM) == 0 &&
(c.flags() & ABSTRACT) == 0) {
@@ -3204,7 +3207,7 @@
Scope.Entry e = c.members().lookup(names.serialVersionUID);
while (e.scope != null && e.sym.kind != VAR) e = e.next();
if (e.scope == null) {
- log.warning(Lint.LintCategory.SERIAL,
+ log.warning(LintCategory.SERIAL,
tree.pos(), "missing.SVUID", c);
return;
}
@@ -3213,17 +3216,17 @@
VarSymbol svuid = (VarSymbol)e.sym;
if ((svuid.flags() & (STATIC | FINAL)) !=
(STATIC | FINAL))
- log.warning(Lint.LintCategory.SERIAL,
+ log.warning(LintCategory.SERIAL,
TreeInfo.diagnosticPositionFor(svuid, tree), "improper.SVUID", c);
// check that it is long
else if (svuid.type.tag != TypeTags.LONG)
- log.warning(Lint.LintCategory.SERIAL,
+ log.warning(LintCategory.SERIAL,
TreeInfo.diagnosticPositionFor(svuid, tree), "long.SVUID", c);
// check constant
else if (svuid.getConstValue() == null)
- log.warning(Lint.LintCategory.SERIAL,
+ log.warning(LintCategory.SERIAL,
TreeInfo.diagnosticPositionFor(svuid, tree), "constant.SVUID", c);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Dec 13 15:11:00 2010 -0800
@@ -75,6 +75,10 @@
// visits all the various parts of the trees during attribution.
private Lint lint;
+ // The method being analyzed in Attr - it is set/reset as needed by
+ // Attr as it visits new method declarations.
+ private MethodSymbol method;
+
public static Check instance(Context context) {
Check instance = context.get(checkKey);
if (instance == null)
@@ -100,6 +104,7 @@
allowGenerics = source.allowGenerics();
allowAnnotations = source.allowAnnotations();
allowCovariantReturns = source.allowCovariantReturns();
+ allowSimplifiedVarargs = source.allowSimplifiedVarargs();
complexInference = options.isSet(COMPLEXINFERENCE);
skipAnnotations = options.isSet("skipAnnotations");
warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
@@ -136,6 +141,10 @@
*/
boolean allowCovariantReturns;
+ /** Switch: simplified varargs enabled?
+ */
+ boolean allowSimplifiedVarargs;
+
/** Switch: -complexinference option set?
*/
boolean complexInference;
@@ -175,6 +184,12 @@
return prev;
}
+ MethodSymbol setMethod(MethodSymbol newMethod) {
+ MethodSymbol prev = method;
+ method = newMethod;
+ return prev;
+ }
+
/** Warn about deprecated symbol.
* @param pos Position to be used for error reporting.
* @param sym The deprecated symbol.
@@ -197,9 +212,9 @@
* @param pos Position to be used for error reporting.
* @param sym The deprecated symbol.
*/
- void warnUnsafeVararg(DiagnosticPosition pos, Type elemType) {
- if (!lint.isSuppressed(LintCategory.VARARGS))
- unsafeVarargsHandler.report(pos, "varargs.non.reifiable.type", elemType);
+ void warnUnsafeVararg(DiagnosticPosition pos, String key, Object... args) {
+ if (lint.isEnabled(LintCategory.VARARGS) && allowSimplifiedVarargs)
+ log.warning(LintCategory.VARARGS, pos, key, args);
}
/** Warn about using proprietary API.
@@ -222,7 +237,6 @@
public void reportDeferredDiagnostics() {
deprecationHandler.reportDeferredDiagnostic();
uncheckedHandler.reportDeferredDiagnostic();
- unsafeVarargsHandler.reportDeferredDiagnostic();
sunApiHandler.reportDeferredDiagnostic();
}
@@ -705,29 +719,56 @@
}
}
- void checkVarargMethodDecl(JCMethodDecl tree) {
+ void checkVarargsMethodDecl(Env<AttrContext> env, JCMethodDecl tree) {
MethodSymbol m = tree.sym;
- //check the element type of the vararg
+ if (!allowSimplifiedVarargs) return;
+ boolean hasTrustMeAnno = m.attribute(syms.trustMeType.tsym) != null;
+ Type varargElemType = null;
if (m.isVarArgs()) {
- Type varargElemType = types.elemtype(tree.params.last().type);
- if (!types.isReifiable(varargElemType)) {
- warnUnsafeVararg(tree.params.head.pos(), varargElemType);
+ varargElemType = types.elemtype(tree.params.last().type);
+ }
+ if (hasTrustMeAnno && !isTrustMeAllowedOnMethod(m)) {
+ if (varargElemType != null) {
+ log.error(tree,
+ "varargs.invalid.trustme.anno",
+ syms.trustMeType.tsym,
+ diags.fragment("varargs.trustme.on.virtual.varargs", m));
+ } else {
+ log.error(tree,
+ "varargs.invalid.trustme.anno",
+ syms.trustMeType.tsym,
+ diags.fragment("varargs.trustme.on.non.varargs.meth", m));
}
+ } else if (hasTrustMeAnno && varargElemType != null &&
+ types.isReifiable(varargElemType)) {
+ warnUnsafeVararg(tree,
+ "varargs.redundant.trustme.anno",
+ syms.trustMeType.tsym,
+ diags.fragment("varargs.trustme.on.reifiable.varargs", varargElemType));
+ }
+ else if (!hasTrustMeAnno && varargElemType != null &&
+ !types.isReifiable(varargElemType)) {
+ warnUnchecked(tree.params.head.pos(), "unchecked.varargs.non.reifiable.type", varargElemType);
}
}
+ //where
+ private boolean isTrustMeAllowedOnMethod(Symbol s) {
+ return (s.flags() & VARARGS) != 0 &&
+ (s.isConstructor() ||
+ (s.flags() & (STATIC | FINAL)) != 0);
+ }
/**
* Check that vararg method call is sound
* @param pos Position to be used for error reporting.
* @param argtypes Actual arguments supplied to vararg method.
*/
- void checkVararg(DiagnosticPosition pos, List<Type> argtypes, Symbol msym, Env<AttrContext> env) {
- Env<AttrContext> calleeLintEnv = env;
- while (calleeLintEnv.info.lint == null)
- calleeLintEnv = calleeLintEnv.next;
- Lint calleeLint = calleeLintEnv.info.lint.augment(msym.attributes_field, msym.flags());
+ void checkVararg(DiagnosticPosition pos, List<Type> argtypes, Symbol msym) {
Type argtype = argtypes.last();
- if (!types.isReifiable(argtype) && !calleeLint.isSuppressed(Lint.LintCategory.VARARGS)) {
+ if (!types.isReifiable(argtype) &&
+ (!allowSimplifiedVarargs ||
+ msym.attribute(syms.trustMeType.tsym) == null ||
+ !isTrustMeAllowedOnMethod(msym))) {
warnUnchecked(pos,
"unchecked.generic.array.creation",
argtype);
@@ -1075,12 +1116,12 @@
}
void checkRaw(JCTree tree, Env<AttrContext> env) {
- if (lint.isEnabled(Lint.LintCategory.RAW) &&
+ if (lint.isEnabled(LintCategory.RAW) &&
tree.type.tag == CLASS &&
!TreeInfo.isDiamond(tree) &&
!env.enclClass.name.isEmpty() && //anonymous or intersection
tree.type.isRaw()) {
- log.warning(Lint.LintCategory.RAW,
+ log.warning(LintCategory.RAW,
tree.pos(), "raw.class.use", tree.type, tree.type.tsym.type);
}
}
@@ -1347,7 +1388,7 @@
Type mtres = mt.getReturnType();
Type otres = types.subst(ot.getReturnType(), otvars, mtvars);
- overrideWarner.warned = false;
+ overrideWarner.clear();
boolean resultTypesOK =
types.returnTypeSubstitutable(mt, ot, otres, overrideWarner);
if (!resultTypesOK) {
@@ -1362,7 +1403,7 @@
mtres, otres);
return;
}
- } else if (overrideWarner.warned) {
+ } else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) {
warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
"override.unchecked.ret",
uncheckedOverrides(m, other),
@@ -1391,7 +1432,7 @@
// Optional warning if varargs don't agree
if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)
- && lint.isEnabled(Lint.LintCategory.OVERRIDES)) {
+ && lint.isEnabled(LintCategory.OVERRIDES)) {
log.warning(TreeInfo.diagnosticPositionFor(m, tree),
((m.flags() & Flags.VARARGS) != 0)
? "override.varargs.missing"
@@ -2380,11 +2421,11 @@
void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) {
if (allowAnnotations &&
- lint.isEnabled(Lint.LintCategory.DEP_ANN) &&
+ lint.isEnabled(LintCategory.DEP_ANN) &&
(s.flags() & DEPRECATED) != 0 &&
!syms.deprecatedType.isErroneous() &&
s.attribute(syms.deprecatedType.tsym) == null) {
- log.warning(Lint.LintCategory.DEP_ANN,
+ log.warning(LintCategory.DEP_ANN,
pos, "missing.deprecated.annotation");
}
}
@@ -2530,13 +2571,13 @@
*/
void checkDivZero(DiagnosticPosition pos, Symbol operator, Type operand) {
if (operand.constValue() != null
- && lint.isEnabled(Lint.LintCategory.DIVZERO)
+ && lint.isEnabled(LintCategory.DIVZERO)
&& operand.tag <= LONG
&& ((Number) (operand.constValue())).longValue() == 0) {
int opc = ((OperatorSymbol)operator).opcode;
if (opc == ByteCodes.idiv || opc == ByteCodes.imod
|| opc == ByteCodes.ldiv || opc == ByteCodes.lmod) {
- log.warning(Lint.LintCategory.DIVZERO, pos, "div.zero");
+ log.warning(LintCategory.DIVZERO, pos, "div.zero");
}
}
}
@@ -2545,8 +2586,8 @@
* Check for empty statements after if
*/
void checkEmptyIf(JCIf tree) {
- if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(Lint.LintCategory.EMPTY))
- log.warning(Lint.LintCategory.EMPTY, tree.thenpart.pos(), "empty.if");
+ if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(LintCategory.EMPTY))
+ log.warning(LintCategory.EMPTY, tree.thenpart.pos(), "empty.if");
}
/** Check that symbol is unique in given scope.
@@ -2654,23 +2695,36 @@
}
private class ConversionWarner extends Warner {
- final String key;
+ final String uncheckedKey;
final Type found;
final Type expected;
- public ConversionWarner(DiagnosticPosition pos, String key, Type found, Type expected) {
+ public ConversionWarner(DiagnosticPosition pos, String uncheckedKey, Type found, Type expected) {
super(pos);
- this.key = key;
+ this.uncheckedKey = uncheckedKey;
this.found = found;
this.expected = expected;
}
@Override
- public void warnUnchecked() {
+ public void warn(LintCategory lint) {
boolean warned = this.warned;
- super.warnUnchecked();
+ super.warn(lint);
if (warned) return; // suppress redundant diagnostics
- Object problem = diags.fragment(key);
- Check.this.warnUnchecked(pos(), "prob.found.req", problem, found, expected);
+ switch (lint) {
+ case UNCHECKED:
+ Check.this.warnUnchecked(pos(), "prob.found.req", diags.fragment(uncheckedKey), found, expected);
+ break;
+ case VARARGS:
+ if (method != null &&
+ method.attribute(syms.trustMeType.tsym) != null &&
+ isTrustMeAllowedOnMethod(method) &&
+ !types.isReifiable(method.type.getParameterTypes().last())) {
+ Check.this.warnUnsafeVararg(pos(), "varargs.unsafe.use.varargs.param", method.params.last());
+ }
+ break;
+ default:
+ throw new AssertionError("Unexpected lint: " + lint);
+ }
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Mon Dec 13 15:11:00 2010 -0800
@@ -481,7 +481,7 @@
checkWithinBounds(all_tvars,
types.subst(inferredTypes, tvars, inferred), warn);
if (useVarargs) {
- chk.checkVararg(env.tree.pos(), formals, msym, env);
+ chk.checkVararg(env.tree.pos(), formals, msym);
}
return super.inst(inferred, types);
}};
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Dec 13 15:11:00 2010 -0800
@@ -77,6 +77,7 @@
private final Target target;
private final boolean skipAnnotations;
+ private final boolean allowSimplifiedVarargs;
public static MemberEnter instance(Context context) {
MemberEnter instance = context.get(memberEnterKey);
@@ -103,6 +104,8 @@
target = Target.instance(context);
Options options = Options.instance(context);
skipAnnotations = options.isSet("skipAnnotations");
+ Source source = Source.instance(context);
+ allowSimplifiedVarargs = source.allowSimplifiedVarargs();
}
/** A queue for classes whose members still need to be entered into the
@@ -617,6 +620,14 @@
localEnv.info.staticLevel++;
}
attr.attribType(tree.vartype, localEnv);
+ if ((tree.mods.flags & VARARGS) != 0) {
+ //if we are entering a varargs parameter, we need to replace its type
+ //(a plain array type) with the more precise VarargsType --- we need
+ //to do it this way because varargs is represented in the tree as a modifier
+ //on the parameter declaration, and not as a distinct type of array node.
+ ArrayType atype = (ArrayType)tree.vartype.type;
+ tree.vartype.type = atype.makeVarargs();
+ }
Scope enclScope = enter.enterScope(env);
VarSymbol v =
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Dec 13 15:11:00 2010 -0800
@@ -815,13 +815,13 @@
}
//where
private boolean signatureMoreSpecific(Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) {
+ noteWarner.clear();
Type mtype1 = types.memberType(site, adjustVarargs(m1, m2, useVarargs));
- noteWarner.unchecked = false;
return (instantiate(env, site, adjustVarargs(m2, m1, useVarargs), types.lowerBoundArgtypes(mtype1), null,
allowBoxing, false, noteWarner) != null ||
useVarargs && instantiate(env, site, adjustVarargs(m2, m1, useVarargs), types.lowerBoundArgtypes(mtype1), null,
allowBoxing, true, noteWarner) != null) &&
- !noteWarner.unchecked;
+ !noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
}
//where
private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) {
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Dec 13 15:11:00 2010 -0800
@@ -105,10 +105,15 @@
*/
boolean allowAnnotations;
- /** Lint option: warn about classfile issues
+ /** Switch: allow simplified varargs.
+ */
+ boolean allowSimplifiedVarargs;
+
+ /** Lint option: warn about classfile issues
*/
boolean lintClassfile;
+
/** Switch: preserve parameter names from the variable table.
*/
public boolean saveParameterNames;
@@ -279,6 +284,7 @@
allowGenerics = source.allowGenerics();
allowVarargs = source.allowVarargs();
allowAnnotations = source.allowAnnotations();
+ allowSimplifiedVarargs = source.allowSimplifiedVarargs();
saveParameterNames = options.isSet("save-parameter-names");
cacheCompletionFailure = options.isUnset("dev");
preferSource = "source".equals(options.get("-Xprefer"));
@@ -1883,7 +1889,7 @@
// instance, however, there is no reliable way to tell so
// we never strip this$n
if (!currentOwner.name.isEmpty())
- type = new MethodType(type.getParameterTypes().tail,
+ type = new MethodType(adjustMethodParams(flags, type.getParameterTypes()),
type.getReturnType(),
type.getThrownTypes(),
syms.methodClass);
@@ -1903,6 +1909,21 @@
return m;
}
+ private List<Type> adjustMethodParams(long flags, List<Type> args) {
+ boolean isVarargs = (flags & VARARGS) != 0;
+ if (isVarargs) {
+ Type varargsElem = args.last();
+ ListBuffer<Type> adjustedArgs = ListBuffer.lb();
+ for (Type t : args) {
+ adjustedArgs.append(t != varargsElem ?
+ t :
+ ((ArrayType)t).makeVarargs());
+ }
+ args = adjustedArgs.toList();
+ }
+ return args.tail;
+ }
+
/**
* Init the parameter names array.
* Parameter names are currently inferred from the names in the
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Dec 13 15:11:00 2010 -0800
@@ -516,6 +516,15 @@
compiler.err.var.might.be.assigned.in.loop=\
variable {0} might be assigned in loop
+compiler.err.varargs.invalid.trustme.anno=\
+ Invalid {0} annotation. {1}
+compiler.misc.varargs.trustme.on.reifiable.varargs=\
+ Varargs element type {0} is reifiable.
+compiler.misc.varargs.trustme.on.non.varargs.meth=\
+ Method {0} is not a varargs method.
+compiler.misc.varargs.trustme.on.virtual.varargs=\
+ Instance method {0} is not final.
+
# In the following string, {1} will always be the detail message from
# java.io.IOException.
compiler.err.class.cant.write=\
@@ -600,20 +609,6 @@
compiler.note.unchecked.plural.additional=\
Some input files additionally use unchecked or unsafe operations.
-compiler.note.varargs.filename=\
- {0} declares unsafe vararg methods.
-compiler.note.varargs.plural=\
- Some input files declare unsafe vararg methods.
-# The following string may appear after one of the above unsafe varargs
-# messages.
-compiler.note.varargs.recompile=\
- Recompile with -Xlint:varargs for details.
-
-compiler.note.varargs.filename.additional=\
- {0} declares additional unsafe vararg methods.
-compiler.note.varargs.plural.additional=\
- Some input files additionally declares unsafe vararg methods.
-
compiler.note.sunapi.filename=\
{0} uses internal proprietary API that may be removed in a future release.
compiler.note.sunapi.plural=\
@@ -841,9 +836,12 @@
compiler.warn.unchecked.generic.array.creation=\
unchecked generic array creation for varargs parameter of type {0}
-compiler.warn.varargs.non.reifiable.type=\
+compiler.warn.unchecked.varargs.non.reifiable.type=\
Possible heap pollution from parameterized vararg type {0}
+compiler.warn.varargs.unsafe.use.varargs.param=\
+ Varargs method could cause heap pollution from non-reifiable varargs parameter {0}
+
compiler.warn.missing.deprecated.annotation=\
deprecated item is not annotated with @Deprecated
@@ -876,6 +874,9 @@
explicit: {0}\n\
inferred: {1}
+compiler.warn.varargs.redundant.trustme.anno=\
+ Redundant {0} annotation. {1}
+
#####
## The following are tokens which are non-terminals in the language. They should
--- a/langtools/src/share/classes/com/sun/tools/javac/util/List.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/List.java Mon Dec 13 15:11:00 2010 -0800
@@ -103,7 +103,7 @@
/** Construct a list consisting of given elements.
*/
- @SuppressWarnings("varargs")
+ @SuppressWarnings({"varargs", "unchecked"})
public static <A> List<A> of(A x1, A x2, A x3, A... rest) {
return new List<A>(x1, new List<A>(x2, new List<A>(x3, from(rest))));
}
--- a/langtools/src/share/classes/com/sun/tools/javac/util/Warner.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/Warner.java Mon Dec 13 15:11:00 2010 -0800
@@ -25,7 +25,9 @@
package com.sun.tools.javac.util;
+import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import java.util.EnumSet;
/**
* An interface to support optional warnings, needed for support of
@@ -40,25 +42,45 @@
public static final Warner noWarnings = new Warner();
private DiagnosticPosition pos = null;
- public boolean warned = false;
- public boolean unchecked = false;
+ protected boolean warned = false;
+ private EnumSet<LintCategory> nonSilentLintSet = EnumSet.noneOf(LintCategory.class);
+ private EnumSet<LintCategory> silentLintSet = EnumSet.noneOf(LintCategory.class);
public DiagnosticPosition pos() {
return pos;
}
- public void warnUnchecked() {
- warned = true;
- unchecked = true;
+ public void warn(LintCategory lint) {
+ nonSilentLintSet.add(lint);
}
- public void silentUnchecked() {
- unchecked = true;
+
+ public void silentWarn(LintCategory lint) {
+ silentLintSet.add(lint);
}
public Warner(DiagnosticPosition pos) {
this.pos = pos;
}
+ public boolean hasSilentLint(LintCategory lint) {
+ return silentLintSet.contains(lint);
+ }
+
+ public boolean hasNonSilentLint(LintCategory lint) {
+ return nonSilentLintSet.contains(lint);
+ }
+
+ public boolean hasLint(LintCategory lint) {
+ return hasSilentLint(lint) ||
+ hasNonSilentLint(lint);
+ }
+
+ public void clear() {
+ nonSilentLintSet.clear();
+ silentLintSet.clear();
+ this.warned = false;
+ }
+
public Warner() {
this(null);
}
--- a/langtools/test/tools/javac/diags/CheckExamples.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/test/tools/javac/diags/CheckExamples.java Mon Dec 13 15:11:00 2010 -0800
@@ -129,12 +129,17 @@
File testSrc = new File(System.getProperty("test.src"));
File examples = new File(testSrc, "examples");
for (File f: examples.listFiles()) {
- if (f.isDirectory() || f.isFile() && f.getName().endsWith(".java"))
+ if (isValidExample(f))
results.add(new Example(f));
}
return results;
}
+ boolean isValidExample(File f) {
+ return (f.isDirectory() && f.list().length > 0) ||
+ (f.isFile() && f.getName().endsWith(".java"));
+ }
+
/**
* Get the contents of the "not-yet" list.
*/
--- a/langtools/test/tools/javac/diags/RunExamples.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/test/tools/javac/diags/RunExamples.java Mon Dec 13 15:11:00 2010 -0800
@@ -52,7 +52,7 @@
*/
public class RunExamples {
public static void main(String... args) throws Exception {
- boolean jtreg = (System.getProperty("test.src") != null);
+ jtreg = (System.getProperty("test.src") != null);
File tmpDir;
if (jtreg) {
// use standard jtreg scratch directory: the current directory
@@ -166,12 +166,17 @@
Set<Example> getExamples(File examplesDir) {
Set<Example> results = new TreeSet<Example>();
for (File f: examplesDir.listFiles()) {
- if (f.isDirectory() || f.isFile() && f.getName().endsWith(".java"))
+ if (isValidExample(f))
results.add(new Example(f));
}
return results;
}
+ boolean isValidExample(File f) {
+ return (f.isDirectory() && (!jtreg || f.list().length > 0)) ||
+ (f.isFile() && f.getName().endsWith(".java"));
+ }
+
/**
* Report an error.
*/
@@ -180,6 +185,8 @@
errors++;
}
+ static boolean jtreg;
+
int errors;
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/TrustMeOnNonVarargsMeth.java Mon Dec 13 15:11:00 2010 -0800
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010, 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.varargs.invalid.trustme.anno
+// key: compiler.misc.varargs.trustme.on.non.varargs.meth
+// options: -Xlint:varargs
+
+class TrustMeOnNonVarargsMeth {
+ @SafeVarargs static void m(String[] args) { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/TrustMeOnReifiableVarargsParam.java Mon Dec 13 15:11:00 2010 -0800
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010, 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.warn.varargs.redundant.trustme.anno
+// key: compiler.misc.varargs.trustme.on.reifiable.varargs
+// options: -Xlint:varargs
+
+class TrustMeOnReifiableVarargsParam {
+ @SafeVarargs static void m(String... args) { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/TrustMeOnVirtualMethod.java Mon Dec 13 15:11:00 2010 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010, 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.varargs.invalid.trustme.anno
+// key: compiler.misc.varargs.trustme.on.virtual.varargs
+// options: -Xlint:varargs,unchecked
+
+import java.util.List;
+
+class TrustMeOnVirtualMethod {
+ @SafeVarargs void m(List<String>... args) { }
+}
--- a/langtools/test/tools/javac/diags/examples/UncheckedGenericArrayCreation.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/test/tools/javac/diags/examples/UncheckedGenericArrayCreation.java Mon Dec 13 15:11:00 2010 -0800
@@ -22,10 +22,8 @@
*/
// key: compiler.warn.unchecked.generic.array.creation
-// key: compiler.warn.varargs.non.reifiable.type
-// options: -Xlint:unchecked,varargs
-
-import java.util.*;
+// key: compiler.warn.unchecked.varargs.non.reifiable.type
+// options: -Xlint:unchecked
class UncheckedGenericArrayCreation<T> {
void m(T t1, T t2, T t3) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/UnsafeUseOfVarargsParam.java Mon Dec 13 15:11:00 2010 -0800
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010, 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.warn.varargs.unsafe.use.varargs.param
+// options: -Xlint:varargs
+
+class UnsafeUseOfVarargsParam {
+ @SafeVarargs static <X> void m(X... x) {
+ Object[] o = x;
+ }
+}
--- a/langtools/test/tools/javac/diags/examples/VarargsFilename.java Mon Dec 13 14:08:01 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2010, 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.note.varargs.filename
-// key: compiler.note.varargs.recompile
-
-class VarargsFilename<T> {
- void m(T... items) { }
-}
--- a/langtools/test/tools/javac/diags/examples/VarargsFilenameAdditional.java Mon Dec 13 14:08:01 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2010, 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.note.varargs.filename.additional
-// key: compiler.warn.varargs.non.reifiable.type
-// options: -Xlint:varargs -Xmaxwarns 1
-
-class VarargsFilenameAdditional<T> {
- void m1(T... items) { }
- void m2(T... items) { }
-}
--- a/langtools/test/tools/javac/diags/examples/VarargsNonReifiableType.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/test/tools/javac/diags/examples/VarargsNonReifiableType.java Mon Dec 13 15:11:00 2010 -0800
@@ -21,10 +21,8 @@
* questions.
*/
-// key: compiler.warn.varargs.non.reifiable.type
-// options: -Xlint:varargs
-
-import java.util.*;
+// key: compiler.warn.unchecked.varargs.non.reifiable.type
+// options: -Xlint:unchecked
class VarargsNonReifiableType<T> {
void m(T... items) {
--- a/langtools/test/tools/javac/diags/examples/VarargsPlural/VarargsFilename.java Mon Dec 13 14:08:01 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2010, 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.
- */
-
-class VarargsFilename<T> {
- void m(T... items) { }
-}
--- a/langtools/test/tools/javac/diags/examples/VarargsPlural/VarargsPlural.java Mon Dec 13 14:08:01 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2010, 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.note.varargs.plural
-// key: compiler.note.varargs.recompile
-
-class VarargsPlural<T> {
- void m(T... items) { }
-}
--- a/langtools/test/tools/javac/diags/examples/VarargsPluralAdditional/VarargsFilename.java Mon Dec 13 14:08:01 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2010, 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.
- */
-
-class VarargsFilename<T> {
- void m(T... items) { }
-}
--- a/langtools/test/tools/javac/diags/examples/VarargsPluralAdditional/VarargsPlural.java Mon Dec 13 14:08:01 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2010, 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.
- */
-
-class VarargsPlural<T> {
- void m(T... items) { }
-}
--- a/langtools/test/tools/javac/diags/examples/VarargsPluralAdditional/VarargsPluralAdditional.java Mon Dec 13 14:08:01 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2010, 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.note.varargs.plural.additional
-// key: compiler.warn.varargs.non.reifiable.type
-// options: -Xlint:varargs -Xmaxwarns 1
-
-class VarargsPluralAdditional<T> {
- void m(T... items) { }
-}
--- a/langtools/test/tools/javac/varargs/6730476/T6730476a.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/test/tools/javac/varargs/6730476/T6730476a.java Mon Dec 13 15:11:00 2010 -0800
@@ -32,6 +32,7 @@
*/
class T6730476a {
+ @SuppressWarnings("unchecked")
<T> void f(int i, T ... x) {}
void g() {
f(1);
--- a/langtools/test/tools/javac/varargs/6806876/T6806876.out Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/test/tools/javac/varargs/6806876/T6806876.out Mon Dec 13 15:11:00 2010 -0800
@@ -1,6 +1,5 @@
T6806876.java:11:32: compiler.warn.unchecked.generic.array.creation: java.lang.Number&java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>[]
+T6806876.java:14:19: compiler.warn.unchecked.varargs.non.reifiable.type: T
- compiler.err.warnings.and.werror
-- compiler.note.varargs.filename: T6806876.java
-- compiler.note.varargs.recompile
1 error
-1 warning
+2 warnings
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/varargs/6993978/T6993978neg.java Mon Dec 13 15:11:00 2010 -0800
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6993978
+ * @author mcimadamore
+ * @summary ClassCastException occurs in assignment expressions without any heap pollutions
+ * @compile/fail/ref=T6993978neg.out -Xlint:unchecked -Werror -XDrawDiagnostics T6993978neg.java
+ */
+
+import java.util.List;
+
+class T6993978neg {
+ @SuppressWarnings({"varargs","unchecked"})
+ static <X> void m(X... x) { }
+ static void test(List<String> ls) {
+ m(ls); //compiler should still give unchecked here
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/varargs/6993978/T6993978neg.out Mon Dec 13 15:11:00 2010 -0800
@@ -0,0 +1,4 @@
+T6993978neg.java:15:9: compiler.warn.unchecked.generic.array.creation: java.util.List<java.lang.String>[]
+- compiler.err.warnings.and.werror
+1 error
+1 warning
--- a/langtools/test/tools/javac/varargs/warning/Warn4.java Mon Dec 13 14:08:01 2010 -0800
+++ b/langtools/test/tools/javac/varargs/warning/Warn4.java Mon Dec 13 15:11:00 2010 -0800
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 6945418
+ * @bug 6945418 6993978
* @summary Project Coin: Simplified Varargs Method Invocation
* @author mcimadamore
* @run main Warn4
@@ -48,96 +48,95 @@
final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
enum Warning {
- UNCHECKED("unchecked"),
- VARARGS("varargs");
+ UNCHECKED("generic.array.creation"),
+ VARARGS("varargs.non.reifiable.type");
- String category;
+ String key;
- Warning(String category) {
- this.category = category;
+ Warning(String key) {
+ this.key = key;
}
- boolean isEnabled(XlintOption xlint, SuppressLevel suppressLevel) {
- return Arrays.asList(xlint.enabledWarnings).contains(this);
- }
+ boolean isSuppressed(TrustMe trustMe, SourceLevel source, SuppressLevel suppressLevelClient,
+ SuppressLevel suppressLevelDecl, ModifierKind modKind) {
+ switch(this) {
+ case VARARGS:
+ return source == SourceLevel.JDK_6 ||
+ suppressLevelDecl == SuppressLevel.UNCHECKED ||
+ trustMe == TrustMe.TRUST;
+ case UNCHECKED:
+ return suppressLevelClient == SuppressLevel.UNCHECKED ||
+ (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE && source == SourceLevel.JDK_7);
+ }
- boolean isSuppressed(SuppressLevel suppressLevel) {
- return Arrays.asList(suppressLevel.suppressedWarnings).contains(VARARGS);
+ SuppressLevel supLev = this == VARARGS ?
+ suppressLevelDecl :
+ suppressLevelClient;
+ return supLev == SuppressLevel.UNCHECKED ||
+ (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE);
}
}
- enum XlintOption {
- NONE(),
- UNCHECKED(Warning.UNCHECKED),
- VARARGS(Warning.VARARGS),
- ALL(Warning.UNCHECKED, Warning.VARARGS);
+ enum SourceLevel {
+ JDK_6("6"),
+ JDK_7("7");
- Warning[] enabledWarnings;
+ String sourceKey;
- XlintOption(Warning... enabledWarnings) {
- this.enabledWarnings = enabledWarnings;
+ SourceLevel(String sourceKey) {
+ this.sourceKey = sourceKey;
}
+ }
- String getXlintOption() {
- StringBuilder buf = new StringBuilder();
- String sep = "";
- for (Warning w : enabledWarnings) {
- buf.append(sep);
- buf.append(w.category);
- sep=",";
- }
- return "-Xlint:" +
- (this == NONE ? "none" : buf.toString());
+ enum TrustMe {
+ DONT_TRUST(""),
+ TRUST("@java.lang.SafeVarargs");
+
+ String anno;
+
+ TrustMe(String anno) {
+ this.anno = anno;
+ }
+ }
+
+ enum ModifierKind {
+ NONE(" "),
+ FINAL("final "),
+ STATIC("static ");
+
+ String mod;
+
+ ModifierKind(String mod) {
+ this.mod = mod;
}
}
enum SuppressLevel {
- NONE(),
- UNCHECKED(Warning.UNCHECKED),
- VARARGS(Warning.VARARGS),
- ALL(Warning.UNCHECKED, Warning.VARARGS);
+ NONE(""),
+ UNCHECKED("unchecked");
- Warning[] suppressedWarnings;
+ String lint;
- SuppressLevel(Warning... suppressedWarnings) {
- this.suppressedWarnings = suppressedWarnings;
+ SuppressLevel(String lint) {
+ this.lint = lint;
}
- String getSuppressAnnotation() {
- StringBuilder buf = new StringBuilder();
- String sep = "";
- for (Warning w : suppressedWarnings) {
- buf.append(sep);
- buf.append("\"");
- buf.append(w.category);
- buf.append("\"");
- sep=",";
- }
- return this == NONE ? "" :
- "@SuppressWarnings({" + buf.toString() + "})";
+ String getSuppressAnno() {
+ return "@SuppressWarnings(\"" + lint + "\")";
}
}
enum Signature {
-
- EXTENDS_TVAR("<Z> void #name(List<? extends Z>#arity arg) { #body }",
- new Warning[][] {both, both, both, both, error, both, both, both, error}),
- SUPER_TVAR("<Z> void #name(List<? super Z>#arity arg) { #body }",
- new Warning[][] {error, both, error, both, error, error, both, both, error}),
UNBOUND("void #name(List<?>#arity arg) { #body }",
- new Warning[][] {none, none, none, none, none, none, none, none, error}),
+ new Warning[][] {none, none, none, none, error}),
INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }",
- new Warning[][] {both, both, both, both, error, both, both, both, error}),
+ new Warning[][] {both, both, error, both, error}),
TVAR("<Z> void #name(Z#arity arg) { #body }",
- new Warning[][] {both, both, both, both, both, both, both, both, vararg}),
- EXTENDS("void #name(List<? extends String>#arity arg) { #body }",
- new Warning[][] {error, error, error, error, error, both, error, both, error}),
- SUPER("void #name(List<? super String>#arity arg) { #body }",
- new Warning[][] {error, error, error, error, error, error, both, both, error}),
+ new Warning[][] {both, both, both, both, vararg}),
INVARIANT("void #name(List<String>#arity arg) { #body }",
- new Warning[][] {error, error, error, error, error, error, error, both, error}),
+ new Warning[][] {error, error, error, both, error}),
UNPARAMETERIZED("void #name(String#arity arg) { #body }",
- new Warning[][] {error, error, error, error, error, error, error, error, none});
+ new Warning[][] {error, error, error, error, none});
String template;
Warning[][] warnings;
@@ -163,15 +162,24 @@
}
public static void main(String... args) throws Exception {
- for (XlintOption xlint : XlintOption.values()) {
- for (SuppressLevel suppressLevel : SuppressLevel.values()) {
- for (Signature vararg_meth : Signature.values()) {
- for (Signature client_meth : Signature.values()) {
- if (vararg_meth.isApplicableTo(client_meth)) {
- test(xlint,
- suppressLevel,
- vararg_meth,
- client_meth);
+ for (SourceLevel sourceLevel : SourceLevel.values()) {
+ for (TrustMe trustMe : TrustMe.values()) {
+ for (SuppressLevel suppressLevelClient : SuppressLevel.values()) {
+ for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) {
+ for (ModifierKind modKind : ModifierKind.values()) {
+ for (Signature vararg_meth : Signature.values()) {
+ for (Signature client_meth : Signature.values()) {
+ if (vararg_meth.isApplicableTo(client_meth)) {
+ test(sourceLevel,
+ trustMe,
+ suppressLevelClient,
+ suppressLevelDecl,
+ modKind,
+ vararg_meth,
+ client_meth);
+ }
+ }
+ }
}
}
}
@@ -179,37 +187,37 @@
}
}
- static void test(XlintOption xlint, SuppressLevel suppressLevel,
- Signature vararg_meth, Signature client_meth) throws Exception {
+ static void test(SourceLevel sourceLevel, TrustMe trustMe, SuppressLevel suppressLevelClient,
+ SuppressLevel suppressLevelDecl, ModifierKind modKind, Signature vararg_meth, Signature client_meth) throws Exception {
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
- JavaSource source = new JavaSource(suppressLevel, vararg_meth, client_meth);
+ JavaSource source = new JavaSource(trustMe, suppressLevelClient, suppressLevelDecl, modKind, vararg_meth, client_meth);
DiagnosticChecker dc = new DiagnosticChecker();
JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
- Arrays.asList(xlint.getXlintOption()), null, Arrays.asList(source));
+ Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey),
+ null, Arrays.asList(source));
ct.generate(); //to get mandatory notes
- check(dc.warnings,
- dc.notes,
+ check(dc.warnings, sourceLevel,
new boolean[] {vararg_meth.giveUnchecked(client_meth),
vararg_meth.giveVarargs(client_meth)},
- source, xlint, suppressLevel);
+ source, trustMe, suppressLevelClient, suppressLevelDecl, modKind);
}
- static void check(Set<Warning> warnings, Set<Warning> notes, boolean[] warnArr, JavaSource source, XlintOption xlint, SuppressLevel suppressLevel) {
+ static void check(Set<Warning> warnings, SourceLevel sourceLevel, boolean[] warnArr, JavaSource source,
+ TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, ModifierKind modKind) {
boolean badOutput = false;
for (Warning wkind : Warning.values()) {
- badOutput |= (warnArr[wkind.ordinal()] && !wkind.isSuppressed(suppressLevel)) !=
- (wkind.isEnabled(xlint, suppressLevel) ?
- warnings.contains(wkind) :
- notes.contains(wkind));
+ boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
+ suppressLevelClient, suppressLevelDecl, modKind);
+ System.out.println("SUPPRESSED = " + isSuppressed);
+ badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != warnings.contains(wkind);
}
if (badOutput) {
throw new Error("invalid diagnostics for source:\n" +
source.getCharContent(true) +
- "\nOptions: " + xlint.getXlintOption() +
"\nExpected unchecked warning: " + warnArr[0] +
"\nExpected unsafe vararg warning: " + warnArr[1] +
"\nWarnings: " + warnings +
- "\nNotes: " + notes);
+ "\nSource level: " + sourceLevel);
}
}
@@ -217,18 +225,20 @@
String source;
- public JavaSource(SuppressLevel suppressLevel, Signature vararg_meth, Signature client_meth) {
+ public JavaSource(TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl,
+ ModifierKind modKind, Signature vararg_meth, Signature client_meth) {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
String meth1 = vararg_meth.template.replace("#arity", "...");
meth1 = meth1.replace("#name", "m");
meth1 = meth1.replace("#body", "");
- meth1 = suppressLevel.getSuppressAnnotation() + meth1;
+ meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + modKind.mod + meth1;
String meth2 = client_meth.template.replace("#arity", "");
meth2 = meth2.replace("#name", "test");
meth2 = meth2.replace("#body", "m(arg);");
+ meth2 = suppressLevelClient.getSuppressAnno() + meth2;
source = "import java.util.List;\n" +
- "class Test {\n" + meth1 +
- "\n" + meth2 + "\n}\n";
+ "class Test {\n" + meth1 +
+ "\n" + meth2 + "\n}\n";
}
@Override
@@ -240,19 +250,15 @@
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
Set<Warning> warnings = new HashSet<>();
- Set<Warning> notes = new HashSet<>();
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
diagnostic.getKind() == Diagnostic.Kind.WARNING) {
- warnings.add(diagnostic.getCode().contains("varargs") ?
- Warning.VARARGS :
- Warning.UNCHECKED);
- }
- else if (diagnostic.getKind() == Diagnostic.Kind.NOTE) {
- notes.add(diagnostic.getCode().contains("varargs") ?
- Warning.VARARGS :
- Warning.UNCHECKED);
+ if (diagnostic.getCode().contains(Warning.VARARGS.key)) {
+ warnings.add(Warning.VARARGS);
+ } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) {
+ warnings.add(Warning.UNCHECKED);
+ }
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/varargs/warning/Warn5.java Mon Dec 13 15:11:00 2010 -0800
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2010, 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
+ * @bug 6993978
+ * @summary Project Coin: Annotation to reduce varargs warnings
+ * @author mcimadamore
+ * @run main Warn5
+ */
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class Warn5 {
+
+ enum XlintOption {
+ NONE("none"),
+ ALL("all");
+
+ String opt;
+
+ XlintOption(String opt) {
+ this.opt = opt;
+ }
+
+ String getXlintOption() {
+ return "-Xlint:" + opt;
+ }
+ }
+
+ enum TrustMe {
+ DONT_TRUST(""),
+ TRUST("@java.lang.SafeVarargs");
+
+ String anno;
+
+ TrustMe(String anno) {
+ this.anno = anno;
+ }
+ }
+
+ enum SuppressLevel {
+ NONE,
+ VARARGS;
+
+ String getSuppressAnno() {
+ return this == VARARGS ?
+ "@SuppressWarnings(\"varargs\")" :
+ "";
+ }
+ }
+
+ enum ModifierKind {
+ NONE(""),
+ FINAL("final"),
+ STATIC("static");
+
+ String mod;
+
+ ModifierKind(String mod) {
+ this.mod = mod;
+ }
+ }
+
+ enum MethodKind {
+ METHOD("void m"),
+ CONSTRUCTOR("Test");
+
+
+ String name;
+
+ MethodKind(String name) {
+ this.name = name;
+ }
+ }
+
+ enum SourceLevel {
+ JDK_6("6"),
+ JDK_7("7");
+
+ String sourceKey;
+
+ SourceLevel(String sourceKey) {
+ this.sourceKey = sourceKey;
+ }
+ }
+
+ enum SignatureKind {
+ VARARGS_X("#K <X>#N(X... x)", false, true),
+ VARARGS_STRING("#K #N(String... x)", true, true),
+ ARRAY_X("#K <X>#N(X[] x)", false, false),
+ ARRAY_STRING("#K #N(String[] x)", true, false);
+
+ String stub;
+ boolean isReifiableArg;
+ boolean isVarargs;
+
+ SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
+ this.stub = stub;
+ this.isReifiableArg = isReifiableArg;
+ this.isVarargs = isVarargs;
+ }
+
+ String getSignature(ModifierKind modKind, MethodKind methKind) {
+ return methKind != MethodKind.CONSTRUCTOR ?
+ stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
+ stub.replace("#K", "").replace("#N", methKind.name);
+ }
+ }
+
+ enum BodyKind {
+ ASSIGN("Object o = x;", true),
+ CAST("Object o = (Object)x;", true),
+ METH("test(x);", true),
+ PRINT("System.out.println(x.toString());", false),
+ ARRAY_ASSIGN("Object[] o = x;", true),
+ ARRAY_CAST("Object[] o = (Object[])x;", true),
+ ARRAY_METH("testArr(x);", true);
+
+ String body;
+ boolean hasAliasing;
+
+ BodyKind(String body, boolean hasAliasing) {
+ this.body = body;
+ this.hasAliasing = hasAliasing;
+ }
+ }
+
+ static class JavaSource extends SimpleJavaFileObject {
+
+ String template = "import com.sun.tools.javac.api.*;\n" +
+ "import java.util.List;\n" +
+ "class Test {\n" +
+ " static void test(Object o) {}\n" +
+ " static void testArr(Object[] o) {}\n" +
+ " #T \n #S #M { #B }\n" +
+ "}\n";
+
+ String source;
+
+ public JavaSource(TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
+ MethodKind methKind, SignatureKind meth, BodyKind body) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ source = template.replace("#T", trustMe.anno).
+ replace("#S", suppressLevel.getSuppressAnno()).
+ replace("#M", meth.getSignature(modKind, methKind)).
+ replace("#B", body.body);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ for (SourceLevel sourceLevel : SourceLevel.values()) {
+ for (XlintOption xlint : XlintOption.values()) {
+ for (TrustMe trustMe : TrustMe.values()) {
+ for (SuppressLevel suppressLevel : SuppressLevel.values()) {
+ for (ModifierKind modKind : ModifierKind.values()) {
+ for (MethodKind methKind : MethodKind.values()) {
+ for (SignatureKind sig : SignatureKind.values()) {
+ for (BodyKind body : BodyKind.values()) {
+ test(sourceLevel,
+ xlint,
+ trustMe,
+ suppressLevel,
+ modKind,
+ methKind,
+ sig,
+ body);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static void test(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel,
+ ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) throws Exception {
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ JavaSource source = new JavaSource(trustMe, suppressLevel, modKind, methKind, sig, body);
+ DiagnosticChecker dc = new DiagnosticChecker();
+ JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
+ Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
+ ct.analyze();
+ check(sourceLevel, dc, source, xlint, trustMe,
+ suppressLevel, modKind, methKind, sig, body);
+ }
+
+ static void check(SourceLevel sourceLevel, DiagnosticChecker dc, JavaSource source,
+ XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
+ MethodKind methKind, SignatureKind meth, BodyKind body) {
+
+ boolean hasPotentiallyUnsafeBody = sourceLevel == SourceLevel.JDK_7 &&
+ trustMe == TrustMe.TRUST &&
+ suppressLevel != SuppressLevel.VARARGS &&
+ xlint != XlintOption.NONE &&
+ meth.isVarargs && !meth.isReifiableArg && body.hasAliasing &&
+ (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE));
+
+ boolean hasPotentiallyPollutingDecl = sourceLevel == SourceLevel.JDK_7 &&
+ trustMe == TrustMe.DONT_TRUST &&
+ meth.isVarargs &&
+ !meth.isReifiableArg &&
+ xlint == XlintOption.ALL;
+
+ boolean hasMalformedAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
+ trustMe == TrustMe.TRUST &&
+ (!meth.isVarargs ||
+ (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD));
+
+ boolean hasRedundantAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
+ trustMe == TrustMe.TRUST &&
+ xlint != XlintOption.NONE &&
+ suppressLevel != SuppressLevel.VARARGS &&
+ (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
+ meth.isVarargs &&
+ meth.isReifiableArg;
+
+ if (hasPotentiallyUnsafeBody != dc.hasPotentiallyUnsafeBody ||
+ hasPotentiallyPollutingDecl != dc.hasPotentiallyPollutingDecl ||
+ hasMalformedAnnoInDecl != dc.hasMalformedAnnoInDecl ||
+ hasRedundantAnnoInDecl != dc.hasRedundantAnnoInDecl) {
+ throw new Error("invalid diagnostics for source:\n" +
+ source.getCharContent(true) +
+ "\nOptions: " + xlint.getXlintOption() +
+ "\nExpected potentially unsafe body warning: " + hasPotentiallyUnsafeBody +
+ "\nExpected potentially polluting decl warning: " + hasPotentiallyPollutingDecl +
+ "\nExpected malformed anno error: " + hasMalformedAnnoInDecl +
+ "\nExpected redundant anno warning: " + hasRedundantAnnoInDecl +
+ "\nFound potentially unsafe body warning: " + dc.hasPotentiallyUnsafeBody +
+ "\nFound potentially polluting decl warning: " + dc.hasPotentiallyPollutingDecl +
+ "\nFound malformed anno error: " + dc.hasMalformedAnnoInDecl +
+ "\nFound redundant anno warning: " + dc.hasRedundantAnnoInDecl);
+ }
+ }
+
+ static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+ boolean hasPotentiallyUnsafeBody = false;
+ boolean hasPotentiallyPollutingDecl = false;
+ boolean hasMalformedAnnoInDecl = false;
+ boolean hasRedundantAnnoInDecl = false;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
+ if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
+ hasPotentiallyUnsafeBody = true;
+ } else if (diagnostic.getCode().contains("redundant.trustme")) {
+ hasRedundantAnnoInDecl = true;
+ }
+ } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
+ diagnostic.getCode().contains("varargs.non.reifiable.type")) {
+ hasPotentiallyPollutingDecl = true;
+ } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
+ diagnostic.getCode().contains("invalid.trustme")) {
+ hasMalformedAnnoInDecl = true;
+ }
+ }
+ }
+}