Tue, 03 Jan 2012 11:37:00 -0800
4881269: improve diagnostic for ill-formed tokens
Reviewed-by: mcimadamore
1 /*
2 * Copyright (c) 2010, 2011, 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 */
24 /**
25 * @test
26 * @bug 7013272
27 * @summary Automatically generate info about how compiler resource keys are used
28 * @build Example ArgTypeCompilerFactory MessageFile MessageInfo
29 * @run main MessageInfo
30 */
32 import java.io.*;
33 import java.text.SimpleDateFormat;
34 import java.util.*;
36 /**
37 * Utility to manipulate compiler.properties, and suggest info comments based
38 * on information derived from running examples.
39 *
40 * Options:
41 * -examples dir location of examples directory
42 * -o file output file
43 * -check just check message file
44 * -ensureNewlines ensure newline after each entry
45 * -fixIndent fix indentation of continuation lines
46 * -sort sort messages
47 * -verbose verbose output
48 * -replace replace comments instead of merging comments
49 * file javac compiler.properties file
50 *
51 */
52 public class MessageInfo {
53 public static void main(String... args) throws Exception {
54 jtreg = (System.getProperty("test.src") != null);
55 File tmpDir;
56 if (jtreg) {
57 // use standard jtreg scratch directory: the current directory
58 tmpDir = new File(System.getProperty("user.dir"));
59 } else {
60 tmpDir = new File(System.getProperty("java.io.tmpdir"),
61 MessageInfo.class.getName()
62 + (new SimpleDateFormat("yyMMddHHmmss")).format(new Date()));
63 }
64 Example.setTempDir(tmpDir);
65 Example.Compiler.factory = new ArgTypeCompilerFactory();
67 MessageInfo mi = new MessageInfo();
69 try {
70 if (mi.run(args))
71 return;
72 } finally {
73 /* VERY IMPORTANT NOTE. In jtreg mode, tmpDir is set to the
74 * jtreg scratch directory, which is the current directory.
75 * In case someone is faking jtreg mode, make sure to only
76 * clean tmpDir when it is reasonable to do so.
77 */
78 if (tmpDir.isDirectory() &&
79 tmpDir.getName().startsWith(MessageInfo.class.getName())) {
80 if (clean(tmpDir))
81 tmpDir.delete();
82 }
83 }
85 if (jtreg)
86 throw new Exception(mi.errors + " errors occurred");
87 else
88 System.exit(1);
89 }
91 void usage() {
92 System.out.println("Usage:");
93 System.out.println(" java MessageInfo [options] [file]");
94 System.out.println("where options include");
95 System.out.println(" -examples dir location of examples directory");
96 System.out.println(" -o file output file");
97 System.out.println(" -check just check message file");
98 System.out.println(" -ensureNewlines ensure newline after each entry");
99 System.out.println(" -fixIndent fix indentation of continuation lines");
100 System.out.println(" -sort sort messages");
101 System.out.println(" -verbose verbose output");
102 System.out.println(" -replace replace comments instead of merging comments");
103 System.out.println(" file javac compiler.properties file");
104 }
106 boolean run(String... args) {
107 File testSrc = new File(System.getProperty("test.src", "."));
108 File examplesDir = new File(testSrc, "examples");
109 File notYetFile = null;
110 File msgFile = null;
111 File outFile = null;
112 boolean verbose = false;
113 boolean ensureNewlines = false;
114 boolean fixIndent = false;
115 boolean sort = false;
116 boolean replace = false;
117 boolean check = jtreg; // default true in jtreg mode
119 for (int i = 0; i < args.length; i++) {
120 String arg = args[i];
121 if (arg.equals("-examples") && (i + 1) < args.length)
122 examplesDir = new File(args[++i]);
123 else if(arg.equals("-notyet") && (i + 1) < args.length)
124 notYetFile = new File(args[++i]);
125 else if (arg.equals("-ensureNewlines"))
126 ensureNewlines = true;
127 else if (arg.equals("-fixIndent"))
128 fixIndent = true;
129 else if (arg.equals("-sort"))
130 sort = true;
131 else if (arg.equals("-verbose"))
132 verbose = true;
133 else if (arg.equals("-replace"))
134 replace = true;
135 else if (arg.equals("-check"))
136 check = true;
137 else if (arg.equals("-o") && (i + 1) < args.length)
138 outFile = new File(args[++i]);
139 else if (arg.startsWith("-")) {
140 error("unknown option: " + arg);
141 return false;
142 } else if (i == args.length - 1) {
143 msgFile = new File(arg);
144 } else {
145 error("unknown arg: " + arg);
146 return false;
147 }
148 }
150 if (!check && outFile == null) {
151 usage();
152 return true;
153 }
155 if ((ensureNewlines || fixIndent || sort) && outFile == null) {
156 error("must set output file for these options");
157 return false;
158 }
160 if (notYetFile == null) {
161 notYetFile = new File(examplesDir.getParentFile(), "examples.not-yet.txt");
162 }
164 if (msgFile == null) {
165 for (File d = testSrc; d != null; d = d.getParentFile()) {
166 if (new File(d, "TEST.ROOT").exists()) {
167 d = d.getParentFile();
168 File f = new File(d, "src/share/classes/com/sun/tools/javac/resources/compiler.properties");
169 if (f.exists()) {
170 msgFile = f;
171 break;
172 }
173 }
174 }
175 if (msgFile == null) {
176 if (jtreg) {
177 System.err.println("Warning: no message file available, test skipped");
178 return true;
179 }
180 error("no message file available");
181 return false;
182 }
183 }
185 MessageFile mf;
186 try {
187 mf = new MessageFile(msgFile);
188 } catch (IOException e) {
189 error("problem reading message file: " + e);
190 return false;
191 }
193 Map<String, Set<String>> msgInfo = runExamples(examplesDir, verbose);
195 if (ensureNewlines)
196 ensureNewlines(mf);
198 if (fixIndent)
199 fixIndent(mf);
201 if (sort)
202 sort(mf, true);
204 for (Map.Entry<String, Set<String>> e: msgInfo.entrySet()) {
205 String k = e.getKey();
206 Set<String> suggestions = e.getValue();
207 MessageFile.Message m = mf.messages.get(k);
208 if (m == null) {
209 error("Can't find message for " + k + " in message file");
210 continue;
211 }
213 MessageFile.Info info = m.getInfo();
214 Set<Integer> placeholders = m.getPlaceholders();
215 MessageFile.Info suggestedInfo = new MessageFile.Info(suggestions);
216 suggestedInfo.markUnused(placeholders);
218 if (!info.isEmpty()) {
219 if (info.contains(suggestedInfo))
220 continue;
221 if (!replace) {
222 if (info.fields.size() != suggestedInfo.fields.size())
223 error("Cannot merge info for " + k);
224 else
225 suggestedInfo.merge(info);
226 }
227 }
229 if (outFile == null) {
230 System.err.println("suggest for " + k);
231 System.err.println(suggestedInfo.toComment());
232 } else
233 m.setInfo(suggestedInfo);
234 }
236 if (check)
237 check(mf, notYetFile);
239 try {
240 if (outFile != null)
241 mf.write(outFile);
242 } catch (IOException e) {
243 error("problem writing file: " + e);
244 return false;
245 }
247 return (errors == 0);
248 }
250 void check(MessageFile mf, File notYetFile) {
251 Set<String> notYetList = null;
252 for (Map.Entry<String, MessageFile.Message> e: mf.messages.entrySet()) {
253 String key = e.getKey();
254 MessageFile.Message m = e.getValue();
255 if (m.needInfo() && m.getInfo().isEmpty()) {
256 if (notYetList == null)
257 notYetList = getNotYetList(notYetFile);
258 if (notYetList.contains(key))
259 System.err.println("Warning: no info for " + key);
260 else
261 error("no info for " + key);
262 }
263 }
265 }
267 void ensureNewlines(MessageFile mf) {
268 for (MessageFile.Message m: mf.messages.values()) {
269 MessageFile.Line l = m.firstLine;
270 while (l.text.endsWith("\\"))
271 l = l.next;
272 if (l.next != null && !l.next.text.isEmpty())
273 l.insertAfter("");
274 }
275 }
277 void fixIndent(MessageFile mf) {
278 for (MessageFile.Message m: mf.messages.values()) {
279 MessageFile.Line l = m.firstLine;
280 while (l.text.endsWith("\\") && l.next != null) {
281 if (!l.next.text.matches("^ \\S.*"))
282 l.next.text = " " + l.next.text.trim();
283 l = l.next;
284 }
285 }
286 }
288 void sort(MessageFile mf, boolean includePrecedingNewlines) {
289 for (MessageFile.Message m: mf.messages.values()) {
290 for (MessageFile.Line l: m.getLines(includePrecedingNewlines)) {
291 l.remove();
292 mf.lastLine.insertAfter(l);
293 }
294 }
295 }
297 Map<String, Set<String>> runExamples(File examplesDir, boolean verbose) {
298 Map<String, Set<String>> map = new TreeMap<String, Set<String>>();
299 for (Example e: getExamples(examplesDir)) {
300 StringWriter sw = new StringWriter();
301 PrintWriter pw = new PrintWriter(sw);
302 e.run(pw, true, verbose);
303 pw.close();
304 String[] lines = sw.toString().split("\n");
305 for (String line: lines) {
306 if (!line.startsWith("compiler."))
307 continue;
308 int colon = line.indexOf(":");
309 if (colon == -1)
310 continue;
311 String key = line.substring(0, colon);
312 StringBuilder sb = new StringBuilder();
313 sb.append("# ");
314 int i = 0;
315 String[] descs = line.substring(colon + 1).split(", *");
316 for (String desc: descs) {
317 if (i > 0) sb.append(", ");
318 sb.append(i++);
319 sb.append(": ");
320 sb.append(desc.trim());
321 }
322 Set<String> set = map.get(key);
323 if (set == null)
324 map.put(key, set = new TreeSet<String>());
325 set.add(sb.toString());
326 }
327 }
329 return map;
330 }
332 /**
333 * Get the complete set of examples to be checked.
334 */
335 Set<Example> getExamples(File examplesDir) {
336 Set<Example> results = new TreeSet<Example>();
337 for (File f: examplesDir.listFiles()) {
338 if (isValidExample(f))
339 results.add(new Example(f));
340 }
341 return results;
342 }
344 boolean isValidExample(File f) {
345 return (f.isDirectory() && (!jtreg || f.list().length > 0)) ||
346 (f.isFile() && f.getName().endsWith(".java"));
347 }
349 /**
350 * Get the contents of the "not-yet" list.
351 */
352 Set<String> getNotYetList(File file) {
353 Set<String> results = new TreeSet<String>();
354 try {
355 String[] lines = read(file).split("[\r\n]");
356 for (String line: lines) {
357 int hash = line.indexOf("#");
358 if (hash != -1)
359 line = line.substring(0, hash).trim();
360 if (line.matches("[A-Za-z0-9-_.]+"))
361 results.add(line);
362 }
363 } catch (IOException e) {
364 throw new Error(e);
365 }
366 return results;
367 }
369 /**
370 * Read the contents of a file.
371 */
372 String read(File f) throws IOException {
373 byte[] bytes = new byte[(int) f.length()];
374 DataInputStream in = new DataInputStream(new FileInputStream(f));
375 try {
376 in.readFully(bytes);
377 } finally {
378 in.close();
379 }
380 return new String(bytes);
381 }
383 /**
384 * Report an error.
385 */
386 void error(String msg) {
387 System.err.println("Error: " + msg);
388 errors++;
389 }
391 static boolean jtreg;
393 int errors;
395 /**
396 * Clean the contents of a directory.
397 */
398 static boolean clean(File dir) {
399 boolean ok = true;
400 for (File f: dir.listFiles()) {
401 if (f.isDirectory())
402 ok &= clean(f);
403 ok &= f.delete();
404 }
405 return ok;
406 }
408 }