| package annotations.tools; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Map; |
| |
| import com.google.common.collect.HashMultimap; |
| import com.google.common.collect.SetMultimap; |
| import com.sun.tools.javac.main.CommandLine; |
| |
| import plume.FileIOException; |
| import annotations.Annotation; |
| import annotations.Annotations; |
| import annotations.el.ABlock; |
| import annotations.el.AClass; |
| import annotations.el.ADeclaration; |
| import annotations.el.AElement; |
| import annotations.el.AExpression; |
| import annotations.el.AField; |
| import annotations.el.AMethod; |
| import annotations.el.AScene; |
| import annotations.el.ATypeElement; |
| import annotations.el.ATypeElementWithType; |
| import annotations.el.AnnotationDef; |
| import annotations.el.DefException; |
| import annotations.el.ElementVisitor; |
| import annotations.field.AnnotationFieldType; |
| import annotations.io.IndexFileParser; |
| import annotations.io.IndexFileWriter; |
| |
| /** |
| * Utility for merging index files, including multiple versions for the |
| * same class. |
| * |
| * @author dbro |
| */ |
| public class IndexFileMerger { |
| public static void main(String[] args) { |
| if (args.length < 1) { System.exit(0); } |
| |
| final SetMultimap<String, String> annotatedFor = HashMultimap.create(); |
| String[] inputArgs; |
| |
| // TODO: document assumptions |
| // collect annotations into scene |
| try { |
| try { |
| inputArgs = CommandLine.parse(args); |
| } catch (IOException ex) { |
| System.err.println(ex); |
| System.err.println("(For non-argfile beginning with \"@\", use \"@@\" for initial \"@\"."); |
| System.err.println("Alternative for filenames: indicate directory, e.g. as './@file'."); |
| System.err.println("Alternative for flags: use '=', as in '-o=@Deprecated'.)"); |
| System.exit(1); |
| return; // so compiler knows inputArgs defined after try/catch |
| } |
| |
| File baseFile = new File(inputArgs[0]); |
| boolean byDir = baseFile.isDirectory(); |
| String basePath = baseFile.getCanonicalPath(); |
| AScene scene = new AScene(); |
| |
| for (int i = byDir ? 1 : 0; i < inputArgs.length; i++) { |
| File inputFile = new File(inputArgs[i]); |
| String inputPath = inputFile.getCanonicalPath(); |
| String filename = inputFile.getName(); |
| |
| if (byDir) { |
| if (!(filename.endsWith(".jaif") || filename.endsWith("jann"))) { |
| System.err.println("WARNING: ignoring non-JAIF " + filename); |
| continue; |
| } |
| if (!inputPath.startsWith(basePath)) { |
| System.err.println("WARNING: ignoring file outside base directory " |
| + filename); |
| continue; |
| } |
| |
| // note which base subdirectory JAIF came from |
| String relPath = inputPath.substring(basePath.length()+1); // +1 '/' |
| int ix = relPath.indexOf(File.separator); |
| String subdir = ix < 0 ? relPath : relPath.substring(0, ix); |
| // trim .jaif or .jann and subdir, convert directory to package id |
| String classname = relPath.substring(0, relPath.lastIndexOf('.')) |
| .substring(relPath.indexOf('/')+1).replace(File.separator, "."); |
| annotatedFor.put(classname, "\"" + subdir + "\""); |
| } |
| |
| try { |
| IndexFileParser.parseFile(inputPath, scene); |
| } catch (FileNotFoundException e) { |
| System.err.println("IndexFileMerger: can't read " |
| + inputPath); |
| System.exit(1); |
| } catch (FileIOException e) { |
| e.printStackTrace(); // TODO |
| System.exit(1); |
| } |
| } |
| |
| if (!byDir) { |
| /* |
| // collect defs |
| Map<String, String> annoPkgs = new HashMap<String, String>(); |
| try { |
| new DefCollector(scene) { |
| @Override |
| protected void visitAnnotationDef(AnnotationDef d) { |
| String[] a = d.name.split("\\."); |
| if (a.length > 2 && a[a.length-2].matches("quals?")) { |
| String s = a[a.length-1]; |
| annoPkgs.put(s, d.name.substring(0)); |
| } |
| } |
| }.visit(); |
| } catch (DefException e) { |
| System.err.println("DefCollector failed!"); |
| e.printStackTrace(); |
| System.exit(1); |
| } |
| */ |
| |
| for (Map.Entry<String, AClass> entry : scene.classes.entrySet()) { |
| // final String classname = entry.getKey(); |
| |
| entry.getValue().accept(new ElementVisitor<Void, Void>() { |
| // Map<String, String> annoPkgs = new HashMap<String, String>(); |
| |
| // Void process(AElement el) { |
| // for (Annotation anno : el.tlAnnotationsHere) { |
| // AnnotationDef def = anno.def(); |
| // String[] a = def.name.split("\\."); |
| // if ("AnnotatedFor".equals(a[a.length-1])) { |
| // @SuppressWarnings("unchecked") |
| // List<String> vals = |
| // (List<String>) anno.getFieldValue("value"); |
| // for (String val : vals) { |
| // annotatedFor.put(classname, val); |
| // } |
| // } else if (a.length > 2 && a[a.length-2].matches("quals?")) { |
| // annotatedFor.put(classname, a[a.length-3]); |
| // } |
| // } |
| // return null; |
| // } |
| |
| Void visit(AElement el) { |
| if (el != null) { el.accept(this, null); } |
| return null; |
| } |
| |
| <T, E extends AElement> Void visitMap(Map<T, E> map) { |
| if (map != null) { |
| for (E el : map.values()) { visit(el); } |
| } |
| return null; |
| } |
| |
| @Override |
| public Void visitAnnotationDef(AnnotationDef d, Void v) { |
| // String[] a = d.name.split("\\."); |
| // if (a.length > 2 && a[a.length-2].matches("quals?")) { |
| // String s = a[a.length-1]; |
| // annoPkgs.put(s, d.name.substring(0)); |
| // } |
| return null; // process(d); |
| } |
| |
| @Override |
| public Void visitBlock(ABlock el, Void v) { |
| visitMap(el.locals); |
| return visitExpression(el, v); |
| } |
| |
| @Override |
| public Void visitClass(AClass el, Void v) { |
| visitMap(el.bounds); |
| visitMap(el.extendsImplements); |
| visitMap(el.instanceInits); |
| visitMap(el.staticInits); |
| visitMap(el.methods); |
| visitMap(el.fields); |
| visitMap(el.fieldInits); |
| return visitDeclaration(el, v); |
| } |
| |
| @Override |
| public Void visitDeclaration(ADeclaration el, Void v) { |
| visitMap(el.insertAnnotations); |
| visitMap(el.insertTypecasts); |
| return visitElement(el, v); |
| } |
| |
| @Override |
| public Void visitExpression(AExpression el, Void v) { |
| visitMap(el.calls); |
| visitMap(el.funs); |
| visitMap(el.instanceofs); |
| visitMap(el.news); |
| visitMap(el.refs); |
| visitMap(el.typecasts); |
| return visitElement(el, v); |
| } |
| |
| @Override |
| public Void visitField(AField el, Void v) { |
| visit(el.init); |
| return visitDeclaration(el, v); |
| } |
| |
| @Override |
| public Void visitMethod(AMethod el, Void v) { |
| visit(el.receiver); |
| visitMap(el.parameters); |
| visitMap(el.bounds); |
| visit(el.returnType); |
| visit(el.body); |
| visitMap(el.throwsException); |
| return visitDeclaration(el, v); |
| } |
| |
| @Override |
| public Void visitTypeElement(ATypeElement el, Void v) { |
| visitMap(el.innerTypes); |
| return visitElement(el, v); |
| } |
| |
| @Override |
| public Void visitTypeElementWithType(ATypeElementWithType el, |
| Void v) { |
| return visitTypeElement(el, v); |
| } |
| |
| @Override |
| public Void visitElement(AElement el, Void v) { |
| visit(el.type); |
| return null; // process(el); |
| } |
| }, null); |
| } |
| } |
| |
| // add AnnotatedFor to each annotated class |
| AnnotationFieldType stringArray = |
| AnnotationFieldType.fromClass(new String[0].getClass(), |
| Collections.<String, AnnotationDef>emptyMap()); |
| AnnotationDef afDef = |
| Annotations.createValueAnnotationDef("AnnotatedFor", |
| Collections.<Annotation>emptySet(), stringArray); |
| for (Map.Entry<String, Collection<String>> entry : |
| annotatedFor.asMap().entrySet()) { |
| String key = entry.getKey(); |
| Collection<String> values = entry.getValue(); |
| Annotation afAnno = new Annotation(afDef, Collections |
| .<String, Collection<String>>singletonMap("value", values)); |
| scene.classes.vivify(key).tlAnnotationsHere.add(afAnno); |
| } |
| scene.prune(); |
| annotatedFor.clear(); // for gc |
| |
| try { |
| IndexFileWriter.write(scene, new PrintWriter(System.out, true)); |
| } catch (SecurityException e) { |
| e.printStackTrace(); |
| System.exit(1); |
| } catch (DefException e) { |
| e.printStackTrace(); |
| System.exit(1); |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |