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;
904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport java.util.Collection;
10f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.Collections;
11adc47d693f66c43acddf4956515c0c94db3e6cb4Dan Brownimport java.util.Comparator;
1204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport java.util.HashMap;
13c31338b45a78642c9b21cce154949870ea826abbDan Brownimport java.util.LinkedHashMap;
14f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.LinkedHashSet;
15f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.List;
16e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brownimport java.util.Map;
17f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.Set;
18f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.TreeSet;
19f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Matcher;
20f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Pattern;
2110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
2243367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernstimport plume.FileIOException;
2343367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernstimport plume.Option;
2443367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernstimport plume.OptionGroup;
2543367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernstimport plume.Options;
2643367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernstimport plume.Pair;
2743367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernstimport plume.UtilMDE;
2804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport type.Type;
2904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.Annotation;
3004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ABlock;
3104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AClass;
3204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ADeclaration;
3304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AElement;
3404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AExpression;
3504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AField;
3604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AMethod;
3704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AScene;
3804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ATypeElement;
3904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ATypeElementWithType;
4004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AnnotationDef;
4104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.DefException;
4204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ElementVisitor;
4304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.LocalLocation;
4404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.io.ASTIndex;
4504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.io.ASTPath;
46d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brownimport annotations.io.ASTRecord;
478819fd6c8f50083311182795717e23e88cd04ac5Dan Brownimport annotations.io.DebugWriter;
48e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brownimport annotations.io.IndexFileParser;
4904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.io.IndexFileWriter;
5004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.util.coll.VivifyingMap;
51afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brownimport annotator.find.AnnotationInsertion;
525491118a39a8545a38eb1a94bbc5f5a00a0b9beeDan Brownimport annotator.find.CastInsertion;
530b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brownimport annotator.find.ConstructorInsertion;
54e13e8963268c825e80bb92e310135617d7275656Eric Spishakimport annotator.find.Criteria;
5504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotator.find.GenericArrayLocationCriterion;
5610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.Insertion;
57290791bf3ace51eca8cb637b47e1e1d01d92111dDan Brownimport annotator.find.Insertions;
5884a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brownimport annotator.find.NewInsertion;
59c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brownimport annotator.find.ReceiverInsertion;
6010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.TreeFinder;
6104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotator.find.TypedInsertion;
6204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotator.scanner.LocalVariableScanner;
6310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.specification.IndexFileSpecification;
6410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
6504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport com.google.common.collect.LinkedHashMultimap;
6604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport com.google.common.collect.Multimap;
67f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.google.common.collect.SetMultimap;
68f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.CompilationUnitTree;
6976f3628361358abc328f92c107a7e11733dad1d7Dan Brownimport com.sun.source.tree.ExpressionTree;
70f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.Tree;
715534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernstimport com.sun.source.util.TreePath;
7204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntry;
73de7d64fbe7b6eb28b7ec1a2393b91b8e9c6afea6Dan Brownimport com.sun.tools.javac.main.CommandLine;
74b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brownimport com.sun.tools.javac.tree.JCTree;
7510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
7610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali/**
7710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * This is the main class for the annotator, which inserts annotations in
78c15d52e959f2b3052978e40552159de77c403428Michael Ernst * Java source code.  You can call it as <tt>java annotator.Main</tt> or by
79c15d52e959f2b3052978e40552159de77c403428Michael Ernst * using the shell script <tt>insert-annotations-to-source</tt>.
80c15d52e959f2b3052978e40552159de77c403428Michael Ernst * <p>
81c15d52e959f2b3052978e40552159de77c403428Michael Ernst *
82c15d52e959f2b3052978e40552159de77c403428Michael Ernst * It takes as input
8310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <ul>
8476be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl *   <li>annotation (index) files, which indicate the annotations to insert</li>
8510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali *   <li>Java source files, into which the annotator inserts annotations</li>
8610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * </ul>
87b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * Annotations that are not for the specified Java files are ignored.
8810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <p>
8910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali *
90b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * The <a name="command-line-options">command-line options</a> are as follows:
91b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * <!-- start options doc (DO NOT EDIT BY HAND) -->
92b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * <ul>
93b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   <li id="optiongroup:General-options">General options
94b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     <ul>
95b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:outdir"><b>-d</b> <b>--outdir=</b><i>directory</i>. Directory in which output files are written. [default annotated/]</li>
96b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:in-place"><b>-i</b> <b>--in-place=</b><i>boolean</i>. If true, overwrite original source files (making a backup first).
97b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  Furthermore, if the backup files already exist, they are used instead
98b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  of the .java files.  This behavior permits a user to tweak the .jaif
99b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  file and re-run the annotator.
100b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  <p>
1014ae81f26445bc9397bd3e1edb062e0388ed82a6fMichael Ernst *
102b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  Note that if the user runs the annotator with --in-place, makes edits,
103b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  and then re-runs the annotator with this --in-place option, those
104b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  edits are lost.  Similarly, if the user runs the annotator twice in a
105b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  row with --in-place, only the last set of annotations will appear in
106b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  the codebase at the end.
107b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  <p>
1084ae81f26445bc9397bd3e1edb062e0388ed82a6fMichael Ernst *
109b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  To preserve changes when using the --in-place option, first remove the
110b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  backup files.  Or, use the <tt>-d .</tt> option, which makes (and
111b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  reads) no backup, instead of --in-place. [default false]</li>
112b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:abbreviate"><b>-a</b> <b>--abbreviate=</b><i>boolean</i>. Abbreviate annotation names [default true]</li>
113b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:comments"><b>-c</b> <b>--comments=</b><i>boolean</i>. Insert annotations in comments [default false]</li>
114b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:omit-annotation"><b>-o</b> <b>--omit-annotation=</b><i>string</i>. Omit given annotation</li>
115b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:nowarn"><b>--nowarn=</b><i>boolean</i>. Suppress warnings about disallowed insertions [default false]</li>
116b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:convert-jaifs"><b>--convert-jaifs=</b><i>boolean</i>. Convert JAIFs to new format [default false]</li>
117b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:help"><b>-h</b> <b>--help=</b><i>boolean</i>. Print usage information and exit [default false]</li>
118b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     </ul>
119b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   </li>
120b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   <li id="optiongroup:Debugging-options">Debugging options
121b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     <ul>
122b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:verbose"><b>-v</b> <b>--verbose=</b><i>boolean</i>. Verbose (print progress information) [default false]</li>
123b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:debug"><b>--debug=</b><i>boolean</i>. Debug (print debug information) [default false]</li>
124b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:print-error-stack"><b>--print-error-stack=</b><i>boolean</i>. Print error stack [default false]</li>
125b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     </ul>
126b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   </li>
127b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * </ul>
128b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * <!-- end options doc -->
12910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali */
13010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Alipublic class Main {
13110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
13210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  /** Directory in which output files are written. */
133b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst  @OptionGroup("General options")
13410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-d <directory> Directory in which output files are written")
13510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static String outdir = "annotated/";
13610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
137fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst  /**
138fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * If true, overwrite original source files (making a backup first).
139fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * Furthermore, if the backup files already exist, they are used instead
140fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * of the .java files.  This behavior permits a user to tweak the .jaif
141fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * file and re-run the annotator.
142fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * <p>
143fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   *
144fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * Note that if the user runs the annotator with --in-place, makes edits,
145fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * and then re-runs the annotator with this --in-place option, those
146fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * edits are lost.  Similarly, if the user runs the annotator twice in a
147fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * row with --in-place, only the last set of annotations will appear in
148fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * the codebase at the end.
149fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * <p>
150fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   *
151fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * To preserve changes when using the --in-place option, first remove the
152fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * backup files.  Or, use the <tt>-d .</tt> option, which makes (and
153fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * reads) no backup, instead of --in-place.
154fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   */
155f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst  @Option("-i Overwrite original source files")
156f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst  public static boolean in_place = false;
157f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
15810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-a Abbreviate annotation names")
15910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean abbreviate = true;
16010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
16110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-c Insert annotations in comments")
16210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean comments = false;
16310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
164bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst  @Option("-o Omit given annotation")
165bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst  public static String omit_annotation;
166bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst
1677a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  @Option("Suppress warnings about disallowed insertions")
1687a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  public static boolean nowarn;
1697a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst
17040cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown  // Instead of doing insertions, create new JAIFs using AST paths
17140cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown  //  extracted from existing JAIFs and source files they match
17240cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown  @Option("Convert JAIFs to AST Path format")
1737a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  public static boolean convert_jaifs = false;
1747a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst
17538326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst  @Option("-h Print usage information and exit")
17638326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst  public static boolean help = false;
17738326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst
1787a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  // Debugging options go below here.
1797a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst
180b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst  @OptionGroup("Debugging options")
18110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-v Verbose (print progress information)")
18210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean verbose;
18310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
18410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("Debug (print debug information)")
18510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean debug = false;
18610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
1878b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak  @Option("Print error stack")
1888b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak  public static boolean print_error_stack = false;
1898b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak
19004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  private static ElementVisitor<Void, AElement> classFilter =
19104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      new ElementVisitor<Void, AElement>() {
19204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    <K, V extends AElement>
19304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Void filter(VivifyingMap<K, V> vm0, VivifyingMap<K, V> vm1) {
19404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      for (Map.Entry<K, V> entry : vm0.entrySet()) {
19504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry.getValue().accept(this, vm1.vivify(entry.getKey()));
19604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
19704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
19804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
19904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
20004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
20104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitAnnotationDef(AnnotationDef def, AElement el) {
20204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      // not used, since package declarations not handled here
20304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
20404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
20504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
20604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
20704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitBlock(ABlock el0, AElement el) {
20804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ABlock el1 = (ABlock) el;
20904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.locals, el1.locals);
21004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitExpression(el0, el);
21104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
21204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
21304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
21404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitClass(AClass el0, AElement el) {
21504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AClass el1 = (AClass) el;
21604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.methods, el1.methods);
21704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.fields, el1.fields);
21804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.fieldInits, el1.fieldInits);
21904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.staticInits, el1.staticInits);
22004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.instanceInits, el1.instanceInits);
22104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitDeclaration(el0, el);
22204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
22304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
22404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
22504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitDeclaration(ADeclaration el0, AElement el) {
22604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ADeclaration el1 = (ADeclaration) el;
22704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      VivifyingMap<ASTPath, ATypeElement> insertAnnotations =
22804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el1.insertAnnotations;
22904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      VivifyingMap<ASTPath, ATypeElementWithType> insertTypecasts =
23004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el1.insertTypecasts;
23104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      for (Map.Entry<ASTPath, ATypeElement> entry :
23204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el0.insertAnnotations.entrySet()) {
23304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ASTPath p = entry.getKey();
23404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ATypeElement e = entry.getValue();
23504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        insertAnnotations.put(p, e);
23652e8495fa4d3730f1ae8e4d97c01dbc24a7ea4a2Michael Ernst        // visitTypeElement(e, insertAnnotations.vivify(p));
23704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
23804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      for (Map.Entry<ASTPath, ATypeElementWithType> entry :
23904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el0.insertTypecasts.entrySet()) {
24004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ASTPath p = entry.getKey();
24104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ATypeElementWithType e = entry.getValue();
24204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        type.Type type = e.getType();
24304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        if (type instanceof type.DeclaredType
24404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            && ((type.DeclaredType) type).getName().isEmpty()) {
24504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          insertAnnotations.put(p, e);
24652e8495fa4d3730f1ae8e4d97c01dbc24a7ea4a2Michael Ernst          // visitTypeElement(e, insertAnnotations.vivify(p));
24704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        } else {
24804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          insertTypecasts.put(p, e);
24952e8495fa4d3730f1ae8e4d97c01dbc24a7ea4a2Michael Ernst          // visitTypeElementWithType(e, insertTypecasts.vivify(p));
25004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
25104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
25204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
25304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
25404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
25504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
25604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitExpression(AExpression el0, AElement el) {
25704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AExpression el1 = (AExpression) el;
25804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.typecasts, el1.typecasts);
25904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.instanceofs, el1.instanceofs);
26004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.news, el1.news);
26104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
26204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
26304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
26404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
26504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitField(AField el0, AElement el) {
26604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitDeclaration(el0, el);
26704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
26804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
26904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
27004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitMethod(AMethod el0, AElement el) {
27104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AMethod el1 = (AMethod) el;
27204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.bounds, el1.bounds);
27304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.parameters, el1.parameters);
27404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.throwsException, el1.throwsException);
27504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el0.returnType.accept(this, el1.returnType);
27604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el0.receiver.accept(this, el1.receiver);
27704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el0.body.accept(this, el1.body);
27804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitDeclaration(el0, el);
27904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
28004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
28104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
28204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitTypeElement(ATypeElement el0, AElement el) {
28304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ATypeElement el1 = (ATypeElement) el;
28404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.innerTypes, el1.innerTypes);
28504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
28604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
28704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
28804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
28904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitTypeElementWithType(ATypeElementWithType el0,
29004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        AElement el) {
29104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ATypeElementWithType el1 = (ATypeElementWithType) el;
29204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el1.setType(el0.getType());
29304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitTypeElement(el0, el);
29404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
29504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
29604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
29704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitElement(AElement el, AElement arg) {
29804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
29904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
30004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  };
30104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
30204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  private static AScene filteredScene(final AScene scene) {
30304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    final AScene filtered = new AScene();
30404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    filtered.packages.putAll(scene.packages);
30504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    filtered.imports.putAll(scene.imports);
30604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    for (Map.Entry<String, AClass> entry : scene.classes.entrySet()) {
30704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      String key = entry.getKey();
30804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AClass clazz0 = entry.getValue();
30904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AClass clazz1 = filtered.classes.vivify(key);
31004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      clazz0.accept(classFilter, clazz1);
31104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
31204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    filtered.prune();
31304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    return filtered;
31404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  }
31504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
31604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  private static ATypeElement findInnerTypeElement(Tree t,
317d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown      ASTRecord rec, ADeclaration decl, Type type, Insertion ins) {
31804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    ASTPath astPath = rec.astPath;
31904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    GenericArrayLocationCriterion galc =
32004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ins.getCriteria().getGenericArrayLocation();
32104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    assert astPath != null && galc != null;
32204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    List<TypePathEntry> tpes = galc.getLocation();
32304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    ASTPath.ASTEntry entry;
32404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    for (TypePathEntry tpe : tpes) {
32504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      switch (tpe.tag) {
32604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case ARRAY:
32704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        if (!astPath.isEmpty()) {
32804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          entry = astPath.get(-1);
32904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          if (entry.getTreeKind() == Tree.Kind.NEW_ARRAY
33004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              && entry.childSelectorIs(ASTPath.TYPE)) {
33104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            entry = new ASTPath.ASTEntry(Tree.Kind.NEW_ARRAY,
33204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                ASTPath.TYPE, entry.getArgument() + 1);
33304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            break;
33404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
33504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
33604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.ARRAY_TYPE,
33704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.TYPE);
33804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
33904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case INNER_TYPE:
34004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.MEMBER_SELECT,
34104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.EXPRESSION);
34204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
34304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case TYPE_ARGUMENT:
34404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.PARAMETERIZED_TYPE,
34504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.TYPE_ARGUMENT, tpe.arg);
34604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
34704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case WILDCARD:
34804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.UNBOUNDED_WILDCARD,
34904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.BOUND);
35004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
35104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      default:
35204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        throw new IllegalArgumentException("unknown type tag " + tpe.tag);
35304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
354d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown      astPath = astPath.extend(entry);
35504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
35604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
35704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    return decl.insertAnnotations.vivify(astPath);
35804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  }
35904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
3602a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown  private static void convertInsertion(String pkg,
3612a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      JCTree.JCCompilationUnit tree, ASTRecord rec, Insertion ins,
3622a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      AScene scene, Multimap<Insertion, Annotation> insertionSources) {
3632a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    Collection<Annotation> annos = insertionSources.get(ins);
3642a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    if (rec == null) {
3652a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (ins.getCriteria().isOnPackage()) {
3662a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        for (Annotation anno : annos) {
3672a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          scene.packages.get(pkg).tlAnnotationsHere.add(anno);
3682a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
3692a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
3702a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    } else if (scene != null && rec.className != null) {
3712a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      AClass clazz = scene.classes.vivify(rec.className);
3722a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      ADeclaration decl = null;  // insertion target
3732a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (ins.getCriteria().onBoundZero()) {
3742a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        int n = rec.astPath.size();
3752a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (!rec.astPath.get(n-1).childSelectorIs(ASTPath.BOUND)) {
3762a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          ASTPath astPath = ASTPath.empty();
3772a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          for (int i = 0; i < n; i++) {
3782a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            astPath = astPath.extend(rec.astPath.get(i));
3792a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
3802a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          astPath = astPath.extend(
3812a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              new ASTPath.ASTEntry(Tree.Kind.TYPE_PARAMETER,
3822a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  ASTPath.BOUND, 0));
3832a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          rec = rec.replacePath(astPath);
3842a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
3852a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
3862a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (rec.methodName == null) {
3872a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        decl = rec.varName == null ? clazz
3882a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            : clazz.fields.vivify(rec.varName);
3892a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      } else {
3902a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        AMethod meth = clazz.methods.vivify(rec.methodName);
3912a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (rec.varName == null) {
3922a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          decl = meth;  // ?
3932a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        } else {
3942a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          try {
3952a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            int i = Integer.parseInt(rec.varName);
3962a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            decl = i < 0 ? meth.receiver
3972a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                : meth.parameters.vivify(i);
3982a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          } catch (NumberFormatException e) {
3992a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            TreePath path = ASTIndex.getTreePath(tree, rec);
4002a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            JCTree.JCVariableDecl varTree = null;
4012a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            JCTree.JCMethodDecl methTree = null;
4022a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            JCTree.JCClassDecl classTree = null;
4032a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            loop:
4042a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              while (path != null) {
4052a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                Tree leaf = path.getLeaf();
4062a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                switch (leaf.getKind()) {
4072a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case VARIABLE:
4082a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  varTree = (JCTree.JCVariableDecl) leaf;
4092a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  break;
4102a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case METHOD:
4112a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  methTree = (JCTree.JCMethodDecl) leaf;
4122a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  break;
4132a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case ANNOTATION:
4142a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case CLASS:
4152a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case ENUM:
4162a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case INTERFACE:
4172a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  break loop;
4182a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                default:
4192a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  path = path.getParentPath();
4202a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                }
4212a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4222a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            while (path != null) {
4232a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              Tree leaf = path.getLeaf();
4242a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              Tree.Kind kind = leaf.getKind();
4252a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              if (kind == Tree.Kind.METHOD) {
4262a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                methTree = (JCTree.JCMethodDecl) leaf;
4272a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int i = LocalVariableScanner.indexOfVarTree(path,
4282a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                    varTree, rec.varName);
4292a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int m = methTree.getStartPosition();
4302a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int a = varTree.getStartPosition();
4312a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int b = varTree.getEndPosition(tree.endPositions);
4322a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                LocalLocation loc = new LocalLocation(i, a-m, b-a);
4332a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                decl = meth.body.locals.vivify(loc);
4342a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                break;
4352a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4362a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              if (ASTPath.isClassEquiv(kind)) {
4372a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                classTree = (JCTree.JCClassDecl) leaf;
4382a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                // ???
4392a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                    break;
4402a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4412a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              path = path.getParentPath();
4422a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            }
4432a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
4442a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4452a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
4462a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (decl != null) {
4472a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        AElement el;
4482a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (rec.astPath.isEmpty()) {
4492a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el = decl;
4502a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        } else if (ins.getKind() == Insertion.Kind.CAST) {
4512a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          annotations.el.ATypeElementWithType elem =
4522a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              decl.insertTypecasts.vivify(rec.astPath);
4532a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          elem.setType(((CastInsertion) ins).getType());
4542a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el = elem;
4552a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        } else {
4562a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el = decl.insertAnnotations.vivify(rec.astPath);
4572a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4582a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        for (Annotation anno : annos) {
4592a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el.tlAnnotationsHere.add(anno);
4602a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4612a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (ins instanceof TypedInsertion) {
4622a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          TypedInsertion ti = (TypedInsertion) ins;
4632a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          if (!rec.astPath.isEmpty()) {
46452e8495fa4d3730f1ae8e4d97c01dbc24a7ea4a2Michael Ernst            // addInnerTypePaths(decl, rec, ti, insertionSources);
4652a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
4662a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          for (Insertion inner : ti.getInnerTypeInsertions()) {
4672a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            Tree t = ASTIndex.getNode(tree, rec);
4682a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            if (t != null) {
4692a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              ATypeElement elem = findInnerTypeElement(t,
4702a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  rec, decl, ti.getType(), inner);
4712a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              for (Annotation a : insertionSources.get(inner)) {
4722a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                elem.tlAnnotationsHere.add(a);
4732a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4742a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            }
4752a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
4762a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4772a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
4782a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    }
4792a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown  }
4802a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown
4812a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown
48210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  // Implementation details:
48310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //  1. The annotator partially compiles source
48410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     files using the compiler API (JSR-199), obtaining an AST.
48510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //  2. The annotator reads the specification file, producing a set of
48610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     annotator.find.Insertions.  Insertions completely specify what to
48710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     write (as a String, which is ultimately translated according to the
48810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     keyword file) and how to write it (as annotator.find.Criteria).
48910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //  3. It then traverses the tree, looking for nodes that satisfy the
49010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     Insertion Criteria, translating the Insertion text against the
49110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     keyword file, and inserting the annotations into the source file.
49210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
49310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  /**
49410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali   * Runs the annotator, parsing the source and spec files and applying
49510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali   * the annotations.
49610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali   */
497de7d64fbe7b6eb28b7ec1a2393b91b8e9c6afea6Dan Brown  public static void main(String[] args) throws IOException {
49810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
49910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    if (verbose) {
50067693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst      System.out.printf("insert-annotations-to-source (%s)",
50167693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst                        annotations.io.classfile.ClassFileReader.INDEX_UTILS_VERSION);
50210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
50310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
504e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown    Options options = new Options(
505a60ebb590bc5ff3836cc4afd1b85bd930fe72a44Michael Ernst        "Main [options] { jaif-file | java-file | @arg-file } ...\n"
506e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown            + "(Contents of argfiles are expanded into the argument list.)",
507e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown        Main.class);
5080ab9de82370c7e2890fd532eca754342a962b452Dan Brown    String[] file_args;
509de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown    try {
510de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      String[] cl_args = CommandLine.parse(args);
511de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      file_args = options.parse_or_usage(cl_args);
512de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown    } catch (IOException ex) {
513de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.err.println(ex);
514e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown      System.err.println("(For non-argfile beginning with \"@\", use \"@@\" for initial \"@\".");
515de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.err.println("Alternative for filenames: indicate directory, e.g. as './@file'.");
516de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.err.println("Alternative for flags: use '=', as in '-o=@Deprecated'.)");
5170ab9de82370c7e2890fd532eca754342a962b452Dan Brown      file_args = null;  // Eclipse compiler issue workaround
518de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.exit(1);
519de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown    }
520f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
5218819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    DebugWriter dbug = new DebugWriter();
5228819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    DebugWriter verb = new DebugWriter();
5238819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    DebugWriter both = dbug.or(verb);
5248819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    dbug.setEnabled(debug);
5258819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    verb.setEnabled(verbose);
5269849f43e0d770ee036b568dbba96d4e6a2a2b270Dan Brown    TreeFinder.warn.setEnabled(!nowarn);
5278819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    TreeFinder.stak.setEnabled(print_error_stack);
5288819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    TreeFinder.dbug.setEnabled(debug);
5298819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    Criteria.dbug.setEnabled(debug);
5301220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst
53110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    if (help) {
53210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      options.print_usage();
53310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      System.exit(0);
53410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
53510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
536f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst    if (in_place && outdir != "annotated/") { // interned
537f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      options.print_usage("The --outdir and --in-place options are mutually exclusive.");
538f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      System.exit(1);
539f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst    }
540f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
54110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    if (file_args.length < 2) {
542f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      options.print_usage("Supplied %d arguments, at least 2 needed%n", file_args.length);
54310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      System.exit(1);
54410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
54510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
54610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    // The insertions specified by the annotation files.
547290791bf3ace51eca8cb637b47e1e1d01d92111dDan Brown    Insertions insertions = new Insertions();
54810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    // The Java files into which to insert.
54910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    List<String> javafiles = new ArrayList<String>();
550d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown
5514ae81f26445bc9397bd3e1edb062e0388ed82a6fMichael Ernst    // Indices to maintain insertion source traces.
55204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Map<String, Multimap<Insertion, Annotation>> insertionIndex =
55304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        new HashMap<String, Multimap<Insertion, Annotation>>();
55404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Map<Insertion, String> insertionOrigins = new HashMap<Insertion, String>();
55504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Map<String, AScene> scenes = new HashMap<String, AScene>();
556e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown
557e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown    IndexFileParser.setAbbreviate(abbreviate);
55810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    for (String arg : file_args) {
55910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      if (arg.endsWith(".java")) {
56010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        javafiles.add(arg);
5618ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl      } else if (arg.endsWith(".jaif") ||
5628ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl                 arg.endsWith(".jann")) {
56304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        IndexFileSpecification spec = new IndexFileSpecification(arg);
56410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        try {
56510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          List<Insertion> parsedSpec = spec.parse();
56604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          AScene scene = spec.getScene();
56770918686c71c2030c56e623a9427f05b99338a5eDan Brown          Collections.sort(parsedSpec, new Comparator<Insertion>() {
56804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            @Override
56904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            public int compare(Insertion i1, Insertion i2) {
57004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              ASTPath p1 = i1.getCriteria().getASTPath();
57104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              ASTPath p2 = i2.getCriteria().getASTPath();
57204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              return p1 == null
57304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                  ? p2 == null ? 0 : -1
57404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                  : p2 == null ? 1 : p1.compareTo(p2);
57504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            }
57604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          });
57740cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown          if (convert_jaifs) {
5789967de5fe4b0240e9b5169020aec35fb29cdfb83Dan Brown            scenes.put(arg, filteredScene(scene));
57940cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            for (Insertion ins : parsedSpec) {
58040cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown              insertionOrigins.put(ins, arg);
58140cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            }
58240cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            if (!insertionIndex.containsKey(arg)) {
58340cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown              insertionIndex.put(arg,
58440cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown                  LinkedHashMultimap.<Insertion, Annotation>create());
58540cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            }
58640cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            insertionIndex.get(arg).putAll(spec.insertionSources());
58704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
5888819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          both.debug("Read %d annotations from %s%n", parsedSpec.size(), arg);
589bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst          if (omit_annotation != null) {
5908819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            List<Insertion> filtered =
5918819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                new ArrayList<Insertion>(parsedSpec.size());
592bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst            for (Insertion insertion : parsedSpec) {
5932441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak              // TODO: this won't omit annotations if the insertion is more than
5942441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak              // just the annotation (such as if the insertion is a cast
5952441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak              // insertion or a 'this' parameter in a method declaration).
596bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst              if (! omit_annotation.equals(insertion.getText())) {
597bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst                filtered.add(insertion);
598bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst              }
599bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst            }
600bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst            parsedSpec = filtered;
6018819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            both.debug("After filtering: %d annotations from %s%n",
6028819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                parsedSpec.size(), arg);
603bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst          }
604bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst          insertions.addAll(parsedSpec);
6052c4067b440b23911687e4a353584b088eccf17fbMichael Ernst        } catch (RuntimeException e) {
6062c4067b440b23911687e4a353584b088eccf17fbMichael Ernst          if (e.getCause() != null
6072c4067b440b23911687e4a353584b088eccf17fbMichael Ernst              && e.getCause() instanceof FileNotFoundException) {
6082c4067b440b23911687e4a353584b088eccf17fbMichael Ernst            System.err.println("File not found: " + arg);
6092c4067b440b23911687e4a353584b088eccf17fbMichael Ernst            System.exit(1);
6102c4067b440b23911687e4a353584b088eccf17fbMichael Ernst          } else {
6112c4067b440b23911687e4a353584b088eccf17fbMichael Ernst            throw e;
6122c4067b440b23911687e4a353584b088eccf17fbMichael Ernst          }
61310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        } catch (FileIOException e) {
614bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          // Add 1 to the line number since line numbers in text editors are usually one-based.
615bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          System.err.println("Error while parsing annotation file " + arg + " at line "
616bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak              + (e.lineNumber + 1) + ":");
61710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          if (e.getMessage() != null) {
618bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak            System.err.println('\t' + e.getMessage());
619bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          }
620bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          if (e.getCause() != null && e.getCause().getMessage() != null) {
621bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak            System.err.println('\t' + e.getCause().getMessage());
622bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          }
6238819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          if (print_error_stack) {
624bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak            e.printStackTrace();
62510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          }
62610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          System.exit(1);
62710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
62810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      } else {
62910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        throw new Error("Unrecognized file extension: " + arg);
63010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
63110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
63210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
6338819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    if (dbug.isEnabled()) {
6348819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      dbug.debug("%d insertions, %d .java files%n",
6358819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          insertions.size(), javafiles.size());
6368819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      dbug.debug("Insertions:%n");
63710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      for (Insertion insertion : insertions) {
6388819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        dbug.debug("  %s%n", insertion);
63910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
64010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
64110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
64210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    for (String javafilename : javafiles) {
6438819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      verb.debug("Processing %s%n", javafilename);
64410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
645f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      File javafile = new File(javafilename);
646f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      File unannotated = new File(javafilename + ".unannotated");
647f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      if (in_place) {
648f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // It doesn't make sense to check timestamps;
649f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // if the .java.unannotated file exists, then just use it.
650f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // A user can rename that file back to just .java to cause the
651f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // .java file to be read.
652f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        if (unannotated.exists()) {
6538819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          verb.debug("Renaming %s to %s%n", unannotated, javafile);
654f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          boolean success = unannotated.renameTo(javafile);
655f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          if (! success) {
656f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst            throw new Error(String.format("Failed renaming %s to %s",
657f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst                                          unannotated, javafile));
658f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          }
659f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        }
660f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      }
661f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
66276f3628361358abc328f92c107a7e11733dad1d7Dan Brown      String fileSep = System.getProperty("file.separator");
66310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      String fileLineSep = System.getProperty("line.separator");
66410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      Source src;
66510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      // Get the source file, and use it to obtain parse trees.
66610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      try {
66710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        // fileLineSep is set here so that exceptions can be caught
66810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        fileLineSep = UtilMDE.inferLineSeparator(javafilename);
66910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        src = new Source(javafilename);
6708819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        verb.debug("Parsed %s%n", javafilename);
67104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      } catch (Source.CompilerException e) {
67210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        e.printStackTrace();
67310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return;
67410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      } catch (IOException e) {
67510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        e.printStackTrace();
67610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return;
67710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
67810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
679c31338b45a78642c9b21cce154949870ea826abbDan Brown      // Imports required to resolve annotations (when abbreviate==true).
680c31338b45a78642c9b21cce154949870ea826abbDan Brown      LinkedHashSet<String> imports = new LinkedHashSet<String>();
681c15d52e959f2b3052978e40552159de77c403428Michael Ernst      int num_insertions = 0;
68276f3628361358abc328f92c107a7e11733dad1d7Dan Brown      String pkg = "";
683c15d52e959f2b3052978e40552159de77c403428Michael Ernst
684b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brown      for (CompilationUnitTree cut : src.parse()) {
685b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brown        JCTree.JCCompilationUnit tree = (JCTree.JCCompilationUnit) cut;
68676f3628361358abc328f92c107a7e11733dad1d7Dan Brown        ExpressionTree pkgExp = cut.getPackageName();
68776f3628361358abc328f92c107a7e11733dad1d7Dan Brown        pkg = pkgExp == null ? "" : pkgExp.toString();
68810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
68910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        // Create a finder, and use it to get positions.
69010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        TreeFinder finder = new TreeFinder(tree);
69152dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        SetMultimap<Pair<Integer, ASTPath>, Insertion> positions =
6928819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            finder.getPositions(tree, insertions);
69310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
69404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        if (convert_jaifs) {
69504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          // program used only for JAIF conversion; execute following
6964ae81f26445bc9397bd3e1edb062e0388ed82a6fMichael Ernst          // block and then skip remainder of loop
697d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown          Multimap<ASTRecord, Insertion> astInsertions =
69804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              finder.getPaths();
699d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown          for (Map.Entry<ASTRecord, Collection<Insertion>> entry :
70004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              astInsertions.asMap().entrySet()) {
701d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown            ASTRecord rec = entry.getKey();
70204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            for (Insertion ins : entry.getValue()) {
70304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              if (ins.getCriteria().getASTPath() != null) { continue; }
70404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              String arg = insertionOrigins.get(ins);
70504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              AScene scene = scenes.get(arg);
70604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              Multimap<Insertion, Annotation> insertionSources =
70704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                  insertionIndex.get(arg);
70852e8495fa4d3730f1ae8e4d97c01dbc24a7ea4a2Michael Ernst              // String text =
70904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              //  ins.getText(comments, abbreviate, false, 0, '\0');
71004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
71104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              // TODO: adjust for missing end of path (?)
71204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
71304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              if (insertionSources.containsKey(ins)) {
7142a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                convertInsertion(pkg, tree, rec, ins, scene, insertionSources);
71504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              }
71604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            }
71704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
71804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          continue;
71904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
72004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
72110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        // Apply the positions to the source file.
7228819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        if (both.isEnabled()) {
7238819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          System.err.printf(
7248819fd6c8f50083311182795717e23e88cd04ac5Dan Brown              "getPositions returned %d positions in tree for %s%n",
7258819fd6c8f50083311182795717e23e88cd04ac5Dan Brown              positions.size(), javafilename);
72610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
72710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
72852dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        Set<Pair<Integer, ASTPath>> positionKeysUnsorted =
72952dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown            positions.keySet();
73052dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        Set<Pair<Integer, ASTPath>> positionKeysSorted =
73152dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown          new TreeSet<Pair<Integer, ASTPath>>(
73252dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown              new Comparator<Pair<Integer, ASTPath>>() {
73352dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                @Override
73452dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                public int compare(Pair<Integer, ASTPath> p1,
73552dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                    Pair<Integer, ASTPath> p2) {
73652dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  int c = Integer.compare(p2.a, p1.a);
73752dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  if (c == 0) {
73852dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                    c = p2.b == null ? p1.b == null ? 0 : -1
73952dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                        : p1.b == null ? 1 : p2.b.compareTo(p1.b);
74052dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  }
74152dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  return c;
74252dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                }
74352dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown              });
74457ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst        positionKeysSorted.addAll(positionKeysUnsorted);
74552dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        for (Pair<Integer, ASTPath> pair : positionKeysSorted) {
746c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown          boolean receiverInserted = false;
74784a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown          boolean newInserted = false;
7480b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown          boolean constructorInserted = false;
74952dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown          Set<String> seen = new TreeSet<String>();
75052dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown          List<Insertion> toInsertList = new ArrayList<Insertion>(positions.get(pair));
751ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst          Collections.reverse(toInsertList);
752553a9a9a17ce582f701841b59edfadb491ed54adDan Brown          dbug.debug("insertion pos: %d%n", pair.a);
753553a9a9a17ce582f701841b59edfadb491ed54adDan Brown          assert pair.a >= 0
754553a9a9a17ce582f701841b59edfadb491ed54adDan Brown            : "pos is negative: " + pair.a + " " + toInsertList.get(0) + " " + javafilename;
755ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst          for (Insertion iToInsert : toInsertList) {
756ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            // Possibly add whitespace after the insertion
7573d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            String trailingWhitespace = "";
758ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            boolean gotSeparateLine = false;
759553a9a9a17ce582f701841b59edfadb491ed54adDan Brown            int pos = pair.a;  // reset each iteration in case of dyn adjustment
760ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            if (iToInsert.getSeparateLine()) {
761a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst              // System.out.printf("getSeparateLine=true for insertion at pos %d: %s%n", pos, iToInsert);
762ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              int indentation = 0;
763ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              while ((pos - indentation != 0)
764ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                     // horizontal whitespace
765ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                     && (src.charAt(pos-indentation-1) == ' '
766ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                         || src.charAt(pos-indentation-1) == '\t')) {
767a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst                // System.out.printf("src.charAt(pos-indentation-1 == %d-%d-1)='%s'%n",
768a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst                //                   pos, indentation, src.charAt(pos-indentation-1));
769ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                indentation++;
770ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              }
771ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              if ((pos - indentation == 0)
772ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                  // horizontal whitespace
773ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                  || (src.charAt(pos-indentation-1) == '\f'
774ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                      || src.charAt(pos-indentation-1) == '\n'
775ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                      || src.charAt(pos-indentation-1) == '\r')) {
7763d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak                trailingWhitespace = fileLineSep + src.substring(pos-indentation, pos);
777ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                gotSeparateLine = true;
778ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              }
779ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            }
780c71d4e21017f8f4412a2d399676e358858999623Michael Ernst
7813d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            char precedingChar;
7823d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            if (pos != 0) {
7833d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak              precedingChar = src.charAt(pos - 1);
7843d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            } else {
7853d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak              precedingChar = '\0';
7863d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            }
787afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown
788afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown            if (iToInsert.getKind() == Insertion.Kind.ANNOTATION) {
789afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown              AnnotationInsertion ai = (AnnotationInsertion) iToInsert;
790dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown              if (ai.isGenerateBound()) {  // avoid multiple ampersands
791dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                try {
792dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  String s = src.substring(pos, pos+9);
793dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  if ("Object & ".equals(s)) {
794dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                    ai.setGenerateBound(false);
795dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                    precedingChar = '.';  // suppress leading space
796dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  }
797dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                } catch (StringIndexOutOfBoundsException e) {}
798dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown              }
799afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown              if (ai.isGenerateExtends()) {  // avoid multiple "extends"
800afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                try {
801dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  String s = src.substring(pos, pos+9);
802dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  if (" extends ".equals(s)) {
803afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                    ai.setGenerateExtends(false);
804553a9a9a17ce582f701841b59edfadb491ed54adDan Brown                    pos += 8;
805afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                  }
806afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                } catch (StringIndexOutOfBoundsException e) {}
807afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown              }
808afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown            } else if (iToInsert.getKind() == Insertion.Kind.CAST) {
8095491118a39a8545a38eb1a94bbc5f5a00a0b9beeDan Brown                ((CastInsertion) iToInsert)
8105491118a39a8545a38eb1a94bbc5f5a00a0b9beeDan Brown                        .setOnArrayLiteral(src.charAt(pos) == '{');
811afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown            } else if (iToInsert.getKind() == Insertion.Kind.RECEIVER) {
812c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown              ReceiverInsertion ri = (ReceiverInsertion) iToInsert;
813c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown              ri.setAnnotationsOnly(receiverInserted);
814c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown              receiverInserted = true;
81584a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            } else if (iToInsert.getKind() == Insertion.Kind.NEW) {
81684a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown              NewInsertion ni = (NewInsertion) iToInsert;
81784a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown              ni.setAnnotationsOnly(newInserted);
81884a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown              newInserted = true;
8190b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown            } else if (iToInsert.getKind() == Insertion.Kind.CONSTRUCTOR) {
8200b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown              ConstructorInsertion ci = (ConstructorInsertion) iToInsert;
8210b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown              if (constructorInserted) { ci.setAnnotationsOnly(true); }
8220b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown              constructorInserted = true;
823c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown            }
824c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown
8253d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            String toInsert = iToInsert.getText(comments, abbreviate,
8268819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                gotSeparateLine, pos, precedingChar) + trailingWhitespace;
82752dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown            if (seen.contains(toInsert)) { continue; }  // eliminate duplicates
82852dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown            seen.add(toInsert);
829ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst
830ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            // If it's already there, don't re-insert.  This is a hack!
831ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            // Also, I think this is already checked when constructing the
83276be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl            // insertions.
833ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            int precedingTextPos = pos-toInsert.length()-1;
834ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            if (precedingTextPos >= 0) {
835ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              String precedingTextPlusChar
836ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                = src.getString().substring(precedingTextPos, pos);
8378819fd6c8f50083311182795717e23e88cd04ac5Dan Brown              if (toInsert.equals(
8388819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                      precedingTextPlusChar.substring(0, toInsert.length()))
839ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                  || toInsert.equals(precedingTextPlusChar.substring(1))) {
8408819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                dbug.debug(
8418819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                    "Inserting %s at %d in code of length %d with preceding text '%s'%n",
8428819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                    toInsert, pos, src.getString().length(),
8438819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                    precedingTextPlusChar);
8448819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                dbug.debug("Already present, skipping%n");
845ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                continue;
8464735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst              }
84710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali            }
8483d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak
84984a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            // TODO: Neither the above hack nor this check should be
85084a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            // necessary.  Find out why re-insertions still occur and
85184a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            // fix properly.
85284a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            if (iToInsert.getInserted()) { continue; }
853ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            src.insert(pos, toInsert);
8548920570aa95ef0072bafd2cccff03d194c478bf1Dan Brown            if (verbose && !debug) {
855c15d52e959f2b3052978e40552159de77c403428Michael Ernst              System.out.print(".");
856c15d52e959f2b3052978e40552159de77c403428Michael Ernst              num_insertions++;
857c15d52e959f2b3052978e40552159de77c403428Michael Ernst              if ((num_insertions % 50) == 0) {
858c15d52e959f2b3052978e40552159de77c403428Michael Ernst                System.out.println();   // terminate the line that contains dots
859c15d52e959f2b3052978e40552159de77c403428Michael Ernst              }
860c15d52e959f2b3052978e40552159de77c403428Michael Ernst            }
8618819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            dbug.debug("Post-insertion source: %n" + src.getString());
862c31338b45a78642c9b21cce154949870ea826abbDan Brown
863c31338b45a78642c9b21cce154949870ea826abbDan Brown            Set<String> packageNames = iToInsert.getPackageNames();
864c31338b45a78642c9b21cce154949870ea826abbDan Brown            if (!packageNames.isEmpty()) {
865c31338b45a78642c9b21cce154949870ea826abbDan Brown              dbug.debug("Need import %s%n  due to insertion %s%n",
866c31338b45a78642c9b21cce154949870ea826abbDan Brown                  packageNames, toInsert);
867c31338b45a78642c9b21cce154949870ea826abbDan Brown              imports.addAll(packageNames);
868c31338b45a78642c9b21cce154949870ea826abbDan Brown            }
86910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          }
87010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
87110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
87204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
87304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      if (convert_jaifs) {
87404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        for (Map.Entry<String, AScene> entry : scenes.entrySet()) {
87504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          String filename = entry.getKey();
87604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          AScene scene = entry.getValue();
87704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          try {
87804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            IndexFileWriter.write(scene, filename + ".converted");
87904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          } catch (DefException e) {
88004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            System.err.println(filename + ": " + " format error in conversion");
88104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            if (print_error_stack) {
88204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              e.printStackTrace();
88304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            }
88404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
88504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
88604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        return;  // done with conversion
88704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
88804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
8898819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      if (dbug.isEnabled()) {
8908819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        dbug.debug("%d imports to insert%n", imports.size());
89104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        for (String classname : imports) {
8928819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          dbug.debug("  %s%n", classname);
89304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
89404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
89504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
89610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      // insert import statements
89710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      {
89810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        Pattern importPattern = Pattern.compile("(?m)^import\\b");
89910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        Pattern packagePattern = Pattern.compile("(?m)^package\\b.*;(\\n|\\r\\n?)");
90010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        int importIndex = 0;      // default: beginning of file
90110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        String srcString = src.getString();
90204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        Matcher m = importPattern.matcher(srcString);
903059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown        Set<String> inSource = new TreeSet<String>();
90410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        if (m.find()) {
90510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          importIndex = m.start();
906059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown          do {
907059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            int i = m.start();
908059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            int j = srcString.indexOf(System.lineSeparator(), i) + 1;
909059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            if (j <= 0) {
910059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown              j = srcString.length();
911059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            }
912059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            String s = srcString.substring(i, j);
913059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            inSource.add(s);
914059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown          } while (m.find());
91510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        } else {
9168819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          // Debug.info("Didn't find import in " + srcString);
91710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          m = packagePattern.matcher(srcString);
91810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          if (m.find()) {
91910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali            importIndex = m.end();
92010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          }
92110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
92210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        for (String classname : imports) {
92310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          String toInsert = "import " + classname + ";" + fileLineSep;
924059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown          if (!inSource.contains(toInsert)) {
925059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            inSource.add(toInsert);
926059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            src.insert(importIndex, toInsert);
927059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown            importIndex += toInsert.length();
928059a80f28ad2932bf2f9cdff444d6087d51d176fDan Brown          }
92910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
93010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
93110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
93210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      // Write the source file.
93376f3628361358abc328f92c107a7e11733dad1d7Dan Brown      File outfile = null;
93410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      try {
935f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        if (in_place) {
93676f3628361358abc328f92c107a7e11733dad1d7Dan Brown          outfile = javafile;
937f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          if (verbose) {
938f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst            System.out.printf("Renaming %s to %s%n", javafile, unannotated);
939f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          }
940f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          boolean success = javafile.renameTo(unannotated);
941f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          if (! success) {
942f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst            throw new Error(String.format("Failed renaming %s to %s",
943f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst                                          javafile, unannotated));
944f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          }
945f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        } else {
94676f3628361358abc328f92c107a7e11733dad1d7Dan Brown          if (pkg.isEmpty()) {
94776f3628361358abc328f92c107a7e11733dad1d7Dan Brown            outfile = new File(outdir, javafile.getName());
94876f3628361358abc328f92c107a7e11733dad1d7Dan Brown          } else {
94976f3628361358abc328f92c107a7e11733dad1d7Dan Brown            String[] pkgPath = pkg.split("\\.");
95076f3628361358abc328f92c107a7e11733dad1d7Dan Brown            StringBuilder sb = new StringBuilder(outdir);
95176f3628361358abc328f92c107a7e11733dad1d7Dan Brown            for (int i = 0 ; i < pkgPath.length ; i++) {
95276f3628361358abc328f92c107a7e11733dad1d7Dan Brown              sb.append(fileSep).append(pkgPath[i]);
95376f3628361358abc328f92c107a7e11733dad1d7Dan Brown            }
95476f3628361358abc328f92c107a7e11733dad1d7Dan Brown            outfile = new File(sb.toString(), javafile.getName());
95576f3628361358abc328f92c107a7e11733dad1d7Dan Brown          }
956f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          outfile.getParentFile().mkdirs();
957f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        }
95810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        OutputStream output = new FileOutputStream(outfile);
959f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        if (verbose) {
960f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          System.out.printf("Writing %s%n", outfile);
961f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        }
96210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        src.write(output);
963f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        output.close();
96410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      } catch (IOException e) {
96510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        System.err.println("Problem while writing file " + outfile);
96610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        e.printStackTrace();
96710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        System.exit(1);
96810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
96910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
97010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  }
97110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
9725534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  public static String pathToString(TreePath path) {
973f363307b8c8b78b369f6770b2d0b95eccf6754c9Michael Ernst    if (path == null) {
9745534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      return "null";
975f363307b8c8b78b369f6770b2d0b95eccf6754c9Michael Ernst    }
976f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst    return treeToString(path.getLeaf());
977f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst  }
978f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst
979f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst  public static String treeToString(Tree node) {
980f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst    String asString = node.toString();
9815534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    String oneLine = firstLine(asString);
9825534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    return "\"" + oneLine + "\"";
9835534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  }
9845534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst
9855534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  /**
9865534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst   * Return the first non-empty line of the string, adding an ellipsis
9875534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst   * (...) if the string was truncated.
9885534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst   */
9895534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  public static String firstLine(String s) {
9905534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    while (s.startsWith("\n")) {
9915534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      s = s.substring(1);
9925534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    }
9935534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    int newlineIndex = s.indexOf('\n');
9945534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    if (newlineIndex == -1) {
9955534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      return s;
9965534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    } else {
9975534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      return s.substring(0, newlineIndex) + "...";
9985534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    }
9995534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  }
10005534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst
1001aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb  /**
1002aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   * Separates the annotation class from its arguments.
1003aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   *
1004aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   * @return given <code>@foo(bar)</code> it returns the pair <code>{ @foo, (bar) }</code>.
1005aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   */
1006aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb  public static Pair<String,String> removeArgs(String s) {
1007aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb    int pidx = s.indexOf("(");
1008aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb    return (pidx == -1) ?
1009615ec652dc360e33296fd763a4fa56e59c35b23cMichael Ernst        Pair.of(s, (String)null) :
1010aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb        Pair.of(s.substring(0, pidx), s.substring(pidx));
1011aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb  }
101210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali}
1013