Main.java revision 9967de5fe4b0240e9b5169020aec35fb29cdfb83
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;
13f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.LinkedHashSet;
14f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.List;
15e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brownimport java.util.Map;
16f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.Set;
17f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.TreeSet;
18f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Matcher;
19f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport java.util.regex.Pattern;
2010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
21f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.FileIOException;
22f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Option;
23b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernstimport plume.OptionGroup;
24f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Options;
25f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.Pair;
26f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport plume.UtilMDE;
2704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport type.Type;
2804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.Annotation;
2904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ABlock;
3004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AClass;
3104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ADeclaration;
3204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AElement;
3304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AExpression;
3404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AField;
3504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AMethod;
3604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AScene;
3704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ATypeElement;
3804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ATypeElementWithType;
3904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.AnnotationDef;
4004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.DefException;
4104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.ElementVisitor;
4204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.el.LocalLocation;
4304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.io.ASTIndex;
4404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.io.ASTPath;
45d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brownimport annotations.io.ASTRecord;
468819fd6c8f50083311182795717e23e88cd04ac5Dan Brownimport annotations.io.DebugWriter;
47e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brownimport annotations.io.IndexFileParser;
4804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.io.IndexFileWriter;
4904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotations.util.coll.VivifyingMap;
50afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brownimport annotator.find.AnnotationInsertion;
515491118a39a8545a38eb1a94bbc5f5a00a0b9beeDan Brownimport annotator.find.CastInsertion;
520b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brownimport annotator.find.ConstructorInsertion;
53e13e8963268c825e80bb92e310135617d7275656Eric Spishakimport annotator.find.Criteria;
5404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotator.find.GenericArrayLocationCriterion;
5510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.Insertion;
56290791bf3ace51eca8cb637b47e1e1d01d92111dDan Brownimport annotator.find.Insertions;
5784a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brownimport annotator.find.NewInsertion;
58c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brownimport annotator.find.ReceiverInsertion;
5910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.find.TreeFinder;
6004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotator.find.TypedInsertion;
6104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport annotator.scanner.LocalVariableScanner;
6210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport annotator.specification.IndexFileSpecification;
6310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
6404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport com.google.common.collect.LinkedHashMultimap;
6504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport com.google.common.collect.Multimap;
66f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.google.common.collect.SetMultimap;
67f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.CompilationUnitTree;
6876f3628361358abc328f92c107a7e11733dad1d7Dan Brownimport com.sun.source.tree.ExpressionTree;
69f41c057e252477de867dd3e5bd9d7bd33d6af4ebEric Spishakimport com.sun.source.tree.Tree;
705534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernstimport com.sun.source.util.TreePath;
7104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brownimport com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntry;
72de7d64fbe7b6eb28b7ec1a2393b91b8e9c6afea6Dan Brownimport com.sun.tools.javac.main.CommandLine;
73b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brownimport com.sun.tools.javac.tree.JCTree;
7410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
7510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali/**
7610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * This is the main class for the annotator, which inserts annotations in
77c15d52e959f2b3052978e40552159de77c403428Michael Ernst * Java source code.  You can call it as <tt>java annotator.Main</tt> or by
78c15d52e959f2b3052978e40552159de77c403428Michael Ernst * using the shell script <tt>insert-annotations-to-source</tt>.
79c15d52e959f2b3052978e40552159de77c403428Michael Ernst * <p>
80c15d52e959f2b3052978e40552159de77c403428Michael Ernst *
81c15d52e959f2b3052978e40552159de77c403428Michael Ernst * It takes as input
8210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <ul>
8376be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl *   <li>annotation (index) files, which indicate the annotations to insert</li>
8410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali *   <li>Java source files, into which the annotator inserts annotations</li>
8510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * </ul>
86b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * Annotations that are not for the specified Java files are ignored.
8710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <p>
8810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali *
89b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * The <a name="command-line-options">command-line options</a> are as follows:
90b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * <!-- start options doc (DO NOT EDIT BY HAND) -->
91b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * <ul>
92b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   <li id="optiongroup:General-options">General options
93b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     <ul>
94b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:outdir"><b>-d</b> <b>--outdir=</b><i>directory</i>. Directory in which output files are written. [default annotated/]</li>
95b890e553cf7b1ab5befaecd852618835aa451c3fMichael 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).
96b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  Furthermore, if the backup files already exist, they are used instead
97b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  of the .java files.  This behavior permits a user to tweak the .jaif
98b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  file and re-run the annotator.
99b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  <p>
100b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *
101b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  Note that if the user runs the annotator with --in-place, makes edits,
102b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  and then re-runs the annotator with this --in-place option, those
103b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  edits are lost.  Similarly, if the user runs the annotator twice in a
104b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  row with --in-place, only the last set of annotations will appear in
105b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  the codebase at the end.
106b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  <p>
107b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *
108b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  To preserve changes when using the --in-place option, first remove the
109b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  backup files.  Or, use the <tt>-d .</tt> option, which makes (and
110b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *  reads) no backup, instead of --in-place. [default false]</li>
111b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:abbreviate"><b>-a</b> <b>--abbreviate=</b><i>boolean</i>. Abbreviate annotation names [default true]</li>
112b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:comments"><b>-c</b> <b>--comments=</b><i>boolean</i>. Insert annotations in comments [default false]</li>
113b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:omit-annotation"><b>-o</b> <b>--omit-annotation=</b><i>string</i>. Omit given annotation</li>
114b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:nowarn"><b>--nowarn=</b><i>boolean</i>. Suppress warnings about disallowed insertions [default false]</li>
115b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:convert-jaifs"><b>--convert-jaifs=</b><i>boolean</i>. Convert JAIFs to new format [default false]</li>
116b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:help"><b>-h</b> <b>--help=</b><i>boolean</i>. Print usage information and exit [default false]</li>
117b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     </ul>
118b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   </li>
119b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   <li id="optiongroup:Debugging-options">Debugging options
120b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     <ul>
121b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:verbose"><b>-v</b> <b>--verbose=</b><i>boolean</i>. Verbose (print progress information) [default false]</li>
122b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:debug"><b>--debug=</b><i>boolean</i>. Debug (print debug information) [default false]</li>
123b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *       <li id="option:print-error-stack"><b>--print-error-stack=</b><i>boolean</i>. Print error stack [default false]</li>
124b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *     </ul>
125b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst *   </li>
126b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * </ul>
127b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst * <!-- end options doc -->
12810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali */
12910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Alipublic class Main {
13010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
13110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  /** Directory in which output files are written. */
132b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst  @OptionGroup("General options")
13310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-d <directory> Directory in which output files are written")
13410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static String outdir = "annotated/";
13510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
136fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst  /**
137fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * If true, overwrite original source files (making a backup first).
138fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * Furthermore, if the backup files already exist, they are used instead
139fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * of the .java files.  This behavior permits a user to tweak the .jaif
140fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * file and re-run the annotator.
141fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * <p>
142fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   *
143fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * Note that if the user runs the annotator with --in-place, makes edits,
144fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * and then re-runs the annotator with this --in-place option, those
145fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * edits are lost.  Similarly, if the user runs the annotator twice in a
146fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * row with --in-place, only the last set of annotations will appear in
147fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * the codebase at the end.
148fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * <p>
149fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   *
150fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * To preserve changes when using the --in-place option, first remove the
151fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * backup files.  Or, use the <tt>-d .</tt> option, which makes (and
152fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   * reads) no backup, instead of --in-place.
153fd37e8455f846ac7d34c53ebe1079797599ebd4fMichael Ernst   */
154f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst  @Option("-i Overwrite original source files")
155f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst  public static boolean in_place = false;
156f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
15710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-a Abbreviate annotation names")
15810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean abbreviate = true;
15910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
16010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-c Insert annotations in comments")
16110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean comments = false;
16210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
163bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst  @Option("-o Omit given annotation")
164bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst  public static String omit_annotation;
165bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst
1667a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  @Option("Suppress warnings about disallowed insertions")
1677a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  public static boolean nowarn;
1687a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst
16940cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown  // Instead of doing insertions, create new JAIFs using AST paths
17040cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown  //  extracted from existing JAIFs and source files they match
17140cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown  @Option("Convert JAIFs to AST Path format")
1727a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  public static boolean convert_jaifs = false;
1737a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst
17438326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst  @Option("-h Print usage information and exit")
17538326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst  public static boolean help = false;
17638326fd68e58af05a0368708acf0099d4c3d0ac1Michael Ernst
1777a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst  // Debugging options go below here.
1787a0f6324bbb31fa634fd61309ea23011a466ea2bMichael Ernst
179b890e553cf7b1ab5befaecd852618835aa451c3fMichael Ernst  @OptionGroup("Debugging options")
18010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("-v Verbose (print progress information)")
18110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean verbose;
18210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
18310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  @Option("Debug (print debug information)")
18410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  public static boolean debug = false;
18510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
1868b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak  @Option("Print error stack")
1878b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak  public static boolean print_error_stack = false;
1888b8c76e4860528031809204af427c71f6ee81fc2Eric Spishak
18904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  private static ElementVisitor<Void, AElement> classFilter =
19004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      new ElementVisitor<Void, AElement>() {
19104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    <K, V extends AElement>
19204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Void filter(VivifyingMap<K, V> vm0, VivifyingMap<K, V> vm1) {
19304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      for (Map.Entry<K, V> entry : vm0.entrySet()) {
19404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry.getValue().accept(this, vm1.vivify(entry.getKey()));
19504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
19604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
19704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
19804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
19904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
20004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitAnnotationDef(AnnotationDef def, AElement el) {
20104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      // not used, since package declarations not handled here
20204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
20304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
20404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
20504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
20604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitBlock(ABlock el0, AElement el) {
20704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ABlock el1 = (ABlock) el;
20804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.locals, el1.locals);
20904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitExpression(el0, el);
21004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
21104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
21204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
21304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitClass(AClass el0, AElement el) {
21404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AClass el1 = (AClass) el;
21504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.methods, el1.methods);
21604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.fields, el1.fields);
21704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.fieldInits, el1.fieldInits);
21804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.staticInits, el1.staticInits);
21904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.instanceInits, el1.instanceInits);
22004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitDeclaration(el0, el);
22104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
22204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
22304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
22404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitDeclaration(ADeclaration el0, AElement el) {
22504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ADeclaration el1 = (ADeclaration) el;
22604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      VivifyingMap<ASTPath, ATypeElement> insertAnnotations =
22704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el1.insertAnnotations;
22804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      VivifyingMap<ASTPath, ATypeElementWithType> insertTypecasts =
22904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el1.insertTypecasts;
23004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      for (Map.Entry<ASTPath, ATypeElement> entry :
23104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el0.insertAnnotations.entrySet()) {
23204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ASTPath p = entry.getKey();
23304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ATypeElement e = entry.getValue();
23404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        insertAnnotations.put(p, e);
23504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        //visitTypeElement(e, insertAnnotations.vivify(p));
23604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
23704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      for (Map.Entry<ASTPath, ATypeElementWithType> entry :
23804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          el0.insertTypecasts.entrySet()) {
23904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ASTPath p = entry.getKey();
24004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ATypeElementWithType e = entry.getValue();
24104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        type.Type type = e.getType();
24204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        if (type instanceof type.DeclaredType
24304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            && ((type.DeclaredType) type).getName().isEmpty()) {
24404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          insertAnnotations.put(p, e);
24504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          //visitTypeElement(e, insertAnnotations.vivify(p));
24604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        } else {
24704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          insertTypecasts.put(p, e);
24804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          //visitTypeElementWithType(e, insertTypecasts.vivify(p));
24904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
25004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
25104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
25204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
25304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
25404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
25504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitExpression(AExpression el0, AElement el) {
25604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AExpression el1 = (AExpression) el;
25704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.typecasts, el1.typecasts);
25804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.instanceofs, el1.instanceofs);
25904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.news, el1.news);
26004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
26104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
26204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
26304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
26404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitField(AField el0, AElement el) {
26504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitDeclaration(el0, el);
26604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
26704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
26804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
26904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitMethod(AMethod el0, AElement el) {
27004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AMethod el1 = (AMethod) el;
27104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.bounds, el1.bounds);
27204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.parameters, el1.parameters);
27304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.throwsException, el1.throwsException);
27404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el0.returnType.accept(this, el1.returnType);
27504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el0.receiver.accept(this, el1.receiver);
27604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el0.body.accept(this, el1.body);
27704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitDeclaration(el0, el);
27804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
27904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
28004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
28104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitTypeElement(ATypeElement el0, AElement el) {
28204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ATypeElement el1 = (ATypeElement) el;
28304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      filter(el0.innerTypes, el1.innerTypes);
28404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
28504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
28604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
28704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
28804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitTypeElementWithType(ATypeElementWithType el0,
28904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        AElement el) {
29004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      ATypeElementWithType el1 = (ATypeElementWithType) el;
29104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      el1.setType(el0.getType());
29204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return visitTypeElement(el0, el);
29304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
29404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
29504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    @Override
29604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    public Void visitElement(AElement el, AElement arg) {
29704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      return null;
29804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
29904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  };
30004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
30104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  private static AScene filteredScene(final AScene scene) {
30204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    final AScene filtered = new AScene();
30304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    filtered.packages.putAll(scene.packages);
30404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    filtered.imports.putAll(scene.imports);
30504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    for (Map.Entry<String, AClass> entry : scene.classes.entrySet()) {
30604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      String key = entry.getKey();
30704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AClass clazz0 = entry.getValue();
30804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      AClass clazz1 = filtered.classes.vivify(key);
30904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      clazz0.accept(classFilter, clazz1);
31004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
31104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    filtered.prune();
31204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    return filtered;
31304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  }
31404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
31504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  private static ATypeElement findInnerTypeElement(Tree t,
316d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown      ASTRecord rec, ADeclaration decl, Type type, Insertion ins) {
31704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    ASTPath astPath = rec.astPath;
31804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    GenericArrayLocationCriterion galc =
31904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        ins.getCriteria().getGenericArrayLocation();
32004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    assert astPath != null && galc != null;
32104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    List<TypePathEntry> tpes = galc.getLocation();
32204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    ASTPath.ASTEntry entry;
32304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    for (TypePathEntry tpe : tpes) {
32404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      switch (tpe.tag) {
32504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case ARRAY:
32604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        if (!astPath.isEmpty()) {
32704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          entry = astPath.get(-1);
32804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          if (entry.getTreeKind() == Tree.Kind.NEW_ARRAY
32904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              && entry.childSelectorIs(ASTPath.TYPE)) {
33004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            entry = new ASTPath.ASTEntry(Tree.Kind.NEW_ARRAY,
33104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                ASTPath.TYPE, entry.getArgument() + 1);
33204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            break;
33304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
33404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
33504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.ARRAY_TYPE,
33604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.TYPE);
33704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
33804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case INNER_TYPE:
33904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.MEMBER_SELECT,
34004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.EXPRESSION);
34104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
34204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case TYPE_ARGUMENT:
34304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.PARAMETERIZED_TYPE,
34404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.TYPE_ARGUMENT, tpe.arg);
34504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
34604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      case WILDCARD:
34704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        entry = new ASTPath.ASTEntry(Tree.Kind.UNBOUNDED_WILDCARD,
34804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            ASTPath.BOUND);
34904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        break;
35004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      default:
35104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        throw new IllegalArgumentException("unknown type tag " + tpe.tag);
35204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
353d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown      astPath = astPath.extend(entry);
35404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    }
35504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
35604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    return decl.insertAnnotations.vivify(astPath);
35704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown  }
35804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
3592a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown  private static void convertInsertion(String pkg,
3602a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      JCTree.JCCompilationUnit tree, ASTRecord rec, Insertion ins,
3612a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      AScene scene, Multimap<Insertion, Annotation> insertionSources) {
3622a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    Collection<Annotation> annos = insertionSources.get(ins);
3632a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    if (rec == null) {
3642a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (ins.getCriteria().isOnPackage()) {
3652a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        for (Annotation anno : annos) {
3662a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          scene.packages.get(pkg).tlAnnotationsHere.add(anno);
3672a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
3682a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
3692a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    } else if (scene != null && rec.className != null) {
3702a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      AClass clazz = scene.classes.vivify(rec.className);
3712a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      ADeclaration decl = null;  // insertion target
3722a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (ins.getCriteria().onBoundZero()) {
3732a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        int n = rec.astPath.size();
3742a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (!rec.astPath.get(n-1).childSelectorIs(ASTPath.BOUND)) {
3752a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          ASTPath astPath = ASTPath.empty();
3762a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          for (int i = 0; i < n; i++) {
3772a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            astPath = astPath.extend(rec.astPath.get(i));
3782a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
3792a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          astPath = astPath.extend(
3802a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              new ASTPath.ASTEntry(Tree.Kind.TYPE_PARAMETER,
3812a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  ASTPath.BOUND, 0));
3822a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          rec = rec.replacePath(astPath);
3832a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
3842a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
3852a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (rec.methodName == null) {
3862a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        decl = rec.varName == null ? clazz
3872a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            : clazz.fields.vivify(rec.varName);
3882a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      } else {
3892a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        AMethod meth = clazz.methods.vivify(rec.methodName);
3902a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (rec.varName == null) {
3912a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          decl = meth;  // ?
3922a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        } else {
3932a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          try {
3942a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            int i = Integer.parseInt(rec.varName);
3952a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            decl = i < 0 ? meth.receiver
3962a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                : meth.parameters.vivify(i);
3972a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          } catch (NumberFormatException e) {
3982a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            TreePath path = ASTIndex.getTreePath(tree, rec);
3992a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            JCTree.JCVariableDecl varTree = null;
4002a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            JCTree.JCMethodDecl methTree = null;
4012a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            JCTree.JCClassDecl classTree = null;
4022a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            loop:
4032a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              while (path != null) {
4042a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                Tree leaf = path.getLeaf();
4052a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                switch (leaf.getKind()) {
4062a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case VARIABLE:
4072a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  varTree = (JCTree.JCVariableDecl) leaf;
4082a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  break;
4092a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case METHOD:
4102a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  methTree = (JCTree.JCMethodDecl) leaf;
4112a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  break;
4122a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case ANNOTATION:
4132a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case CLASS:
4142a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case ENUM:
4152a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                case INTERFACE:
4162a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  break loop;
4172a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                default:
4182a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  path = path.getParentPath();
4192a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                }
4202a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4212a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            while (path != null) {
4222a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              Tree leaf = path.getLeaf();
4232a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              Tree.Kind kind = leaf.getKind();
4242a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              if (kind == Tree.Kind.METHOD) {
4252a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                methTree = (JCTree.JCMethodDecl) leaf;
4262a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int i = LocalVariableScanner.indexOfVarTree(path,
4272a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                    varTree, rec.varName);
4282a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int m = methTree.getStartPosition();
4292a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int a = varTree.getStartPosition();
4302a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                int b = varTree.getEndPosition(tree.endPositions);
4312a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                LocalLocation loc = new LocalLocation(i, a-m, b-a);
4322a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                decl = meth.body.locals.vivify(loc);
4332a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                break;
4342a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4352a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              if (ASTPath.isClassEquiv(kind)) {
4362a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                classTree = (JCTree.JCClassDecl) leaf;
4372a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                // ???
4382a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                    break;
4392a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4402a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              path = path.getParentPath();
4412a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            }
4422a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
4432a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4442a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
4452a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      if (decl != null) {
4462a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        AElement el;
4472a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (rec.astPath.isEmpty()) {
4482a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el = decl;
4492a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        } else if (ins.getKind() == Insertion.Kind.CAST) {
4502a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          annotations.el.ATypeElementWithType elem =
4512a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              decl.insertTypecasts.vivify(rec.astPath);
4522a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          elem.setType(((CastInsertion) ins).getType());
4532a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el = elem;
4542a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        } else {
4552a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el = decl.insertAnnotations.vivify(rec.astPath);
4562a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4572a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        for (Annotation anno : annos) {
4582a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          el.tlAnnotationsHere.add(anno);
4592a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4602a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        if (ins instanceof TypedInsertion) {
4612a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          TypedInsertion ti = (TypedInsertion) ins;
4622a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          if (!rec.astPath.isEmpty()) {
4632a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            //addInnerTypePaths(decl, rec, ti, insertionSources);
4642a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
4652a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          for (Insertion inner : ti.getInnerTypeInsertions()) {
4662a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            Tree t = ASTIndex.getNode(tree, rec);
4672a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            if (t != null) {
4682a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              ATypeElement elem = findInnerTypeElement(t,
4692a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                  rec, decl, ti.getType(), inner);
4702a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              for (Annotation a : insertionSources.get(inner)) {
4712a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                elem.tlAnnotationsHere.add(a);
4722a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown              }
4732a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown            }
4742a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown          }
4752a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown        }
4762a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown      }
4772a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown    }
4782a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown  }
4792a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown
4802a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown
48110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  // Implementation details:
48210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //  1. The annotator partially compiles source
48310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     files using the compiler API (JSR-199), obtaining an AST.
48410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //  2. The annotator reads the specification file, producing a set of
48510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     annotator.find.Insertions.  Insertions completely specify what to
48610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     write (as a String, which is ultimately translated according to the
48710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     keyword file) and how to write it (as annotator.find.Criteria).
48810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //  3. It then traverses the tree, looking for nodes that satisfy the
48910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     Insertion Criteria, translating the Insertion text against the
49010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  //     keyword file, and inserting the annotations into the source file.
49110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
49210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  /**
49310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali   * Runs the annotator, parsing the source and spec files and applying
49410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali   * the annotations.
49510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali   */
496de7d64fbe7b6eb28b7ec1a2393b91b8e9c6afea6Dan Brown  public static void main(String[] args) throws IOException {
49710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
49810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    if (verbose) {
49967693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst      System.out.printf("insert-annotations-to-source (%s)",
50067693622be4bed63a07df6f0ce34f7c8bd52baf5Michael Ernst                        annotations.io.classfile.ClassFileReader.INDEX_UTILS_VERSION);
50110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
50210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
503e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown    Options options = new Options(
504e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown        "Main [options] { ann-file | java-file | @arg-file } ...\n"
505e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown            + "(Contents of argfiles are expanded into the argument list.)",
506e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown        Main.class);
5070ab9de82370c7e2890fd532eca754342a962b452Dan Brown    String[] file_args;
508de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown    try {
509de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      String[] cl_args = CommandLine.parse(args);
510de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      file_args = options.parse_or_usage(cl_args);
511de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown    } catch (IOException ex) {
512de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.err.println(ex);
513e9c1bfc69b183232d9bb18e0b5614a42a5b7219bDan Brown      System.err.println("(For non-argfile beginning with \"@\", use \"@@\" for initial \"@\".");
514de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.err.println("Alternative for filenames: indicate directory, e.g. as './@file'.");
515de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.err.println("Alternative for flags: use '=', as in '-o=@Deprecated'.)");
5160ab9de82370c7e2890fd532eca754342a962b452Dan Brown      file_args = null;  // Eclipse compiler issue workaround
517de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown      System.exit(1);
518de19fb4316549d574979acfedac7fe9fa4892f6dDan Brown    }
519f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
5208819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    DebugWriter dbug = new DebugWriter();
5218819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    DebugWriter verb = new DebugWriter();
5228819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    DebugWriter both = dbug.or(verb);
5238819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    dbug.setEnabled(debug);
5248819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    verb.setEnabled(verbose);
5259849f43e0d770ee036b568dbba96d4e6a2a2b270Dan Brown    TreeFinder.warn.setEnabled(!nowarn);
5268819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    TreeFinder.stak.setEnabled(print_error_stack);
5278819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    TreeFinder.dbug.setEnabled(debug);
5288819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    Criteria.dbug.setEnabled(debug);
5291220f0e5dd7642f90aab557b3bda8e177ce06316Michael Ernst
53010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    if (help) {
53110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      options.print_usage();
53210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      System.exit(0);
53310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
53410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
535f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst    if (in_place && outdir != "annotated/") { // interned
536f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      options.print_usage("The --outdir and --in-place options are mutually exclusive.");
537f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      System.exit(1);
538f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst    }
539f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
54010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    if (file_args.length < 2) {
541f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      options.print_usage("Supplied %d arguments, at least 2 needed%n", file_args.length);
54210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      System.exit(1);
54310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
54410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
54510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    // The insertions specified by the annotation files.
546290791bf3ace51eca8cb637b47e1e1d01d92111dDan Brown    Insertions insertions = new Insertions();
54710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    // The Java files into which to insert.
54810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    List<String> javafiles = new ArrayList<String>();
549d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown    // Imports required to resolve annotations (when abbreviate==true).
550e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown    Set<String> imports = new LinkedHashSet<String>();
551d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown
552d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown    // Indices to maintain insertion source traces.
55304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Map<String, Multimap<Insertion, Annotation>> insertionIndex =
55404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        new HashMap<String, Multimap<Insertion, Annotation>>();
55504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Map<Insertion, String> insertionOrigins = new HashMap<Insertion, String>();
55604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown    Map<String, AScene> scenes = new HashMap<String, AScene>();
557e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown
558e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown    IndexFileParser.setAbbreviate(abbreviate);
55910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    for (String arg : file_args) {
56010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      if (arg.endsWith(".java")) {
56110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        javafiles.add(arg);
5628ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl      } else if (arg.endsWith(".jaif") ||
5638ef7819881d25642b26b60a274f9c148d4356e3dWerner Dietl                 arg.endsWith(".jann")) {
56404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        IndexFileSpecification spec = new IndexFileSpecification(arg);
56510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        try {
56610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          List<Insertion> parsedSpec = spec.parse();
56704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          AScene scene = spec.getScene();
56870918686c71c2030c56e623a9427f05b99338a5eDan Brown          Collections.sort(parsedSpec, new Comparator<Insertion>() {
56904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            @Override
57004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            public int compare(Insertion i1, Insertion i2) {
57104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              ASTPath p1 = i1.getCriteria().getASTPath();
57204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              ASTPath p2 = i2.getCriteria().getASTPath();
57304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              return p1 == null
57404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                  ? p2 == null ? 0 : -1
57504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                  : p2 == null ? 1 : p1.compareTo(p2);
57604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            }
57704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          });
57840cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown          if (convert_jaifs) {
5799967de5fe4b0240e9b5169020aec35fb29cdfb83Dan Brown            scenes.put(arg, filteredScene(scene));
58040cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            for (Insertion ins : parsedSpec) {
58140cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown              insertionOrigins.put(ins, arg);
58240cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            }
58340cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            if (!insertionIndex.containsKey(arg)) {
58440cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown              insertionIndex.put(arg,
58540cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown                  LinkedHashMultimap.<Insertion, Annotation>create());
58640cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            }
58740cd3d4a3b8ae6bd0fe22063def2914f8645a451Dan Brown            insertionIndex.get(arg).putAll(spec.insertionSources());
58804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
589e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown          if (abbreviate) {
590e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown            Map<String, Set<String>> annotationImports =
59104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                spec.annotationImports();
592e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown            for (Set<String> set : annotationImports.values()) {
593e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown              imports.addAll(set);
594e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown            }
595e4003a2bdd8f2634d19cdac8875a10979f87a0e4Dan Brown          }
5968819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          both.debug("Read %d annotations from %s%n", parsedSpec.size(), arg);
597bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst          if (omit_annotation != null) {
5988819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            List<Insertion> filtered =
5998819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                new ArrayList<Insertion>(parsedSpec.size());
600bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst            for (Insertion insertion : parsedSpec) {
6012441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak              // TODO: this won't omit annotations if the insertion is more than
6022441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak              // just the annotation (such as if the insertion is a cast
6032441c4b66f26bf96ea7a8749645a933aa09a2d62Eric Spishak              // insertion or a 'this' parameter in a method declaration).
604bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst              if (! omit_annotation.equals(insertion.getText())) {
605bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst                filtered.add(insertion);
606bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst              }
607bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst            }
608bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst            parsedSpec = filtered;
6098819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            both.debug("After filtering: %d annotations from %s%n",
6108819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                parsedSpec.size(), arg);
611bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst          }
612bbda219dcbd366aaf1786384a8171e0409fd5a11Michael Ernst          insertions.addAll(parsedSpec);
6132c4067b440b23911687e4a353584b088eccf17fbMichael Ernst        } catch (RuntimeException e) {
6142c4067b440b23911687e4a353584b088eccf17fbMichael Ernst          if (e.getCause() != null
6152c4067b440b23911687e4a353584b088eccf17fbMichael Ernst              && e.getCause() instanceof FileNotFoundException) {
6162c4067b440b23911687e4a353584b088eccf17fbMichael Ernst            System.err.println("File not found: " + arg);
6172c4067b440b23911687e4a353584b088eccf17fbMichael Ernst            System.exit(1);
6182c4067b440b23911687e4a353584b088eccf17fbMichael Ernst          } else {
6192c4067b440b23911687e4a353584b088eccf17fbMichael Ernst            throw e;
6202c4067b440b23911687e4a353584b088eccf17fbMichael Ernst          }
62110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        } catch (FileIOException e) {
622bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          // Add 1 to the line number since line numbers in text editors are usually one-based.
623bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          System.err.println("Error while parsing annotation file " + arg + " at line "
624bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak              + (e.lineNumber + 1) + ":");
62510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          if (e.getMessage() != null) {
626bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak            System.err.println('\t' + e.getMessage());
627bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          }
628bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          if (e.getCause() != null && e.getCause().getMessage() != null) {
629bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak            System.err.println('\t' + e.getCause().getMessage());
630bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak          }
6318819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          if (print_error_stack) {
632bcf0e58623d43433c1c05a2fc954f69411b86759Eric Spishak            e.printStackTrace();
63310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          }
63410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          System.exit(1);
63510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
63610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      } else {
63710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        throw new Error("Unrecognized file extension: " + arg);
63810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
63910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
64010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
6418819fd6c8f50083311182795717e23e88cd04ac5Dan Brown    if (dbug.isEnabled()) {
6428819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      dbug.debug("%d insertions, %d .java files%n",
6438819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          insertions.size(), javafiles.size());
6448819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      dbug.debug("Insertions:%n");
64510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      for (Insertion insertion : insertions) {
6468819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        dbug.debug("  %s%n", insertion);
64710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
64810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
64910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
65010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    for (String javafilename : javafiles) {
6518819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      verb.debug("Processing %s%n", javafilename);
65210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
653f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      File javafile = new File(javafilename);
654f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      File unannotated = new File(javafilename + ".unannotated");
655f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      if (in_place) {
656f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // It doesn't make sense to check timestamps;
657f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // if the .java.unannotated file exists, then just use it.
658f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // A user can rename that file back to just .java to cause the
659f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        // .java file to be read.
660f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        if (unannotated.exists()) {
6618819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          verb.debug("Renaming %s to %s%n", unannotated, javafile);
662f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          boolean success = unannotated.renameTo(javafile);
663f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          if (! success) {
664f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst            throw new Error(String.format("Failed renaming %s to %s",
665f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst                                          unannotated, javafile));
666f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          }
667f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        }
668f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst      }
669f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst
67076f3628361358abc328f92c107a7e11733dad1d7Dan Brown      String fileSep = System.getProperty("file.separator");
67110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      String fileLineSep = System.getProperty("line.separator");
67210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      Source src;
67310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      // Get the source file, and use it to obtain parse trees.
67410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      try {
67510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        // fileLineSep is set here so that exceptions can be caught
67610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        fileLineSep = UtilMDE.inferLineSeparator(javafilename);
67710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        src = new Source(javafilename);
6788819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        verb.debug("Parsed %s%n", javafilename);
67904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      } catch (Source.CompilerException e) {
68010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        e.printStackTrace();
68110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return;
68210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      } catch (IOException e) {
68310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        e.printStackTrace();
68410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return;
68510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
68610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
687c15d52e959f2b3052978e40552159de77c403428Michael Ernst      int num_insertions = 0;
68876f3628361358abc328f92c107a7e11733dad1d7Dan Brown      String pkg = "";
689c15d52e959f2b3052978e40552159de77c403428Michael Ernst
690b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brown      for (CompilationUnitTree cut : src.parse()) {
691b7158c74813fa9eed49afea2189aee0cf51cfb73Dan Brown        JCTree.JCCompilationUnit tree = (JCTree.JCCompilationUnit) cut;
69276f3628361358abc328f92c107a7e11733dad1d7Dan Brown        ExpressionTree pkgExp = cut.getPackageName();
69376f3628361358abc328f92c107a7e11733dad1d7Dan Brown        pkg = pkgExp == null ? "" : pkgExp.toString();
69410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
69510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        // Create a finder, and use it to get positions.
69610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        TreeFinder finder = new TreeFinder(tree);
69752dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        SetMultimap<Pair<Integer, ASTPath>, Insertion> positions =
6988819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            finder.getPositions(tree, insertions);
69910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
70004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        if (convert_jaifs) {
70104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          // program used only for JAIF conversion; execute following
70204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          // block and then skip remainder of loop
703d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown          Multimap<ASTRecord, Insertion> astInsertions =
70404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              finder.getPaths();
705d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown          for (Map.Entry<ASTRecord, Collection<Insertion>> entry :
70604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              astInsertions.asMap().entrySet()) {
707d429e5d87eb48b6c7ad9041eba400e775a1796efDan Brown            ASTRecord rec = entry.getKey();
70804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            for (Insertion ins : entry.getValue()) {
70904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              if (ins.getCriteria().getASTPath() != null) { continue; }
71004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              String arg = insertionOrigins.get(ins);
71104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              AScene scene = scenes.get(arg);
71204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              Multimap<Insertion, Annotation> insertionSources =
71304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown                  insertionIndex.get(arg);
71404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              //String text =
71504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              //  ins.getText(comments, abbreviate, false, 0, '\0');
71604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
71704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              // TODO: adjust for missing end of path (?)
71804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
71904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              if (insertionSources.containsKey(ins)) {
7202a5d572aa18c2cfeab9f706eb8796ec1553a6c46Dan Brown                convertInsertion(pkg, tree, rec, ins, scene, insertionSources);
72104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              }
72204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            }
72304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
72404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          continue;
72504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
72604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
72710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        // Apply the positions to the source file.
7288819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        if (both.isEnabled()) {
7298819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          System.err.printf(
7308819fd6c8f50083311182795717e23e88cd04ac5Dan Brown              "getPositions returned %d positions in tree for %s%n",
7318819fd6c8f50083311182795717e23e88cd04ac5Dan Brown              positions.size(), javafilename);
73210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
73310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
73452dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        Set<Pair<Integer, ASTPath>> positionKeysUnsorted =
73552dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown            positions.keySet();
73652dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        Set<Pair<Integer, ASTPath>> positionKeysSorted =
73752dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown          new TreeSet<Pair<Integer, ASTPath>>(
73852dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown              new Comparator<Pair<Integer, ASTPath>>() {
73952dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                @Override
74052dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                public int compare(Pair<Integer, ASTPath> p1,
74152dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                    Pair<Integer, ASTPath> p2) {
74252dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  int c = Integer.compare(p2.a, p1.a);
74352dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  if (c == 0) {
74452dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                    c = p2.b == null ? p1.b == null ? 0 : -1
74552dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                        : p1.b == null ? 1 : p2.b.compareTo(p1.b);
74652dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  }
74752dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                  return c;
74852dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown                }
74952dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown              });
75057ea23519ad96aca616e5fe41b4a1db896b91096Michael Ernst        positionKeysSorted.addAll(positionKeysUnsorted);
75152dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown        for (Pair<Integer, ASTPath> pair : positionKeysSorted) {
752c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown          boolean receiverInserted = false;
75384a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown          boolean newInserted = false;
7540b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown          boolean constructorInserted = false;
75552dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown          Set<String> seen = new TreeSet<String>();
75652dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown          List<Insertion> toInsertList = new ArrayList<Insertion>(positions.get(pair));
757ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst          Collections.reverse(toInsertList);
758553a9a9a17ce582f701841b59edfadb491ed54adDan Brown          dbug.debug("insertion pos: %d%n", pair.a);
759553a9a9a17ce582f701841b59edfadb491ed54adDan Brown          assert pair.a >= 0
760553a9a9a17ce582f701841b59edfadb491ed54adDan Brown            : "pos is negative: " + pair.a + " " + toInsertList.get(0) + " " + javafilename;
761ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst          for (Insertion iToInsert : toInsertList) {
762ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            // Possibly add whitespace after the insertion
7633d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            String trailingWhitespace = "";
764ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            boolean gotSeparateLine = false;
765553a9a9a17ce582f701841b59edfadb491ed54adDan Brown            int pos = pair.a;  // reset each iteration in case of dyn adjustment
766ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            if (iToInsert.getSeparateLine()) {
767a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst              // System.out.printf("getSeparateLine=true for insertion at pos %d: %s%n", pos, iToInsert);
768ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              int indentation = 0;
769ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              while ((pos - indentation != 0)
770ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                     // horizontal whitespace
771ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                     && (src.charAt(pos-indentation-1) == ' '
772ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                         || src.charAt(pos-indentation-1) == '\t')) {
773a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst                // System.out.printf("src.charAt(pos-indentation-1 == %d-%d-1)='%s'%n",
774a1b0d6cb20867adf4fad0359336510469353ad29Michael Ernst                //                   pos, indentation, src.charAt(pos-indentation-1));
775ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                indentation++;
776ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              }
777ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              if ((pos - indentation == 0)
778ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                  // horizontal whitespace
779ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                  || (src.charAt(pos-indentation-1) == '\f'
780ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                      || src.charAt(pos-indentation-1) == '\n'
781ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                      || src.charAt(pos-indentation-1) == '\r')) {
7823d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak                trailingWhitespace = fileLineSep + src.substring(pos-indentation, pos);
783ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                gotSeparateLine = true;
784ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              }
785ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            }
786c71d4e21017f8f4412a2d399676e358858999623Michael Ernst
7873d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            char precedingChar;
7883d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            if (pos != 0) {
7893d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak              precedingChar = src.charAt(pos - 1);
7903d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            } else {
7913d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak              precedingChar = '\0';
7923d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            }
793afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown
794afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown            if (iToInsert.getKind() == Insertion.Kind.ANNOTATION) {
795afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown              AnnotationInsertion ai = (AnnotationInsertion) iToInsert;
796dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown              if (ai.isGenerateBound()) {  // avoid multiple ampersands
797dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                try {
798dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  String s = src.substring(pos, pos+9);
799dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  if ("Object & ".equals(s)) {
800dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                    ai.setGenerateBound(false);
801dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                    precedingChar = '.';  // suppress leading space
802dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  }
803dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                } catch (StringIndexOutOfBoundsException e) {}
804dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown              }
805afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown              if (ai.isGenerateExtends()) {  // avoid multiple "extends"
806afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                try {
807dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  String s = src.substring(pos, pos+9);
808dd5ddd43212d92e5d5051c2f070fb299a1e1e43bDan Brown                  if (" extends ".equals(s)) {
809afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                    ai.setGenerateExtends(false);
810553a9a9a17ce582f701841b59edfadb491ed54adDan Brown                    pos += 8;
811afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                  }
812afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown                } catch (StringIndexOutOfBoundsException e) {}
813afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown              }
814afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown            } else if (iToInsert.getKind() == Insertion.Kind.CAST) {
8155491118a39a8545a38eb1a94bbc5f5a00a0b9beeDan Brown                ((CastInsertion) iToInsert)
8165491118a39a8545a38eb1a94bbc5f5a00a0b9beeDan Brown                        .setOnArrayLiteral(src.charAt(pos) == '{');
817afbac03e4be6a7c9f2e45998b56f9f0e6ae58c17Dan Brown            } else if (iToInsert.getKind() == Insertion.Kind.RECEIVER) {
818c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown              ReceiverInsertion ri = (ReceiverInsertion) iToInsert;
819c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown              ri.setAnnotationsOnly(receiverInserted);
820c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown              receiverInserted = true;
82184a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            } else if (iToInsert.getKind() == Insertion.Kind.NEW) {
82284a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown              NewInsertion ni = (NewInsertion) iToInsert;
82384a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown              ni.setAnnotationsOnly(newInserted);
82484a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown              newInserted = true;
8250b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown            } else if (iToInsert.getKind() == Insertion.Kind.CONSTRUCTOR) {
8260b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown              ConstructorInsertion ci = (ConstructorInsertion) iToInsert;
8270b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown              if (constructorInserted) { ci.setAnnotationsOnly(true); }
8280b2301392682d3b2cbaa314cf5f90b960c6f0253Dan Brown              constructorInserted = true;
829c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown            }
830c448ebefd28e4a67c0c4957ee387f02ab9020502Dan Brown
8313d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak            String toInsert = iToInsert.getText(comments, abbreviate,
8328819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                gotSeparateLine, pos, precedingChar) + trailingWhitespace;
8339967de5fe4b0240e9b5169020aec35fb29cdfb83Dan Brown            Set<String> packageNames = iToInsert.getPackageNames();
83452dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown            if (seen.contains(toInsert)) { continue; }  // eliminate duplicates
83552dda95b775d6ad255fb35f2582be363ab1ce4d2Dan Brown            seen.add(toInsert);
8369967de5fe4b0240e9b5169020aec35fb29cdfb83Dan Brown            if (!packageNames.isEmpty()) {
8378819fd6c8f50083311182795717e23e88cd04ac5Dan Brown              dbug.debug("Need import %s%n  due to insertion %s%n",
8388819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                  packageNames, toInsert);
8393d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak              imports.addAll(packageNames);
8404735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst            }
841ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst
842ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            // If it's already there, don't re-insert.  This is a hack!
843ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            // Also, I think this is already checked when constructing the
84476be24f6310e0f8e8120e223e14bc0b4690408d4Werner Dietl            // insertions.
845ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            int precedingTextPos = pos-toInsert.length()-1;
846ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            if (precedingTextPos >= 0) {
847ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst              String precedingTextPlusChar
848ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                = src.getString().substring(precedingTextPos, pos);
8498819fd6c8f50083311182795717e23e88cd04ac5Dan Brown              if (toInsert.equals(
8508819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                      precedingTextPlusChar.substring(0, toInsert.length()))
851ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                  || toInsert.equals(precedingTextPlusChar.substring(1))) {
8528819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                dbug.debug(
8538819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                    "Inserting %s at %d in code of length %d with preceding text '%s'%n",
8548819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                    toInsert, pos, src.getString().length(),
8558819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                    precedingTextPlusChar);
8568819fd6c8f50083311182795717e23e88cd04ac5Dan Brown                dbug.debug("Already present, skipping%n");
857ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst                continue;
8584735bdd95fe3025e721476ae821d0aca6127f80aMichael Ernst              }
85910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali            }
8603d8c27ef3f539aea5f49643fed2b38e49e99eda4Eric Spishak
86184a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            // TODO: Neither the above hack nor this check should be
86284a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            // necessary.  Find out why re-insertions still occur and
86384a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            // fix properly.
86484a43e620e89518fa2b0909bb51eb46c455bfd1fDan Brown            if (iToInsert.getInserted()) { continue; }
865ed468b7eb950854ef28a3407e1887dfec12fee67Michael Ernst            src.insert(pos, toInsert);
8668920570aa95ef0072bafd2cccff03d194c478bf1Dan Brown            if (verbose && !debug) {
867c15d52e959f2b3052978e40552159de77c403428Michael Ernst              System.out.print(".");
868c15d52e959f2b3052978e40552159de77c403428Michael Ernst              num_insertions++;
869c15d52e959f2b3052978e40552159de77c403428Michael Ernst              if ((num_insertions % 50) == 0) {
870c15d52e959f2b3052978e40552159de77c403428Michael Ernst                System.out.println();   // terminate the line that contains dots
871c15d52e959f2b3052978e40552159de77c403428Michael Ernst              }
872c15d52e959f2b3052978e40552159de77c403428Michael Ernst            }
8738819fd6c8f50083311182795717e23e88cd04ac5Dan Brown            dbug.debug("Post-insertion source: %n" + src.getString());
87410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          }
87510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
87610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
87704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
87804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      if (convert_jaifs) {
87904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        for (Map.Entry<String, AScene> entry : scenes.entrySet()) {
88004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          String filename = entry.getKey();
88104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          AScene scene = entry.getValue();
88204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          try {
88304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            IndexFileWriter.write(scene, filename + ".converted");
88404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          } catch (DefException e) {
88504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            System.err.println(filename + ": " + " format error in conversion");
88604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            if (print_error_stack) {
88704cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown              e.printStackTrace();
88804cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown            }
88904cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown          }
89004cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
89104cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        return;  // done with conversion
89204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
89304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
894c15d52e959f2b3052978e40552159de77c403428Michael Ernst      if (verbose) {
895c15d52e959f2b3052978e40552159de77c403428Michael Ernst        if ((num_insertions % 50) != 0) {
896c15d52e959f2b3052978e40552159de77c403428Michael Ernst          System.out.println();   // terminate the line that contains dots
897c15d52e959f2b3052978e40552159de77c403428Michael Ernst        }
898c15d52e959f2b3052978e40552159de77c403428Michael Ernst      }
89910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
9008819fd6c8f50083311182795717e23e88cd04ac5Dan Brown      if (dbug.isEnabled()) {
9018819fd6c8f50083311182795717e23e88cd04ac5Dan Brown        dbug.debug("%d imports to insert%n", imports.size());
90204cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        for (String classname : imports) {
9038819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          dbug.debug("  %s%n", classname);
90404cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        }
90504cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown      }
90604cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown
90710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      // insert import statements
90810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      {
90910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        Pattern importPattern = Pattern.compile("(?m)^import\\b");
91010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        Pattern packagePattern = Pattern.compile("(?m)^package\\b.*;(\\n|\\r\\n?)");
91110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        int importIndex = 0;      // default: beginning of file
91210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        String srcString = src.getString();
91304cf7f6206930db04e8a8c085bf18ba237b9dc05Dan Brown        Matcher m = importPattern.matcher(srcString);
91410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        if (m.find()) {
91510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          importIndex = m.start();
91610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        } else {
9178819fd6c8f50083311182795717e23e88cd04ac5Dan Brown          // Debug.info("Didn't find import in " + srcString);
91810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          m = packagePattern.matcher(srcString);
91910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          if (m.find()) {
92010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali            importIndex = m.end();
92110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          }
92210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
92310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        for (String classname : imports) {
92410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          String toInsert = "import " + classname + ";" + fileLineSep;
92510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          src.insert(importIndex, toInsert);
92610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali          importIndex += toInsert.length();
92710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
92810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
92910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
93010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      // Write the source file.
93176f3628361358abc328f92c107a7e11733dad1d7Dan Brown      File outfile = null;
93210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      try {
933f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        if (in_place) {
93476f3628361358abc328f92c107a7e11733dad1d7Dan Brown          outfile = javafile;
935f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          if (verbose) {
936f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst            System.out.printf("Renaming %s to %s%n", javafile, unannotated);
937f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          }
938f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          boolean success = javafile.renameTo(unannotated);
939f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          if (! success) {
940f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst            throw new Error(String.format("Failed renaming %s to %s",
941f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst                                          javafile, unannotated));
942f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          }
943f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        } else {
94476f3628361358abc328f92c107a7e11733dad1d7Dan Brown          if (pkg.isEmpty()) {
94576f3628361358abc328f92c107a7e11733dad1d7Dan Brown            outfile = new File(outdir, javafile.getName());
94676f3628361358abc328f92c107a7e11733dad1d7Dan Brown          } else {
94776f3628361358abc328f92c107a7e11733dad1d7Dan Brown            String[] pkgPath = pkg.split("\\.");
94876f3628361358abc328f92c107a7e11733dad1d7Dan Brown            StringBuilder sb = new StringBuilder(outdir);
94976f3628361358abc328f92c107a7e11733dad1d7Dan Brown            for (int i = 0 ; i < pkgPath.length ; i++) {
95076f3628361358abc328f92c107a7e11733dad1d7Dan Brown              sb.append(fileSep).append(pkgPath[i]);
95176f3628361358abc328f92c107a7e11733dad1d7Dan Brown            }
95276f3628361358abc328f92c107a7e11733dad1d7Dan Brown            outfile = new File(sb.toString(), javafile.getName());
95376f3628361358abc328f92c107a7e11733dad1d7Dan Brown          }
954f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          outfile.getParentFile().mkdirs();
955f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        }
95610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        OutputStream output = new FileOutputStream(outfile);
957f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        if (verbose) {
958f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst          System.out.printf("Writing %s%n", outfile);
959f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        }
96010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        src.write(output);
961f5fbd2ee90bc394cb18e8cf7dbaf3ecbbd4e7ad7Michael Ernst        output.close();
96210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      } catch (IOException e) {
96310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        System.err.println("Problem while writing file " + outfile);
96410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        e.printStackTrace();
96510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        System.exit(1);
96610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali      }
96710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
96810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali  }
96910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
9705534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  public static String pathToString(TreePath path) {
9715534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    if (path == null)
9725534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      return "null";
973f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst    return treeToString(path.getLeaf());
974f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst  }
975f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst
976f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst  public static String treeToString(Tree node) {
977f8955bfb5d46ff31634832d5143a95f2faaa14beMichael Ernst    String asString = node.toString();
9785534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    String oneLine = firstLine(asString);
9795534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    return "\"" + oneLine + "\"";
9805534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  }
9815534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst
9825534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  /**
9835534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst   * Return the first non-empty line of the string, adding an ellipsis
9845534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst   * (...) if the string was truncated.
9855534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst   */
9865534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  public static String firstLine(String s) {
9875534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    while (s.startsWith("\n")) {
9885534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      s = s.substring(1);
9895534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    }
9905534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    int newlineIndex = s.indexOf('\n');
9915534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    if (newlineIndex == -1) {
9925534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      return s;
9935534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    } else {
9945534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst      return s.substring(0, newlineIndex) + "...";
9955534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst    }
9965534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst  }
9975534e50f6966d53ba8c8104a4bf847df0cd53409Michael Ernst
998aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb  /**
999aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   * Separates the annotation class from its arguments.
1000aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   *
1001aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   * @return given <code>@foo(bar)</code> it returns the pair <code>{ @foo, (bar) }</code>.
1002aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb   */
1003aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb  public static Pair<String,String> removeArgs(String s) {
1004aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb    int pidx = s.indexOf("(");
1005aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb    return (pidx == -1) ?
1006615ec652dc360e33296fd763a4fa56e59c35b23cMichael Ernst        Pair.of(s, (String)null) :
1007aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb        Pair.of(s.substring(0, pidx), s.substring(pidx));
1008aad82c9e3793937a33a4e6b2cd2e38f6478e0704mdb  }
100910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali}
1010