Merge "Support all UnsupportedAppUsage annotations in processor"
am: 3423014cbe
Change-Id: I2126ed1ed52d61f814d9feccd9da45a9358cf317
This commit is contained in:
@@ -763,6 +763,7 @@ java_library_host {
|
||||
srcs: [
|
||||
"core/java/android/annotation/IntDef.java",
|
||||
"core/java/android/annotation/UnsupportedAppUsage.java",
|
||||
":unsupportedappusage_annotation_files",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,13 @@ import static javax.lang.model.element.ElementKind.PACKAGE;
|
||||
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||
import static javax.tools.Diagnostic.Kind.WARNING;
|
||||
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -69,6 +70,7 @@ public class SignatureBuilder {
|
||||
public SignatureBuilderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public void report(Element offendingElement) {
|
||||
mMessager.printMessage(ERROR, getMessage(), offendingElement);
|
||||
}
|
||||
@@ -153,7 +155,7 @@ public class SignatureBuilder {
|
||||
/**
|
||||
* Get the signature for an executable, either a method or a constructor.
|
||||
*
|
||||
* @param name "<init>" for constructor, else the method name
|
||||
* @param name "<init>" for constructor, else the method name
|
||||
* @param method The executable element in question.
|
||||
*/
|
||||
private String getExecutableSignature(CharSequence name, ExecutableElement method)
|
||||
@@ -191,8 +193,13 @@ public class SignatureBuilder {
|
||||
return sig.toString();
|
||||
}
|
||||
|
||||
public String buildSignature(Element element) {
|
||||
UnsupportedAppUsage uba = element.getAnnotation(UnsupportedAppUsage.class);
|
||||
/**
|
||||
* Creates the signature for an annotated element.
|
||||
*
|
||||
* @param annotationType type of annotation being processed.
|
||||
* @param element element for which we want to create a signature.
|
||||
*/
|
||||
public String buildSignature(Class<? extends Annotation> annotationType, Element element) {
|
||||
try {
|
||||
String signature;
|
||||
switch (element.getKind()) {
|
||||
@@ -208,18 +215,35 @@ public class SignatureBuilder {
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
// if we have an expected signature on the annotation, warn if it doesn't match.
|
||||
if (!Strings.isNullOrEmpty(uba.expectedSignature())) {
|
||||
if (!signature.equals(uba.expectedSignature())) {
|
||||
mMessager.printMessage(
|
||||
WARNING,
|
||||
String.format("Expected signature doesn't match generated signature.\n"
|
||||
+ " Expected: %s\n Generated: %s",
|
||||
uba.expectedSignature(), signature),
|
||||
element);
|
||||
}
|
||||
// Obtain annotation objects
|
||||
Annotation annotation = element.getAnnotation(annotationType);
|
||||
if (annotation == null) {
|
||||
throw new IllegalStateException(
|
||||
"Element doesn't have any UnsupportedAppUsage annotation");
|
||||
}
|
||||
try {
|
||||
Method expectedSignatureMethod = annotationType.getMethod("expectedSignature");
|
||||
// If we have an expected signature on the annotation, warn if it doesn't match.
|
||||
String expectedSignature = expectedSignatureMethod.invoke(annotation).toString();
|
||||
if (!Strings.isNullOrEmpty(expectedSignature)) {
|
||||
if (!signature.equals(expectedSignature)) {
|
||||
mMessager.printMessage(
|
||||
WARNING,
|
||||
String.format(
|
||||
"Expected signature doesn't match generated signature.\n"
|
||||
+ " Expected: %s\n Generated: %s",
|
||||
expectedSignature, signature),
|
||||
element);
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalStateException(
|
||||
"Annotation type does not have expectedSignature parameter", e);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException(
|
||||
"Could not get expectedSignature parameter for annotation", e);
|
||||
}
|
||||
return signature;
|
||||
} catch (SignatureBuilderException problem) {
|
||||
problem.report(element);
|
||||
return null;
|
||||
|
||||
@@ -18,9 +18,8 @@ package android.processor.unsupportedappusage;
|
||||
|
||||
import static javax.tools.StandardLocation.CLASS_OUTPUT;
|
||||
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.sun.tools.javac.model.JavacElements;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.util.Pair;
|
||||
@@ -28,6 +27,7 @@ import com.sun.tools.javac.util.Position;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -47,14 +47,14 @@ import javax.lang.model.element.TypeElement;
|
||||
/**
|
||||
* Annotation processor for {@link UnsupportedAppUsage} annotations.
|
||||
*
|
||||
* This processor currently outputs two things:
|
||||
* 1. A greylist.txt containing dex signatures of all annotated elements.
|
||||
* 2. A CSV file with a mapping of dex signatures to corresponding source positions.
|
||||
* This processor currently outputs a CSV file with a mapping of dex signatures to corresponding
|
||||
* source positions.
|
||||
*
|
||||
* The first will be used at a later stage of the build to add access flags to the dex file. The
|
||||
* second is used for automating updates to the annotations themselves.
|
||||
* This is used for automating updates to the annotations themselves.
|
||||
*/
|
||||
@SupportedAnnotationTypes({"android.annotation.UnsupportedAppUsage"})
|
||||
@SupportedAnnotationTypes({"android.annotation.UnsupportedAppUsage",
|
||||
"dalvik.annotation.compat.UnsupportedAppUsage"
|
||||
})
|
||||
public class UnsupportedAppUsageProcessor extends AbstractProcessor {
|
||||
|
||||
// Package name for writing output. Output will be written to the "class output" location within
|
||||
@@ -62,6 +62,13 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
|
||||
private static final String PACKAGE = "unsupportedappusage";
|
||||
private static final String INDEX_CSV = "unsupportedappusage_index.csv";
|
||||
|
||||
private static final ImmutableSet<Class<? extends Annotation>> SUPPORTED_ANNOTATIONS =
|
||||
ImmutableSet.of(android.annotation.UnsupportedAppUsage.class,
|
||||
dalvik.annotation.compat.UnsupportedAppUsage.class);
|
||||
private static final ImmutableSet<String> SUPPORTED_ANNOTATION_NAMES =
|
||||
SUPPORTED_ANNOTATIONS.stream().map(annotation -> annotation.getCanonicalName()).collect(
|
||||
ImmutableSet.toImmutableSet());
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
@@ -92,8 +99,7 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
|
||||
private AnnotationMirror getUnsupportedAppUsageAnnotationMirror(Element e) {
|
||||
for (AnnotationMirror m : e.getAnnotationMirrors()) {
|
||||
TypeElement type = (TypeElement) m.getAnnotationType().asElement();
|
||||
if (type.getQualifiedName().toString().equals(
|
||||
UnsupportedAppUsage.class.getCanonicalName())) {
|
||||
if (SUPPORTED_ANNOTATION_NAMES.contains(type.getQualifiedName().toString())) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
@@ -133,12 +139,12 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
|
||||
/**
|
||||
* Maps an annotated element to the source position of the @UnsupportedAppUsage annotation
|
||||
* attached to it. It returns CSV in the format:
|
||||
* dex-signature,filename,start-line,start-col,end-line,end-col
|
||||
* dex-signature,filename,start-line,start-col,end-line,end-col
|
||||
*
|
||||
* The positions refer to the annotation itself, *not* the annotated member. This can therefore
|
||||
* be used to read just the annotation from the file, and to perform in-place edits on it.
|
||||
*
|
||||
* @param signature the dex signature for the element.
|
||||
* @param signature the dex signature for the element.
|
||||
* @param annotatedElement The annotated element
|
||||
* @return A single line of CSV text
|
||||
*/
|
||||
@@ -164,28 +170,34 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
|
||||
*/
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(
|
||||
UnsupportedAppUsage.class);
|
||||
if (annotated.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
// build signatures for each annotated member, and put them in a map of signature to member
|
||||
Map<String, Element> signatureMap = new TreeMap<>();
|
||||
SignatureBuilder sb = new SignatureBuilder(processingEnv.getMessager());
|
||||
for (Element e : annotated) {
|
||||
String sig = sb.buildSignature(e);
|
||||
if (sig != null) {
|
||||
signatureMap.put(sig, e);
|
||||
for (Class<? extends Annotation> supportedAnnotation : SUPPORTED_ANNOTATIONS) {
|
||||
Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(
|
||||
supportedAnnotation);
|
||||
if (annotated.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
// Build signatures for each annotated member and put them in a map from signature to
|
||||
// member.
|
||||
for (Element e : annotated) {
|
||||
String sig = sb.buildSignature(supportedAnnotation, e);
|
||||
if (sig != null) {
|
||||
signatureMap.put(sig, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
writeToFile(INDEX_CSV,
|
||||
getCsvHeaders(),
|
||||
signatureMap.entrySet()
|
||||
.stream()
|
||||
.map(e -> getAnnotationIndex(e.getKey() ,e.getValue())));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to write output", e);
|
||||
|
||||
if (!signatureMap.isEmpty()) {
|
||||
try {
|
||||
writeToFile(INDEX_CSV,
|
||||
getCsvHeaders(),
|
||||
signatureMap.entrySet()
|
||||
.stream()
|
||||
.map(e -> getAnnotationIndex(e.getKey(), e.getValue())));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to write output", e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user