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 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 annoPkgs = new HashMap(); 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 entry : scene.classes.entrySet()) { // final String classname = entry.getKey(); entry.getValue().accept(new ElementVisitor() { // Map annoPkgs = new HashMap(); // 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 vals = // (List) 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; } Void visitMap(Map 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.emptyMap()); AnnotationDef afDef = Annotations.createValueAnnotationDef("AnnotatedFor", Collections.emptySet(), stringArray); for (Map.Entry> entry : annotatedFor.asMap().entrySet()) { String key = entry.getKey(); Collection values = entry.getValue(); Annotation afAnno = new Annotation(afDef, Collections .>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(); } } }