Main.java revision 2441c4b66f26bf96ea7a8749645a933aa09a2d62
110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Alipackage annotator; 210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 3f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.io.File; 4f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.io.FileNotFoundException; 5f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.io.FileOutputStream; 6f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.io.IOException; 7f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.io.OutputStream; 8f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.ArrayList; 9f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.Collections; 10f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.LinkedHashSet; 11f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.List; 12f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.Set; 13f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.TreeSet; 14f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Matcher; 15f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Pattern; 1610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 17f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.FileIOException; 18f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Option; 19f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Options; 20f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Pair; 21f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.UtilMDE; 22f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport annotator.Source.CompilerException; 23e13e8963268c825e80bb92e310135617d7275656Eric Spishakimport annotator.find.Criteria; 2410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.Insertion; 2510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.TreeFinder; 2610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.specification.IndexFileSpecification; 2710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.specification.Specification; 2810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 29f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.google.common.collect.SetMultimap; 30f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.CompilationUnitTree; 31f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.Tree; 325534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernstimport com.sun.source.util.TreePath; 3310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 3410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali/** 3510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * This is the main class for the annotator, which inserts annotations in 36c15d52e959f2b3052978e40552159de77c403428Michael Ernst * Java source code. You can call it as <tt>java annotator.Main</tt> or by 37c15d52e959f2b3052978e40552159de77c403428Michael Ernst * using the shell script <tt>insert-annotations-to-source</tt>. 38c15d52e959f2b3052978e40552159de77c403428Michael Ernst * <p> 39c15d52e959f2b3052978e40552159de77c403428Michael Ernst * 40c15d52e959f2b3052978e40552159de77c403428Michael Ernst * It takes as input 4110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <ul> 4276be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl * <li>annotation (index) files, which indicate the annotations to insert</li> 4310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <li>Java source files, into which the annotator inserts annotations</li> 4410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * </ul> 4510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * Use the --help option for full usage details. 4610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <p> 4710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * 4810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * Annotations that are not for the specified Java files are ignored. 4910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali */ 5010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Alipublic class Main { 5110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 5210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali /** Directory in which output files are written. */ 5310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-d <directory> Directory in which output files are written") 5410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static String outdir = "annotated/"; 5510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 56fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst /** 57fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * If true, overwrite original source files (making a backup first). 58fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * Furthermore, if the backup files already exist, they are used instead 59fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * of the .java files. This behavior permits a user to tweak the .jaif 60fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * file and re-run the annotator. 61fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * <p> 62fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * 63fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * Note that if the user runs the annotator with --in-place, makes edits, 64fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * and then re-runs the annotator with this --in-place option, those 65fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * edits are lost. Similarly, if the user runs the annotator twice in a 66fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * row with --in-place, only the last set of annotations will appear in 67fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * the codebase at the end. 68fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * <p> 69fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * 70fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * To preserve changes when using the --in-place option, first remove the 71fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * backup files. Or, use the <tt>-d .</tt> option, which makes (and 72fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * reads) no backup, instead of --in-place. 73fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst */ 74f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst @Option("-i Overwrite original source files") 75f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst public static boolean in_place = false; 76f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 7710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-h Print usage information and exit") 7810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean help = false; 7910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 8010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-a Abbreviate annotation names") 8110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean abbreviate = true; 8210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 8310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-c Insert annotations in comments") 8410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean comments = false; 8510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 86bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst @Option("-o Omit given annotation") 87bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst public static String omit_annotation; 88bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst 8910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-v Verbose (print progress information)") 9010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean verbose; 9110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 9210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("Debug (print debug information)") 9310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean debug = false; 9410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 9510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Implementation details: 9610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // 1. The annotator partially compiles source 9710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // files using the compiler API (JSR-199), obtaining an AST. 9810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // 2. The annotator reads the specification file, producing a set of 9910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // annotator.find.Insertions. Insertions completely specify what to 10010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // write (as a String, which is ultimately translated according to the 10110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // keyword file) and how to write it (as annotator.find.Criteria). 10210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // 3. It then traverses the tree, looking for nodes that satisfy the 10310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Insertion Criteria, translating the Insertion text against the 10410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // keyword file, and inserting the annotations into the source file. 10510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 10610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali /** 10710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * Runs the annotator, parsing the source and spec files and applying 10810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * the annotations. 10910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali */ 11010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static void main(String[] args) { 11110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 11210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (verbose) { 11367693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst System.out.printf("insert-annotations-to-source (%s)", 11467693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst annotations.io.classfile.ClassFileReader.INDEX_UTILS_VERSION); 11510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 11610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 117f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst Options options = new Options("Main [options] ann-file... java-file...", Main.class); 11876be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl String[] file_args = options.parse_or_usage (args); 119f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 1201220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst if (debug) { 1211220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst TreeFinder.debug = true; 122e13e8963268c825e80bb92e310135617d7275656Eric Spishak Criteria.debug = true; 1231220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst } 1241220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst 12510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (help) { 12610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali options.print_usage(); 12710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(0); 12810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 12910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 130f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (in_place && outdir != "annotated/") { // interned 131f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst options.print_usage("The --outdir and --in-place options are mutually exclusive."); 132f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.exit(1); 133f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 134f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 13510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (file_args.length < 2) { 136f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst options.print_usage("Supplied %d arguments, at least 2 needed%n", file_args.length); 13710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(1); 13810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 13910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 14010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // The insertions specified by the annotation files. 14110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali List<Insertion> insertions = new ArrayList<Insertion>(); 14210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // The Java files into which to insert. 14310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali List<String> javafiles = new ArrayList<String>(); 14410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 14510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (String arg : file_args) { 14610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (arg.endsWith(".java")) { 14710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali javafiles.add(arg); 1488ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl } else if (arg.endsWith(".jaif") || 1498ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl arg.endsWith(".jann")) { 15010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali try { 15110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Specification spec = new IndexFileSpecification(arg); 15210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali List<Insertion> parsedSpec = spec.parse(); 1534735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst if (verbose || debug) { 15410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.out.printf("Read %d annotations from %s%n", 15510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali parsedSpec.size(), arg); 15610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 157bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst if (omit_annotation != null) { 158bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst List<Insertion> filtered = new ArrayList<Insertion>(parsedSpec.size()); 159bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst for (Insertion insertion : parsedSpec) { 1602441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak // TODO: this won't omit annotations if the insertion is more than 1612441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak // just the annotation (such as if the insertion is a cast 1622441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak // insertion or a 'this' parameter in a method declaration). 163bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst if (! omit_annotation.equals(insertion.getText())) { 164bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst filtered.add(insertion); 165bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 166bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 167bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst parsedSpec = filtered; 168bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst if (verbose || debug) { 169bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst System.out.printf("After filtering: %d annotations from %s%n", 170bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst parsedSpec.size(), arg); 171bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 172bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 173bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst insertions.addAll(parsedSpec); 1742c4067b440b23911687e4a353584b088eccf17fbMichael Ernst } catch (RuntimeException e) { 1752c4067b440b23911687e4a353584b088eccf17fbMichael Ernst if (e.getCause() != null 1762c4067b440b23911687e4a353584b088eccf17fbMichael Ernst && e.getCause() instanceof FileNotFoundException) { 1772c4067b440b23911687e4a353584b088eccf17fbMichael Ernst System.err.println("File not found: " + arg); 1782c4067b440b23911687e4a353584b088eccf17fbMichael Ernst System.exit(1); 1792c4067b440b23911687e4a353584b088eccf17fbMichael Ernst } else { 1802c4067b440b23911687e4a353584b088eccf17fbMichael Ernst throw e; 1812c4067b440b23911687e4a353584b088eccf17fbMichael Ernst } 18210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (FileIOException e) { 18310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.err.println("Error while parsing annotation file " + arg); 18410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (e.getMessage() != null) { 18510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.err.println(e.getMessage()); 18610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 18710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali e.printStackTrace(); 18810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(1); 18910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 19010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } else { 19110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali throw new Error("Unrecognized file extension: " + arg); 19210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 19310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 19410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 19510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (debug) { 196b3ca4989984b4c0c85719bbac77ec93477099b32Michael Ernst System.out.printf("%d insertions, %d .java files%n", insertions.size(), javafiles.size()); 19710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 19810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (debug) { 199b3ca4989984b4c0c85719bbac77ec93477099b32Michael Ernst System.out.printf("Insertions:%n"); 20010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (Insertion insertion : insertions) { 201b3ca4989984b4c0c85719bbac77ec93477099b32Michael Ernst System.out.printf(" %s%n", insertion); 20210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 20310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 20410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 20510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (String javafilename : javafiles) { 20610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 20710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (verbose) { 20810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.out.println("Processing " + javafilename); 20910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 21010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 211f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst File javafile = new File(javafilename); 212f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 213f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst File outfile; 214f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst File unannotated = new File(javafilename + ".unannotated"); 215f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (in_place) { 216f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // It doesn't make sense to check timestamps; 217f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // if the .java.unannotated file exists, then just use it. 218f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // A user can rename that file back to just .java to cause the 219f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // .java file to be read. 220f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (unannotated.exists()) { 221f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (verbose) { 222f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.out.printf("Renaming %s to %s%n", unannotated, javafile); 223f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 224f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst boolean success = unannotated.renameTo(javafile); 225f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (! success) { 226f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst throw new Error(String.format("Failed renaming %s to %s", 227f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst unannotated, javafile)); 228f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 229f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 230f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst outfile = javafile; 231f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } else { 232f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst String baseName; 233f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (javafile.isAbsolute()) { 234f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst baseName = javafile.getName(); 235f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } else { 236f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst baseName = javafile.getPath(); 237f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 238f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst outfile = new File(outdir, baseName); 239f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 240f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 241f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst Set<String> imports = new LinkedHashSet<String>(); 242f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 24310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali String fileLineSep = System.getProperty("line.separator"); 24410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Source src; 24510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Get the source file, and use it to obtain parse trees. 24610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali try { 24710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // fileLineSep is set here so that exceptions can be caught 24810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali fileLineSep = UtilMDE.inferLineSeparator(javafilename); 24910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali src = new Source(javafilename); 250c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (verbose) { 251c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.printf("Parsed %s%n", javafilename); 252c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 25310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (CompilerException e) { 25410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali e.printStackTrace(); 25510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali return; 25610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (IOException e) { 25710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali e.printStackTrace(); 25810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali return; 25910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 26010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 261c15d52e959f2b3052978e40552159de77c403428Michael Ernst int num_insertions = 0; 262c15d52e959f2b3052978e40552159de77c403428Michael Ernst 26310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (CompilationUnitTree tree : src.parse()) { 26410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 26510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Create a finder, and use it to get positions. 26610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali TreeFinder finder = new TreeFinder(tree); 2675c6791fb104c246b6a37144b59dbfaad1f800de6Michael Ernst if (debug) { 2681d9ddfee01826d63c802f5356c250e3841a68e71wdietl TreeFinder.debug = true; 2695c6791fb104c246b6a37144b59dbfaad1f800de6Michael Ernst } 270ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst SetMultimap<Integer, Insertion> positions = finder.getPositions(tree, insertions); 27110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 27210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Apply the positions to the source file. 273c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (debug || verbose) { 274c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.err.printf("getPositions returned %d positions in tree for %s%n", positions.size(), javafilename); 27510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 27610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 27757ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst Set<Integer> positionKeysUnsorted = positions.keySet(); 27857ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst Set<Integer> positionKeysSorted = new TreeSet<Integer>(new TreeFinder.ReverseIntegerComparator()); 27957ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst positionKeysSorted.addAll(positionKeysUnsorted); 28057ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst for (Integer pos : positionKeysSorted) { 281ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst List<Insertion> toInsertList = new ArrayList<Insertion>(positions.get(pos)); 282ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst Collections.reverse(toInsertList); 283a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst if (debug) { 284a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst System.out.printf("insertion pos: %d%n", pos); 285a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst } 286d2c419e0399881f6e63361a637ccb90cc4a898bdMichael Ernst assert pos >= 0 287d2c419e0399881f6e63361a637ccb90cc4a898bdMichael Ernst : "pos is negative: " + pos + " " + toInsertList.get(0) + " " + javafilename; 288ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst for (Insertion iToInsert : toInsertList) { 289d6e7a874aafafbcc2dd63cd89c58b7483366bc08Eric Spishak String toInsert = iToInsert.getText(comments, abbreviate); 290ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (abbreviate) { 2916161d8ca12f86ec5a5032a4a614a8b89d27d5c23Eric Spishak Set<String> packageNames = iToInsert.getPackageNames(); 2926161d8ca12f86ec5a5032a4a614a8b89d27d5c23Eric Spishak if (debug) { 2936161d8ca12f86ec5a5032a4a614a8b89d27d5c23Eric Spishak System.out.printf("Need import %s%n due to insertion %s%n", 2946161d8ca12f86ec5a5032a4a614a8b89d27d5c23Eric Spishak packageNames, toInsert); 2950f7ed8e9f456276945e3cc04203c31dbce61a0b5Michael Ernst } 2966161d8ca12f86ec5a5032a4a614a8b89d27d5c23Eric Spishak imports.addAll(packageNames); 29710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 29810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 299ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // Possibly add whitespace after the insertion 300ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst boolean gotSeparateLine = false; 301ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (iToInsert.getSeparateLine()) { 302a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst // System.out.printf("getSeparateLine=true for insertion at pos %d: %s%n", pos, iToInsert); 303ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst int indentation = 0; 304ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst while ((pos - indentation != 0) 305ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // horizontal whitespace 306ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst && (src.charAt(pos-indentation-1) == ' ' 307ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || src.charAt(pos-indentation-1) == '\t')) { 308a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst // System.out.printf("src.charAt(pos-indentation-1 == %d-%d-1)='%s'%n", 309a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst // pos, indentation, src.charAt(pos-indentation-1)); 310ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst indentation++; 311ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 312ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if ((pos - indentation == 0) 313ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // horizontal whitespace 314ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || (src.charAt(pos-indentation-1) == '\f' 315ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || src.charAt(pos-indentation-1) == '\n' 316ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || src.charAt(pos-indentation-1) == '\r')) { 317ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst toInsert = toInsert + fileLineSep + src.substring(pos-indentation, pos); 318ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst gotSeparateLine = true; 319ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 320ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 321c71d4e21017f8f4412a2d399676e358858999623Michael Ernst 322ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // Possibly add a leading space before the insertion 323ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if ((! gotSeparateLine) && (pos != 0)) { 324ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst char precedingChar = src.charAt(pos-1); 325ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (! (Character.isWhitespace(precedingChar) 326ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // No space if it's the first formal or generic parameter 32707a61175c257cf7fb7738d5eede16733440c1b56Eric Spishak // or if it's a CloseParenthesesInsertion 328ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || precedingChar == '(' 32907a61175c257cf7fb7738d5eede16733440c1b56Eric Spishak || precedingChar == '<' 33007a61175c257cf7fb7738d5eede16733440c1b56Eric Spishak || precedingChar == '[' 33107a61175c257cf7fb7738d5eede16733440c1b56Eric Spishak || toInsert.equals("))"))) { 332ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst toInsert = " " + toInsert; 333ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 3344735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst } 335ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst 336ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // If it's already there, don't re-insert. This is a hack! 337ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // Also, I think this is already checked when constructing the 33876be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl // insertions. 339ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst int precedingTextPos = pos-toInsert.length()-1; 340ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (precedingTextPos >= 0) { 341ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst String precedingTextPlusChar 342ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst = src.getString().substring(precedingTextPos, pos); 343ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // System.out.println("Inserting " + toInsert + " at " + pos + " in code of length " + src.getString().length() + " with preceding text '" + precedingTextPlusChar + "'"); 344ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (toInsert.equals(precedingTextPlusChar.substring(0, toInsert.length())) 345ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || toInsert.equals(precedingTextPlusChar.substring(1))) { 346ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (debug) { 347050043fa0fe1286433a9c5985f6e7f1514b3e19bwdietl System.out.println("Inserting " + toInsert + " at " + pos + " in code of length " + src.getString().length() + " with preceding text '" + precedingTextPlusChar + "'"); 3483e5089aea50851069fffb66a96b731c6b06a2666wdietl System.out.println("Already present, skipping"); 349ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 350ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst continue; 3514735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst } 35210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 353ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // add trailing whitespace 35409e02e2c623aae704a60e026404686c147532d80Michael Ernst // (test is not for "extends " because we just added a leading space, above) 35507a61175c257cf7fb7738d5eede16733440c1b56Eric Spishak if ((! gotSeparateLine) && (! toInsert.startsWith(" extends ")) 35607a61175c257cf7fb7738d5eede16733440c1b56Eric Spishak && (! toInsert.startsWith("((")) && (! toInsert.startsWith(" ((")) 35767ef4360e4d0b2c90124f1185357989682d62359Eric Spishak && (! toInsert.equals("))")) && (! toInsert.endsWith(" this"))) { 358ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst toInsert = toInsert + " "; 359ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 360ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst src.insert(pos, toInsert); 361c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (verbose) { 362c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.print("."); 363c15d52e959f2b3052978e40552159de77c403428Michael Ernst num_insertions++; 364c15d52e959f2b3052978e40552159de77c403428Michael Ernst if ((num_insertions % 50) == 0) { 365c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.println(); // terminate the line that contains dots 366c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 367c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 368ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (debug) { 369ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst System.out.println("Post-insertion source: " + src.getString()); 370ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 37110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 37210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 37310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 374c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (verbose) { 375c15d52e959f2b3052978e40552159de77c403428Michael Ernst if ((num_insertions % 50) != 0) { 376c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.println(); // terminate the line that contains dots 377c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 378c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 37910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 38010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // insert import statements 38110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali { 38210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (debug) { 38310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.out.println(imports.size() + " imports to insert"); 38457ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst for (String classname : imports) { 38557ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst System.out.println(" " + classname); 38657ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst } 38710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 38810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Pattern importPattern = Pattern.compile("(?m)^import\\b"); 38910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Pattern packagePattern = Pattern.compile("(?m)^package\\b.*;(\\n|\\r\\n?)"); 39010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali int importIndex = 0; // default: beginning of file 39110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali String srcString = src.getString(); 39210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Matcher m; 39310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali m = importPattern.matcher(srcString); 39410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (m.find()) { 39510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali importIndex = m.start(); 39610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } else { 39710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // if (debug) { 39810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // System.out.println("Didn't find import in " + srcString); 39910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // } 40010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali m = packagePattern.matcher(srcString); 40110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (m.find()) { 40210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali importIndex = m.end(); 40310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 40410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 40510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (String classname : imports) { 40610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali String toInsert = "import " + classname + ";" + fileLineSep; 40710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali src.insert(importIndex, toInsert); 40810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali importIndex += toInsert.length(); 40910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 41010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 41110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 41210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Write the source file. 41310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali try { 414f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (in_place) { 415f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (verbose) { 416f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.out.printf("Renaming %s to %s%n", javafile, unannotated); 417f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 418f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst boolean success = javafile.renameTo(unannotated); 419f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (! success) { 420f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst throw new Error(String.format("Failed renaming %s to %s", 421f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst javafile, unannotated)); 422f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 423f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } else { 424f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst outfile.getParentFile().mkdirs(); 425f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 42610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali OutputStream output = new FileOutputStream(outfile); 427f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (verbose) { 428f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.out.printf("Writing %s%n", outfile); 429f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 43010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali src.write(output); 431f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst output.close(); 43210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (IOException e) { 43310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.err.println("Problem while writing file " + outfile); 43410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali e.printStackTrace(); 43510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(1); 43610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 43710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 43810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 43910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 4405534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /// 4415534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /// Utility methods 4425534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /// 4435534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst 4445534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst public static String pathToString(TreePath path) { 4455534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst if (path == null) 4465534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return "null"; 447f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst return treeToString(path.getLeaf()); 448f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst } 449f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst 450f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst public static String treeToString(Tree node) { 451f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst String asString = node.toString(); 4525534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst String oneLine = firstLine(asString); 4535534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return "\"" + oneLine + "\""; 4545534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4555534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst 4565534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /** 4575534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst * Return the first non-empty line of the string, adding an ellipsis 4585534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst * (...) if the string was truncated. 4595534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst */ 4605534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst public static String firstLine(String s) { 4615534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst while (s.startsWith("\n")) { 4625534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst s = s.substring(1); 4635534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4645534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst int newlineIndex = s.indexOf('\n'); 4655534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst if (newlineIndex == -1) { 4665534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return s; 4675534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } else { 4685534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return s.substring(0, newlineIndex) + "..."; 4695534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4705534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4715534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst 472aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb /** 473aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb * Separates the annotation class from its arguments. 474aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb * 475aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb * @return given <code>@foo(bar)</code> it returns the pair <code>{ @foo, (bar) }</code>. 476aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb */ 477aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb public static Pair<String,String> removeArgs(String s) { 478aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb int pidx = s.indexOf("("); 479aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb return (pidx == -1) ? 480615ec652dc360e33296fd763a4fa56e59c35b23cMichael Ernst Pair.of(s, (String)null) : 481aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb Pair.of(s.substring(0, pidx), s.substring(pidx)); 482aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb } 483aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb 48410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali} 485