• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package annotations.tools;
2 
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.IOException;
6 import java.io.PrintWriter;
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.Map;
10 
11 import com.google.common.collect.HashMultimap;
12 import com.google.common.collect.SetMultimap;
13 import com.sun.tools.javac.main.CommandLine;
14 
15 import plume.FileIOException;
16 import annotations.Annotation;
17 import annotations.Annotations;
18 import annotations.el.ABlock;
19 import annotations.el.AClass;
20 import annotations.el.ADeclaration;
21 import annotations.el.AElement;
22 import annotations.el.AExpression;
23 import annotations.el.AField;
24 import annotations.el.AMethod;
25 import annotations.el.AScene;
26 import annotations.el.ATypeElement;
27 import annotations.el.ATypeElementWithType;
28 import annotations.el.AnnotationDef;
29 import annotations.el.DefException;
30 import annotations.el.ElementVisitor;
31 import annotations.field.AnnotationFieldType;
32 import annotations.io.IndexFileParser;
33 import annotations.io.IndexFileWriter;
34 
35 /**
36  * Utility for merging index files, including multiple versions for the
37  *  same class.
38  *
39  * @author dbro
40  */
41 public class IndexFileMerger {
main(String[] args)42   public static void main(String[] args) {
43     if (args.length < 1) { System.exit(0); }
44 
45     final SetMultimap<String, String> annotatedFor = HashMultimap.create();
46     String[] inputArgs;
47 
48     // TODO: document assumptions
49     // collect annotations into scene
50     try {
51       try {
52         inputArgs = CommandLine.parse(args);
53       } catch (IOException ex) {
54         System.err.println(ex);
55         System.err.println("(For non-argfile beginning with \"@\", use \"@@\" for initial \"@\".");
56         System.err.println("Alternative for filenames: indicate directory, e.g. as './@file'.");
57         System.err.println("Alternative for flags: use '=', as in '-o=@Deprecated'.)");
58         System.exit(1);
59         return;  // so compiler knows inputArgs defined after try/catch
60       }
61 
62       File baseFile = new File(inputArgs[0]);
63       boolean byDir = baseFile.isDirectory();
64       String basePath = baseFile.getCanonicalPath();
65       AScene scene = new AScene();
66 
67       for (int i = byDir ? 1 : 0; i < inputArgs.length; i++) {
68         File inputFile = new File(inputArgs[i]);
69         String inputPath = inputFile.getCanonicalPath();
70         String filename = inputFile.getName();
71 
72         if (byDir) {
73           if (!(filename.endsWith(".jaif") || filename.endsWith("jann"))) {
74             System.err.println("WARNING: ignoring non-JAIF " + filename);
75             continue;
76           }
77           if (!inputPath.startsWith(basePath)) {
78             System.err.println("WARNING: ignoring file outside base directory "
79                 + filename);
80             continue;
81           }
82 
83           // note which base subdirectory JAIF came from
84           String relPath = inputPath.substring(basePath.length()+1);  // +1 '/'
85           int ix = relPath.indexOf(File.separator);
86           String subdir = ix < 0 ? relPath : relPath.substring(0, ix);
87           // trim .jaif or .jann and subdir, convert directory to package id
88           String classname = relPath.substring(0, relPath.lastIndexOf('.'))
89               .substring(relPath.indexOf('/')+1).replace(File.separator, ".");
90           annotatedFor.put(classname, "\"" + subdir + "\"");
91         }
92 
93         try {
94           IndexFileParser.parseFile(inputPath, scene);
95         } catch (FileNotFoundException e) {
96           System.err.println("IndexFileMerger: can't read "
97               + inputPath);
98           System.exit(1);
99         } catch (FileIOException e) {
100           e.printStackTrace();  // TODO
101           System.exit(1);
102         }
103       }
104 
105       if (!byDir) {
106 /*
107         // collect defs
108         Map<String, String> annoPkgs = new HashMap<String, String>();
109         try {
110           new DefCollector(scene) {
111             @Override
112             protected void visitAnnotationDef(AnnotationDef d) {
113               String[] a = d.name.split("\\.");
114               if (a.length > 2 && a[a.length-2].matches("quals?")) {
115                 String s = a[a.length-1];
116                 annoPkgs.put(s, d.name.substring(0));
117               }
118             }
119           }.visit();
120         } catch (DefException e) {
121           System.err.println("DefCollector failed!");
122           e.printStackTrace();
123           System.exit(1);
124         }
125 */
126 
127         for (Map.Entry<String, AClass> entry : scene.classes.entrySet()) {
128           // final String classname = entry.getKey();
129 
130           entry.getValue().accept(new ElementVisitor<Void, Void>() {
131             // Map<String, String> annoPkgs = new HashMap<String, String>();
132 
133             // Void process(AElement el) {
134             //  for (Annotation anno : el.tlAnnotationsHere) {
135             //    AnnotationDef def = anno.def();
136             //    String[] a = def.name.split("\\.");
137             //    if ("AnnotatedFor".equals(a[a.length-1])) {
138             //      @SuppressWarnings("unchecked")
139             //      List<String> vals =
140             //          (List<String>) anno.getFieldValue("value");
141             //      for (String val : vals) {
142             //        annotatedFor.put(classname, val);
143             //      }
144             //    } else if (a.length > 2 && a[a.length-2].matches("quals?")) {
145             //      annotatedFor.put(classname, a[a.length-3]);
146             //    }
147             //  }
148             //  return null;
149             // }
150 
151             Void visit(AElement el) {
152               if (el != null) { el.accept(this, null); }
153               return null;
154             }
155 
156             <T, E extends AElement> Void visitMap(Map<T, E> map) {
157               if (map != null) {
158                 for (E el : map.values()) { visit(el); }
159               }
160               return null;
161             }
162 
163             @Override
164             public Void visitAnnotationDef(AnnotationDef d, Void v) {
165               // String[] a = d.name.split("\\.");
166               // if (a.length > 2 && a[a.length-2].matches("quals?")) {
167               //  String s = a[a.length-1];
168               //  annoPkgs.put(s, d.name.substring(0));
169               // }
170               return null;  // process(d);
171             }
172 
173             @Override
174             public Void visitBlock(ABlock el, Void v) {
175               visitMap(el.locals);
176               return visitExpression(el, v);
177             }
178 
179             @Override
180             public Void visitClass(AClass el, Void v) {
181               visitMap(el.bounds);
182               visitMap(el.extendsImplements);
183               visitMap(el.instanceInits);
184               visitMap(el.staticInits);
185               visitMap(el.methods);
186               visitMap(el.fields);
187               visitMap(el.fieldInits);
188               return visitDeclaration(el, v);
189             }
190 
191             @Override
192             public Void visitDeclaration(ADeclaration el, Void v) {
193               visitMap(el.insertAnnotations);
194               visitMap(el.insertTypecasts);
195               return visitElement(el, v);
196             }
197 
198             @Override
199             public Void visitExpression(AExpression el, Void v) {
200               visitMap(el.calls);
201               visitMap(el.funs);
202               visitMap(el.instanceofs);
203               visitMap(el.news);
204               visitMap(el.refs);
205               visitMap(el.typecasts);
206               return visitElement(el, v);
207             }
208 
209             @Override
210             public Void visitField(AField el, Void v) {
211               visit(el.init);
212               return visitDeclaration(el, v);
213             }
214 
215             @Override
216             public Void visitMethod(AMethod el, Void v) {
217               visit(el.receiver);
218               visitMap(el.parameters);
219               visitMap(el.bounds);
220               visit(el.returnType);
221               visit(el.body);
222               visitMap(el.throwsException);
223               return visitDeclaration(el, v);
224             }
225 
226             @Override
227             public Void visitTypeElement(ATypeElement el, Void v) {
228               visitMap(el.innerTypes);
229               return visitElement(el, v);
230             }
231 
232             @Override
233             public Void visitTypeElementWithType(ATypeElementWithType el,
234                 Void v) {
235               return visitTypeElement(el, v);
236             }
237 
238             @Override
239             public Void visitElement(AElement el, Void v) {
240               visit(el.type);
241               return null;  // process(el);
242             }
243           }, null);
244         }
245       }
246 
247       // add AnnotatedFor to each annotated class
248       AnnotationFieldType stringArray =
249           AnnotationFieldType.fromClass(new String[0].getClass(),
250               Collections.<String, AnnotationDef>emptyMap());
251       AnnotationDef afDef =
252           Annotations.createValueAnnotationDef("AnnotatedFor",
253               Collections.<Annotation>emptySet(), stringArray);
254       for (Map.Entry<String, Collection<String>> entry :
255           annotatedFor.asMap().entrySet()) {
256         String key = entry.getKey();
257         Collection<String> values = entry.getValue();
258         Annotation afAnno = new Annotation(afDef, Collections
259                 .<String, Collection<String>>singletonMap("value", values));
260         scene.classes.vivify(key).tlAnnotationsHere.add(afAnno);
261       }
262       scene.prune();
263       annotatedFor.clear();  // for gc
264 
265       try {
266         IndexFileWriter.write(scene, new PrintWriter(System.out, true));
267       } catch (SecurityException e) {
268         e.printStackTrace();
269         System.exit(1);
270       } catch (DefException e) {
271         e.printStackTrace();
272         System.exit(1);
273       }
274     } catch (IOException e) {
275       e.printStackTrace();
276     }
277   }
278 }
279