Warn4.java revision 580:f2fdd52e4e87
1/*
2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * @test
26 * @bug     6945418
27 * @summary Project Coin: Simplified Varargs Method Invocation
28 * @author  mcimadamore
29 * @run main Warn4
30 */
31import com.sun.source.util.JavacTask;
32import java.net.URI;
33import java.util.Arrays;
34import java.util.Set;
35import java.util.HashSet;
36import javax.tools.Diagnostic;
37import javax.tools.JavaCompiler;
38import javax.tools.JavaFileObject;
39import javax.tools.SimpleJavaFileObject;
40import javax.tools.ToolProvider;
41
42public class Warn4 {
43
44    final static Warning[] error = null;
45    final static Warning[] none = new Warning[] {};
46    final static Warning[] vararg = new Warning[] { Warning.VARARGS };
47    final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED };
48    final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
49
50    enum Warning {
51        UNCHECKED("unchecked"),
52        VARARGS("varargs");
53
54        String category;
55
56        Warning(String category) {
57            this.category = category;
58        }
59
60        boolean isEnabled(XlintOption xlint, SuppressLevel suppressLevel) {
61            return Arrays.asList(xlint.enabledWarnings).contains(this);
62        }
63
64        boolean isSuppressed(SuppressLevel suppressLevel) {
65            return Arrays.asList(suppressLevel.suppressedWarnings).contains(VARARGS);
66        }
67    }
68
69    enum XlintOption {
70        NONE(),
71        UNCHECKED(Warning.UNCHECKED),
72        VARARGS(Warning.VARARGS),
73        ALL(Warning.UNCHECKED, Warning.VARARGS);
74
75        Warning[] enabledWarnings;
76
77        XlintOption(Warning... enabledWarnings) {
78            this.enabledWarnings = enabledWarnings;
79        }
80
81        String getXlintOption() {
82            StringBuilder buf = new StringBuilder();
83            String sep = "";
84            for (Warning w : enabledWarnings) {
85                buf.append(sep);
86                buf.append(w.category);
87                sep=",";
88            }
89            return "-Xlint:" +
90                    (this == NONE ? "none" : buf.toString());
91        }
92    }
93
94    enum SuppressLevel {
95        NONE(),
96        UNCHECKED(Warning.UNCHECKED),
97        VARARGS(Warning.VARARGS),
98        ALL(Warning.UNCHECKED, Warning.VARARGS);
99
100        Warning[] suppressedWarnings;
101
102        SuppressLevel(Warning... suppressedWarnings) {
103            this.suppressedWarnings = suppressedWarnings;
104        }
105
106        String getSuppressAnnotation() {
107            StringBuilder buf = new StringBuilder();
108            String sep = "";
109            for (Warning w : suppressedWarnings) {
110                buf.append(sep);
111                buf.append("\"");
112                buf.append(w.category);
113                buf.append("\"");
114                sep=",";
115            }
116            return this == NONE ? "" :
117                "@SuppressWarnings({" + buf.toString() + "})";
118        }
119    }
120
121    enum Signature {
122
123        EXTENDS_TVAR("<Z> void #name(List<? extends Z>#arity arg) { #body }",
124            new Warning[][] {both, both, both, both, error, both, both, both, error}),
125        SUPER_TVAR("<Z> void #name(List<? super Z>#arity arg) { #body }",
126            new Warning[][] {error, both, error, both, error, error, both, both, error}),
127        UNBOUND("void #name(List<?>#arity arg) { #body }",
128            new Warning[][] {none, none, none, none, none, none, none, none, error}),
129        INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }",
130            new Warning[][] {both, both, both, both, error, both, both, both, error}),
131        TVAR("<Z> void #name(Z#arity arg) { #body }",
132            new Warning[][] {both, both, both, both, both, both, both, both, vararg}),
133        EXTENDS("void #name(List<? extends String>#arity arg) { #body }",
134            new Warning[][] {error, error, error, error, error, both, error, both, error}),
135        SUPER("void #name(List<? super String>#arity arg) { #body }",
136            new Warning[][] {error, error, error, error, error, error, both, both, error}),
137        INVARIANT("void #name(List<String>#arity arg) { #body }",
138            new Warning[][] {error, error, error, error, error, error, error, both, error}),
139        UNPARAMETERIZED("void #name(String#arity arg) { #body }",
140            new Warning[][] {error, error, error, error, error, error, error, error, none});
141
142        String template;
143        Warning[][] warnings;
144
145        Signature(String template, Warning[][] warnings) {
146            this.template = template;
147            this.warnings = warnings;
148        }
149
150        boolean isApplicableTo(Signature other) {
151            return warnings[other.ordinal()] != null;
152        }
153
154        boolean giveUnchecked(Signature other) {
155            return warnings[other.ordinal()] == unchecked ||
156                    warnings[other.ordinal()] == both;
157        }
158
159        boolean giveVarargs(Signature other) {
160            return warnings[other.ordinal()] == vararg ||
161                    warnings[other.ordinal()] == both;
162        }
163    }
164
165    public static void main(String... args) throws Exception {
166        for (XlintOption xlint : XlintOption.values()) {
167            for (SuppressLevel suppressLevel : SuppressLevel.values()) {
168                for (Signature vararg_meth : Signature.values()) {
169                    for (Signature client_meth : Signature.values()) {
170                        if (vararg_meth.isApplicableTo(client_meth)) {
171                            test(xlint,
172                                    suppressLevel,
173                                    vararg_meth,
174                                    client_meth);
175                        }
176                    }
177                }
178            }
179        }
180    }
181
182    static void test(XlintOption xlint, SuppressLevel suppressLevel,
183            Signature vararg_meth, Signature client_meth) throws Exception {
184        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
185        JavaSource source = new JavaSource(suppressLevel, vararg_meth, client_meth);
186        DiagnosticChecker dc = new DiagnosticChecker();
187        JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
188                Arrays.asList(xlint.getXlintOption()), null, Arrays.asList(source));
189        ct.generate(); //to get mandatory notes
190        check(dc.warnings,
191                dc.notes,
192                new boolean[] {vararg_meth.giveUnchecked(client_meth),
193                               vararg_meth.giveVarargs(client_meth)},
194                source, xlint, suppressLevel);
195    }
196
197    static void check(Set<Warning> warnings, Set<Warning> notes, boolean[] warnArr, JavaSource source, XlintOption xlint, SuppressLevel suppressLevel) {
198        boolean badOutput = false;
199        for (Warning wkind : Warning.values()) {
200            badOutput |= (warnArr[wkind.ordinal()] && !wkind.isSuppressed(suppressLevel)) !=
201                    (wkind.isEnabled(xlint, suppressLevel) ?
202                        warnings.contains(wkind) :
203                        notes.contains(wkind));
204        }
205        if (badOutput) {
206            throw new Error("invalid diagnostics for source:\n" +
207                    source.getCharContent(true) +
208                    "\nOptions: " + xlint.getXlintOption() +
209                    "\nExpected unchecked warning: " + warnArr[0] +
210                    "\nExpected unsafe vararg warning: " + warnArr[1] +
211                    "\nWarnings: " + warnings +
212                    "\nNotes: " + notes);
213        }
214    }
215
216    static class JavaSource extends SimpleJavaFileObject {
217
218        String source;
219
220        public JavaSource(SuppressLevel suppressLevel, Signature vararg_meth, Signature client_meth) {
221            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
222            String meth1 = vararg_meth.template.replace("#arity", "...");
223            meth1 = meth1.replace("#name", "m");
224            meth1 = meth1.replace("#body", "");
225            meth1 = suppressLevel.getSuppressAnnotation() + meth1;
226            String meth2 = client_meth.template.replace("#arity", "");
227            meth2 = meth2.replace("#name", "test");
228            meth2 = meth2.replace("#body", "m(arg);");
229            source = "import java.util.List;\n" +
230               "class Test {\n" + meth1 +
231               "\n" + meth2 + "\n}\n";
232        }
233
234        @Override
235        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
236            return source;
237        }
238    }
239
240    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
241
242        Set<Warning> warnings = new HashSet<>();
243        Set<Warning> notes = new HashSet<>();
244
245        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
246            if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
247                    diagnostic.getKind() == Diagnostic.Kind.WARNING) {
248                warnings.add(diagnostic.getCode().contains("varargs") ?
249                    Warning.VARARGS :
250                    Warning.UNCHECKED);
251            }
252            else if (diagnostic.getKind() == Diagnostic.Kind.NOTE) {
253                notes.add(diagnostic.getCode().contains("varargs") ?
254                    Warning.VARARGS :
255                    Warning.UNCHECKED);
256            }
257        }
258    }
259}
260