Main.java revision 290791bf3ace51eca8cb637b47e1e1d01d92111d
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; 10adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brownimport java.util.Comparator; 11f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.LinkedHashSet; 12f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.List; 13f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.Set; 14f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.TreeSet; 15f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Matcher; 16f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Pattern; 1710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 18f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.FileIOException; 19f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Option; 20f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Options; 21f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Pair; 22f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.UtilMDE; 23f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport annotator.Source.CompilerException; 24e13e8963268c825e80bb92e310135617d7275656Eric Spishakimport annotator.find.Criteria; 2510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.Insertion; 26290791bf3ace51eca8cb637b47e1e1d01d92111dDan Brownimport annotator.find.Insertions; 27c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brownimport annotator.find.ReceiverInsertion; 2810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.TreeFinder; 2910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.specification.IndexFileSpecification; 3010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.specification.Specification; 3110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 32f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.google.common.collect.SetMultimap; 33f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.CompilationUnitTree; 34f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.Tree; 355534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernstimport com.sun.source.util.TreePath; 36de7d64fbe7b6eb28b7ec1a2393b91b8e9c6afea6Dan Brownimport com.sun.tools.javac.main.CommandLine; 37b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brownimport com.sun.tools.javac.tree.JCTree; 3810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 3910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali/** 4010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * This is the main class for the annotator, which inserts annotations in 41c15d52e959f2b3052978e40552159de77c403428Michael Ernst * Java source code. You can call it as <tt>java annotator.Main</tt> or by 42c15d52e959f2b3052978e40552159de77c403428Michael Ernst * using the shell script <tt>insert-annotations-to-source</tt>. 43c15d52e959f2b3052978e40552159de77c403428Michael Ernst * <p> 44c15d52e959f2b3052978e40552159de77c403428Michael Ernst * 45c15d52e959f2b3052978e40552159de77c403428Michael Ernst * It takes as input 4610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <ul> 4776be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl * <li>annotation (index) files, which indicate the annotations to insert</li> 4810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <li>Java source files, into which the annotator inserts annotations</li> 4910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * </ul> 5010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * Use the --help option for full usage details. 5110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <p> 5210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * 5310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * Annotations that are not for the specified Java files are ignored. 5410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali */ 5510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Alipublic class Main { 5610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 5710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali /** Directory in which output files are written. */ 5810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-d <directory> Directory in which output files are written") 5910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static String outdir = "annotated/"; 6010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 61fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst /** 62fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * If true, overwrite original source files (making a backup first). 63fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * Furthermore, if the backup files already exist, they are used instead 64fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * of the .java files. This behavior permits a user to tweak the .jaif 65fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * file and re-run the annotator. 66fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * <p> 67fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * 68fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * Note that if the user runs the annotator with --in-place, makes edits, 69fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * and then re-runs the annotator with this --in-place option, those 70fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * edits are lost. Similarly, if the user runs the annotator twice in a 71fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * row with --in-place, only the last set of annotations will appear in 72fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * the codebase at the end. 73fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * <p> 74fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * 75fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * To preserve changes when using the --in-place option, first remove the 76fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * backup files. Or, use the <tt>-d .</tt> option, which makes (and 77fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst * reads) no backup, instead of --in-place. 78fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst */ 79f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst @Option("-i Overwrite original source files") 80f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst public static boolean in_place = false; 81f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 8210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-a Abbreviate annotation names") 8310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean abbreviate = true; 8410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 8510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-c Insert annotations in comments") 8610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean comments = false; 8710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 88bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst @Option("-o Omit given annotation") 89bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst public static String omit_annotation; 90bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst 9138326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst @Option("-h Print usage information and exit") 9238326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst public static boolean help = false; 9338326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst 9410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("-v Verbose (print progress information)") 9510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean verbose; 9610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 9710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali @Option("Debug (print debug information)") 9810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali public static boolean debug = false; 9910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 1008b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak @Option("Print error stack") 1018b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak public static boolean print_error_stack = false; 1028b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak 10310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Implementation details: 10410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // 1. The annotator partially compiles source 10510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // files using the compiler API (JSR-199), obtaining an AST. 10610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // 2. The annotator reads the specification file, producing a set of 10710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // annotator.find.Insertions. Insertions completely specify what to 10810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // write (as a String, which is ultimately translated according to the 10910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // keyword file) and how to write it (as annotator.find.Criteria). 11010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // 3. It then traverses the tree, looking for nodes that satisfy the 11110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Insertion Criteria, translating the Insertion text against the 11210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // keyword file, and inserting the annotations into the source file. 11310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 11410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali /** 11510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * Runs the annotator, parsing the source and spec files and applying 11610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * the annotations. 11710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali */ 118de7d64fbe7b6eb28b7ec1a2393b91b8e9c6afea6Dan Brown public static void main(String[] args) throws IOException { 11910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 12010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (verbose) { 12167693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst System.out.printf("insert-annotations-to-source (%s)", 12267693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst annotations.io.classfile.ClassFileReader.INDEX_UTILS_VERSION); 12310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 12410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 125f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst Options options = new Options("Main [options] ann-file... java-file...", Main.class); 126de7d64fbe7b6eb28b7ec1a2393b91b8e9c6afea6Dan Brown String[] file_args = options.parse_or_usage(CommandLine.parse(args)); 127f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 1281220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst if (debug) { 1291220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst TreeFinder.debug = true; 130e13e8963268c825e80bb92e310135617d7275656Eric Spishak Criteria.debug = true; 1311220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst } 1321220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst 13310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (help) { 13410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali options.print_usage(); 13510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(0); 13610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 13710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 138f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (in_place && outdir != "annotated/") { // interned 139f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst options.print_usage("The --outdir and --in-place options are mutually exclusive."); 140f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.exit(1); 141f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 142f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 14310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (file_args.length < 2) { 144f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst options.print_usage("Supplied %d arguments, at least 2 needed%n", file_args.length); 14510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(1); 14610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 14710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 14810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // The insertions specified by the annotation files. 149290791bf3ace51eca8cb637b47e1e1d01d92111dDan Brown Insertions insertions = new Insertions(); 15010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // The Java files into which to insert. 15110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali List<String> javafiles = new ArrayList<String>(); 15210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 15310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (String arg : file_args) { 15410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (arg.endsWith(".java")) { 15510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali javafiles.add(arg); 1568ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl } else if (arg.endsWith(".jaif") || 1578ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl arg.endsWith(".jann")) { 15810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali try { 15910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Specification spec = new IndexFileSpecification(arg); 16010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali List<Insertion> parsedSpec = spec.parse(); 1614735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst if (verbose || debug) { 16210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.out.printf("Read %d annotations from %s%n", 16310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali parsedSpec.size(), arg); 16410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 165bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst if (omit_annotation != null) { 166bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst List<Insertion> filtered = new ArrayList<Insertion>(parsedSpec.size()); 167bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst for (Insertion insertion : parsedSpec) { 1682441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak // TODO: this won't omit annotations if the insertion is more than 1692441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak // just the annotation (such as if the insertion is a cast 1702441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak // insertion or a 'this' parameter in a method declaration). 171bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst if (! omit_annotation.equals(insertion.getText())) { 172bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst filtered.add(insertion); 173bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 174bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 175bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst parsedSpec = filtered; 176bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst if (verbose || debug) { 177bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst System.out.printf("After filtering: %d annotations from %s%n", 178bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst parsedSpec.size(), arg); 179bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 180bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst } 181bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst insertions.addAll(parsedSpec); 1822c4067b440b23911687e4a353584b088eccf17fbMichael Ernst } catch (RuntimeException e) { 1832c4067b440b23911687e4a353584b088eccf17fbMichael Ernst if (e.getCause() != null 1842c4067b440b23911687e4a353584b088eccf17fbMichael Ernst && e.getCause() instanceof FileNotFoundException) { 1852c4067b440b23911687e4a353584b088eccf17fbMichael Ernst System.err.println("File not found: " + arg); 1862c4067b440b23911687e4a353584b088eccf17fbMichael Ernst System.exit(1); 1872c4067b440b23911687e4a353584b088eccf17fbMichael Ernst } else { 1882c4067b440b23911687e4a353584b088eccf17fbMichael Ernst throw e; 1892c4067b440b23911687e4a353584b088eccf17fbMichael Ernst } 19010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (FileIOException e) { 191bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak // Add 1 to the line number since line numbers in text editors are usually one-based. 192bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak System.err.println("Error while parsing annotation file " + arg + " at line " 193bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak + (e.lineNumber + 1) + ":"); 19410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (e.getMessage() != null) { 195bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak System.err.println('\t' + e.getMessage()); 196bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak } 197bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak if (e.getCause() != null && e.getCause().getMessage() != null) { 198bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak System.err.println('\t' + e.getCause().getMessage()); 199bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak } 200bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak if (debug) { 201bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak e.printStackTrace(); 20210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 20310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(1); 20410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 20510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } else { 20610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali throw new Error("Unrecognized file extension: " + arg); 20710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 20810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 20910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 21010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (debug) { 211b3ca4989984b4c0c85719bbac77ec93477099b32Michael Ernst System.out.printf("%d insertions, %d .java files%n", insertions.size(), javafiles.size()); 21210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 21310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (debug) { 214b3ca4989984b4c0c85719bbac77ec93477099b32Michael Ernst System.out.printf("Insertions:%n"); 21510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (Insertion insertion : insertions) { 216b3ca4989984b4c0c85719bbac77ec93477099b32Michael Ernst System.out.printf(" %s%n", insertion); 21710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 21810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 21910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 22010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (String javafilename : javafiles) { 22110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 22210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (verbose) { 22310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.out.println("Processing " + javafilename); 22410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 22510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 226f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst File javafile = new File(javafilename); 227f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 228f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst File outfile; 229f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst File unannotated = new File(javafilename + ".unannotated"); 230f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (in_place) { 231f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // It doesn't make sense to check timestamps; 232f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // if the .java.unannotated file exists, then just use it. 233f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // A user can rename that file back to just .java to cause the 234f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst // .java file to be read. 235f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (unannotated.exists()) { 236f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (verbose) { 237f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.out.printf("Renaming %s to %s%n", unannotated, javafile); 238f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 239f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst boolean success = unannotated.renameTo(javafile); 240f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (! success) { 241f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst throw new Error(String.format("Failed renaming %s to %s", 242f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst unannotated, javafile)); 243f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 244f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 245f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst outfile = javafile; 246f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } else { 247f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst String baseName; 248f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (javafile.isAbsolute()) { 249f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst baseName = javafile.getName(); 250f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } else { 251f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst baseName = javafile.getPath(); 252f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 253f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst outfile = new File(outdir, baseName); 254f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 255f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 256f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst Set<String> imports = new LinkedHashSet<String>(); 257f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst 25810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali String fileLineSep = System.getProperty("line.separator"); 25910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Source src; 26010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Get the source file, and use it to obtain parse trees. 26110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali try { 26210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // fileLineSep is set here so that exceptions can be caught 26310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali fileLineSep = UtilMDE.inferLineSeparator(javafilename); 26410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali src = new Source(javafilename); 265c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (verbose) { 266c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.printf("Parsed %s%n", javafilename); 267c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 26810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (CompilerException e) { 26910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali e.printStackTrace(); 27010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali return; 27110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (IOException e) { 27210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali e.printStackTrace(); 27310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali return; 27410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 27510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 276c15d52e959f2b3052978e40552159de77c403428Michael Ernst int num_insertions = 0; 277c15d52e959f2b3052978e40552159de77c403428Michael Ernst 278b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brown for (CompilationUnitTree cut : src.parse()) { 279b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brown JCTree.JCCompilationUnit tree = (JCTree.JCCompilationUnit) cut; 28010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 28110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Create a finder, and use it to get positions. 28210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali TreeFinder finder = new TreeFinder(tree); 2835c6791fb104c246b6a37144b59dbfaad1f800de6Michael Ernst if (debug) { 2841d9ddfee01826d63c802f5356c250e3841a68e71wdietl TreeFinder.debug = true; 2855c6791fb104c246b6a37144b59dbfaad1f800de6Michael Ernst } 286ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst SetMultimap<Integer, Insertion> positions = finder.getPositions(tree, insertions); 28710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 28810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Apply the positions to the source file. 289c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (debug || verbose) { 290c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.err.printf("getPositions returned %d positions in tree for %s%n", positions.size(), javafilename); 29110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 29210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 29357ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst Set<Integer> positionKeysUnsorted = positions.keySet(); 294adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brown Set<Integer> positionKeysSorted = 295adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brown new TreeSet<Integer>(new Comparator<Integer>() { 296adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brown @Override 297adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brown public int compare(Integer o1, Integer o2) { 298adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brown return o1.compareTo(o2) * -1; 299adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brown } 300adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brown }); 30157ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst positionKeysSorted.addAll(positionKeysUnsorted); 30257ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst for (Integer pos : positionKeysSorted) { 303c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown boolean receiverInserted = false; 304ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst List<Insertion> toInsertList = new ArrayList<Insertion>(positions.get(pos)); 305ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst Collections.reverse(toInsertList); 306a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst if (debug) { 307a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst System.out.printf("insertion pos: %d%n", pos); 308a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst } 309d2c419e0399881f6e63361a637ccb90cc4a898bdMichael Ernst assert pos >= 0 310d2c419e0399881f6e63361a637ccb90cc4a898bdMichael Ernst : "pos is negative: " + pos + " " + toInsertList.get(0) + " " + javafilename; 311ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst for (Insertion iToInsert : toInsertList) { 312ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // Possibly add whitespace after the insertion 3133d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak String trailingWhitespace = ""; 314ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst boolean gotSeparateLine = false; 315ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (iToInsert.getSeparateLine()) { 316a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst // System.out.printf("getSeparateLine=true for insertion at pos %d: %s%n", pos, iToInsert); 317ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst int indentation = 0; 318ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst while ((pos - indentation != 0) 319ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // horizontal whitespace 320ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst && (src.charAt(pos-indentation-1) == ' ' 321ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || src.charAt(pos-indentation-1) == '\t')) { 322a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst // System.out.printf("src.charAt(pos-indentation-1 == %d-%d-1)='%s'%n", 323a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst // pos, indentation, src.charAt(pos-indentation-1)); 324ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst indentation++; 325ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 326ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if ((pos - indentation == 0) 327ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // horizontal whitespace 328ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || (src.charAt(pos-indentation-1) == '\f' 329ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || src.charAt(pos-indentation-1) == '\n' 330ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || src.charAt(pos-indentation-1) == '\r')) { 3313d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak trailingWhitespace = fileLineSep + src.substring(pos-indentation, pos); 332ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst gotSeparateLine = true; 333ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 334ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 335c71d4e21017f8f4412a2d399676e358858999623Michael Ernst 3363d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak char precedingChar; 3373d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak if (pos != 0) { 3383d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak precedingChar = src.charAt(pos - 1); 3393d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak } else { 3403d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak precedingChar = '\0'; 3413d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak } 3423d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak 343c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown if (iToInsert.getKind() == Insertion.Kind.RECEIVER) { 344c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown ReceiverInsertion ri = (ReceiverInsertion) iToInsert; 345c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown ri.setAnnotationsOnly(receiverInserted); 346c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown receiverInserted = true; 347c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown } 348c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown 3493d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak String toInsert = iToInsert.getText(comments, abbreviate, 3503d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak gotSeparateLine, pos, precedingChar) + trailingWhitespace; 3513d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak if (abbreviate) { 3523d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak Set<String> packageNames = iToInsert.getPackageNames(); 3533d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak if (debug) { 3543d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak System.out.printf("Need import %s%n due to insertion %s%n", 3553d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak packageNames, toInsert); 356ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 3573d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak imports.addAll(packageNames); 3584735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst } 359ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst 360ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // If it's already there, don't re-insert. This is a hack! 361ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // Also, I think this is already checked when constructing the 36276be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl // insertions. 363ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst int precedingTextPos = pos-toInsert.length()-1; 364ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (precedingTextPos >= 0) { 365ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst String precedingTextPlusChar 366ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst = src.getString().substring(precedingTextPos, pos); 367ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst // System.out.println("Inserting " + toInsert + " at " + pos + " in code of length " + src.getString().length() + " with preceding text '" + precedingTextPlusChar + "'"); 368ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (toInsert.equals(precedingTextPlusChar.substring(0, toInsert.length())) 369ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst || toInsert.equals(precedingTextPlusChar.substring(1))) { 370ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (debug) { 371050043fa0fe1286433a9c5985f6e7f1514b3e19bwdietl System.out.println("Inserting " + toInsert + " at " + pos + " in code of length " + src.getString().length() + " with preceding text '" + precedingTextPlusChar + "'"); 3723e5089aea50851069fffb66a96b731c6b06a2666wdietl System.out.println("Already present, skipping"); 373ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 374ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst continue; 3754735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst } 37610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 3773d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak 378ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst src.insert(pos, toInsert); 379c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (verbose) { 380c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.print("."); 381c15d52e959f2b3052978e40552159de77c403428Michael Ernst num_insertions++; 382c15d52e959f2b3052978e40552159de77c403428Michael Ernst if ((num_insertions % 50) == 0) { 383c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.println(); // terminate the line that contains dots 384c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 385c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 386ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst if (debug) { 387ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst System.out.println("Post-insertion source: " + src.getString()); 388ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst } 38910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 39010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 39110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 392c15d52e959f2b3052978e40552159de77c403428Michael Ernst if (verbose) { 393c15d52e959f2b3052978e40552159de77c403428Michael Ernst if ((num_insertions % 50) != 0) { 394c15d52e959f2b3052978e40552159de77c403428Michael Ernst System.out.println(); // terminate the line that contains dots 395c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 396c15d52e959f2b3052978e40552159de77c403428Michael Ernst } 39710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 39810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // insert import statements 39910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali { 40010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (debug) { 40110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.out.println(imports.size() + " imports to insert"); 40257ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst for (String classname : imports) { 40357ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst System.out.println(" " + classname); 40457ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst } 40510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 40610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Pattern importPattern = Pattern.compile("(?m)^import\\b"); 40710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Pattern packagePattern = Pattern.compile("(?m)^package\\b.*;(\\n|\\r\\n?)"); 40810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali int importIndex = 0; // default: beginning of file 40910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali String srcString = src.getString(); 41010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali Matcher m; 41110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali m = importPattern.matcher(srcString); 41210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (m.find()) { 41310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali importIndex = m.start(); 41410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } else { 41510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // if (debug) { 41610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // System.out.println("Didn't find import in " + srcString); 41710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // } 41810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali m = packagePattern.matcher(srcString); 41910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali if (m.find()) { 42010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali importIndex = m.end(); 42110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 42210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 42310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali for (String classname : imports) { 42410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali String toInsert = "import " + classname + ";" + fileLineSep; 42510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali src.insert(importIndex, toInsert); 42610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali importIndex += toInsert.length(); 42710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 42810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 42910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 43010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali // Write the source file. 43110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali try { 432f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (in_place) { 433f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (verbose) { 434f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.out.printf("Renaming %s to %s%n", javafile, unannotated); 435f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 436f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst boolean success = javafile.renameTo(unannotated); 437f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (! success) { 438f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst throw new Error(String.format("Failed renaming %s to %s", 439f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst javafile, unannotated)); 440f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 441f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } else { 442f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst outfile.getParentFile().mkdirs(); 443f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 44410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali OutputStream output = new FileOutputStream(outfile); 445f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst if (verbose) { 446f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst System.out.printf("Writing %s%n", outfile); 447f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst } 44810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali src.write(output); 449f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst output.close(); 45010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } catch (IOException e) { 45110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.err.println("Problem while writing file " + outfile); 45210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali e.printStackTrace(); 45310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali System.exit(1); 45410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 45510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 45610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali } 45710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali 4585534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /// 4595534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /// Utility methods 4605534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /// 4615534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst 4625534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst public static String pathToString(TreePath path) { 4635534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst if (path == null) 4645534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return "null"; 465f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst return treeToString(path.getLeaf()); 466f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst } 467f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst 468f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst public static String treeToString(Tree node) { 469f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst String asString = node.toString(); 4705534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst String oneLine = firstLine(asString); 4715534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return "\"" + oneLine + "\""; 4725534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4735534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst 4745534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst /** 4755534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst * Return the first non-empty line of the string, adding an ellipsis 4765534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst * (...) if the string was truncated. 4775534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst */ 4785534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst public static String firstLine(String s) { 4795534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst while (s.startsWith("\n")) { 4805534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst s = s.substring(1); 4815534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4825534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst int newlineIndex = s.indexOf('\n'); 4835534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst if (newlineIndex == -1) { 4845534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return s; 4855534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } else { 4865534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst return s.substring(0, newlineIndex) + "..."; 4875534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4885534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst } 4895534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst 490aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb /** 491aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb * Separates the annotation class from its arguments. 492aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb * 493aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb * @return given <code>@foo(bar)</code> it returns the pair <code>{ @foo, (bar) }</code>. 494aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb */ 495aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb public static Pair<String,String> removeArgs(String s) { 496aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb int pidx = s.indexOf("("); 497aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb return (pidx == -1) ? 498615ec652dc360e33296fd763a4fa56e59c35b23cMichael Ernst Pair.of(s, (String)null) : 499aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb Pair.of(s.substring(0, pidx), s.substring(pidx)); 500aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb } 501aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb 50210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali} 503