adding annotation processor to build class -> source map, with proper deps this time

Reviewed By: jeremydubreil

Differential Revision: D2823991

fb-gh-sync-id: 78f0d2c
master
Sam Blackshear 9 years ago committed by facebook-github-bot-7
parent d5baa2a1de
commit e27959f655

@ -27,7 +27,7 @@ $(ANNOTATIONS_JAR): $(ANNOT_SOURCES)
$(PROCESSOR_JAR): $(PROCESSOR_SOURCES) $(PROCESSOR_JAR): $(PROCESSOR_SOURCES)
mkdir -p $(PROCESSOR_CLASSES) mkdir -p $(PROCESSOR_CLASSES)
javac $(PROCESSOR_SOURCES) -d $(PROCESSOR_CLASSES) javac $(PROCESSOR_SOURCES) -cp .:$(JAVA_HOME)/lib/tools.jar -d $(PROCESSOR_CLASSES)
jar cvMf processor.jar -C resources META-INF -C $(PROCESSOR_CLASSES) com jar cvMf processor.jar -C resources META-INF -C $(PROCESSOR_CLASSES) com
mv processor.jar $(PROCESSOR_JAR) mv processor.jar $(PROCESSOR_JAR)

@ -0,0 +1,102 @@
/*
* Copyright (c) 2015 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.infer.annotprocess;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.Trees;
import com.sun.source.util.TreePath;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
@SupportedOptions({ "classSourceMapOutputFilename" })
// this says: "process all classes, even ones without any annotations"
@SupportedAnnotationTypes({ "*" })
public class ClassToSourceMapper extends AbstractProcessor {
// map from class name -> absolute path to source file
// e.g., com.example.MyClass -> = /Users/me/MyClass.Java
// note that this map does not contain inner or anonymous classes
private Map<String, String> mClassSourceMap = new LinkedHashMap<String, String>();
private static final String DEFAULT_OUTPUT_FILENAME = "classSourceMap.json";
private static final String OUTPUT_FILENAME_OPTION = "classSourceMapOutputFilename";
private void exportClassSourceMap(String filename) throws FileNotFoundException, IOException {
try (PrintWriter out = new PrintWriter(filename)) {
out.println("{");
int elemCount = 0;
int elemMax = mClassSourceMap.size();
for (Map.Entry<String, String> entry : mClassSourceMap.entrySet()) {
String className = entry.getKey();
String sourcePath = entry.getValue();
JSONOutputUtils.outputClassSourcePair(out, className, sourcePath, ++elemCount, elemMax);
}
out.println("}");
}
}
private void makeClassSourceMap(RoundEnvironment env) {
Set<? extends Element> rootEnv = env.getRootElements();
Trees trees = Trees.instance(processingEnv);
for (Element e : rootEnv) {
if (e instanceof TypeElement) { // class or interface
TreePath path = trees.getPath(e);
TypeElement typeElem = (TypeElement) e;
CompilationUnitTree compilationUnit = path.getCompilationUnit();
String absoluteSourcePath = compilationUnit.getSourceFile().toUri().getPath();
// map a class name to its source file. this will only capture top-level class names; inner
// classes (anonymous and otherwise) are dealt with later reading each top-level class's
// list of inner classes and mapping each one to the source file of the parent class
mClassSourceMap.put(typeElem.getQualifiedName().toString(), absoluteSourcePath);
}
}
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
makeClassSourceMap(env);
if (env.processingOver()) {
try {
Map<String,String> options = processingEnv.getOptions();
String outputFilename = options.get(OUTPUT_FILENAME_OPTION);
if (outputFilename == null) {
outputFilename = DEFAULT_OUTPUT_FILENAME;
}
exportClassSourceMap(outputFilename);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return false;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}

@ -54,14 +54,8 @@ public class JSONOutputUtils {
public static void outputClassSourcePair(PrintWriter out, String clazz, String source, public static void outputClassSourcePair(PrintWriter out, String clazz, String source,
int elemCount, int elemMax) { int elemCount, int elemMax) {
String TAB1 = " "; String TAB = " ";
String TAB2 = TAB1 + TAB1; out.print(TAB + "\"" + clazz + "\": \"" + source + "\"");
out.println(TAB1 + "{");
out.print(TAB2 + "\"class\": \"" + clazz + "\"");
out.println(",");
out.println(TAB2 + "\"source\": \"" + source + "\"");
out.print(TAB1 + "}");
outputCommaIfNotLast(out, elemCount, elemMax); outputCommaIfNotLast(out, elemCount, elemMax);
} }

Loading…
Cancel
Save