mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
6993978: Project Coin: Compiler support of annotation to reduce varargs warnings
Reviewed-by: jjg, darcy
This commit is contained in:
parent
87db401cf5
commit
6ef5228632
30 changed files with 718 additions and 300 deletions
|
@ -177,6 +177,9 @@ public enum Source {
|
||||||
public boolean allowStringsInSwitch() {
|
public boolean allowStringsInSwitch() {
|
||||||
return compareTo(JDK1_7) >= 0;
|
return compareTo(JDK1_7) >= 0;
|
||||||
}
|
}
|
||||||
|
public boolean allowSimplifiedVarargs() {
|
||||||
|
return compareTo(JDK1_7) >= 0;
|
||||||
|
}
|
||||||
public static SourceVersion toSourceVersion(Source source) {
|
public static SourceVersion toSourceVersion(Source source) {
|
||||||
switch(source) {
|
switch(source) {
|
||||||
case JDK1_2:
|
case JDK1_2:
|
||||||
|
|
|
@ -154,6 +154,7 @@ public class Symtab {
|
||||||
public final Type proprietaryType;
|
public final Type proprietaryType;
|
||||||
public final Type systemType;
|
public final Type systemType;
|
||||||
public final Type autoCloseableType;
|
public final Type autoCloseableType;
|
||||||
|
public final Type trustMeType;
|
||||||
|
|
||||||
/** The symbol representing the length field of an array.
|
/** The symbol representing the length field of an array.
|
||||||
*/
|
*/
|
||||||
|
@ -461,6 +462,7 @@ public class Symtab {
|
||||||
new MethodType(List.<Type>nil(), voidType,
|
new MethodType(List.<Type>nil(), voidType,
|
||||||
List.of(exceptionType), methodClass),
|
List.of(exceptionType), methodClass),
|
||||||
autoCloseableType.tsym);
|
autoCloseableType.tsym);
|
||||||
|
trustMeType = enterClass("java.lang.SafeVarargs");
|
||||||
|
|
||||||
synthesizeEmptyInterfaceIfMissing(cloneableType);
|
synthesizeEmptyInterfaceIfMissing(cloneableType);
|
||||||
synthesizeEmptyInterfaceIfMissing(serializableType);
|
synthesizeEmptyInterfaceIfMissing(serializableType);
|
||||||
|
|
|
@ -754,6 +754,10 @@ public class Type implements PrimitiveType {
|
||||||
return (ARRAY << 5) + elemtype.hashCode();
|
return (ARRAY << 5) + elemtype.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isVarargs() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Type> allparams() { return elemtype.allparams(); }
|
public List<Type> allparams() { return elemtype.allparams(); }
|
||||||
|
|
||||||
public boolean isErroneous() {
|
public boolean isErroneous() {
|
||||||
|
@ -768,6 +772,15 @@ public class Type implements PrimitiveType {
|
||||||
return elemtype.isRaw();
|
return elemtype.isRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayType makeVarargs() {
|
||||||
|
return new ArrayType(elemtype, tsym) {
|
||||||
|
@Override
|
||||||
|
public boolean isVarargs() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public Type map(Mapping f) {
|
public Type map(Mapping f) {
|
||||||
Type elemtype1 = f.apply(elemtype);
|
Type elemtype1 = f.apply(elemtype);
|
||||||
if (elemtype1 == elemtype) return this;
|
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.jvm.ClassReader;
|
||||||
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
|
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
|
||||||
|
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||||
import com.sun.tools.javac.comp.Check;
|
import com.sun.tools.javac.comp.Check;
|
||||||
|
|
||||||
import static com.sun.tools.javac.code.Type.*;
|
import static com.sun.tools.javac.code.Type.*;
|
||||||
|
@ -272,13 +273,36 @@ public class Types {
|
||||||
public boolean isConvertible(Type t, Type s, Warner warn) {
|
public boolean isConvertible(Type t, Type s, Warner warn) {
|
||||||
boolean tPrimitive = t.isPrimitive();
|
boolean tPrimitive = t.isPrimitive();
|
||||||
boolean sPrimitive = s.isPrimitive();
|
boolean sPrimitive = s.isPrimitive();
|
||||||
if (tPrimitive == sPrimitive)
|
if (tPrimitive == sPrimitive) {
|
||||||
|
checkUnsafeVarargsConversion(t, s, warn);
|
||||||
return isSubtypeUnchecked(t, s, warn);
|
return isSubtypeUnchecked(t, s, warn);
|
||||||
|
}
|
||||||
if (!allowBoxing) return false;
|
if (!allowBoxing) return false;
|
||||||
return tPrimitive
|
return tPrimitive
|
||||||
? isSubtype(boxedClass(t).type, s)
|
? isSubtype(boxedClass(t).type, s)
|
||||||
: isSubtype(unboxedType(t), 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
|
* 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) {
|
public boolean isSubtypeUnchecked(Type t, Type s, Warner warn) {
|
||||||
if (t.tag == ARRAY && s.tag == ARRAY) {
|
if (t.tag == ARRAY && s.tag == ARRAY) {
|
||||||
return (((ArrayType)t).elemtype.tag <= lastBaseTag)
|
if (((ArrayType)t).elemtype.tag <= lastBaseTag) {
|
||||||
? isSameType(elemtype(t), elemtype(s))
|
return isSameType(elemtype(t), elemtype(s));
|
||||||
: isSubtypeUnchecked(elemtype(t), elemtype(s), warn);
|
} 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)) {
|
} else if (isSubtype(t, s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -319,9 +352,9 @@ public class Types {
|
||||||
Type t2 = asSuper(t, s.tsym);
|
Type t2 = asSuper(t, s.tsym);
|
||||||
if (t2 != null && t2.isRaw()) {
|
if (t2 != null && t2.isRaw()) {
|
||||||
if (isReifiable(s))
|
if (isReifiable(s))
|
||||||
warn.silentUnchecked();
|
warn.silentWarn(LintCategory.UNCHECKED);
|
||||||
else
|
else
|
||||||
warn.warnUnchecked();
|
warn.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -922,6 +955,7 @@ public class Types {
|
||||||
if (warn != warnStack.head) {
|
if (warn != warnStack.head) {
|
||||||
try {
|
try {
|
||||||
warnStack = warnStack.prepend(warn);
|
warnStack = warnStack.prepend(warn);
|
||||||
|
checkUnsafeVarargsConversion(t, s, warn);
|
||||||
return isCastable.visit(t,s);
|
return isCastable.visit(t,s);
|
||||||
} finally {
|
} finally {
|
||||||
warnStack = warnStack.tail;
|
warnStack = warnStack.tail;
|
||||||
|
@ -964,7 +998,7 @@ public class Types {
|
||||||
|
|
||||||
if (s.tag == TYPEVAR) {
|
if (s.tag == TYPEVAR) {
|
||||||
if (isCastable(t, s.getUpperBound(), Warner.noWarnings)) {
|
if (isCastable(t, s.getUpperBound(), Warner.noWarnings)) {
|
||||||
warnStack.head.warnUnchecked();
|
warnStack.head.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -980,8 +1014,8 @@ public class Types {
|
||||||
if (!visit(intf, s))
|
if (!visit(intf, s))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (warnStack.head.unchecked == true)
|
if (warnStack.head.hasLint(LintCategory.UNCHECKED))
|
||||||
oldWarner.warnUnchecked();
|
oldWarner.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,13 +1030,13 @@ public class Types {
|
||||||
|| isSubtype(erasure(s), erasure(t))) {
|
|| isSubtype(erasure(s), erasure(t))) {
|
||||||
if (!upcast && s.tag == ARRAY) {
|
if (!upcast && s.tag == ARRAY) {
|
||||||
if (!isReifiable(s))
|
if (!isReifiable(s))
|
||||||
warnStack.head.warnUnchecked();
|
warnStack.head.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
} else if (s.isRaw()) {
|
} else if (s.isRaw()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (t.isRaw()) {
|
} else if (t.isRaw()) {
|
||||||
if (!isUnbounded(s))
|
if (!isUnbounded(s))
|
||||||
warnStack.head.warnUnchecked();
|
warnStack.head.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Assume |a| <: |b|
|
// Assume |a| <: |b|
|
||||||
|
@ -1035,7 +1069,7 @@ public class Types {
|
||||||
&& !disjointTypes(aLow.allparams(), lowSub.allparams())) {
|
&& !disjointTypes(aLow.allparams(), lowSub.allparams())) {
|
||||||
if (upcast ? giveWarning(a, b) :
|
if (upcast ? giveWarning(a, b) :
|
||||||
giveWarning(b, a))
|
giveWarning(b, a))
|
||||||
warnStack.head.warnUnchecked();
|
warnStack.head.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1072,7 +1106,7 @@ public class Types {
|
||||||
return true;
|
return true;
|
||||||
case TYPEVAR:
|
case TYPEVAR:
|
||||||
if (isCastable(s, t, Warner.noWarnings)) {
|
if (isCastable(s, t, Warner.noWarnings)) {
|
||||||
warnStack.head.warnUnchecked();
|
warnStack.head.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1101,7 +1135,7 @@ public class Types {
|
||||||
if (isSubtype(t, s)) {
|
if (isSubtype(t, s)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (isCastable(t.bound, s, Warner.noWarnings)) {
|
} else if (isCastable(t.bound, s, Warner.noWarnings)) {
|
||||||
warnStack.head.warnUnchecked();
|
warnStack.head.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2906,7 +2940,7 @@ public class Types {
|
||||||
return true;
|
return true;
|
||||||
if (!isSubtype(r1.getReturnType(), erasure(r2res)))
|
if (!isSubtype(r1.getReturnType(), erasure(r2res)))
|
||||||
return false;
|
return false;
|
||||||
warner.warnUnchecked();
|
warner.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3122,7 +3156,7 @@ public class Types {
|
||||||
commonSupers = commonSupers.tail;
|
commonSupers = commonSupers.tail;
|
||||||
}
|
}
|
||||||
if (giveWarning && !isReifiable(reverse ? from : to))
|
if (giveWarning && !isReifiable(reverse ? from : to))
|
||||||
warn.warnUnchecked();
|
warn.warn(LintCategory.UNCHECKED);
|
||||||
if (!source.allowCovariantReturns())
|
if (!source.allowCovariantReturns())
|
||||||
// reject if there is a common method signature with
|
// reject if there is a common method signature with
|
||||||
// incompatible return types.
|
// incompatible return types.
|
||||||
|
@ -3156,7 +3190,7 @@ public class Types {
|
||||||
chk.checkCompatibleAbstracts(warn.pos(), from, to);
|
chk.checkCompatibleAbstracts(warn.pos(), from, to);
|
||||||
if (!isReifiable(target) &&
|
if (!isReifiable(target) &&
|
||||||
(reverse ? giveWarning(t2, t1) : giveWarning(t1, t2)))
|
(reverse ? giveWarning(t2, t1) : giveWarning(t1, t2)))
|
||||||
warn.warnUnchecked();
|
warn.warn(LintCategory.UNCHECKED);
|
||||||
return true;
|
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.util.List;
|
||||||
|
|
||||||
import com.sun.tools.javac.jvm.Target;
|
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.code.Symbol.*;
|
||||||
import com.sun.tools.javac.tree.JCTree.*;
|
import com.sun.tools.javac.tree.JCTree.*;
|
||||||
import com.sun.tools.javac.code.Type.*;
|
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 lint = env.info.lint.augment(m.attributes_field, m.flags());
|
||||||
Lint prevLint = chk.setLint(lint);
|
Lint prevLint = chk.setLint(lint);
|
||||||
|
MethodSymbol prevMethod = chk.setMethod(m);
|
||||||
try {
|
try {
|
||||||
chk.checkDeprecatedAnnotation(tree.pos(), m);
|
chk.checkDeprecatedAnnotation(tree.pos(), m);
|
||||||
|
|
||||||
|
@ -700,7 +702,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
attribStat(l.head, localEnv);
|
attribStat(l.head, localEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
chk.checkVarargMethodDecl(tree);
|
chk.checkVarargsMethodDecl(localEnv, tree);
|
||||||
|
|
||||||
// Check that type parameters are well-formed.
|
// Check that type parameters are well-formed.
|
||||||
chk.validate(tree.typarams, localEnv);
|
chk.validate(tree.typarams, localEnv);
|
||||||
|
@ -789,6 +791,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
chk.setLint(prevLint);
|
chk.setLint(prevLint);
|
||||||
|
chk.setMethod(prevMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2272,8 +2275,8 @@ public class Attr extends JCTree.Visitor {
|
||||||
((VarSymbol)sitesym).isResourceVariable() &&
|
((VarSymbol)sitesym).isResourceVariable() &&
|
||||||
sym.kind == MTH &&
|
sym.kind == MTH &&
|
||||||
sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true) &&
|
sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true) &&
|
||||||
env.info.lint.isEnabled(Lint.LintCategory.TRY)) {
|
env.info.lint.isEnabled(LintCategory.TRY)) {
|
||||||
log.warning(Lint.LintCategory.TRY, tree, "try.explicit.close.call");
|
log.warning(LintCategory.TRY, tree, "try.explicit.close.call");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disallow selecting a type from an expression
|
// 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
|
// For methods, we need to compute the instance type by
|
||||||
// Resolve.instantiate from the symbol's type as well as
|
// Resolve.instantiate from the symbol's type as well as
|
||||||
// any type arguments and value arguments.
|
// any type arguments and value arguments.
|
||||||
noteWarner.warned = false;
|
noteWarner.clear();
|
||||||
Type owntype = rs.instantiate(env,
|
Type owntype = rs.instantiate(env,
|
||||||
site,
|
site,
|
||||||
sym,
|
sym,
|
||||||
|
@ -2709,7 +2712,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
true,
|
true,
|
||||||
useVarargs,
|
useVarargs,
|
||||||
noteWarner);
|
noteWarner);
|
||||||
boolean warned = noteWarner.warned;
|
boolean warned = noteWarner.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||||
|
|
||||||
// If this fails, something went wrong; we should not have
|
// If this fails, something went wrong; we should not have
|
||||||
// found the identifier in the first place.
|
// found the identifier in the first place.
|
||||||
|
@ -2734,7 +2737,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
JCTree arg = args.head;
|
JCTree arg = args.head;
|
||||||
Warner warn = chk.convertWarner(arg.pos(), arg.type, formals.head);
|
Warner warn = chk.convertWarner(arg.pos(), arg.type, formals.head);
|
||||||
assertConvertible(arg, arg.type, formals.head, warn);
|
assertConvertible(arg, arg.type, formals.head, warn);
|
||||||
warned |= warn.warned;
|
warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||||
args = args.tail;
|
args = args.tail;
|
||||||
formals = formals.tail;
|
formals = formals.tail;
|
||||||
}
|
}
|
||||||
|
@ -2744,7 +2747,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
JCTree arg = args.head;
|
JCTree arg = args.head;
|
||||||
Warner warn = chk.convertWarner(arg.pos(), arg.type, varArg);
|
Warner warn = chk.convertWarner(arg.pos(), arg.type, varArg);
|
||||||
assertConvertible(arg, arg.type, varArg, warn);
|
assertConvertible(arg, arg.type, varArg, warn);
|
||||||
warned |= warn.warned;
|
warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||||
args = args.tail;
|
args = args.tail;
|
||||||
}
|
}
|
||||||
} else if ((sym.flags() & VARARGS) != 0 && allowVarargs) {
|
} else if ((sym.flags() & VARARGS) != 0 && allowVarargs) {
|
||||||
|
@ -2776,7 +2779,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
JCTree tree = env.tree;
|
JCTree tree = env.tree;
|
||||||
Type argtype = owntype.getParameterTypes().last();
|
Type argtype = owntype.getParameterTypes().last();
|
||||||
if (owntype.getReturnType().tag != FORALL || warned) {
|
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);
|
Type elemtype = types.elemtype(argtype);
|
||||||
switch (tree.getTag()) {
|
switch (tree.getTag()) {
|
||||||
|
@ -3175,7 +3178,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
chk.checkNonCyclicElements(tree);
|
chk.checkNonCyclicElements(tree);
|
||||||
|
|
||||||
// Check for proper use of serialVersionUID
|
// Check for proper use of serialVersionUID
|
||||||
if (env.info.lint.isEnabled(Lint.LintCategory.SERIAL) &&
|
if (env.info.lint.isEnabled(LintCategory.SERIAL) &&
|
||||||
isSerializable(c) &&
|
isSerializable(c) &&
|
||||||
(c.flags() & Flags.ENUM) == 0 &&
|
(c.flags() & Flags.ENUM) == 0 &&
|
||||||
(c.flags() & ABSTRACT) == 0) {
|
(c.flags() & ABSTRACT) == 0) {
|
||||||
|
@ -3204,7 +3207,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
Scope.Entry e = c.members().lookup(names.serialVersionUID);
|
Scope.Entry e = c.members().lookup(names.serialVersionUID);
|
||||||
while (e.scope != null && e.sym.kind != VAR) e = e.next();
|
while (e.scope != null && e.sym.kind != VAR) e = e.next();
|
||||||
if (e.scope == null) {
|
if (e.scope == null) {
|
||||||
log.warning(Lint.LintCategory.SERIAL,
|
log.warning(LintCategory.SERIAL,
|
||||||
tree.pos(), "missing.SVUID", c);
|
tree.pos(), "missing.SVUID", c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3213,17 +3216,17 @@ public class Attr extends JCTree.Visitor {
|
||||||
VarSymbol svuid = (VarSymbol)e.sym;
|
VarSymbol svuid = (VarSymbol)e.sym;
|
||||||
if ((svuid.flags() & (STATIC | FINAL)) !=
|
if ((svuid.flags() & (STATIC | FINAL)) !=
|
||||||
(STATIC | FINAL))
|
(STATIC | FINAL))
|
||||||
log.warning(Lint.LintCategory.SERIAL,
|
log.warning(LintCategory.SERIAL,
|
||||||
TreeInfo.diagnosticPositionFor(svuid, tree), "improper.SVUID", c);
|
TreeInfo.diagnosticPositionFor(svuid, tree), "improper.SVUID", c);
|
||||||
|
|
||||||
// check that it is long
|
// check that it is long
|
||||||
else if (svuid.type.tag != TypeTags.LONG)
|
else if (svuid.type.tag != TypeTags.LONG)
|
||||||
log.warning(Lint.LintCategory.SERIAL,
|
log.warning(LintCategory.SERIAL,
|
||||||
TreeInfo.diagnosticPositionFor(svuid, tree), "long.SVUID", c);
|
TreeInfo.diagnosticPositionFor(svuid, tree), "long.SVUID", c);
|
||||||
|
|
||||||
// check constant
|
// check constant
|
||||||
else if (svuid.getConstValue() == null)
|
else if (svuid.getConstValue() == null)
|
||||||
log.warning(Lint.LintCategory.SERIAL,
|
log.warning(LintCategory.SERIAL,
|
||||||
TreeInfo.diagnosticPositionFor(svuid, tree), "constant.SVUID", c);
|
TreeInfo.diagnosticPositionFor(svuid, tree), "constant.SVUID", c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,10 @@ public class Check {
|
||||||
// visits all the various parts of the trees during attribution.
|
// visits all the various parts of the trees during attribution.
|
||||||
private Lint lint;
|
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) {
|
public static Check instance(Context context) {
|
||||||
Check instance = context.get(checkKey);
|
Check instance = context.get(checkKey);
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
|
@ -100,6 +104,7 @@ public class Check {
|
||||||
allowGenerics = source.allowGenerics();
|
allowGenerics = source.allowGenerics();
|
||||||
allowAnnotations = source.allowAnnotations();
|
allowAnnotations = source.allowAnnotations();
|
||||||
allowCovariantReturns = source.allowCovariantReturns();
|
allowCovariantReturns = source.allowCovariantReturns();
|
||||||
|
allowSimplifiedVarargs = source.allowSimplifiedVarargs();
|
||||||
complexInference = options.isSet(COMPLEXINFERENCE);
|
complexInference = options.isSet(COMPLEXINFERENCE);
|
||||||
skipAnnotations = options.isSet("skipAnnotations");
|
skipAnnotations = options.isSet("skipAnnotations");
|
||||||
warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
|
warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
|
||||||
|
@ -136,6 +141,10 @@ public class Check {
|
||||||
*/
|
*/
|
||||||
boolean allowCovariantReturns;
|
boolean allowCovariantReturns;
|
||||||
|
|
||||||
|
/** Switch: simplified varargs enabled?
|
||||||
|
*/
|
||||||
|
boolean allowSimplifiedVarargs;
|
||||||
|
|
||||||
/** Switch: -complexinference option set?
|
/** Switch: -complexinference option set?
|
||||||
*/
|
*/
|
||||||
boolean complexInference;
|
boolean complexInference;
|
||||||
|
@ -175,6 +184,12 @@ public class Check {
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MethodSymbol setMethod(MethodSymbol newMethod) {
|
||||||
|
MethodSymbol prev = method;
|
||||||
|
method = newMethod;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
/** Warn about deprecated symbol.
|
/** Warn about deprecated symbol.
|
||||||
* @param pos Position to be used for error reporting.
|
* @param pos Position to be used for error reporting.
|
||||||
* @param sym The deprecated symbol.
|
* @param sym The deprecated symbol.
|
||||||
|
@ -197,9 +212,9 @@ public class Check {
|
||||||
* @param pos Position to be used for error reporting.
|
* @param pos Position to be used for error reporting.
|
||||||
* @param sym The deprecated symbol.
|
* @param sym The deprecated symbol.
|
||||||
*/
|
*/
|
||||||
void warnUnsafeVararg(DiagnosticPosition pos, Type elemType) {
|
void warnUnsafeVararg(DiagnosticPosition pos, String key, Object... args) {
|
||||||
if (!lint.isSuppressed(LintCategory.VARARGS))
|
if (lint.isEnabled(LintCategory.VARARGS) && allowSimplifiedVarargs)
|
||||||
unsafeVarargsHandler.report(pos, "varargs.non.reifiable.type", elemType);
|
log.warning(LintCategory.VARARGS, pos, key, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Warn about using proprietary API.
|
/** Warn about using proprietary API.
|
||||||
|
@ -222,7 +237,6 @@ public class Check {
|
||||||
public void reportDeferredDiagnostics() {
|
public void reportDeferredDiagnostics() {
|
||||||
deprecationHandler.reportDeferredDiagnostic();
|
deprecationHandler.reportDeferredDiagnostic();
|
||||||
uncheckedHandler.reportDeferredDiagnostic();
|
uncheckedHandler.reportDeferredDiagnostic();
|
||||||
unsafeVarargsHandler.reportDeferredDiagnostic();
|
|
||||||
sunApiHandler.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;
|
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()) {
|
if (m.isVarArgs()) {
|
||||||
Type varargElemType = types.elemtype(tree.params.last().type);
|
varargElemType = types.elemtype(tree.params.last().type);
|
||||||
if (!types.isReifiable(varargElemType)) {
|
}
|
||||||
warnUnsafeVararg(tree.params.head.pos(), varargElemType);
|
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
|
* Check that vararg method call is sound
|
||||||
* @param pos Position to be used for error reporting.
|
* @param pos Position to be used for error reporting.
|
||||||
* @param argtypes Actual arguments supplied to vararg method.
|
* @param argtypes Actual arguments supplied to vararg method.
|
||||||
*/
|
*/
|
||||||
void checkVararg(DiagnosticPosition pos, List<Type> argtypes, Symbol msym, Env<AttrContext> env) {
|
void checkVararg(DiagnosticPosition pos, List<Type> argtypes, Symbol msym) {
|
||||||
Env<AttrContext> calleeLintEnv = env;
|
|
||||||
while (calleeLintEnv.info.lint == null)
|
|
||||||
calleeLintEnv = calleeLintEnv.next;
|
|
||||||
Lint calleeLint = calleeLintEnv.info.lint.augment(msym.attributes_field, msym.flags());
|
|
||||||
Type argtype = argtypes.last();
|
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,
|
warnUnchecked(pos,
|
||||||
"unchecked.generic.array.creation",
|
"unchecked.generic.array.creation",
|
||||||
argtype);
|
argtype);
|
||||||
|
@ -1075,12 +1116,12 @@ public class Check {
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkRaw(JCTree tree, Env<AttrContext> env) {
|
void checkRaw(JCTree tree, Env<AttrContext> env) {
|
||||||
if (lint.isEnabled(Lint.LintCategory.RAW) &&
|
if (lint.isEnabled(LintCategory.RAW) &&
|
||||||
tree.type.tag == CLASS &&
|
tree.type.tag == CLASS &&
|
||||||
!TreeInfo.isDiamond(tree) &&
|
!TreeInfo.isDiamond(tree) &&
|
||||||
!env.enclClass.name.isEmpty() && //anonymous or intersection
|
!env.enclClass.name.isEmpty() && //anonymous or intersection
|
||||||
tree.type.isRaw()) {
|
tree.type.isRaw()) {
|
||||||
log.warning(Lint.LintCategory.RAW,
|
log.warning(LintCategory.RAW,
|
||||||
tree.pos(), "raw.class.use", tree.type, tree.type.tsym.type);
|
tree.pos(), "raw.class.use", tree.type, tree.type.tsym.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1347,7 +1388,7 @@ public class Check {
|
||||||
Type mtres = mt.getReturnType();
|
Type mtres = mt.getReturnType();
|
||||||
Type otres = types.subst(ot.getReturnType(), otvars, mtvars);
|
Type otres = types.subst(ot.getReturnType(), otvars, mtvars);
|
||||||
|
|
||||||
overrideWarner.warned = false;
|
overrideWarner.clear();
|
||||||
boolean resultTypesOK =
|
boolean resultTypesOK =
|
||||||
types.returnTypeSubstitutable(mt, ot, otres, overrideWarner);
|
types.returnTypeSubstitutable(mt, ot, otres, overrideWarner);
|
||||||
if (!resultTypesOK) {
|
if (!resultTypesOK) {
|
||||||
|
@ -1362,7 +1403,7 @@ public class Check {
|
||||||
mtres, otres);
|
mtres, otres);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (overrideWarner.warned) {
|
} else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) {
|
||||||
warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
|
warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
|
||||||
"override.unchecked.ret",
|
"override.unchecked.ret",
|
||||||
uncheckedOverrides(m, other),
|
uncheckedOverrides(m, other),
|
||||||
|
@ -1391,7 +1432,7 @@ public class Check {
|
||||||
|
|
||||||
// Optional warning if varargs don't agree
|
// Optional warning if varargs don't agree
|
||||||
if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)
|
if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)
|
||||||
&& lint.isEnabled(Lint.LintCategory.OVERRIDES)) {
|
&& lint.isEnabled(LintCategory.OVERRIDES)) {
|
||||||
log.warning(TreeInfo.diagnosticPositionFor(m, tree),
|
log.warning(TreeInfo.diagnosticPositionFor(m, tree),
|
||||||
((m.flags() & Flags.VARARGS) != 0)
|
((m.flags() & Flags.VARARGS) != 0)
|
||||||
? "override.varargs.missing"
|
? "override.varargs.missing"
|
||||||
|
@ -2380,11 +2421,11 @@ public class Check {
|
||||||
|
|
||||||
void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) {
|
void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) {
|
||||||
if (allowAnnotations &&
|
if (allowAnnotations &&
|
||||||
lint.isEnabled(Lint.LintCategory.DEP_ANN) &&
|
lint.isEnabled(LintCategory.DEP_ANN) &&
|
||||||
(s.flags() & DEPRECATED) != 0 &&
|
(s.flags() & DEPRECATED) != 0 &&
|
||||||
!syms.deprecatedType.isErroneous() &&
|
!syms.deprecatedType.isErroneous() &&
|
||||||
s.attribute(syms.deprecatedType.tsym) == null) {
|
s.attribute(syms.deprecatedType.tsym) == null) {
|
||||||
log.warning(Lint.LintCategory.DEP_ANN,
|
log.warning(LintCategory.DEP_ANN,
|
||||||
pos, "missing.deprecated.annotation");
|
pos, "missing.deprecated.annotation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2530,13 +2571,13 @@ public class Check {
|
||||||
*/
|
*/
|
||||||
void checkDivZero(DiagnosticPosition pos, Symbol operator, Type operand) {
|
void checkDivZero(DiagnosticPosition pos, Symbol operator, Type operand) {
|
||||||
if (operand.constValue() != null
|
if (operand.constValue() != null
|
||||||
&& lint.isEnabled(Lint.LintCategory.DIVZERO)
|
&& lint.isEnabled(LintCategory.DIVZERO)
|
||||||
&& operand.tag <= LONG
|
&& operand.tag <= LONG
|
||||||
&& ((Number) (operand.constValue())).longValue() == 0) {
|
&& ((Number) (operand.constValue())).longValue() == 0) {
|
||||||
int opc = ((OperatorSymbol)operator).opcode;
|
int opc = ((OperatorSymbol)operator).opcode;
|
||||||
if (opc == ByteCodes.idiv || opc == ByteCodes.imod
|
if (opc == ByteCodes.idiv || opc == ByteCodes.imod
|
||||||
|| opc == ByteCodes.ldiv || opc == ByteCodes.lmod) {
|
|| 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
|
* Check for empty statements after if
|
||||||
*/
|
*/
|
||||||
void checkEmptyIf(JCIf tree) {
|
void checkEmptyIf(JCIf tree) {
|
||||||
if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(Lint.LintCategory.EMPTY))
|
if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(LintCategory.EMPTY))
|
||||||
log.warning(Lint.LintCategory.EMPTY, tree.thenpart.pos(), "empty.if");
|
log.warning(LintCategory.EMPTY, tree.thenpart.pos(), "empty.if");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check that symbol is unique in given scope.
|
/** Check that symbol is unique in given scope.
|
||||||
|
@ -2654,23 +2695,36 @@ public class Check {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ConversionWarner extends Warner {
|
private class ConversionWarner extends Warner {
|
||||||
final String key;
|
final String uncheckedKey;
|
||||||
final Type found;
|
final Type found;
|
||||||
final Type expected;
|
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);
|
super(pos);
|
||||||
this.key = key;
|
this.uncheckedKey = uncheckedKey;
|
||||||
this.found = found;
|
this.found = found;
|
||||||
this.expected = expected;
|
this.expected = expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void warnUnchecked() {
|
public void warn(LintCategory lint) {
|
||||||
boolean warned = this.warned;
|
boolean warned = this.warned;
|
||||||
super.warnUnchecked();
|
super.warn(lint);
|
||||||
if (warned) return; // suppress redundant diagnostics
|
if (warned) return; // suppress redundant diagnostics
|
||||||
Object problem = diags.fragment(key);
|
switch (lint) {
|
||||||
Check.this.warnUnchecked(pos(), "prob.found.req", problem, found, expected);
|
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,
|
checkWithinBounds(all_tvars,
|
||||||
types.subst(inferredTypes, tvars, inferred), warn);
|
types.subst(inferredTypes, tvars, inferred), warn);
|
||||||
if (useVarargs) {
|
if (useVarargs) {
|
||||||
chk.checkVararg(env.tree.pos(), formals, msym, env);
|
chk.checkVararg(env.tree.pos(), formals, msym);
|
||||||
}
|
}
|
||||||
return super.inst(inferred, types);
|
return super.inst(inferred, types);
|
||||||
}};
|
}};
|
||||||
|
|
|
@ -77,6 +77,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
|
||||||
private final Target target;
|
private final Target target;
|
||||||
|
|
||||||
private final boolean skipAnnotations;
|
private final boolean skipAnnotations;
|
||||||
|
private final boolean allowSimplifiedVarargs;
|
||||||
|
|
||||||
public static MemberEnter instance(Context context) {
|
public static MemberEnter instance(Context context) {
|
||||||
MemberEnter instance = context.get(memberEnterKey);
|
MemberEnter instance = context.get(memberEnterKey);
|
||||||
|
@ -103,6 +104,8 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
|
||||||
target = Target.instance(context);
|
target = Target.instance(context);
|
||||||
Options options = Options.instance(context);
|
Options options = Options.instance(context);
|
||||||
skipAnnotations = options.isSet("skipAnnotations");
|
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
|
/** 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++;
|
localEnv.info.staticLevel++;
|
||||||
}
|
}
|
||||||
attr.attribType(tree.vartype, localEnv);
|
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);
|
Scope enclScope = enter.enterScope(env);
|
||||||
VarSymbol v =
|
VarSymbol v =
|
||||||
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
|
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
|
||||||
|
|
|
@ -815,13 +815,13 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
private boolean signatureMoreSpecific(Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) {
|
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));
|
Type mtype1 = types.memberType(site, adjustVarargs(m1, m2, useVarargs));
|
||||||
noteWarner.unchecked = false;
|
|
||||||
return (instantiate(env, site, adjustVarargs(m2, m1, useVarargs), types.lowerBoundArgtypes(mtype1), null,
|
return (instantiate(env, site, adjustVarargs(m2, m1, useVarargs), types.lowerBoundArgtypes(mtype1), null,
|
||||||
allowBoxing, false, noteWarner) != null ||
|
allowBoxing, false, noteWarner) != null ||
|
||||||
useVarargs && instantiate(env, site, adjustVarargs(m2, m1, useVarargs), types.lowerBoundArgtypes(mtype1), null,
|
useVarargs && instantiate(env, site, adjustVarargs(m2, m1, useVarargs), types.lowerBoundArgtypes(mtype1), null,
|
||||||
allowBoxing, true, noteWarner) != null) &&
|
allowBoxing, true, noteWarner) != null) &&
|
||||||
!noteWarner.unchecked;
|
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) {
|
private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) {
|
||||||
|
|
|
@ -105,10 +105,15 @@ public class ClassReader implements Completer {
|
||||||
*/
|
*/
|
||||||
boolean allowAnnotations;
|
boolean allowAnnotations;
|
||||||
|
|
||||||
/** Lint option: warn about classfile issues
|
/** Switch: allow simplified varargs.
|
||||||
|
*/
|
||||||
|
boolean allowSimplifiedVarargs;
|
||||||
|
|
||||||
|
/** Lint option: warn about classfile issues
|
||||||
*/
|
*/
|
||||||
boolean lintClassfile;
|
boolean lintClassfile;
|
||||||
|
|
||||||
|
|
||||||
/** Switch: preserve parameter names from the variable table.
|
/** Switch: preserve parameter names from the variable table.
|
||||||
*/
|
*/
|
||||||
public boolean saveParameterNames;
|
public boolean saveParameterNames;
|
||||||
|
@ -279,6 +284,7 @@ public class ClassReader implements Completer {
|
||||||
allowGenerics = source.allowGenerics();
|
allowGenerics = source.allowGenerics();
|
||||||
allowVarargs = source.allowVarargs();
|
allowVarargs = source.allowVarargs();
|
||||||
allowAnnotations = source.allowAnnotations();
|
allowAnnotations = source.allowAnnotations();
|
||||||
|
allowSimplifiedVarargs = source.allowSimplifiedVarargs();
|
||||||
saveParameterNames = options.isSet("save-parameter-names");
|
saveParameterNames = options.isSet("save-parameter-names");
|
||||||
cacheCompletionFailure = options.isUnset("dev");
|
cacheCompletionFailure = options.isUnset("dev");
|
||||||
preferSource = "source".equals(options.get("-Xprefer"));
|
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
|
// instance, however, there is no reliable way to tell so
|
||||||
// we never strip this$n
|
// we never strip this$n
|
||||||
if (!currentOwner.name.isEmpty())
|
if (!currentOwner.name.isEmpty())
|
||||||
type = new MethodType(type.getParameterTypes().tail,
|
type = new MethodType(adjustMethodParams(flags, type.getParameterTypes()),
|
||||||
type.getReturnType(),
|
type.getReturnType(),
|
||||||
type.getThrownTypes(),
|
type.getThrownTypes(),
|
||||||
syms.methodClass);
|
syms.methodClass);
|
||||||
|
@ -1903,6 +1909,21 @@ public class ClassReader implements Completer {
|
||||||
return m;
|
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.
|
* Init the parameter names array.
|
||||||
* Parameter names are currently inferred from the names in the
|
* 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=\
|
compiler.err.var.might.be.assigned.in.loop=\
|
||||||
variable {0} 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
|
# In the following string, {1} will always be the detail message from
|
||||||
# java.io.IOException.
|
# java.io.IOException.
|
||||||
compiler.err.class.cant.write=\
|
compiler.err.class.cant.write=\
|
||||||
|
@ -600,20 +609,6 @@ compiler.note.unchecked.filename.additional=\
|
||||||
compiler.note.unchecked.plural.additional=\
|
compiler.note.unchecked.plural.additional=\
|
||||||
Some input files additionally use unchecked or unsafe operations.
|
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=\
|
compiler.note.sunapi.filename=\
|
||||||
{0} uses internal proprietary API that may be removed in a future release.
|
{0} uses internal proprietary API that may be removed in a future release.
|
||||||
compiler.note.sunapi.plural=\
|
compiler.note.sunapi.plural=\
|
||||||
|
@ -841,9 +836,12 @@ compiler.warn.unchecked.meth.invocation.applied=\
|
||||||
compiler.warn.unchecked.generic.array.creation=\
|
compiler.warn.unchecked.generic.array.creation=\
|
||||||
unchecked generic array creation for varargs parameter of type {0}
|
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}
|
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=\
|
compiler.warn.missing.deprecated.annotation=\
|
||||||
deprecated item is not annotated with @Deprecated
|
deprecated item is not annotated with @Deprecated
|
||||||
|
|
||||||
|
@ -876,6 +874,9 @@ compiler.warn.diamond.redundant.args.1=\
|
||||||
explicit: {0}\n\
|
explicit: {0}\n\
|
||||||
inferred: {1}
|
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
|
## 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.
|
/** 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) {
|
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))));
|
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;
|
package com.sun.tools.javac.util;
|
||||||
|
|
||||||
|
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface to support optional warnings, needed for support of
|
* An interface to support optional warnings, needed for support of
|
||||||
|
@ -40,25 +42,45 @@ public class Warner {
|
||||||
public static final Warner noWarnings = new Warner();
|
public static final Warner noWarnings = new Warner();
|
||||||
|
|
||||||
private DiagnosticPosition pos = null;
|
private DiagnosticPosition pos = null;
|
||||||
public boolean warned = false;
|
protected boolean warned = false;
|
||||||
public boolean unchecked = false;
|
private EnumSet<LintCategory> nonSilentLintSet = EnumSet.noneOf(LintCategory.class);
|
||||||
|
private EnumSet<LintCategory> silentLintSet = EnumSet.noneOf(LintCategory.class);
|
||||||
|
|
||||||
public DiagnosticPosition pos() {
|
public DiagnosticPosition pos() {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void warnUnchecked() {
|
public void warn(LintCategory lint) {
|
||||||
warned = true;
|
nonSilentLintSet.add(lint);
|
||||||
unchecked = true;
|
|
||||||
}
|
}
|
||||||
public void silentUnchecked() {
|
|
||||||
unchecked = true;
|
public void silentWarn(LintCategory lint) {
|
||||||
|
silentLintSet.add(lint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Warner(DiagnosticPosition pos) {
|
public Warner(DiagnosticPosition pos) {
|
||||||
this.pos = 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() {
|
public Warner() {
|
||||||
this(null);
|
this(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,12 +129,17 @@ public class CheckExamples {
|
||||||
File testSrc = new File(System.getProperty("test.src"));
|
File testSrc = new File(System.getProperty("test.src"));
|
||||||
File examples = new File(testSrc, "examples");
|
File examples = new File(testSrc, "examples");
|
||||||
for (File f: examples.listFiles()) {
|
for (File f: examples.listFiles()) {
|
||||||
if (f.isDirectory() || f.isFile() && f.getName().endsWith(".java"))
|
if (isValidExample(f))
|
||||||
results.add(new Example(f));
|
results.add(new Example(f));
|
||||||
}
|
}
|
||||||
return results;
|
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.
|
* Get the contents of the "not-yet" list.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -52,7 +52,7 @@ import java.util.regex.Pattern;
|
||||||
*/
|
*/
|
||||||
public class RunExamples {
|
public class RunExamples {
|
||||||
public static void main(String... args) throws Exception {
|
public static void main(String... args) throws Exception {
|
||||||
boolean jtreg = (System.getProperty("test.src") != null);
|
jtreg = (System.getProperty("test.src") != null);
|
||||||
File tmpDir;
|
File tmpDir;
|
||||||
if (jtreg) {
|
if (jtreg) {
|
||||||
// use standard jtreg scratch directory: the current directory
|
// use standard jtreg scratch directory: the current directory
|
||||||
|
@ -166,12 +166,17 @@ public class RunExamples {
|
||||||
Set<Example> getExamples(File examplesDir) {
|
Set<Example> getExamples(File examplesDir) {
|
||||||
Set<Example> results = new TreeSet<Example>();
|
Set<Example> results = new TreeSet<Example>();
|
||||||
for (File f: examplesDir.listFiles()) {
|
for (File f: examplesDir.listFiles()) {
|
||||||
if (f.isDirectory() || f.isFile() && f.getName().endsWith(".java"))
|
if (isValidExample(f))
|
||||||
results.add(new Example(f));
|
results.add(new Example(f));
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isValidExample(File f) {
|
||||||
|
return (f.isDirectory() && (!jtreg || f.list().length > 0)) ||
|
||||||
|
(f.isFile() && f.getName().endsWith(".java"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report an error.
|
* Report an error.
|
||||||
*/
|
*/
|
||||||
|
@ -180,6 +185,8 @@ public class RunExamples {
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean jtreg;
|
||||||
|
|
||||||
int errors;
|
int errors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.note.varargs.plural.additional
|
// key: compiler.err.varargs.invalid.trustme.anno
|
||||||
// key: compiler.warn.varargs.non.reifiable.type
|
// key: compiler.misc.varargs.trustme.on.non.varargs.meth
|
||||||
// options: -Xlint:varargs -Xmaxwarns 1
|
// options: -Xlint:varargs
|
||||||
|
|
||||||
class VarargsPluralAdditional<T> {
|
class TrustMeOnNonVarargsMeth {
|
||||||
void m(T... items) { }
|
@SafeVarargs static void m(String[] args) { }
|
||||||
}
|
}
|
|
@ -21,9 +21,10 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.note.varargs.plural
|
// key: compiler.warn.varargs.redundant.trustme.anno
|
||||||
// key: compiler.note.varargs.recompile
|
// key: compiler.misc.varargs.trustme.on.reifiable.varargs
|
||||||
|
// options: -Xlint:varargs
|
||||||
|
|
||||||
class VarargsPlural<T> {
|
class TrustMeOnReifiableVarargsParam {
|
||||||
void m(T... items) { }
|
@SafeVarargs static void m(String... args) { }
|
||||||
}
|
}
|
|
@ -21,11 +21,12 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.note.varargs.filename.additional
|
// key: compiler.err.varargs.invalid.trustme.anno
|
||||||
// key: compiler.warn.varargs.non.reifiable.type
|
// key: compiler.misc.varargs.trustme.on.virtual.varargs
|
||||||
// options: -Xlint:varargs -Xmaxwarns 1
|
// options: -Xlint:varargs,unchecked
|
||||||
|
|
||||||
class VarargsFilenameAdditional<T> {
|
import java.util.List;
|
||||||
void m1(T... items) { }
|
|
||||||
void m2(T... items) { }
|
class TrustMeOnVirtualMethod {
|
||||||
|
@SafeVarargs void m(List<String>... args) { }
|
||||||
}
|
}
|
|
@ -22,10 +22,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.warn.unchecked.generic.array.creation
|
// key: compiler.warn.unchecked.generic.array.creation
|
||||||
// key: compiler.warn.varargs.non.reifiable.type
|
// key: compiler.warn.unchecked.varargs.non.reifiable.type
|
||||||
// options: -Xlint:unchecked,varargs
|
// options: -Xlint:unchecked
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
class UncheckedGenericArrayCreation<T> {
|
class UncheckedGenericArrayCreation<T> {
|
||||||
void m(T t1, T t2, T t3) {
|
void m(T t1, T t2, T t3) {
|
||||||
|
|
|
@ -21,9 +21,11 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.note.varargs.filename
|
// key: compiler.warn.varargs.unsafe.use.varargs.param
|
||||||
// key: compiler.note.varargs.recompile
|
// options: -Xlint:varargs
|
||||||
|
|
||||||
class VarargsFilename<T> {
|
class UnsafeUseOfVarargsParam {
|
||||||
void m(T... items) { }
|
@SafeVarargs static <X> void m(X... x) {
|
||||||
|
Object[] o = x;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,10 +21,8 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.warn.varargs.non.reifiable.type
|
// key: compiler.warn.unchecked.varargs.non.reifiable.type
|
||||||
// options: -Xlint:varargs
|
// options: -Xlint:unchecked
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
class VarargsNonReifiableType<T> {
|
class VarargsNonReifiableType<T> {
|
||||||
void m(T... items) {
|
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 {
|
class T6730476a {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
<T> void f(int i, T ... x) {}
|
<T> void f(int i, T ... x) {}
|
||||||
void g() {
|
void g() {
|
||||||
f(1);
|
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: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.err.warnings.and.werror
|
||||||
- compiler.note.varargs.filename: T6806876.java
|
|
||||||
- compiler.note.varargs.recompile
|
|
||||||
1 error
|
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
|
* @test
|
||||||
* @bug 6945418
|
* @bug 6945418 6993978
|
||||||
* @summary Project Coin: Simplified Varargs Method Invocation
|
* @summary Project Coin: Simplified Varargs Method Invocation
|
||||||
* @author mcimadamore
|
* @author mcimadamore
|
||||||
* @run main Warn4
|
* @run main Warn4
|
||||||
|
@ -48,96 +48,95 @@ public class Warn4 {
|
||||||
final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
|
final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
|
||||||
|
|
||||||
enum Warning {
|
enum Warning {
|
||||||
UNCHECKED("unchecked"),
|
UNCHECKED("generic.array.creation"),
|
||||||
VARARGS("varargs");
|
VARARGS("varargs.non.reifiable.type");
|
||||||
|
|
||||||
String category;
|
String key;
|
||||||
|
|
||||||
Warning(String category) {
|
Warning(String key) {
|
||||||
this.category = category;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEnabled(XlintOption xlint, SuppressLevel suppressLevel) {
|
boolean isSuppressed(TrustMe trustMe, SourceLevel source, SuppressLevel suppressLevelClient,
|
||||||
return Arrays.asList(xlint.enabledWarnings).contains(this);
|
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) {
|
SuppressLevel supLev = this == VARARGS ?
|
||||||
return Arrays.asList(suppressLevel.suppressedWarnings).contains(VARARGS);
|
suppressLevelDecl :
|
||||||
|
suppressLevelClient;
|
||||||
|
return supLev == SuppressLevel.UNCHECKED ||
|
||||||
|
(trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum XlintOption {
|
enum SourceLevel {
|
||||||
NONE(),
|
JDK_6("6"),
|
||||||
UNCHECKED(Warning.UNCHECKED),
|
JDK_7("7");
|
||||||
VARARGS(Warning.VARARGS),
|
|
||||||
ALL(Warning.UNCHECKED, Warning.VARARGS);
|
|
||||||
|
|
||||||
Warning[] enabledWarnings;
|
String sourceKey;
|
||||||
|
|
||||||
XlintOption(Warning... enabledWarnings) {
|
SourceLevel(String sourceKey) {
|
||||||
this.enabledWarnings = enabledWarnings;
|
this.sourceKey = sourceKey;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String getXlintOption() {
|
enum TrustMe {
|
||||||
StringBuilder buf = new StringBuilder();
|
DONT_TRUST(""),
|
||||||
String sep = "";
|
TRUST("@java.lang.SafeVarargs");
|
||||||
for (Warning w : enabledWarnings) {
|
|
||||||
buf.append(sep);
|
String anno;
|
||||||
buf.append(w.category);
|
|
||||||
sep=",";
|
TrustMe(String anno) {
|
||||||
}
|
this.anno = anno;
|
||||||
return "-Xlint:" +
|
}
|
||||||
(this == NONE ? "none" : buf.toString());
|
}
|
||||||
|
|
||||||
|
enum ModifierKind {
|
||||||
|
NONE(" "),
|
||||||
|
FINAL("final "),
|
||||||
|
STATIC("static ");
|
||||||
|
|
||||||
|
String mod;
|
||||||
|
|
||||||
|
ModifierKind(String mod) {
|
||||||
|
this.mod = mod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SuppressLevel {
|
enum SuppressLevel {
|
||||||
NONE(),
|
NONE(""),
|
||||||
UNCHECKED(Warning.UNCHECKED),
|
UNCHECKED("unchecked");
|
||||||
VARARGS(Warning.VARARGS),
|
|
||||||
ALL(Warning.UNCHECKED, Warning.VARARGS);
|
|
||||||
|
|
||||||
Warning[] suppressedWarnings;
|
String lint;
|
||||||
|
|
||||||
SuppressLevel(Warning... suppressedWarnings) {
|
SuppressLevel(String lint) {
|
||||||
this.suppressedWarnings = suppressedWarnings;
|
this.lint = lint;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getSuppressAnnotation() {
|
String getSuppressAnno() {
|
||||||
StringBuilder buf = new StringBuilder();
|
return "@SuppressWarnings(\"" + lint + "\")";
|
||||||
String sep = "";
|
|
||||||
for (Warning w : suppressedWarnings) {
|
|
||||||
buf.append(sep);
|
|
||||||
buf.append("\"");
|
|
||||||
buf.append(w.category);
|
|
||||||
buf.append("\"");
|
|
||||||
sep=",";
|
|
||||||
}
|
|
||||||
return this == NONE ? "" :
|
|
||||||
"@SuppressWarnings({" + buf.toString() + "})";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Signature {
|
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 }",
|
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 }",
|
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 }",
|
TVAR("<Z> void #name(Z#arity arg) { #body }",
|
||||||
new Warning[][] {both, both, both, both, both, both, both, both, vararg}),
|
new Warning[][] {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}),
|
|
||||||
INVARIANT("void #name(List<String>#arity arg) { #body }",
|
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 }",
|
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;
|
String template;
|
||||||
Warning[][] warnings;
|
Warning[][] warnings;
|
||||||
|
@ -163,15 +162,24 @@ public class Warn4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String... args) throws Exception {
|
public static void main(String... args) throws Exception {
|
||||||
for (XlintOption xlint : XlintOption.values()) {
|
for (SourceLevel sourceLevel : SourceLevel.values()) {
|
||||||
for (SuppressLevel suppressLevel : SuppressLevel.values()) {
|
for (TrustMe trustMe : TrustMe.values()) {
|
||||||
for (Signature vararg_meth : Signature.values()) {
|
for (SuppressLevel suppressLevelClient : SuppressLevel.values()) {
|
||||||
for (Signature client_meth : Signature.values()) {
|
for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) {
|
||||||
if (vararg_meth.isApplicableTo(client_meth)) {
|
for (ModifierKind modKind : ModifierKind.values()) {
|
||||||
test(xlint,
|
for (Signature vararg_meth : Signature.values()) {
|
||||||
suppressLevel,
|
for (Signature client_meth : Signature.values()) {
|
||||||
vararg_meth,
|
if (vararg_meth.isApplicableTo(client_meth)) {
|
||||||
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,
|
static void test(SourceLevel sourceLevel, TrustMe trustMe, SuppressLevel suppressLevelClient,
|
||||||
Signature vararg_meth, Signature client_meth) throws Exception {
|
SuppressLevel suppressLevelDecl, ModifierKind modKind, Signature vararg_meth, Signature client_meth) throws Exception {
|
||||||
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
|
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();
|
DiagnosticChecker dc = new DiagnosticChecker();
|
||||||
JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
|
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
|
ct.generate(); //to get mandatory notes
|
||||||
check(dc.warnings,
|
check(dc.warnings, sourceLevel,
|
||||||
dc.notes,
|
|
||||||
new boolean[] {vararg_meth.giveUnchecked(client_meth),
|
new boolean[] {vararg_meth.giveUnchecked(client_meth),
|
||||||
vararg_meth.giveVarargs(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;
|
boolean badOutput = false;
|
||||||
for (Warning wkind : Warning.values()) {
|
for (Warning wkind : Warning.values()) {
|
||||||
badOutput |= (warnArr[wkind.ordinal()] && !wkind.isSuppressed(suppressLevel)) !=
|
boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
|
||||||
(wkind.isEnabled(xlint, suppressLevel) ?
|
suppressLevelClient, suppressLevelDecl, modKind);
|
||||||
warnings.contains(wkind) :
|
System.out.println("SUPPRESSED = " + isSuppressed);
|
||||||
notes.contains(wkind));
|
badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != warnings.contains(wkind);
|
||||||
}
|
}
|
||||||
if (badOutput) {
|
if (badOutput) {
|
||||||
throw new Error("invalid diagnostics for source:\n" +
|
throw new Error("invalid diagnostics for source:\n" +
|
||||||
source.getCharContent(true) +
|
source.getCharContent(true) +
|
||||||
"\nOptions: " + xlint.getXlintOption() +
|
|
||||||
"\nExpected unchecked warning: " + warnArr[0] +
|
"\nExpected unchecked warning: " + warnArr[0] +
|
||||||
"\nExpected unsafe vararg warning: " + warnArr[1] +
|
"\nExpected unsafe vararg warning: " + warnArr[1] +
|
||||||
"\nWarnings: " + warnings +
|
"\nWarnings: " + warnings +
|
||||||
"\nNotes: " + notes);
|
"\nSource level: " + sourceLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,18 +225,20 @@ public class Warn4 {
|
||||||
|
|
||||||
String source;
|
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);
|
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
|
||||||
String meth1 = vararg_meth.template.replace("#arity", "...");
|
String meth1 = vararg_meth.template.replace("#arity", "...");
|
||||||
meth1 = meth1.replace("#name", "m");
|
meth1 = meth1.replace("#name", "m");
|
||||||
meth1 = meth1.replace("#body", "");
|
meth1 = meth1.replace("#body", "");
|
||||||
meth1 = suppressLevel.getSuppressAnnotation() + meth1;
|
meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + modKind.mod + meth1;
|
||||||
String meth2 = client_meth.template.replace("#arity", "");
|
String meth2 = client_meth.template.replace("#arity", "");
|
||||||
meth2 = meth2.replace("#name", "test");
|
meth2 = meth2.replace("#name", "test");
|
||||||
meth2 = meth2.replace("#body", "m(arg);");
|
meth2 = meth2.replace("#body", "m(arg);");
|
||||||
|
meth2 = suppressLevelClient.getSuppressAnno() + meth2;
|
||||||
source = "import java.util.List;\n" +
|
source = "import java.util.List;\n" +
|
||||||
"class Test {\n" + meth1 +
|
"class Test {\n" + meth1 +
|
||||||
"\n" + meth2 + "\n}\n";
|
"\n" + meth2 + "\n}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -240,19 +250,15 @@ public class Warn4 {
|
||||||
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
|
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
|
||||||
|
|
||||||
Set<Warning> warnings = new HashSet<>();
|
Set<Warning> warnings = new HashSet<>();
|
||||||
Set<Warning> notes = new HashSet<>();
|
|
||||||
|
|
||||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||||
if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
|
if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
|
||||||
diagnostic.getKind() == Diagnostic.Kind.WARNING) {
|
diagnostic.getKind() == Diagnostic.Kind.WARNING) {
|
||||||
warnings.add(diagnostic.getCode().contains("varargs") ?
|
if (diagnostic.getCode().contains(Warning.VARARGS.key)) {
|
||||||
Warning.VARARGS :
|
warnings.add(Warning.VARARGS);
|
||||||
Warning.UNCHECKED);
|
} else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) {
|
||||||
}
|
warnings.add(Warning.UNCHECKED);
|
||||||
else if (diagnostic.getKind() == Diagnostic.Kind.NOTE) {
|
}
|
||||||
notes.add(diagnostic.getCode().contains("varargs") ?
|
|
||||||
Warning.VARARGS :
|
|
||||||
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…
Add table
Add a link
Reference in a new issue