6993978: Project Coin: Compiler support of annotation to reduce varargs warnings
Reviewed-by: jjg, darcy
This commit is contained in:
parent
87db401cf5
commit
6ef5228632
@ -177,6 +177,9 @@ public enum Source {
|
||||
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:
|
||||
|
@ -154,6 +154,7 @@ public class Symtab {
|
||||
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 @@ public class Symtab {
|
||||
new MethodType(List.<Type>nil(), voidType,
|
||||
List.of(exceptionType), methodClass),
|
||||
autoCloseableType.tsym);
|
||||
trustMeType = enterClass("java.lang.SafeVarargs");
|
||||
|
||||
synthesizeEmptyInterfaceIfMissing(cloneableType);
|
||||
synthesizeEmptyInterfaceIfMissing(serializableType);
|
||||
|
@ -754,6 +754,10 @@ public class Type implements PrimitiveType {
|
||||
return (ARRAY << 5) + elemtype.hashCode();
|
||||
}
|
||||
|
||||
public boolean isVarargs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Type> allparams() { return elemtype.allparams(); }
|
||||
|
||||
public boolean isErroneous() {
|
||||
@ -768,6 +772,15 @@ public class Type implements PrimitiveType {
|
||||
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;
|
||||
|
@ -33,6 +33,7 @@ import com.sun.tools.javac.util.List;
|
||||
|
||||
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 class Types {
|
||||
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 class Types {
|
||||
*/
|
||||
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 @@ public class Types {
|
||||
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 @@ public class Types {
|
||||
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 @@ public class Types {
|
||||
|
||||
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 @@ public class Types {
|
||||
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 @@ public class Types {
|
||||
|| 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 @@ public class Types {
|
||||
&& !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 @@ public class Types {
|
||||
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 @@ public class Types {
|
||||
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 @@ public class Types {
|
||||
return true;
|
||||
if (!isSubtype(r1.getReturnType(), erasure(r2res)))
|
||||
return false;
|
||||
warner.warnUnchecked();
|
||||
warner.warn(LintCategory.UNCHECKED);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3122,7 +3156,7 @@ public class Types {
|
||||
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 @@ public class Types {
|
||||
chk.checkCompatibleAbstracts(warn.pos(), from, to);
|
||||
if (!isReifiable(target) &&
|
||||
(reverse ? giveWarning(t2, t1) : giveWarning(t1, t2)))
|
||||
warn.warnUnchecked();
|
||||
warn.warn(LintCategory.UNCHECKED);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
finally {
|
||||
chk.setLint(prevLint);
|
||||
chk.setMethod(prevMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2272,8 +2275,8 @@ public class Attr extends JCTree.Visitor {
|
||||
((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 @@ public class Attr extends JCTree.Visitor {
|
||||
// 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 @@ public class Attr extends JCTree.Visitor {
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
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 @@ public class Attr extends JCTree.Visitor {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,10 @@ public class Check {
|
||||
// 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 @@ public class Check {
|
||||
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 @@ public class Check {
|
||||
*/
|
||||
boolean allowCovariantReturns;
|
||||
|
||||
/** Switch: simplified varargs enabled?
|
||||
*/
|
||||
boolean allowSimplifiedVarargs;
|
||||
|
||||
/** Switch: -complexinference option set?
|
||||
*/
|
||||
boolean complexInference;
|
||||
@ -175,6 +184,12 @@ public class Check {
|
||||
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 @@ public class Check {
|
||||
* @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 class Check {
|
||||
public void reportDeferredDiagnostics() {
|
||||
deprecationHandler.reportDeferredDiagnostic();
|
||||
uncheckedHandler.reportDeferredDiagnostic();
|
||||
unsafeVarargsHandler.reportDeferredDiagnostic();
|
||||
sunApiHandler.reportDeferredDiagnostic();
|
||||
}
|
||||
|
||||
@ -705,29 +719,56 @@ public class Check {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class Check {
|
||||
}
|
||||
|
||||
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 @@ public class Check {
|
||||
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 @@ public class Check {
|
||||
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 @@ public class Check {
|
||||
|
||||
// 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 @@ public class Check {
|
||||
|
||||
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 @@ public class Check {
|
||||
*/
|
||||
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 @@ public class Check {
|
||||
* 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 @@ public class Check {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,7 @@ public class Infer {
|
||||
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);
|
||||
}};
|
||||
|
@ -77,6 +77,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
|
||||
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 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
|
||||
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 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
|
||||
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);
|
||||
|
@ -815,13 +815,13 @@ public class Resolve {
|
||||
}
|
||||
//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) {
|
||||
|
@ -105,10 +105,15 @@ public class ClassReader implements Completer {
|
||||
*/
|
||||
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 @@ public class ClassReader implements Completer {
|
||||
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 @@ public class ClassReader implements Completer {
|
||||
// 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 @@ public class ClassReader implements Completer {
|
||||
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
|
||||
|
@ -516,6 +516,15 @@ compiler.err.var.might.not.have.been.initialized=\
|
||||
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.filename.additional=\
|
||||
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.meth.invocation.applied=\
|
||||
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 @@ compiler.warn.diamond.redundant.args.1=\
|
||||
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
|
||||
|
@ -103,7 +103,7 @@ public class List<A> extends AbstractCollection<A> implements java.util.List<A>
|
||||
|
||||
/** 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))));
|
||||
}
|
||||
|
@ -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 class Warner {
|
||||
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);
|
||||
}
|
||||
|
@ -129,12 +129,17 @@ public class CheckExamples {
|
||||
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.
|
||||
*/
|
||||
|
@ -52,7 +52,7 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
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 @@ public class RunExamples {
|
||||
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 @@ public class RunExamples {
|
||||
errors++;
|
||||
}
|
||||
|
||||
static boolean jtreg;
|
||||
|
||||
int errors;
|
||||
|
||||
/**
|
||||
|
@ -21,10 +21,10 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.note.varargs.plural.additional
|
||||
// key: compiler.warn.varargs.non.reifiable.type
|
||||
// options: -Xlint:varargs -Xmaxwarns 1
|
||||
// key: compiler.err.varargs.invalid.trustme.anno
|
||||
// key: compiler.misc.varargs.trustme.on.non.varargs.meth
|
||||
// options: -Xlint:varargs
|
||||
|
||||
class VarargsPluralAdditional<T> {
|
||||
void m(T... items) { }
|
||||
class TrustMeOnNonVarargsMeth {
|
||||
@SafeVarargs static void m(String[] args) { }
|
||||
}
|
@ -21,9 +21,10 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.note.varargs.plural
|
||||
// key: compiler.note.varargs.recompile
|
||||
// key: compiler.warn.varargs.redundant.trustme.anno
|
||||
// key: compiler.misc.varargs.trustme.on.reifiable.varargs
|
||||
// options: -Xlint:varargs
|
||||
|
||||
class VarargsPlural<T> {
|
||||
void m(T... items) { }
|
||||
class TrustMeOnReifiableVarargsParam {
|
||||
@SafeVarargs static void m(String... args) { }
|
||||
}
|
@ -21,11 +21,12 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.note.varargs.filename.additional
|
||||
// key: compiler.warn.varargs.non.reifiable.type
|
||||
// options: -Xlint:varargs -Xmaxwarns 1
|
||||
// key: compiler.err.varargs.invalid.trustme.anno
|
||||
// key: compiler.misc.varargs.trustme.on.virtual.varargs
|
||||
// options: -Xlint:varargs,unchecked
|
||||
|
||||
class VarargsFilenameAdditional<T> {
|
||||
void m1(T... items) { }
|
||||
void m2(T... items) { }
|
||||
import java.util.List;
|
||||
|
||||
class TrustMeOnVirtualMethod {
|
||||
@SafeVarargs void m(List<String>... args) { }
|
||||
}
|
@ -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) {
|
||||
|
@ -21,9 +21,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.note.varargs.filename
|
||||
// key: compiler.note.varargs.recompile
|
||||
// key: compiler.warn.varargs.unsafe.use.varargs.param
|
||||
// options: -Xlint:varargs
|
||||
|
||||
class VarargsFilename<T> {
|
||||
void m(T... items) { }
|
||||
class UnsafeUseOfVarargsParam {
|
||||
@SafeVarargs static <X> void m(X... x) {
|
||||
Object[] o = x;
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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) { }
|
||||
}
|
@ -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) { }
|
||||
}
|
@ -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) { }
|
||||
}
|
@ -32,6 +32,7 @@
|
||||
*/
|
||||
|
||||
class T6730476a {
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> void f(int i, T ... x) {}
|
||||
void g() {
|
||||
f(1);
|
||||
|
@ -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
|
||||
|
17
langtools/test/tools/javac/varargs/6993978/T6993978neg.java
Normal file
17
langtools/test/tools/javac/varargs/6993978/T6993978neg.java
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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
|
@ -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 @@ public class Warn4 {
|
||||
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 class Warn4 {
|
||||
}
|
||||
|
||||
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 @@ public class Warn4 {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class Warn4 {
|
||||
|
||||
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 @@ public class Warn4 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
293
langtools/test/tools/javac/varargs/warning/Warn5.java
Normal file
293
langtools/test/tools/javac/varargs/warning/Warn5.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user