langtools/test/tools/javac/tree/TreePosTest.java
changeset 10950 e87b50888909
parent 7846 f72ce57eb9c1
child 11055 ec1418effa77
equal deleted inserted replaced
10949:42f7cc0468dd 10950:e87b50888909
     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) {
   437      * Utility class providing easy access to position and other info for a tree node.
   444      * Utility class providing easy access to position and other info for a tree node.
   438      */
   445      */
   439     private class Info {
   446     private class Info {
   440         Info() {
   447         Info() {
   441             tree = null;
   448             tree = null;
   442             tag = JCTree.ERRONEOUS;
   449             tag = ERRONEOUS;
   443             start = 0;
   450             start = 0;
   444             pos = 0;
   451             pos = 0;
   445             end = Integer.MAX_VALUE;
   452             end = Integer.MAX_VALUE;
   446         }
   453         }
   447 
   454 
   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