Mercurial > hg > openjdk > icedtea > jdk7 > langtools
changeset 1148:8556ecc20a5b jdk7u4-b02
Merge
author | lana |
---|---|
date | Tue, 22 Nov 2011 15:09:16 -0800 |
parents | 2fd31b33bda3 (current diff) f65eebb8d25f (diff) |
children | 9e9ba3147b1c 0b858fc21092 e424ab0b2e00 |
files | |
diffstat | 10 files changed, 504 insertions(+), 172 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Wed Nov 16 16:10:09 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Tue Nov 22 15:09:16 2011 -0800 @@ -278,7 +278,6 @@ boolean tPrimitive = t.isPrimitive(); boolean sPrimitive = s.isPrimitive(); if (tPrimitive == sPrimitive) { - checkUnsafeVarargsConversion(t, s, warn); return isSubtypeUnchecked(t, s, warn); } if (!allowBoxing) return false; @@ -286,27 +285,6 @@ ? 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 @@ -328,42 +306,63 @@ * Is t an unchecked subtype of s? */ public boolean isSubtypeUnchecked(Type t, Type s, Warner warn) { - if (t.tag == ARRAY && s.tag == ARRAY) { - 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; + boolean result = isSubtypeUncheckedInternal(t, s, warn); + if (result) { + checkUnsafeVarargsConversion(t, s, warn); } - else if (t.tag == TYPEVAR) { - return isSubtypeUnchecked(t.getUpperBound(), s, warn); - } - else if (s.tag == UNDETVAR) { - UndetVar uv = (UndetVar)s; - if (uv.inst != null) - return isSubtypeUnchecked(t, uv.inst, warn); - } - else if (!s.isRaw()) { - Type t2 = asSuper(t, s.tsym); - if (t2 != null && t2.isRaw()) { - if (isReifiable(s)) - warn.silentWarn(LintCategory.UNCHECKED); - else - warn.warn(LintCategory.UNCHECKED); + return result; + } + //where + private boolean isSubtypeUncheckedInternal(Type t, Type s, Warner warn) { + if (t.tag == ARRAY && s.tag == ARRAY) { + if (((ArrayType)t).elemtype.tag <= lastBaseTag) { + return isSameType(elemtype(t), elemtype(s)); + } else { + return isSubtypeUnchecked(elemtype(t), elemtype(s), warn); + } + } else if (isSubtype(t, s)) { return true; } + else if (t.tag == TYPEVAR) { + return isSubtypeUnchecked(t.getUpperBound(), s, warn); + } + else if (s.tag == UNDETVAR) { + UndetVar uv = (UndetVar)s; + if (uv.inst != null) + return isSubtypeUnchecked(t, uv.inst, warn); + } + else if (!s.isRaw()) { + Type t2 = asSuper(t, s.tsym); + if (t2 != null && t2.isRaw()) { + if (isReifiable(s)) + warn.silentWarn(LintCategory.UNCHECKED); + else + warn.warn(LintCategory.UNCHECKED); + return true; + } + } + return false; } - return false; - } + + 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(); + break; + } + if (shouldWarn) { + warn.warn(LintCategory.VARARGS); + } + } /** * Is t a subtype of s?<br>
--- a/src/share/classes/com/sun/tools/javac/comp/Infer.java Wed Nov 16 16:10:09 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java Tue Nov 22 15:09:16 2011 -0800 @@ -276,21 +276,18 @@ // VGJ: sort of inlined maximizeInst() below. Adding // bounds can cause lobounds that are above hibounds. List<Type> hibounds = Type.filter(that.hibounds, errorFilter); + Type hb = null; if (hibounds.isEmpty()) - return; - Type hb = null; - if (hibounds.tail.isEmpty()) + hb = syms.objectType; + else if (hibounds.tail.isEmpty()) hb = hibounds.head; - else for (List<Type> bs = hibounds; - bs.nonEmpty() && hb == null; - bs = bs.tail) { - if (isSubClass(bs.head, hibounds)) - hb = types.fromUnknownFun.apply(bs.head); - } + else + hb = types.glb(hibounds); if (hb == null || - !types.isSubtypeUnchecked(hb, hibounds, warn) || - !types.isSubtypeUnchecked(that.inst, hb, warn)) - throw ambiguousNoInstanceException; + hb.isErroneous()) + throw ambiguousNoInstanceException + .setMessage("incompatible.upper.bounds", + that.qtype, hibounds); } }
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Nov 16 16:10:09 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Nov 22 15:09:16 2011 -0800 @@ -1602,6 +1602,10 @@ compiler.misc.no.unique.minimal.instance.exists=\ no unique minimal instance exists for type variable {0} with lower bounds {1} +# 0: type, 1: list of type +compiler.misc.incompatible.upper.bounds=\ + inference variable {0} has incompatible upper bounds {1} + # 0: list of type, 1: type, 2: type compiler.misc.infer.no.conforming.instance.exists=\ no instance(s) of type variable(s) {0} exist so that {1} conforms to {2}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/diags/examples/IncompatibleUpperBounds.java Tue Nov 22 15:09:16 2011 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +//key: compiler.err.cant.apply.symbols +//key: compiler.misc.inapplicable.method +//key: compiler.misc.arg.length.mismatch +//key: compiler.misc.incompatible.upper.bounds + +import java.util.List; + +class IncompatibleUpperBounds { + <S> void m(List<? super S> s1, List<? super S> s2) { } + void m(Object o) {} + + void test(List<Integer> li, List<String> ls) { + m(li, ls); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/generics/inference/7086601/T7086601a.java Tue Nov 22 15:09:16 2011 -0800 @@ -0,0 +1,34 @@ +/** + * @test /nodynamiccopyright/ + * @bug 7086601 + * @summary Error message bug: cause for method mismatch is 'null' + * @compile/fail/ref=T7086601a.out -XDrawDiagnostics T7086601a.java + */ + +class T7086601 { + static <S> void m1(Iterable<? super S> s1, Iterable<? super S> s2) { } + static void m1(Object o) {} + + static <S> void m2(Iterable<? super S> s1, Iterable<? super S> s2, Iterable<? super S> s3) { } + static void m2(Object o) {} + + @SafeVarargs + static <S> void m3(Iterable<? super S>... ss) { } + static void m3(Object o) {} + + static void test1(Iterable<String> is, Iterable<Integer> ii) { + m1(is, ii); + } + + static void test2(Iterable<String> is, Iterable<Integer> ii, Iterable<Double> id) { + m2(is, ii, id); + } + + static void test3(Iterable<String> is, Iterable<Integer> ii) { + m3(is, ii); + } + + static void test4(Iterable<String> is, Iterable<Integer> ii, Iterable<Double> id) { + m3(is, ii, id); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/generics/inference/7086601/T7086601a.out Tue Nov 22 15:09:16 2011 -0800 @@ -0,0 +1,5 @@ +T7086601a.java:20:9: compiler.err.cant.apply.symbols: kindname.method, m1, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m1(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m1(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String))} +T7086601a.java:24:9: compiler.err.cant.apply.symbols: kindname.method, m2, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m2(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m2(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String))} +T7086601a.java:28:9: compiler.err.cant.apply.symbols: kindname.method, m3, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m3(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m3(java.lang.Iterable<? super S>...), (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String))} +T7086601a.java:32:9: compiler.err.cant.apply.symbols: kindname.method, m3, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m3(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m3(java.lang.Iterable<? super S>...), (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String))} +4 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/generics/inference/7086601/T7086601b.java Tue Nov 22 15:09:16 2011 -0800 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2011, 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 7086601 + * @summary Error message bug: cause for method mismatch is 'null' + */ + +import com.sun.source.util.JavacTask; +import java.net.URI; +import java.util.Arrays; +import java.util.ArrayList; +import javax.tools.Diagnostic; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + + +public class T7086601b { + + static int checkCount = 0; + + enum TypeKind { + STRING("String", false), + INTEGER("Integer", false), + NUMBER("Number", false), + SERIALIZABLE("java.io.Serializable", true), + CLONEABLE("Cloneable", true), + X("X", false), + Y("Y", false), + Z("Z", false); + + String typeStr; + boolean isInterface; + + private TypeKind(String typeStr, boolean isInterface) { + this.typeStr = typeStr; + this.isInterface = isInterface; + } + + boolean isSubtypeof(TypeKind other) { + return (this == INTEGER && other == NUMBER || + this == Z && other == Y || + this == other); + } + } + + enum MethodCallKind { + ARITY_ONE("m(a1);", 1), + ARITY_TWO("m(a1, a2);", 2), + ARITY_THREE("m(a1, a2, a3);", 3); + + String invokeString; + int arity; + + private MethodCallKind(String invokeString, int arity) { + this.invokeString = invokeString; + this.arity = arity; + } + } + + public static void main(String... args) throws Exception { + + //create default shared JavaCompiler - reused across multiple compilations + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + + for (TypeKind a1 : TypeKind.values()) { + for (TypeKind a2 : TypeKind.values()) { + for (TypeKind a3 : TypeKind.values()) { + for (MethodCallKind mck : MethodCallKind.values()) { + new T7086601b(a1, a2, a3, mck).run(comp, fm); + } + } + } + } + System.out.println("Total check executed: " + checkCount); + } + + TypeKind a1; + TypeKind a2; + TypeKind a3; + MethodCallKind mck; + JavaSource source; + DiagnosticChecker diagChecker; + + T7086601b(TypeKind a1, TypeKind a2, TypeKind a3, MethodCallKind mck) { + this.a1 = a1; + this.a2 = a2; + this.a3 = a3; + this.mck = mck; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + + class JavaSource extends SimpleJavaFileObject { + + final String bodyTemplate = "import java.util.List;\n"+ + "class Test {\n" + + " <Z> void m(List<? super Z> l1) { }\n" + + " <Z> void m(List<? super Z> l1, List<? super Z> l2) { }\n" + + " <Z> void m(List<? super Z> l1, List<? super Z> l2, List<? super Z> l3) { }\n" + + " <X,Y,Z extends Y> void test(List<#A1> a1, List<#A2> a2, List<#A3> a3) { #MC } }"; + + String source; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + source = bodyTemplate.replace("#A1", a1.typeStr) + .replace("#A2", a2.typeStr).replace("#A3", a3.typeStr) + .replace("#MC", mck.invokeString); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, + null, null, Arrays.asList(source)); + try { + ct.analyze(); + } catch (Throwable ex) { + throw new AssertionError("Error thron when compiling the following code:\n" + source.getCharContent(true)); + } + check(); + } + + void check() { + checkCount++; + + boolean errorExpected = false; + + if (mck.arity > 1) { + TypeKind[] argtypes = { a1, a2, a3 }; + ArrayList<TypeKind> classes = new ArrayList<>(); + for (int i = 0 ; i < mck.arity ; i ++ ) { + if (!argtypes[i].isInterface) { + classes.add(argtypes[i]); + } + } + boolean glb_exists = true; + for (TypeKind arg_i : classes) { + glb_exists = true; + for (TypeKind arg_j : classes) { + if (!arg_i.isSubtypeof(arg_j)) { + glb_exists = false; + break; + } + } + if (glb_exists) break; + } + errorExpected = !glb_exists; + } + + if (errorExpected != diagChecker.errorFound) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nFound error: " + diagChecker.errorFound + + "\nExpected error: " + errorExpected); + } + } + + static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { + + boolean errorFound; + + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/varargs/7097436/T7097436.java Tue Nov 22 15:09:16 2011 -0800 @@ -0,0 +1,18 @@ +/* + * @test /nodynamiccopyright/ + * @bug 7097436 + * @summary ClassCastException occurs in assignment expressions without any heap pollutions + * @compile/fail/ref=T7097436.out -Xlint:varargs -Werror -XDrawDiagnostics T7097436.java + */ + +import java.util.List; + +class T7097436 { + @SafeVarargs + static void m(List<String>... ls) { + Object o = ls; //warning + Object[] oArr = ls; //warning + String s = ls; // no warning + Integer[] iArr = ls; // no warning + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/varargs/7097436/T7097436.out Tue Nov 22 15:09:16 2011 -0800 @@ -0,0 +1,6 @@ +T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls +T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls +T7097436.java:15:20: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.util.List<java.lang.String>[], java.lang.String +T7097436.java:16:26: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.util.List<java.lang.String>[], java.lang.Integer[] +2 errors +2 warnings
--- a/test/tools/javac/varargs/warning/Warn5.java Wed Nov 16 16:10:09 2011 -0800 +++ b/test/tools/javac/varargs/warning/Warn5.java Tue Nov 22 15:09:16 2011 -0800 @@ -23,7 +23,7 @@ /** * @test - * @bug 6993978 + * @bug 6993978 7097436 * @summary Project Coin: Annotation to reduce varargs warnings * @author mcimadamore * @run main Warn5 @@ -31,8 +31,8 @@ import com.sun.source.util.JavacTask; import com.sun.tools.javac.api.JavacTool; import java.net.URI; -import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; import javax.tools.Diagnostic; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; @@ -95,7 +95,6 @@ METHOD("void m"), CONSTRUCTOR("Test"); - String name; MethodKind(String name) { @@ -155,7 +154,124 @@ } } - static class JavaSource extends SimpleJavaFileObject { + enum WarningKind { + UNSAFE_BODY, + UNSAFE_DECL, + MALFORMED_SAFEVARARGS, + REDUNDANT_SAFEVARARGS; + } + + // Create a single file manager and reuse it for each compile to save time. + static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); + + 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()) { + new Warn5(sourceLevel, + xlint, + trustMe, + suppressLevel, + modKind, + methKind, + sig, + body).test(); + } + } + } + } + } + } + } + } + } + + final SourceLevel sourceLevel; + final XlintOption xlint; + final TrustMe trustMe; + final SuppressLevel suppressLevel; + final ModifierKind modKind; + final MethodKind methKind; + final SignatureKind sig; + final BodyKind body; + final JavaSource source; + final DiagnosticChecker dc; + + public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) { + this.sourceLevel = sourceLevel; + this.xlint = xlint; + this.trustMe = trustMe; + this.suppressLevel = suppressLevel; + this.modKind = modKind; + this.methKind = methKind; + this.sig = sig; + this.body = body; + this.source = new JavaSource(); + this.dc = new DiagnosticChecker(); + } + + void test() throws Exception { + final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + JavacTask ct = (JavacTask)tool.getTask(null, fm, dc, + Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source)); + ct.analyze(); + check(); + } + + void check() { + + EnumSet<WarningKind> expectedWarnings = EnumSet.noneOf(WarningKind.class); + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.TRUST && + suppressLevel != SuppressLevel.VARARGS && + xlint != XlintOption.NONE && + sig.isVarargs && !sig.isReifiableArg && body.hasAliasing && + (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE))) { + expectedWarnings.add(WarningKind.UNSAFE_BODY); + } + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.DONT_TRUST && + sig.isVarargs && + !sig.isReifiableArg && + xlint == XlintOption.ALL) { + expectedWarnings.add(WarningKind.UNSAFE_DECL); + } + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.TRUST && + (!sig.isVarargs || + (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD))) { + expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS); + } + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.TRUST && + xlint != XlintOption.NONE && + suppressLevel != SuppressLevel.VARARGS && + (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) && + sig.isVarargs && + sig.isReifiableArg) { + expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS); + } + + if (!expectedWarnings.containsAll(dc.warnings) || + !dc.warnings.containsAll(expectedWarnings)) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nOptions: " + xlint.getXlintOption() + + "\nExpected warnings: " + expectedWarnings + + "\nFound warnings: " + dc.warnings); + } + } + + class JavaSource extends SimpleJavaFileObject { String template = "import com.sun.tools.javac.api.*;\n" + "import java.util.List;\n" + @@ -167,12 +283,11 @@ String source; - public JavaSource(TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, - MethodKind methKind, SignatureKind meth, BodyKind body) { + public JavaSource() { 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("#M", sig.getSignature(modKind, methKind)). replace("#B", body.body); } @@ -182,117 +297,34 @@ } } - 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); - } - } - } - } - } - } - } - } - } - - // Create a single file manager and reuse it for each compile to save time. - static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); - - 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, fm, 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) { + class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { - 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; + EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class); public void report(Diagnostic<? extends JavaFileObject> diagnostic) { if (diagnostic.getKind() == Diagnostic.Kind.WARNING) { if (diagnostic.getCode().contains("unsafe.use.varargs.param")) { - hasPotentiallyUnsafeBody = true; + setWarning(WarningKind.UNSAFE_BODY); } else if (diagnostic.getCode().contains("redundant.trustme")) { - hasRedundantAnnoInDecl = true; + setWarning(WarningKind.REDUNDANT_SAFEVARARGS); } } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING && diagnostic.getCode().contains("varargs.non.reifiable.type")) { - hasPotentiallyPollutingDecl = true; + setWarning(WarningKind.UNSAFE_DECL); } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR && diagnostic.getCode().contains("invalid.trustme")) { - hasMalformedAnnoInDecl = true; + setWarning(WarningKind.MALFORMED_SAFEVARARGS); } } + + void setWarning(WarningKind wk) { + if (!warnings.add(wk)) { + throw new AssertionError("Duplicate warning of kind " + wk + " in source:\n" + source); + } + } + + boolean hasWarning(WarningKind wk) { + return warnings.contains(wk); + } } }