Tue, 31 Mar 2009 11:16:15 -0700
6813059: replace use of JavaCompiler.errorCount with shouldContinue
Reviewed-by: mcimadamore
1.1 --- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Mar 31 11:07:55 2009 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Mar 31 11:16:15 2009 -0700 1.3 @@ -386,6 +386,11 @@ 1.4 (options.get("failcomplete") != null) 1.5 ? names.fromString(options.get("failcomplete")) 1.6 : null; 1.7 + 1.8 + shouldStopPolicy = 1.9 + (options.get("shouldStopPolicy") != null) 1.10 + ? CompileState.valueOf(options.get("shouldStopPolicy")) 1.11 + : null; 1.12 } 1.13 1.14 /* Switches: 1.15 @@ -459,14 +464,26 @@ 1.16 */ 1.17 public boolean verboseCompilePolicy; 1.18 1.19 + /** 1.20 + * Policy of how far to continue processing. null means until first 1.21 + * error. 1.22 + */ 1.23 + public CompileState shouldStopPolicy; 1.24 + 1.25 /** A queue of all as yet unattributed classes. 1.26 */ 1.27 public Todo todo; 1.28 1.29 + /** Ordered list of compiler phases for each compilation unit. */ 1.30 protected enum CompileState { 1.31 - TODO(0), 1.32 - ATTR(1), 1.33 - FLOW(2); 1.34 + PARSE(1), 1.35 + ENTER(2), 1.36 + PROCESS(3), 1.37 + ATTR(4), 1.38 + FLOW(5), 1.39 + TRANSTYPES(6), 1.40 + LOWER(7), 1.41 + GENERATE(8); 1.42 CompileState(int value) { 1.43 this.value = value; 1.44 } 1.45 @@ -475,6 +492,9 @@ 1.46 } 1.47 private int value; 1.48 }; 1.49 + /** Partial map to record which compiler phases have been executed 1.50 + * for each compilation unit. Used for ATTR and FLOW phases. 1.51 + */ 1.52 protected class CompileStates extends HashMap<Env<AttrContext>,CompileState> { 1.53 private static final long serialVersionUID = 1812267524140424433L; 1.54 boolean isDone(Env<AttrContext> env, CompileState cs) { 1.55 @@ -490,6 +510,13 @@ 1.56 */ 1.57 protected Set<JavaFileObject> inputFiles = new HashSet<JavaFileObject>(); 1.58 1.59 + protected boolean shouldStop(CompileState cs) { 1.60 + if (shouldStopPolicy == null) 1.61 + return (errorCount() > 0); 1.62 + else 1.63 + return cs.ordinal() > shouldStopPolicy.ordinal(); 1.64 + } 1.65 + 1.66 /** The number of errors reported so far. 1.67 */ 1.68 public int errorCount() { 1.69 @@ -503,18 +530,12 @@ 1.70 return log.nerrors; 1.71 } 1.72 1.73 - protected final <T> Queue<T> stopIfError(Queue<T> queue) { 1.74 - if (errorCount() == 0) 1.75 - return queue; 1.76 - else 1.77 - return ListBuffer.lb(); 1.78 + protected final <T> Queue<T> stopIfError(CompileState cs, Queue<T> queue) { 1.79 + return shouldStop(cs) ? ListBuffer.<T>lb() : queue; 1.80 } 1.81 1.82 - protected final <T> List<T> stopIfError(List<T> list) { 1.83 - if (errorCount() == 0) 1.84 - return list; 1.85 - else 1.86 - return List.nil(); 1.87 + protected final <T> List<T> stopIfError(CompileState cs, List<T> list) { 1.88 + return shouldStop(cs) ? List.<T>nil() : list; 1.89 } 1.90 1.91 /** The number of warnings reported so far. 1.92 @@ -669,7 +690,7 @@ 1.93 */ 1.94 JavaFileObject genCode(Env<AttrContext> env, JCClassDecl cdef) throws IOException { 1.95 try { 1.96 - if (gen.genClass(env, cdef)) 1.97 + if (gen.genClass(env, cdef) && (errorCount() == 0)) 1.98 return writer.writeClass(cdef.sym); 1.99 } catch (ClassWriter.PoolOverflow ex) { 1.100 log.error(cdef.pos(), "limit.pool"); 1.101 @@ -779,8 +800,10 @@ 1.102 initProcessAnnotations(processors); 1.103 1.104 // These method calls must be chained to avoid memory leaks 1.105 - delegateCompiler = processAnnotations(enterTrees(stopIfError(parseFiles(sourceFileObjects))), 1.106 - classnames); 1.107 + delegateCompiler = 1.108 + processAnnotations( 1.109 + enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))), 1.110 + classnames); 1.111 1.112 delegateCompiler.compile2(); 1.113 delegateCompiler.close(); 1.114 @@ -812,7 +835,7 @@ 1.115 1.116 case BY_FILE: { 1.117 Queue<Queue<Env<AttrContext>>> q = todo.groupByFile(); 1.118 - while (!q.isEmpty() && errorCount() == 0) { 1.119 + while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) { 1.120 generate(desugar(flow(attribute(q.remove())))); 1.121 } 1.122 } 1.123 @@ -850,7 +873,7 @@ 1.124 * Parses a list of files. 1.125 */ 1.126 public List<JCCompilationUnit> parseFiles(List<JavaFileObject> fileObjects) throws IOException { 1.127 - if (errorCount() > 0) 1.128 + if (shouldStop(CompileState.PARSE)) 1.129 return List.nil(); 1.130 1.131 //parse all files 1.132 @@ -961,7 +984,7 @@ 1.133 public JavaCompiler processAnnotations(List<JCCompilationUnit> roots, 1.134 List<String> classnames) 1.135 throws IOException { // TODO: see TEMP note in JavacProcessingEnvironment 1.136 - if (errorCount() != 0) { 1.137 + if (shouldStop(CompileState.PROCESS)) { 1.138 // Errors were encountered. If todo is empty, then the 1.139 // encountered errors were parse errors. Otherwise, the 1.140 // errors were found during the enter phase which should 1.141 @@ -1068,7 +1091,7 @@ 1.142 ListBuffer<Env<AttrContext>> results = lb(); 1.143 while (!envs.isEmpty()) 1.144 results.append(attribute(envs.remove())); 1.145 - return results; 1.146 + return stopIfError(CompileState.ATTR, results); 1.147 } 1.148 1.149 /** 1.150 @@ -1115,7 +1138,7 @@ 1.151 for (Env<AttrContext> env: envs) { 1.152 flow(env, results); 1.153 } 1.154 - return stopIfError(results); 1.155 + return stopIfError(CompileState.FLOW, results); 1.156 } 1.157 1.158 /** 1.159 @@ -1124,7 +1147,7 @@ 1.160 public Queue<Env<AttrContext>> flow(Env<AttrContext> env) { 1.161 ListBuffer<Env<AttrContext>> results = lb(); 1.162 flow(env, results); 1.163 - return stopIfError(results); 1.164 + return stopIfError(CompileState.FLOW, results); 1.165 } 1.166 1.167 /** 1.168 @@ -1132,7 +1155,7 @@ 1.169 */ 1.170 protected void flow(Env<AttrContext> env, Queue<Env<AttrContext>> results) { 1.171 try { 1.172 - if (errorCount() > 0) 1.173 + if (shouldStop(CompileState.FLOW)) 1.174 return; 1.175 1.176 if (relax || compileStates.isDone(env, CompileState.FLOW)) { 1.177 @@ -1141,7 +1164,7 @@ 1.178 } 1.179 1.180 if (verboseCompilePolicy) 1.181 - log.printLines(log.noticeWriter, "[flow " + env.enclClass.sym + "]"); 1.182 + printNote("[flow " + env.enclClass.sym + "]"); 1.183 JavaFileObject prev = log.useSource( 1.184 env.enclClass.sym.sourcefile != null ? 1.185 env.enclClass.sym.sourcefile : 1.186 @@ -1152,7 +1175,7 @@ 1.187 flow.analyzeTree(env.tree, localMake); 1.188 compileStates.put(env, CompileState.FLOW); 1.189 1.190 - if (errorCount() > 0) 1.191 + if (shouldStop(CompileState.FLOW)) 1.192 return; 1.193 1.194 results.add(env); 1.195 @@ -1179,7 +1202,7 @@ 1.196 ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = lb(); 1.197 for (Env<AttrContext> env: envs) 1.198 desugar(env, results); 1.199 - return stopIfError(results); 1.200 + return stopIfError(CompileState.FLOW, results); 1.201 } 1.202 1.203 /** 1.204 @@ -1189,7 +1212,7 @@ 1.205 * The preparation stops as soon as an error is found. 1.206 */ 1.207 protected void desugar(final Env<AttrContext> env, Queue<Pair<Env<AttrContext>, JCClassDecl>> results) { 1.208 - if (errorCount() > 0) 1.209 + if (shouldStop(CompileState.TRANSTYPES)) 1.210 return; 1.211 1.212 if (implicitSourcePolicy == ImplicitSourcePolicy.NONE 1.213 @@ -1204,6 +1227,7 @@ 1.214 */ 1.215 class ScanNested extends TreeScanner { 1.216 Set<Env<AttrContext>> dependencies = new LinkedHashSet<Env<AttrContext>>(); 1.217 + @Override 1.218 public void visitClassDef(JCClassDecl node) { 1.219 Type st = types.supertype(node.sym.type); 1.220 if (st.tag == TypeTags.CLASS) { 1.221 @@ -1226,11 +1250,11 @@ 1.222 1.223 //We need to check for error another time as more classes might 1.224 //have been attributed and analyzed at this stage 1.225 - if (errorCount() > 0) 1.226 + if (shouldStop(CompileState.TRANSTYPES)) 1.227 return; 1.228 1.229 if (verboseCompilePolicy) 1.230 - log.printLines(log.noticeWriter, "[desugar " + env.enclClass.sym + "]"); 1.231 + printNote("[desugar " + env.enclClass.sym + "]"); 1.232 1.233 JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ? 1.234 env.enclClass.sym.sourcefile : 1.235 @@ -1244,6 +1268,8 @@ 1.236 1.237 if (env.tree instanceof JCCompilationUnit) { 1.238 if (!(stubOutput || sourceOutput || printFlat)) { 1.239 + if (shouldStop(CompileState.LOWER)) 1.240 + return; 1.241 List<JCTree> pdef = lower.translateTopLevelClass(env, env.tree, localMake); 1.242 if (pdef.head != null) { 1.243 assert pdef.tail.isEmpty(); 1.244 @@ -1266,9 +1292,12 @@ 1.245 return; 1.246 } 1.247 1.248 + if (shouldStop(CompileState.TRANSTYPES)) 1.249 + return; 1.250 + 1.251 env.tree = transTypes.translateTopLevelClass(env.tree, localMake); 1.252 1.253 - if (errorCount() != 0) 1.254 + if (shouldStop(CompileState.LOWER)) 1.255 return; 1.256 1.257 if (sourceOutput) { 1.258 @@ -1285,7 +1314,7 @@ 1.259 //translate out inner classes 1.260 List<JCTree> cdefs = lower.translateTopLevelClass(env, env.tree, localMake); 1.261 1.262 - if (errorCount() != 0) 1.263 + if (shouldStop(CompileState.LOWER)) 1.264 return; 1.265 1.266 //generate code for each class 1.267 @@ -1310,6 +1339,9 @@ 1.268 } 1.269 1.270 public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) { 1.271 + if (shouldStop(CompileState.GENERATE)) 1.272 + return; 1.273 + 1.274 boolean usePrintSource = (stubOutput || sourceOutput || printFlat); 1.275 1.276 for (Pair<Env<AttrContext>, JCClassDecl> x: queue) { 1.277 @@ -1317,7 +1349,7 @@ 1.278 JCClassDecl cdef = x.snd; 1.279 1.280 if (verboseCompilePolicy) { 1.281 - log.printLines(log.noticeWriter, "[generate " 1.282 + printNote("[generate " 1.283 + (usePrintSource ? " source" : "code") 1.284 + " " + cdef.sym + "]"); 1.285 } 1.286 @@ -1371,6 +1403,7 @@ 1.287 JCClassDecl removeMethodBodies(JCClassDecl cdef) { 1.288 final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0; 1.289 class MethodBodyRemover extends TreeTranslator { 1.290 + @Override 1.291 public void visitMethodDef(JCMethodDecl tree) { 1.292 tree.mods.flags &= ~Flags.SYNCHRONIZED; 1.293 for (JCVariableDecl vd : tree.params) 1.294 @@ -1378,11 +1411,13 @@ 1.295 tree.body = null; 1.296 super.visitMethodDef(tree); 1.297 } 1.298 + @Override 1.299 public void visitVarDef(JCVariableDecl tree) { 1.300 if (tree.init != null && tree.init.type.constValue() == null) 1.301 tree.init = null; 1.302 super.visitVarDef(tree); 1.303 } 1.304 + @Override 1.305 public void visitClassDef(JCClassDecl tree) { 1.306 ListBuffer<JCTree> newdefs = lb(); 1.307 for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) { 1.308 @@ -1469,12 +1504,16 @@ 1.309 } 1.310 } 1.311 1.312 + protected void printNote(String lines) { 1.313 + Log.printLines(log.noticeWriter, lines); 1.314 + } 1.315 + 1.316 /** Output for "-verbose" option. 1.317 * @param key The key to look up the correct internationalized string. 1.318 * @param arg An argument for substitution into the output string. 1.319 */ 1.320 protected void printVerbose(String key, Object arg) { 1.321 - Log.printLines(log.noticeWriter, log.getLocalizedString("verbose." + key, arg)); 1.322 + Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg)); 1.323 } 1.324 1.325 /** Print numbers of errors and warnings. 1.326 @@ -1483,9 +1522,9 @@ 1.327 if (count != 0) { 1.328 String text; 1.329 if (count == 1) 1.330 - text = log.getLocalizedString("count." + kind, String.valueOf(count)); 1.331 + text = Log.getLocalizedString("count." + kind, String.valueOf(count)); 1.332 else 1.333 - text = log.getLocalizedString("count." + kind + ".plural", String.valueOf(count)); 1.334 + text = Log.getLocalizedString("count." + kind + ".plural", String.valueOf(count)); 1.335 Log.printLines(log.errWriter, text); 1.336 log.errWriter.flush(); 1.337 }
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/tools/javac/policy/test3/A.java Tue Mar 31 11:16:15 2009 -0700 2.3 @@ -0,0 +1,10 @@ 2.4 +class A { 2.5 + void m1() { 2.6 + System.err.println("hello"); 2.7 + 0 // syntax error 2.8 + System.err.println("world"); 2.9 + } 2.10 + 2.11 + void m2() { 2.12 + } 2.13 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/tools/javac/policy/test3/Test.java Tue Mar 31 11:16:15 2009 -0700 3.3 @@ -0,0 +1,169 @@ 3.4 +/* 3.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 3.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 3.24 + * have any questions. 3.25 + */ 3.26 + 3.27 + 3.28 +/* @test 3.29 + * @bug 6813059 3.30 + * @summary 3.31 + */ 3.32 + 3.33 +import java.io.*; 3.34 +import java.util.*; 3.35 + 3.36 +// Simple test of -XDshouldStopPolicy. 3.37 +// For each of the permissable values, we compile a file with an error in it, 3.38 +// then using -XDverboseCompilePolicy we check that the compilation gets as 3.39 +// far as expected, but no further. 3.40 + 3.41 +public class Test { 3.42 + enum ShouldStopPolicy { 3.43 + BLANK(false, null, "attr"), 3.44 + PROCESS(true, null, "attr"), 3.45 + ATTR(true, "attr", "flow"), 3.46 + FLOW(true, "flow", "desugar"), 3.47 + TRANSTYPES(true, "desugar", "generate"), 3.48 + LOWER(true, "desugar", "generate"), 3.49 + GENERATE(true, "generate", null); 3.50 + ShouldStopPolicy(boolean needOption, String expect, String dontExpect) { 3.51 + this.needOption = needOption; 3.52 + this.expect = expect; 3.53 + this.dontExpect = dontExpect; 3.54 + } 3.55 + boolean needOption; 3.56 + String expect; 3.57 + String dontExpect; 3.58 + } 3.59 + 3.60 + enum CompilePolicy { 3.61 + BYFILE, 3.62 + BYTODO 3.63 + } 3.64 + 3.65 + public static void main(String... args) throws Exception { 3.66 + new Test().run(); 3.67 + } 3.68 + 3.69 + public void run() throws Exception { 3.70 + for (CompilePolicy cp: CompilePolicy.values()) { 3.71 + for (ShouldStopPolicy ssp: ShouldStopPolicy.values()) { 3.72 + test(cp, ssp); 3.73 + } 3.74 + } 3.75 + 3.76 + if (errors > 0) 3.77 + throw new Exception(errors + " errors occurred"); 3.78 + } 3.79 + 3.80 + public void test(CompilePolicy cp, ShouldStopPolicy ssp) { 3.81 + System.err.println(); 3.82 + System.err.println("test " + cp + " " + ssp); 3.83 + List<String> args = new ArrayList<String>(); 3.84 + args.add("-XDverboseCompilePolicy"); 3.85 + args.add("-XDcompilePolicy=" + cp.toString().toLowerCase()); 3.86 + args.add("-d"); 3.87 + args.add("."); 3.88 + if (ssp.needOption) 3.89 + args.add("-XDshouldStopPolicy=" + ssp); 3.90 + args.add(new File(System.getProperty("test.src", "."), "A.java").getPath()); 3.91 + 3.92 + StringWriter sw = new StringWriter(); 3.93 + PrintWriter pw = new PrintWriter(sw); 3.94 + System.err.println("compile " + args); 3.95 + int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw); 3.96 + if (rc == 0) 3.97 + throw new Error("compilation succeeded unexpectedly"); 3.98 + //System.err.println(sw); 3.99 + 3.100 + // The following is a workaround for the current javac implementation, 3.101 + // that in bytodo mode, it will still attribute files after syntax errors. 3.102 + // Changing that behavior may surprise existing users, so for now, we 3.103 + // work around it. 3.104 + if (cp == CompilePolicy.BYTODO && ssp == ShouldStopPolicy.PROCESS) 3.105 + ssp = ShouldStopPolicy.ATTR; 3.106 + 3.107 + boolean foundExpected = (ssp.expect == null); 3.108 + String[] lines = sw.toString().split("\n"); 3.109 + for (String line: lines) { 3.110 + if (ssp.expect != null && line.startsWith("[" + ssp.expect)) 3.111 + foundExpected = true; 3.112 + if (ssp.dontExpect != null && line.startsWith("[" + ssp.dontExpect)) { 3.113 + error("Unexpected output: " + ssp.dontExpect + "\n" + sw); 3.114 + return; 3.115 + } 3.116 + } 3.117 + 3.118 + if (!foundExpected) 3.119 + error("Expected output not found: " + ssp.expect + "\n" + sw); 3.120 + } 3.121 + 3.122 + void error(String message) { 3.123 + System.err.println(message); 3.124 + errors++; 3.125 + } 3.126 + 3.127 + int errors; 3.128 +} 3.129 + 3.130 + 3.131 + 3.132 + 3.133 + 3.134 + 3.135 + 3.136 + 3.137 + 3.138 + 3.139 + 3.140 + 3.141 +// These tests test the ability of the compiler to continue in the face of 3.142 +// errors, accordining to the shouldStopPolicy 3.143 + 3.144 +/* @ test /nodynamiccopyright/ 3.145 + * @bug 6813059 3.146 + * @summary 3.147 + * @compile/fail/ref=flow.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=FLOW Test.java 3.148 + 3.149 + * @compile/fail/ref=default.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy Test.java 3.150 + * @compile/fail/ref=enter.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=ENTER Test.java 3.151 + * @compile/fail/ref=attr.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=ATTR Test.java 3.152 + * @compile/fail/ref=transtypes.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=TRANSTYPES Test.java 3.153 + * @compile/fail/ref=lower.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=LOWER Test.java 3.154 + * @compile/fail/ref=generate.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=GENERATE Test.java 3.155 + */ 3.156 + 3.157 +/* 3.158 +class Test { 3.159 + void m1() { 3.160 + System.err.println("hello"); 3.161 + 0 // syntax error 3.162 + System.err.println("world"); 3.163 + } 3.164 + 3.165 + void m2() { 3.166 + } 3.167 +} 3.168 + 3.169 +class Test2 { 3.170 +} 3.171 +*/ 3.172 +