1 /* |
1 /* |
2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. |
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. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
78 import com.sun.tools.javac.tree.JCTree.JCNewClass; |
78 import com.sun.tools.javac.tree.JCTree.JCNewClass; |
79 import com.sun.tools.javac.tree.JCTree.JCVariableDecl; |
79 import com.sun.tools.javac.tree.JCTree.JCVariableDecl; |
80 import com.sun.tools.javac.tree.TreeInfo; |
80 import com.sun.tools.javac.tree.TreeInfo; |
81 import com.sun.tools.javac.tree.TreeScanner; |
81 import com.sun.tools.javac.tree.TreeScanner; |
82 |
82 |
|
83 import static com.sun.tools.javac.tree.JCTree.Tag.*; |
83 import static com.sun.tools.javac.util.Position.NOPOS; |
84 import static com.sun.tools.javac.util.Position.NOPOS; |
84 |
85 |
85 /** |
86 /** |
86 * Utility and test program to check validity of tree positions for tree nodes. |
87 * Utility and test program to check validity of tree positions for tree nodes. |
87 * The program can be run standalone, or as a jtreg test. In standalone mode, |
88 * The program can be run standalone, or as a jtreg test. In standalone mode, |
289 void error(String msg) { |
290 void error(String msg) { |
290 System.err.println(msg); |
291 System.err.println(msg); |
291 errors++; |
292 errors++; |
292 } |
293 } |
293 |
294 |
|
295 /** |
|
296 * Names for tree tags. |
|
297 */ |
|
298 private static String getTagName(JCTree.Tag tag) { |
|
299 String name = tag.name(); |
|
300 return (name == null) ? "??" : name; |
|
301 } |
|
302 |
294 /** Number of files that have been analyzed. */ |
303 /** Number of files that have been analyzed. */ |
295 int fileCount; |
304 int fileCount; |
296 /** Number of errors reported. */ |
305 /** Number of errors reported. */ |
297 int errors; |
306 int errors; |
298 /** Flag: don't report irrelevant files. */ |
307 /** Flag: don't report irrelevant files. */ |
310 Set<String> tags = new HashSet<String>(); |
319 Set<String> tags = new HashSet<String>(); |
311 /** Set of files and directories to be excluded from analysis. */ |
320 /** Set of files and directories to be excluded from analysis. */ |
312 Set<File> excludeFiles = new HashSet<File>(); |
321 Set<File> excludeFiles = new HashSet<File>(); |
313 /** Set of tag names to be excluded from analysis. */ |
322 /** Set of tag names to be excluded from analysis. */ |
314 Set<String> excludeTags = new HashSet<String>(); |
323 Set<String> excludeTags = new HashSet<String>(); |
315 /** Table of printable names for tree tag values. */ |
|
316 TagNames tagNames = new TagNames(); |
|
317 |
324 |
318 /** |
325 /** |
319 * Main class for testing assertions concerning tree positions for tree nodes. |
326 * Main class for testing assertions concerning tree positions for tree nodes. |
320 */ |
327 */ |
321 private class PosTester extends TreeScanner { |
328 private class PosTester extends TreeScanner { |
335 if (check(encl, self)) { |
342 if (check(encl, self)) { |
336 // Modifiers nodes are present throughout the tree even where |
343 // Modifiers nodes are present throughout the tree even where |
337 // there is no corresponding source text. |
344 // there is no corresponding source text. |
338 // Redundant semicolons in a class definition can cause empty |
345 // Redundant semicolons in a class definition can cause empty |
339 // initializer blocks with no positions. |
346 // initializer blocks with no positions. |
340 if ((self.tag == JCTree.MODIFIERS || self.tag == JCTree.BLOCK) |
347 if ((self.tag == MODIFIERS || self.tag == BLOCK) |
341 && self.pos == NOPOS) { |
348 && self.pos == NOPOS) { |
342 // If pos is NOPOS, so should be the start and end positions |
349 // If pos is NOPOS, so should be the start and end positions |
343 check("start == NOPOS", encl, self, self.start == NOPOS); |
350 check("start == NOPOS", encl, self, self.start == NOPOS); |
344 check("end == NOPOS", encl, self, self.end == NOPOS); |
351 check("end == NOPOS", encl, self, self.end == NOPOS); |
345 } else { |
352 } else { |
357 // and because of inconsistent nesting of left and right of |
364 // and because of inconsistent nesting of left and right of |
358 // array declarations: |
365 // array declarations: |
359 // e.g. int[][] a = new int[2][]; |
366 // e.g. int[][] a = new int[2][]; |
360 check("encl.start <= start", encl, self, encl.start <= self.start); |
367 check("encl.start <= start", encl, self, encl.start <= self.start); |
361 check("start <= pos", encl, self, self.start <= self.pos); |
368 check("start <= pos", encl, self, self.start <= self.pos); |
362 if (!(self.tag == JCTree.TYPEARRAY |
369 if (!(self.tag == TYPEARRAY |
363 && (encl.tag == JCTree.VARDEF || |
370 && (encl.tag == VARDEF || |
364 encl.tag == JCTree.METHODDEF || |
371 encl.tag == METHODDEF || |
365 encl.tag == JCTree.TYPEARRAY))) { |
372 encl.tag == TYPEARRAY))) { |
366 check("encl.pos <= start || end <= encl.pos", |
373 check("encl.pos <= start || end <= encl.pos", |
367 encl, self, encl.pos <= self.start || self.end <= encl.pos); |
374 encl, self, encl.pos <= self.start || self.end <= encl.pos); |
368 } |
375 } |
369 check("pos <= end", encl, self, self.pos <= self.end); |
376 check("pos <= end", encl, self, self.pos <= self.end); |
370 if (!(self.tag == JCTree.TYPEARRAY && encl.tag == JCTree.TYPEARRAY)) { |
377 if (!(self.tag == TYPEARRAY && encl.tag == TYPEARRAY)) { |
371 check("end <= encl.end", encl, self, self.end <= encl.end); |
378 check("end <= encl.end", encl, self, self.end <= encl.end); |
372 } |
379 } |
373 } |
380 } |
374 } |
381 } |
375 |
382 |
386 // skip the synthesized bits and just check parts which came from |
393 // skip the synthesized bits and just check parts which came from |
387 // the original source text |
394 // the original source text |
388 if ((tree.mods.flags & Flags.ENUM) != 0) { |
395 if ((tree.mods.flags & Flags.ENUM) != 0) { |
389 scan(tree.mods); |
396 scan(tree.mods); |
390 if (tree.init != null) { |
397 if (tree.init != null) { |
391 if (tree.init.getTag() == JCTree.NEWCLASS) { |
398 if (tree.init.hasTag(NEWCLASS)) { |
392 JCNewClass init = (JCNewClass) tree.init; |
399 JCNewClass init = (JCNewClass) tree.init; |
393 if (init.args != null && init.args.nonEmpty()) { |
400 if (init.args != null && init.args.nonEmpty()) { |
394 scan(init.args); |
401 scan(init.args); |
395 } |
402 } |
396 if (init.def != null && init.def.defs != null) { |
403 if (init.def != null && init.def.defs != null) { |
402 super.visitVarDef(tree); |
409 super.visitVarDef(tree); |
403 } |
410 } |
404 |
411 |
405 boolean check(Info encl, Info self) { |
412 boolean check(Info encl, Info self) { |
406 if (excludeTags.size() > 0) { |
413 if (excludeTags.size() > 0) { |
407 if (encl != null && excludeTags.contains(tagNames.get(encl.tag)) |
414 if (encl != null && excludeTags.contains(getTagName(encl.tag)) |
408 || excludeTags.contains(tagNames.get(self.tag))) |
415 || excludeTags.contains(getTagName(self.tag))) |
409 return false; |
416 return false; |
410 } |
417 } |
411 return tags.size() == 0 || tags.contains(tagNames.get(self.tag)); |
418 return tags.size() == 0 || tags.contains(getTagName(self.tag)); |
412 } |
419 } |
413 |
420 |
414 void check(String label, Info encl, Info self, boolean ok) { |
421 void check(String label, Info encl, Info self, boolean ok) { |
415 if (!ok) { |
422 if (!ok) { |
416 if (gui) { |
423 if (gui) { |
453 end = TreeInfo.getEndPos(tree, endPosTable); |
460 end = TreeInfo.getEndPos(tree, endPosTable); |
454 } |
461 } |
455 |
462 |
456 @Override |
463 @Override |
457 public String toString() { |
464 public String toString() { |
458 return tagNames.get(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]"; |
465 return getTagName(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]"; |
459 } |
466 } |
460 |
467 |
461 final JCTree tree; |
468 final JCTree tree; |
462 final int tag; |
469 final JCTree.Tag tag; |
463 final int start; |
470 final int start; |
464 final int pos; |
471 final int pos; |
465 final int end; |
472 final int end; |
466 } |
|
467 |
|
468 /** |
|
469 * Names for tree tags. |
|
470 * javac does not provide an API to convert tag values to strings, so this class uses |
|
471 * reflection to determine names of public static final int values in JCTree. |
|
472 */ |
|
473 private static class TagNames { |
|
474 String get(int tag) { |
|
475 if (map == null) { |
|
476 map = new HashMap<Integer, String>(); |
|
477 Class c = JCTree.class; |
|
478 for (Field f : c.getDeclaredFields()) { |
|
479 if (f.getType().equals(int.class)) { |
|
480 int mods = f.getModifiers(); |
|
481 if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) { |
|
482 try { |
|
483 map.put(f.getInt(null), f.getName()); |
|
484 } catch (IllegalAccessException e) { |
|
485 } |
|
486 } |
|
487 } |
|
488 } |
|
489 } |
|
490 String name = map.get(tag); |
|
491 return (name == null) ? "??" : name; |
|
492 } |
|
493 |
|
494 private Map<Integer, String> map; |
|
495 } |
473 } |
496 |
474 |
497 /** |
475 /** |
498 * Thrown when errors are found parsing a java file. |
476 * Thrown when errors are found parsing a java file. |
499 */ |
477 */ |
717 add(addListener(end = createTextField(6))); |
695 add(addListener(end = createTextField(6))); |
718 } |
696 } |
719 |
697 |
720 void setInfo(Info info) { |
698 void setInfo(Info info) { |
721 this.info = info; |
699 this.info = info; |
722 tagName.setText(tagNames.get(info.tag)); |
700 tagName.setText(getTagName(info.tag)); |
723 start.setText(String.valueOf(info.start)); |
701 start.setText(String.valueOf(info.start)); |
724 pos.setText(String.valueOf(info.pos)); |
702 pos.setText(String.valueOf(info.pos)); |
725 end.setText(String.valueOf(info.end)); |
703 end.setText(String.valueOf(info.end)); |
726 } |
704 } |
727 |
705 |