Merge "Support all UnsupportedAppUsage annotations in processor"

am: 3423014cbe

Change-Id: I2126ed1ed52d61f814d9feccd9da45a9358cf317
This commit is contained in:
Andrei-Valentin Onea
2019-05-09 05:36:07 -07:00
committed by android-build-merger
3 changed files with 83 additions and 46 deletions

View File

@@ -763,6 +763,7 @@ java_library_host {
srcs: [
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/UnsupportedAppUsage.java",
":unsupportedappusage_annotation_files",
],
}

View File

@@ -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;

View File

@@ -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;
}