mcimadamore@580: /* ohair@962: * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. mcimadamore@580: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. mcimadamore@580: * mcimadamore@580: * This code is free software; you can redistribute it and/or modify it mcimadamore@580: * under the terms of the GNU General Public License version 2 only, as mcimadamore@580: * published by the Free Software Foundation. mcimadamore@580: * mcimadamore@580: * This code is distributed in the hope that it will be useful, but WITHOUT mcimadamore@580: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or mcimadamore@580: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License mcimadamore@580: * version 2 for more details (a copy is included in the LICENSE file that mcimadamore@580: * accompanied this code). mcimadamore@580: * mcimadamore@580: * You should have received a copy of the GNU General Public License version mcimadamore@580: * 2 along with this work; if not, write to the Free Software Foundation, mcimadamore@580: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. mcimadamore@580: * jjg@581: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jjg@581: * or visit www.oracle.com if you need additional information or have any jjg@581: * questions. mcimadamore@580: */ mcimadamore@580: mcimadamore@580: /** mcimadamore@580: * @test mcimadamore@795: * @bug 6945418 6993978 mcimadamore@580: * @summary Project Coin: Simplified Varargs Method Invocation mcimadamore@580: * @author mcimadamore mcimadamore@580: * @run main Warn4 mcimadamore@580: */ mcimadamore@580: import com.sun.source.util.JavacTask; jjh@892: import com.sun.tools.javac.api.JavacTool; mcimadamore@580: import java.net.URI; mcimadamore@580: import java.util.Arrays; mcimadamore@580: import java.util.Set; mcimadamore@580: import java.util.HashSet; mcimadamore@580: import javax.tools.Diagnostic; mcimadamore@580: import javax.tools.JavaCompiler; mcimadamore@580: import javax.tools.JavaFileObject; mcimadamore@580: import javax.tools.SimpleJavaFileObject; jjh@892: import javax.tools.StandardJavaFileManager; mcimadamore@580: import javax.tools.ToolProvider; mcimadamore@580: mcimadamore@580: public class Warn4 { mcimadamore@580: mcimadamore@580: final static Warning[] error = null; mcimadamore@580: final static Warning[] none = new Warning[] {}; mcimadamore@580: final static Warning[] vararg = new Warning[] { Warning.VARARGS }; mcimadamore@580: final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; mcimadamore@580: final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; mcimadamore@580: mcimadamore@580: enum Warning { mcimadamore@795: UNCHECKED("generic.array.creation"), mcimadamore@795: VARARGS("varargs.non.reifiable.type"); mcimadamore@580: mcimadamore@795: String key; mcimadamore@580: mcimadamore@795: Warning(String key) { mcimadamore@795: this.key = key; mcimadamore@580: } mcimadamore@580: mcimadamore@795: boolean isSuppressed(TrustMe trustMe, SourceLevel source, SuppressLevel suppressLevelClient, mcimadamore@795: SuppressLevel suppressLevelDecl, ModifierKind modKind) { mcimadamore@795: switch(this) { mcimadamore@795: case VARARGS: mcimadamore@795: return source == SourceLevel.JDK_6 || mcimadamore@795: suppressLevelDecl == SuppressLevel.UNCHECKED || mcimadamore@795: trustMe == TrustMe.TRUST; mcimadamore@795: case UNCHECKED: mcimadamore@795: return suppressLevelClient == SuppressLevel.UNCHECKED || mcimadamore@795: (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE && source == SourceLevel.JDK_7); mcimadamore@795: } mcimadamore@580: mcimadamore@795: SuppressLevel supLev = this == VARARGS ? mcimadamore@795: suppressLevelDecl : mcimadamore@795: suppressLevelClient; mcimadamore@795: return supLev == SuppressLevel.UNCHECKED || mcimadamore@795: (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE); mcimadamore@580: } mcimadamore@580: } mcimadamore@580: mcimadamore@795: enum SourceLevel { mcimadamore@795: JDK_6("6"), mcimadamore@795: JDK_7("7"); mcimadamore@580: mcimadamore@795: String sourceKey; mcimadamore@580: mcimadamore@795: SourceLevel(String sourceKey) { mcimadamore@795: this.sourceKey = sourceKey; mcimadamore@580: } mcimadamore@795: } mcimadamore@580: mcimadamore@795: enum TrustMe { mcimadamore@795: DONT_TRUST(""), mcimadamore@795: TRUST("@java.lang.SafeVarargs"); mcimadamore@795: mcimadamore@795: String anno; mcimadamore@795: mcimadamore@795: TrustMe(String anno) { mcimadamore@795: this.anno = anno; mcimadamore@795: } mcimadamore@795: } mcimadamore@795: mcimadamore@795: enum ModifierKind { mcimadamore@795: NONE(" "), mcimadamore@795: FINAL("final "), mcimadamore@795: STATIC("static "); mcimadamore@795: mcimadamore@795: String mod; mcimadamore@795: mcimadamore@795: ModifierKind(String mod) { mcimadamore@795: this.mod = mod; mcimadamore@580: } mcimadamore@580: } mcimadamore@580: mcimadamore@580: enum SuppressLevel { mcimadamore@795: NONE(""), mcimadamore@795: UNCHECKED("unchecked"); mcimadamore@580: mcimadamore@795: String lint; mcimadamore@580: mcimadamore@795: SuppressLevel(String lint) { mcimadamore@795: this.lint = lint; mcimadamore@580: } mcimadamore@580: mcimadamore@795: String getSuppressAnno() { mcimadamore@795: return "@SuppressWarnings(\"" + lint + "\")"; mcimadamore@580: } mcimadamore@580: } mcimadamore@580: mcimadamore@580: enum Signature { mcimadamore@580: UNBOUND("void #name(List#arity arg) { #body }", mcimadamore@795: new Warning[][] {none, none, none, none, error}), mcimadamore@580: INVARIANT_TVAR(" void #name(List#arity arg) { #body }", mcimadamore@795: new Warning[][] {both, both, error, both, error}), mcimadamore@580: TVAR(" void #name(Z#arity arg) { #body }", mcimadamore@795: new Warning[][] {both, both, both, both, vararg}), mcimadamore@580: INVARIANT("void #name(List#arity arg) { #body }", mcimadamore@795: new Warning[][] {error, error, error, both, error}), mcimadamore@580: UNPARAMETERIZED("void #name(String#arity arg) { #body }", mcimadamore@795: new Warning[][] {error, error, error, error, none}); mcimadamore@580: mcimadamore@580: String template; mcimadamore@580: Warning[][] warnings; mcimadamore@580: mcimadamore@580: Signature(String template, Warning[][] warnings) { mcimadamore@580: this.template = template; mcimadamore@580: this.warnings = warnings; mcimadamore@580: } mcimadamore@580: mcimadamore@580: boolean isApplicableTo(Signature other) { mcimadamore@580: return warnings[other.ordinal()] != null; mcimadamore@580: } mcimadamore@580: mcimadamore@580: boolean giveUnchecked(Signature other) { mcimadamore@580: return warnings[other.ordinal()] == unchecked || mcimadamore@580: warnings[other.ordinal()] == both; mcimadamore@580: } mcimadamore@580: mcimadamore@580: boolean giveVarargs(Signature other) { mcimadamore@580: return warnings[other.ordinal()] == vararg || mcimadamore@580: warnings[other.ordinal()] == both; mcimadamore@580: } mcimadamore@580: } mcimadamore@580: mcimadamore@580: public static void main(String... args) throws Exception { mcimadamore@795: for (SourceLevel sourceLevel : SourceLevel.values()) { mcimadamore@795: for (TrustMe trustMe : TrustMe.values()) { mcimadamore@795: for (SuppressLevel suppressLevelClient : SuppressLevel.values()) { mcimadamore@795: for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) { mcimadamore@795: for (ModifierKind modKind : ModifierKind.values()) { mcimadamore@795: for (Signature vararg_meth : Signature.values()) { mcimadamore@795: for (Signature client_meth : Signature.values()) { mcimadamore@795: if (vararg_meth.isApplicableTo(client_meth)) { mcimadamore@795: test(sourceLevel, mcimadamore@795: trustMe, mcimadamore@795: suppressLevelClient, mcimadamore@795: suppressLevelDecl, mcimadamore@795: modKind, mcimadamore@795: vararg_meth, mcimadamore@795: client_meth); mcimadamore@795: } mcimadamore@795: } mcimadamore@795: } mcimadamore@580: } mcimadamore@580: } mcimadamore@580: } mcimadamore@580: } mcimadamore@580: } mcimadamore@580: } mcimadamore@580: jjh@892: // Create a single file manager and reuse it for each compile to save time. jjh@892: static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); jjh@892: mcimadamore@795: static void test(SourceLevel sourceLevel, TrustMe trustMe, SuppressLevel suppressLevelClient, mcimadamore@795: SuppressLevel suppressLevelDecl, ModifierKind modKind, Signature vararg_meth, Signature client_meth) throws Exception { mcimadamore@580: final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); mcimadamore@795: JavaSource source = new JavaSource(trustMe, suppressLevelClient, suppressLevelDecl, modKind, vararg_meth, client_meth); mcimadamore@580: DiagnosticChecker dc = new DiagnosticChecker(); jjh@892: JavacTask ct = (JavacTask)tool.getTask(null, fm, dc, mcimadamore@795: Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey), mcimadamore@795: null, Arrays.asList(source)); mcimadamore@580: ct.generate(); //to get mandatory notes mcimadamore@795: check(dc.warnings, sourceLevel, mcimadamore@580: new boolean[] {vararg_meth.giveUnchecked(client_meth), mcimadamore@580: vararg_meth.giveVarargs(client_meth)}, mcimadamore@795: source, trustMe, suppressLevelClient, suppressLevelDecl, modKind); mcimadamore@580: } mcimadamore@580: mcimadamore@795: static void check(Set warnings, SourceLevel sourceLevel, boolean[] warnArr, JavaSource source, mcimadamore@795: TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, ModifierKind modKind) { mcimadamore@580: boolean badOutput = false; mcimadamore@580: for (Warning wkind : Warning.values()) { mcimadamore@795: boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel, mcimadamore@795: suppressLevelClient, suppressLevelDecl, modKind); mcimadamore@795: System.out.println("SUPPRESSED = " + isSuppressed); mcimadamore@795: badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != warnings.contains(wkind); mcimadamore@580: } mcimadamore@580: if (badOutput) { mcimadamore@580: throw new Error("invalid diagnostics for source:\n" + mcimadamore@580: source.getCharContent(true) + mcimadamore@580: "\nExpected unchecked warning: " + warnArr[0] + mcimadamore@580: "\nExpected unsafe vararg warning: " + warnArr[1] + mcimadamore@580: "\nWarnings: " + warnings + mcimadamore@795: "\nSource level: " + sourceLevel); mcimadamore@580: } mcimadamore@580: } mcimadamore@580: mcimadamore@580: static class JavaSource extends SimpleJavaFileObject { mcimadamore@580: mcimadamore@580: String source; mcimadamore@580: mcimadamore@795: public JavaSource(TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, mcimadamore@795: ModifierKind modKind, Signature vararg_meth, Signature client_meth) { mcimadamore@580: super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); mcimadamore@580: String meth1 = vararg_meth.template.replace("#arity", "..."); mcimadamore@580: meth1 = meth1.replace("#name", "m"); mcimadamore@580: meth1 = meth1.replace("#body", ""); mcimadamore@795: meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + modKind.mod + meth1; mcimadamore@580: String meth2 = client_meth.template.replace("#arity", ""); mcimadamore@580: meth2 = meth2.replace("#name", "test"); mcimadamore@580: meth2 = meth2.replace("#body", "m(arg);"); mcimadamore@795: meth2 = suppressLevelClient.getSuppressAnno() + meth2; mcimadamore@580: source = "import java.util.List;\n" + mcimadamore@795: "class Test {\n" + meth1 + mcimadamore@795: "\n" + meth2 + "\n}\n"; mcimadamore@580: } mcimadamore@580: mcimadamore@580: @Override mcimadamore@580: public CharSequence getCharContent(boolean ignoreEncodingErrors) { mcimadamore@580: return source; mcimadamore@580: } mcimadamore@580: } mcimadamore@580: mcimadamore@580: static class DiagnosticChecker implements javax.tools.DiagnosticListener { mcimadamore@580: mcimadamore@580: Set warnings = new HashSet<>(); mcimadamore@580: mcimadamore@580: public void report(Diagnostic diagnostic) { mcimadamore@580: if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING || mcimadamore@580: diagnostic.getKind() == Diagnostic.Kind.WARNING) { mcimadamore@795: if (diagnostic.getCode().contains(Warning.VARARGS.key)) { mcimadamore@795: warnings.add(Warning.VARARGS); mcimadamore@795: } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) { mcimadamore@795: warnings.add(Warning.UNCHECKED); mcimadamore@795: } mcimadamore@580: } mcimadamore@580: } mcimadamore@580: } mcimadamore@580: }