1/* 2 * Copyright (c) 2010, 2015, 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 6403465 27 * @summary javac should defer diagnostics until it can be determined they are persistent 28 * @modules jdk.compiler/com.sun.tools.javac.api 29 * jdk.compiler/com.sun.tools.javac.file 30 * jdk.compiler/com.sun.tools.javac.util 31 */ 32 33import java.io.*; 34import java.util.*; 35import javax.annotation.processing.*; 36import javax.lang.model.*; 37import javax.lang.model.element.TypeElement; 38import javax.tools.*; 39 40import com.sun.source.util.JavacTask; 41import com.sun.tools.javac.api.ClientCodeWrapper; 42import com.sun.tools.javac.api.JavacTool; 43import com.sun.tools.javac.util.JCDiagnostic; 44 45import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; 46 47 48public class TestSuppression { 49 public static void main(String... args) throws Exception { 50 new TestSuppression().run(args); 51 } 52 53 enum WarningKind { NO, YES }; 54 55 String[] cases = { 56 // missing class C 57 "class X { C c; }", 58 "class X { C foo() { return null; } }", 59 "class X { void foo(C c) { } }", 60 "class X extends C { }", 61 "class X<T extends C> { }", 62 // missing interface I 63 "class X implements I { }", 64 "interface X extends I { }", 65 // missing exception E 66 "class X { void m() throws E { } }", 67 // missing method m 68 "class X extends C { int i = m(); }", 69 // missing field f 70 "class X extends C { int i = f; }" 71 }; 72 73 void run(String... args) throws Exception { 74 for (String c: cases) { 75 for (WarningKind wk: WarningKind.values()) { 76 for (int g = 1; g <= 3; g++) { 77 try { 78 test(c, wk, g); 79 } catch (Throwable t) { 80 error("caught: " + t); 81 } 82 if (errors > 0) throw new AssertionError(); 83 } 84 } 85 } 86 87 System.err.println(count + " test cases"); 88 89 if (errors > 0) 90 throw new Exception(errors + " errors occurred"); 91 } 92 93 void test(String src, WarningKind wk, int gen) throws Exception { 94 count++; 95 System.err.println("Test " + count + ": wk:" + wk + " gen:" + gen + " src:" +src); 96 97 File testDir = new File("test" + count); 98 File srcDir = createDir(testDir, "src"); 99 File gensrcDir = createDir(testDir, "gensrc"); 100 File classesDir = createDir(testDir, "classes"); 101 102 File x = writeFile(new File(srcDir, "X.java"), src); 103 104 DiagListener dl = new DiagListener(); 105 JavacTool tool = JavacTool.create(); 106 try (StandardJavaFileManager fm = tool.getStandardFileManager(dl, null, null)) { 107 fm.setLocation(StandardLocation.CLASS_PATH, 108 Arrays.asList(classesDir, new File(System.getProperty("test.classes")))); 109 fm.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(classesDir)); 110 fm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(gensrcDir)); 111 List<String> args = new ArrayList<String>(); 112 // args.add("-XprintProcessorInfo"); 113 args.add("-XprintRounds"); 114 args.add("-Agen=" + gen); 115 if (wk == WarningKind.YES) 116 args.add("-Xlint:serial"); 117 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(x); 118 119 StringWriter sw = new StringWriter(); 120 PrintWriter pw = new PrintWriter(sw); 121 JavacTask task = tool.getTask(pw, fm, dl, args, null, files); 122 task.setProcessors(Arrays.asList(new AnnoProc())); 123 boolean ok = task.call(); 124 pw.close(); 125 126 System.err.println("ok:" + ok + " diags:" + dl.counts); 127 if (sw.toString().length() > 0) { 128 System.err.println("output:\n" + sw.toString()); 129 } 130 131 for (Diagnostic.Kind dk: Diagnostic.Kind.values()) { 132 Integer v = dl.counts.get(dk); 133 int found = (v == null) ? 0 : v; 134 int expect = (dk == Diagnostic.Kind.WARNING && wk == WarningKind.YES) ? gen : 0; 135 if (found != expect) { 136 error("Unexpected value for " + dk + ": expected: " + expect + " found: " + found); 137 } 138 } 139 140 System.err.println(); 141 } 142 } 143 144 File createDir(File parent, String name) { 145 File dir = new File(parent, name); 146 dir.mkdirs(); 147 return dir; 148 } 149 150 File writeFile(File f, String content) throws IOException { 151 FileWriter out = new FileWriter(f); 152 try { 153 out.write(content); 154 } finally { 155 out.close(); 156 } 157 return f; 158 } 159 160 <T> void add(List<T> list, T... values) { 161 for (T v: values) 162 list.add(v); 163 } 164 165 void error(String msg) { 166 System.err.println("Error: " + msg); 167 errors++; 168 } 169 170 int count; 171 int errors; 172 173 static class DiagListener implements DiagnosticListener<JavaFileObject> { 174 int total; 175 Map<Diagnostic.Kind,Integer> counts = new TreeMap<Diagnostic.Kind,Integer>(); 176 177 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 178 System.err.println((++total) + ": " 179 + "resolveError:" + isResolveError(unwrap(diagnostic)) + "\n" 180 + diagnostic); 181 Diagnostic.Kind dk = diagnostic.getKind(); 182 Integer c = counts.get(dk); 183 counts.put(dk, (c == null ? 1 : c + 1)); 184 } 185 186 private static boolean isResolveError(JCDiagnostic d) { 187 return d.isFlagSet(RESOLVE_ERROR); 188 } 189 190 private JCDiagnostic unwrap(Diagnostic<? extends JavaFileObject> diagnostic) { 191 if (diagnostic instanceof JCDiagnostic) 192 return (JCDiagnostic) diagnostic; 193 if (diagnostic instanceof ClientCodeWrapper.DiagnosticSourceUnwrapper) 194 return ((ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic).d; 195 throw new IllegalArgumentException(); 196 } 197 } 198 199 @SupportedAnnotationTypes("*") 200 @SupportedOptions("gen") 201 public static class AnnoProc extends AbstractProcessor { 202 Filer f; 203 Messager m; 204 int gen; 205 206 @Override 207 public void init(ProcessingEnvironment processingEnv) { 208 f = processingEnv.getFiler(); 209 m = processingEnv.getMessager(); 210 Map<String,String> options = processingEnv.getOptions(); 211 gen = Integer.parseInt(options.get("gen")); 212 } 213 214 @Override 215 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 216 round++; 217 if (round < gen) 218 writeSource("Dummy" + round, "class Dummy" + round + " extends java.util.ArrayList{ }"); 219 else if (round == gen) { 220 writeSource("C", "class C { int f; int m() { return 0; } }"); 221 writeSource("I", "interface I { }"); 222 writeSource("E", "class E extends Exception { }"); 223 } 224 return true; 225 } 226 227 @Override 228 public SourceVersion getSupportedSourceVersion() { 229 return SourceVersion.latest(); 230 } 231 232 private void writeSource(String name, String text) { 233 try { 234 JavaFileObject fo = f.createSourceFile(name); 235 Writer out = fo.openWriter(); 236 out.write(text); 237 out.close(); 238 } catch (IOException e) { 239 m.printMessage(Diagnostic.Kind.ERROR, e.toString()); 240 } 241 } 242 243 int round = 0; 244 } 245} 246