summaryrefslogtreecommitdiff
path: root/tools/processors
diff options
context:
space:
mode:
Diffstat (limited to 'tools/processors')
-rw-r--r--tools/processors/view_inspector/Android.bp1
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java37
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java80
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java14
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java117
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java481
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java4
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java21
-rw-r--r--tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java28
-rw-r--r--tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java12
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt2
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt16
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt12
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt2
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt2
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt2
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt2
-rw-r--r--tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt5
18 files changed, 478 insertions, 360 deletions
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index 06ff05e5d755..069e61f5b921 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -8,6 +8,7 @@ java_plugin {
static_libs: [
"javapoet",
+ "stub-annotations",
],
use_tools_jar: true,
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
index 2690ee87f5b2..c833e477e265 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
@@ -16,6 +16,8 @@
package android.processor.view.inspector;
+import androidx.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -40,7 +42,7 @@ final class AnnotationUtils {
private final Elements mElementUtils;
private final Types mTypeUtils;
- AnnotationUtils(ProcessingEnvironment processingEnv) {
+ AnnotationUtils(@NonNull ProcessingEnvironment processingEnv) {
mElementUtils = processingEnv.getElementUtils();
mTypeUtils = processingEnv.getTypeUtils();
}
@@ -53,7 +55,8 @@ final class AnnotationUtils {
* @return The mirror of the requested annotation
* @throws ProcessingException If there is not exactly one of the requested annotation.
*/
- AnnotationMirror exactlyOneMirror(String qualifiedName, Element element) {
+ @NonNull
+ AnnotationMirror exactlyOneMirror(@NonNull String qualifiedName, @NonNull Element element) {
final Element targetTypeElment = mElementUtils.getTypeElement(qualifiedName);
final TypeMirror targetType = targetTypeElment.asType();
AnnotationMirror result = null;
@@ -89,7 +92,7 @@ final class AnnotationUtils {
* @param annotationQualifiedName The name of the annotation to check for
* @return True if the annotation is present, false otherwise
*/
- boolean hasAnnotation(Element element, String annotationQualifiedName) {
+ boolean hasAnnotation(@NonNull Element element, @NonNull String annotationQualifiedName) {
final TypeElement namedElement = mElementUtils.getTypeElement(annotationQualifiedName);
if (namedElement != null) {
@@ -118,10 +121,10 @@ final class AnnotationUtils {
* @return A list containing the requested types
*/
<T> List<T> typedArrayValuesByName(
- String propertyName,
- Class<T> valueClass,
- Element element,
- AnnotationMirror annotationMirror) {
+ @NonNull String propertyName,
+ @NonNull Class<T> valueClass,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
return untypedArrayValuesByName(propertyName, element, annotationMirror)
.stream()
.map(annotationValue -> {
@@ -159,10 +162,11 @@ final class AnnotationUtils {
* @param annotationMirror An annotation mirror to search for the property
* @return A list of annotation values, empty list if none found
*/
+ @NonNull
List<AnnotationValue> untypedArrayValuesByName(
- String propertyName,
- Element element,
- AnnotationMirror annotationMirror) {
+ @NonNull String propertyName,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
return typedValueByName(propertyName, List.class, element, annotationMirror)
.map(untypedValues -> {
List<AnnotationValue> typedValues = new ArrayList<>(untypedValues.size());
@@ -195,6 +199,7 @@ final class AnnotationUtils {
* @param <T> The type of the value
* @return An optional containing the typed value of the named property
*/
+ @NonNull
<T> Optional<T> typedValueByName(
String propertyName,
Class<T> valueClass,
@@ -241,10 +246,11 @@ final class AnnotationUtils {
* @return An optional containing the untyped value of the named property
* @see AnnotationValue#getValue()
*/
+ @NonNull
Optional<Object> untypedValueByName(
- String propertyName,
- Element element,
- AnnotationMirror annotationMirror) {
+ @NonNull String propertyName,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
return valueByName(propertyName, annotationMirror).map(annotationValue -> {
final Object value = annotationValue.getValue();
@@ -269,7 +275,10 @@ final class AnnotationUtils {
* @param annotationMirror The mirror to search for the property
* @return The value of the property
*/
- Optional<AnnotationValue> valueByName(String propertyName, AnnotationMirror annotationMirror) {
+ @NonNull
+ Optional<AnnotationValue> valueByName(
+ @NonNull String propertyName,
+ @NonNull AnnotationMirror annotationMirror) {
final Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap =
annotationMirror.getElementValues();
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
index 1ad7ada95018..147f054b1abb 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
@@ -16,6 +16,9 @@
package android.processor.view.inspector;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.squareup.javapoet.ClassName;
import java.util.Collection;
@@ -34,27 +37,29 @@ import java.util.Optional;
* testing {@link InspectionCompanionGenerator}.
*/
public final class InspectableClassModel {
- private final ClassName mClassName;
- private final Map<String, Property> mPropertyMap;
- private Optional<String> mNodeName = Optional.empty();
+ private final @NonNull ClassName mClassName;
+ private final @NonNull Map<String, Property> mPropertyMap;
+ private @NonNull Optional<String> mNodeName = Optional.empty();
/**
* @param className The name of the modeled class
*/
- public InspectableClassModel(ClassName className) {
+ public InspectableClassModel(@NonNull ClassName className) {
mClassName = className;
mPropertyMap = new HashMap<>();
}
+ @NonNull
public ClassName getClassName() {
return mClassName;
}
+ @NonNull
public Optional<String> getNodeName() {
return mNodeName;
}
- public void setNodeName(Optional<String> nodeName) {
+ public void setNodeName(@NonNull Optional<String> nodeName) {
mNodeName = nodeName;
}
@@ -63,7 +68,7 @@ public final class InspectableClassModel {
*
* @param property The property to add or replace
*/
- public void putProperty(Property property) {
+ public void putProperty(@NonNull Property property) {
mPropertyMap.put(property.getName(), property);
}
@@ -73,7 +78,8 @@ public final class InspectableClassModel {
* @param name The name of the property
* @return The property or an empty optional
*/
- public Optional<Property> getProperty(String name) {
+ @NonNull
+ public Optional<Property> getProperty(@NonNull String name) {
return Optional.ofNullable(mPropertyMap.get(name));
}
@@ -82,6 +88,7 @@ public final class InspectableClassModel {
*
* @return An un-ordered collection of properties
*/
+ @NonNull
public Collection<Property> getAllProperties() {
return mPropertyMap.values();
}
@@ -90,8 +97,8 @@ public final class InspectableClassModel {
* Represents a way to access a property, either a getter or a field.
*/
public static final class Accessor {
- private final String mName;
- private final Type mType;
+ private final @NonNull String mName;
+ private final @NonNull Type mType;
/**
* Construct an accessor for a field.
@@ -100,7 +107,8 @@ public final class InspectableClassModel {
* @return The new accessor
* @see Type#FIELD
*/
- static Accessor ofField(String name) {
+ @NonNull
+ static Accessor ofField(@NonNull String name) {
return new Accessor(name, Type.FIELD);
}
@@ -111,19 +119,22 @@ public final class InspectableClassModel {
* @return The new accessor
* @see Type#GETTER
*/
- static Accessor ofGetter(String name) {
+ @NonNull
+ static Accessor ofGetter(@NonNull String name) {
return new Accessor(name, Type.GETTER);
}
- public Accessor(String name, Type type) {
+ public Accessor(@NonNull String name, @NonNull Type type) {
mName = Objects.requireNonNull(name, "Accessor name must not be null");
mType = Objects.requireNonNull(type, "Accessor type must not be null");
}
+ @NonNull
public String getName() {
return mName;
}
+ @NonNull
public Type getType() {
return mType;
}
@@ -135,6 +146,7 @@ public final class InspectableClassModel {
*
* @return A string representing the invocation of this accessor
*/
+ @NonNull
public String invocation() {
switch (mType) {
case FIELD:
@@ -168,15 +180,15 @@ public final class InspectableClassModel {
* Model an inspectable property
*/
public static final class Property {
- private final String mName;
- private final Accessor mAccessor;
- private final Type mType;
+ private final @NonNull String mName;
+ private final @NonNull Accessor mAccessor;
+ private final @NonNull Type mType;
private boolean mAttributeIdInferrableFromR = true;
private int mAttributeId = 0;
- private List<IntEnumEntry> mIntEnumEntries;
- private List<IntFlagEntry> mIntFlagEntries;
+ private @Nullable List<IntEnumEntry> mIntEnumEntries;
+ private @Nullable List<IntFlagEntry> mIntFlagEntries;
- public Property(String name, Accessor accessor, Type type) {
+ public Property(@NonNull String name, @NonNull Accessor accessor, @NonNull Type type) {
mName = Objects.requireNonNull(name, "Name must not be null");
mAccessor = Objects.requireNonNull(accessor, "Accessor must not be null");
mType = Objects.requireNonNull(type, "Type must not be null");
@@ -204,14 +216,17 @@ public final class InspectableClassModel {
mAttributeIdInferrableFromR = attributeIdInferrableFromR;
}
+ @NonNull
public String getName() {
return mName;
}
+ @NonNull
public Accessor getAccessor() {
return mAccessor;
}
+ @NonNull
public Type getType() {
return mType;
}
@@ -221,6 +236,7 @@ public final class InspectableClassModel {
*
* @return A list of mapping entries, empty if absent
*/
+ @NonNull
public List<IntEnumEntry> getIntEnumEntries() {
if (mIntEnumEntries != null) {
return mIntEnumEntries;
@@ -229,7 +245,7 @@ public final class InspectableClassModel {
}
}
- public void setIntEnumEntries(List<IntEnumEntry> intEnumEntries) {
+ public void setIntEnumEntries(@NonNull List<IntEnumEntry> intEnumEntries) {
mIntEnumEntries = intEnumEntries;
}
@@ -238,6 +254,7 @@ public final class InspectableClassModel {
*
* @return A list of mapping entries, empty if absent
*/
+ @NonNull
public List<IntFlagEntry> getIntFlagEntries() {
if (mIntFlagEntries != null) {
return mIntFlagEntries;
@@ -246,7 +263,7 @@ public final class InspectableClassModel {
}
}
- public void setIntFlagEntries(List<IntFlagEntry> intFlagEntries) {
+ public void setIntFlagEntries(@NonNull List<IntFlagEntry> intFlagEntries) {
mIntFlagEntries = intFlagEntries;
}
@@ -321,14 +338,15 @@ public final class InspectableClassModel {
* @see android.view.inspector.IntEnumMapping
*/
public static final class IntEnumEntry {
- private final String mName;
+ private final @NonNull String mName;
private final int mValue;
- public IntEnumEntry(String name, int value) {
+ public IntEnumEntry(int value, @NonNull String name) {
mName = Objects.requireNonNull(name, "Name must not be null");
mValue = value;
}
+ @NonNull
public String getName() {
return mName;
}
@@ -344,29 +362,21 @@ public final class InspectableClassModel {
* @see android.view.inspector.IntFlagMapping
*/
public static final class IntFlagEntry {
- private final String mName;
+ private final @NonNull String mName;
private final int mTarget;
private final int mMask;
- public IntFlagEntry(String name, int target, int mask) {
+ public IntFlagEntry(int mask, int target, @NonNull String name) {
mName = Objects.requireNonNull(name, "Name must not be null");
mTarget = target;
mMask = mask;
}
- public IntFlagEntry(String name, int target) {
- this(name, target, target);
- }
-
- /**
- * Determine if this entry has a bitmask.
- *
- * @return True if the bitmask and target are different, false otherwise
- */
- public boolean hasMask() {
- return mTarget != mMask;
+ public IntFlagEntry(int target, String name) {
+ this(target, target, name);
}
+ @NonNull
public String getName() {
return mName;
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
index 46819b28c1e8..64a60fbc9179 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
@@ -16,6 +16,8 @@
package android.processor.view.inspector;
+import androidx.annotation.NonNull;
+
import java.util.Optional;
import javax.annotation.processing.ProcessingEnvironment;
@@ -28,17 +30,17 @@ import javax.lang.model.element.Element;
* @see android.view.inspector.InspectableNodeName
*/
public final class InspectableNodeNameProcessor implements ModelProcessor {
- private final String mQualifiedName;
- private final ProcessingEnvironment mProcessingEnv;
- private final AnnotationUtils mAnnotationUtils;
+ private final @NonNull String mQualifiedName;
+ private final @NonNull ProcessingEnvironment mProcessingEnv;
+ private final @NonNull AnnotationUtils mAnnotationUtils;
/**
* @param annotationQualifiedName The qualified name of the annotation to process
* @param processingEnv The processing environment from the parent processor
*/
public InspectableNodeNameProcessor(
- String annotationQualifiedName,
- ProcessingEnvironment processingEnv) {
+ @NonNull String annotationQualifiedName,
+ @NonNull ProcessingEnvironment processingEnv) {
mQualifiedName = annotationQualifiedName;
mProcessingEnv = processingEnv;
mAnnotationUtils = new AnnotationUtils(processingEnv);
@@ -54,7 +56,7 @@ public final class InspectableNodeNameProcessor implements ModelProcessor {
* @param model The model this element should be merged into
*/
@Override
- public void process(Element element, InspectableClassModel model) {
+ public void process(@NonNull Element element, @NonNull InspectableClassModel model) {
try {
final AnnotationMirror mirror =
mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
index 20de90d51482..2042a68857fb 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -21,6 +21,8 @@ import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
import android.processor.view.inspector.InspectableClassModel.Property;
+import androidx.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -45,9 +47,9 @@ import javax.lang.model.type.TypeMirror;
* @see android.view.inspector.InspectableProperty
*/
public final class InspectablePropertyProcessor implements ModelProcessor {
- private final String mQualifiedName;
- private final ProcessingEnvironment mProcessingEnv;
- private final AnnotationUtils mAnnotationUtils;
+ private final @NonNull String mQualifiedName;
+ private final @NonNull ProcessingEnvironment mProcessingEnv;
+ private final @NonNull AnnotationUtils mAnnotationUtils;
/**
* Regex that matches methods names of the form {@code #getValue()}.
@@ -130,15 +132,15 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param processingEnv The processing environment from the parent processor
*/
public InspectablePropertyProcessor(
- String annotationQualifiedName,
- ProcessingEnvironment processingEnv) {
+ @NonNull String annotationQualifiedName,
+ @NonNull ProcessingEnvironment processingEnv) {
mQualifiedName = annotationQualifiedName;
mProcessingEnv = processingEnv;
mAnnotationUtils = new AnnotationUtils(processingEnv);
}
@Override
- public void process(Element element, InspectableClassModel model) {
+ public void process(@NonNull Element element, @NonNull InspectableClassModel model) {
try {
final AnnotationMirror annotation =
mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
@@ -169,7 +171,10 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @return A property for the getter and annotation
* @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
*/
- private Property buildProperty(Element accessor, AnnotationMirror annotation) {
+ @NonNull
+ private Property buildProperty(
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
final Property property;
final Optional<String> nameFromAnnotation = mAnnotationUtils
.typedValueByName("name", String.class, accessor, annotation);
@@ -227,7 +232,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param element The element to check
* @throws ProcessingException If the element's modifiers are invalid
*/
- private void validateModifiers(Element element) {
+ private void validateModifiers(@NonNull Element element) {
final Set<Modifier> modifiers = element.getModifiers();
if (!modifiers.contains(Modifier.PUBLIC)) {
@@ -256,7 +261,8 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @return An {@link ExecutableElement} that represents a getter method.
* @throws ProcessingException if the element isn't a getter
*/
- private ExecutableElement ensureGetter(Element element) {
+ @NonNull
+ private ExecutableElement ensureGetter(@NonNull Element element) {
if (element.getKind() != ElementKind.METHOD) {
throw new ProcessingException(
String.format("Expected a method, got a %s", element.getKind()),
@@ -300,10 +306,10 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @throws ProcessingException If the property type cannot be resolved or is invalid
* @see android.view.inspector.InspectableProperty#valueType()
*/
+ @NonNull
private Property.Type determinePropertyType(
- Element accessor,
- AnnotationMirror annotation) {
-
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
final String valueType = mAnnotationUtils
.untypedValueByName("valueType", accessor, annotation)
.map(Object::toString)
@@ -437,7 +443,8 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @return The return or field type of the element
* @throws ProcessingException If the element is not a field or a method
*/
- private TypeMirror extractReturnOrFieldType(Element element) {
+ @NonNull
+ private TypeMirror extractReturnOrFieldType(@NonNull Element element) {
switch (element.getKind()) {
case FIELD:
return element.asType();
@@ -460,7 +467,10 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @return The property type returned by the getter
* @throws ProcessingException If the return type is not a primitive or an object
*/
- private Property.Type convertTypeMirrorToPropertyType(TypeMirror typeMirror, Element element) {
+ @NonNull
+ private Property.Type convertTypeMirrorToPropertyType(
+ @NonNull TypeMirror typeMirror,
+ @NonNull Element element) {
switch (unboxType(typeMirror)) {
case BOOLEAN:
return Property.Type.BOOLEAN;
@@ -503,10 +513,10 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @throws ProcessingException If the return type is not an int
*/
private static void requirePackedIntToBeInt(
- String typeName,
- Property.Type returnType,
- Element accessor,
- AnnotationMirror annotation) {
+ @NonNull String typeName,
+ @NonNull Property.Type returnType,
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
if (returnType != Property.Type.INT) {
throw new ProcessingException(
String.format(
@@ -528,7 +538,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param accessor The getter or field to query
* @return True if the getter has a color annotation, false otherwise
*/
- private boolean hasColorAnnotation(Element accessor) {
+ private boolean hasColorAnnotation(@NonNull Element accessor) {
switch (unboxType(extractReturnOrFieldType(accessor))) {
case INT:
for (String name : COLOR_INT_ANNOTATION_NAMES) {
@@ -555,7 +565,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param accessor The getter or field to query
* @return True if the accessor is an integer and has a resource ID annotation, false otherwise
*/
- private boolean hasResourceIdAnnotation(Element accessor) {
+ private boolean hasResourceIdAnnotation(@NonNull Element accessor) {
if (unboxType(extractReturnOrFieldType(accessor)) == TypeKind.INT) {
for (String name : RESOURCE_ID_ANNOTATION_NAMES) {
if (mAnnotationUtils.hasAnnotation(accessor, name)) {
@@ -581,7 +591,8 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param getter An element representing a getter
* @return A string property name
*/
- private String inferPropertyNameFromGetter(ExecutableElement getter) {
+ @NonNull
+ private String inferPropertyNameFromGetter(@NonNull ExecutableElement getter) {
final String name = getter.getSimpleName().toString();
if (GETTER_GET_PREFIX.matcher(name).find()) {
@@ -600,7 +611,6 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* {@link android.view.inspector.InspectableProperty.EnumMap} annotations into
* {@link IntEnumEntry} objects. Further validation should be handled elsewhere
*
- * @see android.view.inspector.IntEnumMapping
* @see android.view.inspector.InspectableProperty#enumMapping()
* @param accessor The accessor of the property, used for exceptions
* @param annotation The {@link android.view.inspector.InspectableProperty} annotation to
@@ -608,9 +618,10 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @return A list of int enum entries, in the order specified in source
* @throws ProcessingException if mapping doesn't exist or is invalid
*/
+ @NonNull
private List<IntEnumEntry> processEnumMapping(
- Element accessor,
- AnnotationMirror annotation) {
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
List<AnnotationMirror> enumAnnotations = mAnnotationUtils.typedArrayValuesByName(
"enumMapping", AnnotationMirror.class, accessor, annotation);
List<IntEnumEntry> enumEntries = new ArrayList<>(enumAnnotations.size());
@@ -623,23 +634,19 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
for (AnnotationMirror enumAnnotation : enumAnnotations) {
final String name = mAnnotationUtils.typedValueByName(
"name", String.class, accessor, enumAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Name is required for @EnumMap",
- accessor,
- enumAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Name is required for @EnumMap",
+ accessor,
+ enumAnnotation));
final int value = mAnnotationUtils.typedValueByName(
"value", Integer.class, accessor, enumAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Value is required for @EnumMap",
- accessor,
- enumAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Value is required for @EnumMap",
+ accessor,
+ enumAnnotation));
- enumEntries.add(new IntEnumEntry(name, value));
+ enumEntries.add(new IntEnumEntry(value, name));
}
return enumEntries;
@@ -660,9 +667,10 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @return A list of int flags entries, in the order specified in source
* @throws ProcessingException if mapping doesn't exist or is invalid
*/
+ @NonNull
private List<IntFlagEntry> processFlagMapping(
- Element accessor,
- AnnotationMirror annotation) {
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
List<AnnotationMirror> flagAnnotations = mAnnotationUtils.typedArrayValuesByName(
"flagMapping", AnnotationMirror.class, accessor, annotation);
List<IntFlagEntry> flagEntries = new ArrayList<>(flagAnnotations.size());
@@ -675,29 +683,25 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
for (AnnotationMirror flagAnnotation : flagAnnotations) {
final String name = mAnnotationUtils.typedValueByName(
"name", String.class, accessor, flagAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Name is required for @FlagMap",
- accessor,
- flagAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Name is required for @FlagMap",
+ accessor,
+ flagAnnotation));
final int target = mAnnotationUtils.typedValueByName(
"target", Integer.class, accessor, flagAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Target is required for @FlagMap",
- accessor,
- flagAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Target is required for @FlagMap",
+ accessor,
+ flagAnnotation));
final Optional<Integer> mask = mAnnotationUtils.typedValueByName(
"mask", Integer.class, accessor, flagAnnotation);
if (mask.isPresent()) {
- flagEntries.add(new IntFlagEntry(name, target, mask.get()));
+ flagEntries.add(new IntFlagEntry(mask.get(), target, name));
} else {
- flagEntries.add(new IntFlagEntry(name, target));
+ flagEntries.add(new IntFlagEntry(target, name));
}
}
@@ -710,7 +714,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param type The type mirror to check
* @return True if the type is a boolean
*/
- private boolean isBoolean(TypeMirror type) {
+ private boolean isBoolean(@NonNull TypeMirror type) {
if (type.getKind() == TypeKind.DECLARED) {
return mProcessingEnv.getTypeUtils().unboxedType(type).getKind() == TypeKind.BOOLEAN;
} else {
@@ -724,7 +728,8 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param typeMirror The type mirror to unbox
* @return The same type mirror, or an unboxed primitive version
*/
- private TypeKind unboxType(TypeMirror typeMirror) {
+ @NonNull
+ private TypeKind unboxType(@NonNull TypeMirror typeMirror) {
final TypeKind typeKind = typeMirror.getKind();
if (typeKind.isPrimitive()) {
@@ -746,7 +751,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor {
* @param typeMirror The type mirror to test
* @return True if it represents a subclass of color, false otherwise
*/
- private boolean isColorType(TypeMirror typeMirror) {
+ private boolean isColorType(@NonNull TypeMirror typeMirror) {
final TypeElement colorType = mProcessingEnv
.getElementUtils()
.getTypeElement("android.graphics.Color");
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index 6f6c1aa485ac..c428a4613c95 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -16,11 +16,12 @@
package android.processor.view.inspector;
-
import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
import android.processor.view.inspector.InspectableClassModel.Property;
+import androidx.annotation.NonNull;
+
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
@@ -34,9 +35,11 @@ import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
-import java.util.Optional;
+import java.util.stream.Collectors;
import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier;
@@ -45,8 +48,8 @@ import javax.lang.model.element.Modifier;
* Generates a source file defining a {@link android.view.inspector.InspectionCompanion}.
*/
public final class InspectionCompanionGenerator {
- private final Filer mFiler;
- private final Class mRequestingClass;
+ private final @NonNull Filer mFiler;
+ private final @NonNull Class mRequestingClass;
/**
* The class name for {@code R.java}.
@@ -72,10 +75,9 @@ public final class InspectionCompanionGenerator {
"android.view.inspector", "PropertyReader");
/**
- * The class name of {@link android.view.inspector.IntEnumMapping}.
+ * The class name of {@link android.util.SparseArray}.
*/
- private static final ClassName INT_ENUM_MAPPING = ClassName.get(
- "android.view.inspector", "IntEnumMapping");
+ private static final ClassName SPARSE_ARRAY = ClassName.get("android.util", "SparseArray");
/**
* The class name of {@link android.view.inspector.IntFlagMapping}.
@@ -84,17 +86,6 @@ public final class InspectionCompanionGenerator {
"android.view.inspector", "IntFlagMapping");
/**
- * The {@code mPropertiesMapped} field.
- */
- private static final FieldSpec M_PROPERTIES_MAPPED = FieldSpec
- .builder(TypeName.BOOLEAN, "mPropertiesMapped", Modifier.PRIVATE)
- .initializer("false")
- .addJavadoc(
- "Set by {@link #mapProperties($T)} once properties have been mapped.\n",
- PROPERTY_MAPPER)
- .build();
-
- /**
* The suffix of the generated class name after the class's binary name.
*/
private static final String GENERATED_CLASS_SUFFIX = "$InspectionCompanion";
@@ -110,7 +101,7 @@ public final class InspectionCompanionGenerator {
* @param filer A filer to write the generated source to
* @param requestingClass A class object representing the class that invoked the generator
*/
- public InspectionCompanionGenerator(Filer filer, Class requestingClass) {
+ public InspectionCompanionGenerator(@NonNull Filer filer, @NonNull Class requestingClass) {
mFiler = filer;
mRequestingClass = requestingClass;
}
@@ -121,7 +112,7 @@ public final class InspectionCompanionGenerator {
* @param model The model to generated
* @throws IOException From the Filer
*/
- public void generate(InspectableClassModel model) throws IOException {
+ public void generate(@NonNull InspectableClassModel model) throws IOException {
generateFile(model).writeTo(mFiler);
}
@@ -133,7 +124,8 @@ public final class InspectionCompanionGenerator {
* @param model The model to generate from
* @return A generated file of an {@link android.view.inspector.InspectionCompanion}
*/
- JavaFile generateFile(InspectableClassModel model) {
+ @NonNull
+ JavaFile generateFile(@NonNull InspectableClassModel model) {
return JavaFile
.builder(model.getClassName().packageName(), generateTypeSpec(model))
.indent(" ")
@@ -147,8 +139,12 @@ public final class InspectionCompanionGenerator {
* @param model The model to generate from
* @return A TypeSpec of the inspection companion
*/
- private TypeSpec generateTypeSpec(InspectableClassModel model) {
- final List<PropertyIdField> propertyIdFields = generatePropertyIdFields(model);
+ @NonNull
+ private TypeSpec generateTypeSpec(@NonNull InspectableClassModel model) {
+ final List<Property> properties = new ArrayList<>(model.getAllProperties());
+ properties.sort(Comparator.comparing(Property::getName));
+
+ final Map<Property, FieldSpec> fields = generateIdFieldSpecs(properties);
TypeSpec.Builder builder = TypeSpec
.classBuilder(generateClassName(model))
@@ -158,238 +154,325 @@ public final class InspectionCompanionGenerator {
.addJavadoc("Inspection companion for {@link $T}.\n\n", model.getClassName())
.addJavadoc("Generated by {@link $T}\n", getClass())
.addJavadoc("on behalf of {@link $T}.\n", mRequestingClass)
- .addField(M_PROPERTIES_MAPPED);
-
- for (PropertyIdField propertyIdField : propertyIdFields) {
- builder.addField(propertyIdField.mFieldSpec);
- }
+ .addField(FieldSpec
+ .builder(TypeName.BOOLEAN, "mPropertiesMapped", Modifier.PRIVATE)
+ .initializer("false")
+ .addJavadoc("Guards against reading properties before mapping them.\n")
+ .build())
+ .addFields(properties.stream().map(fields::get).collect(Collectors.toList()))
+ .addMethod(generateMapProperties(properties, fields))
+ .addMethod(generateReadProperties(properties, fields, model.getClassName()));
- builder.addMethod(generateMapProperties(propertyIdFields))
- .addMethod(generateReadProperties(model, propertyIdFields));
-
- generateGetNodeName(model).ifPresent(builder::addMethod);
+ model.getNodeName().ifPresent(name -> builder.addMethod(generateGetNodeName(name)));
return builder.build();
}
/**
- * Build a list of {@link PropertyIdField}'s for a model.
- *
- * To insure idempotency of the generated code, this method sorts the list of properties
- * alphabetically by name.
+ * Map properties to fields to store the mapping IDs in the generated inspection companion.
*
- * A {@link NameAllocator} is used to ensure that the field names are valid Java identifiers,
- * and it prevents overlaps in names by suffixing them as needed.
- *
- * @param model The model to get properties from
- * @return A list of properties and fields
+ * @param properties A list of property models
+ * @return A map of properties to their {@link FieldSpec}
*/
- private List<PropertyIdField> generatePropertyIdFields(InspectableClassModel model) {
- final NameAllocator nameAllocator = new NameAllocator();
- final List<Property> sortedProperties = new ArrayList<>(model.getAllProperties());
- final List<PropertyIdField> propertyIdFields = new ArrayList<>(sortedProperties.size());
-
- sortedProperties.sort(Comparator.comparing(Property::getName));
-
- for (Property property : sortedProperties) {
- // Format a property to a member field name like "someProperty" -> "mSomePropertyId"
- final String memberName = String.format(
+ @NonNull
+ private Map<Property, FieldSpec> generateIdFieldSpecs(@NonNull List<Property> properties) {
+ final Map<Property, FieldSpec> fields = new HashMap<>();
+ final NameAllocator fieldNames = new NameAllocator();
+ fieldNames.newName("mPropertiesMapped");
+
+ for (Property property : properties) {
+ final String memberName = fieldNames.newName(String.format(
"m%s%sId",
property.getName().substring(0, 1).toUpperCase(),
- property.getName().substring(1));
- final FieldSpec fieldSpec = FieldSpec
- .builder(TypeName.INT, nameAllocator.newName(memberName), Modifier.PRIVATE)
- .addJavadoc("Property ID of {@code $L}.\n", property.getName())
- .build();
+ property.getName().substring(1)));
- propertyIdFields.add(new PropertyIdField(fieldSpec, property));
+ fields.put(property, FieldSpec
+ .builder(TypeName.INT, memberName, Modifier.PRIVATE)
+ .addJavadoc("Property ID of {@code $L}.\n", property.getName())
+ .build());
}
- return propertyIdFields;
+ return fields;
}
/**
- * Generate a method definition for
- * {@link android.view.inspector.InspectionCompanion#getNodeName()}, if needed.
- *
- * If {@link InspectableClassModel#getNodeName()} is empty, This method returns an empty
- * optional, otherwise, it generates a simple method that returns the string value of the
- * node name.
- *
- * @param model The model to generate from
- * @return The method definition or an empty Optional
- */
- private Optional<MethodSpec> generateGetNodeName(InspectableClassModel model) {
- return model.getNodeName().map(nodeName -> MethodSpec.methodBuilder("getNodeName")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .returns(String.class)
- .addStatement("return $S", nodeName)
- .build());
- }
-
- /**
- * Generate a method definition for
+ * Generates an implementation of
* {@link android.view.inspector.InspectionCompanion#mapProperties(
* android.view.inspector.PropertyMapper)}.
*
- * @param propertyIdFields A list of properties to map to ID fields
- * @return The method definition
+ * Example:
+ * <pre>
+ * @Override
+ * public void mapProperties(PropertyMapper propertyMapper) {
+ * mValueId = propertyMapper.mapInt("value", R.attr.value);
+ * mPropertiesMapped = true;
+ * }
+ * </pre>
+ *
+ * @param properties A sorted list of property models
+ * @param fields A map of properties to their ID field specs
+ * @return A method definition
*/
- private MethodSpec generateMapProperties(List<PropertyIdField> propertyIdFields) {
+ @NonNull
+ private MethodSpec generateMapProperties(
+ @NonNull List<Property> properties,
+ @NonNull Map<Property, FieldSpec> fields) {
+ final NameAllocator mappingVariables = new NameAllocator();
+
final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapProperties")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.addParameter(PROPERTY_MAPPER, "propertyMapper");
- propertyIdFields.forEach(p -> builder.addStatement(generatePropertyMapperInvocation(p)));
- builder.addStatement("$N = true", M_PROPERTIES_MAPPED);
+ // Reserve existing names
+ mappingVariables.newName("mPropertiesMapped");
+ mappingVariables.newName("propertyMapper");
+ properties.forEach(p -> mappingVariables.newName(fields.get(p).name));
+
+ for (Property property : properties) {
+ final FieldSpec field = fields.get(property);
+ switch (property.getType()) {
+ case INT_ENUM:
+ builder.addCode(generateIntEnumPropertyMapperInvocation(
+ property,
+ field,
+ mappingVariables.newName(property.getName() + "EnumMapping")));
+ break;
+ case INT_FLAG:
+ builder.addCode(generateIntFlagPropertyMapperInvocation(
+ property,
+ field,
+ mappingVariables.newName(property.getName() + "FlagMapping")));
+ break;
+ default:
+ builder.addCode(generateSimplePropertyMapperInvocation(property, field));
+ }
+ }
+
+ builder.addStatement("mPropertiesMapped = true");
return builder.build();
}
/**
- * Generate a method definition for
- * {@link android.view.inspector.InspectionCompanion#readProperties(
- * Object, android.view.inspector.PropertyReader)}.
+ * Generate a {@link android.view.inspector.PropertyMapper} invocation.
*
- * @param model The model to generate from
- * @param propertyIdFields A list of properties and ID fields to read from
- * @return The method definition
+ * Example:
+ * <pre>
+ * mValueId = propertyMapper.mapInt("value", R.attr.value);
+ * </pre>
+ *
+ * @param property A property model to map
+ * @param field The property ID field for the property
+ * @return A code block containing a statement
*/
- private MethodSpec generateReadProperties(
- InspectableClassModel model,
- List<PropertyIdField> propertyIdFields) {
- final MethodSpec.Builder builder = MethodSpec.methodBuilder("readProperties")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(model.getClassName(), "node")
- .addParameter(PROPERTY_READER, "propertyReader")
- .addCode(generatePropertyMapInitializationCheck());
+ @NonNull
+ private CodeBlock generateSimplePropertyMapperInvocation(
+ @NonNull Property property,
+ @NonNull FieldSpec field) {
+ return CodeBlock
+ .builder()
+ .addStatement(
+ "$N = propertyMapper.map$L($S, $L)",
+ field,
+ methodSuffixForPropertyType(property.getType()),
+ property.getName(),
+ generateAttributeId(property))
+ .build();
+ }
+
+ /**
+ * Generate a {@link android.view.inspector.PropertyMapper} invocation for an int enum.
+ *
+ * Example:
+ * <pre>
+ * final SparseArray<String> valueEnumMapping = new SparseArray<>();
+ * valueEnumMapping.put(1, "ONE");
+ * valueEnumMapping.put(2, "TWO");
+ * mValueId = propertyMapper.mapIntEnum("value", R.attr.value, valueEnumMapping::get);
+ * </pre>
+ *
+ * @param property A property model to map
+ * @param field The property ID field for the property
+ * @param variable The name of a local variable to use to store the mapping in
+ * @return A code block containing a series of statements
+ */
+ @NonNull
+ private CodeBlock generateIntEnumPropertyMapperInvocation(
+ @NonNull Property property,
+ @NonNull FieldSpec field,
+ @NonNull String variable) {
+ final CodeBlock.Builder builder = CodeBlock.builder();
+
+ final List<IntEnumEntry> enumEntries = property.getIntEnumEntries();
+ enumEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
+
+ builder.addStatement(
+ "final $1T<$2T> $3N = new $1T<>()",
+ SPARSE_ARRAY,
+ String.class,
+ variable);
- for (PropertyIdField propertyIdField : propertyIdFields) {
+ for (IntEnumEntry enumEntry : enumEntries) {
builder.addStatement(
- "propertyReader.read$L($N, node.$L)",
- methodSuffixForPropertyType(propertyIdField.mProperty.getType()),
- propertyIdField.mFieldSpec,
- propertyIdField.mProperty.getAccessor().invocation());
+ "$N.put($L, $S)",
+ variable,
+ enumEntry.getValue(),
+ enumEntry.getName());
}
+ builder.addStatement(
+ "$N = propertyMapper.mapIntEnum($S, $L, $N::get)",
+ field,
+ property.getName(),
+ generateAttributeId(property),
+ variable);
+
return builder.build();
}
/**
- * Generate a statement maps a property with a {@link android.view.inspector.PropertyMapper}.
+ * Generate a {@link android.view.inspector.PropertyMapper} invocation for an int flag.
*
- * @param propertyIdField The property model and ID field to generate from
- * @return A statement that invokes property mapper method
+ * Example:
+ * <pre>
+ * final IntFlagMapping valueFlagMapping = new IntFlagMapping();
+ * valueFlagMapping.add(0x00000003, 0x00000001, "ONE");
+ * valueFlagMapping.add(0x00000003, 0x00000002, "TWO");
+ * mValueId = propertyMapper.mapIntFlag("value", R.attr.value, valueFlagMapping::get);
+ * </pre>
+ *
+ * @param property A property model to map
+ * @param field The property ID field for the property
+ * @param variable The name of a local variable to use to store the mapping in
+ * @return A code block containing a series of statements
*/
- private CodeBlock generatePropertyMapperInvocation(PropertyIdField propertyIdField) {
+ @NonNull
+ private CodeBlock generateIntFlagPropertyMapperInvocation(
+ @NonNull Property property,
+ @NonNull FieldSpec field,
+ @NonNull String variable) {
final CodeBlock.Builder builder = CodeBlock.builder();
- final Property property = propertyIdField.mProperty;
- final FieldSpec fieldSpec = propertyIdField.mFieldSpec;
- builder.add(
- "$N = propertyMapper.map$L($S,$W",
- fieldSpec,
- methodSuffixForPropertyType(property.getType()),
- property.getName());
+ final List<IntFlagEntry> flagEntries = property.getIntFlagEntries();
+ flagEntries.sort(Comparator.comparing(IntFlagEntry::getName));
+
+ builder.addStatement(
+ "final $1T $2N = new $1T()",
+ INT_FLAG_MAPPING,
+ variable);
+
+ for (IntFlagEntry flagEntry : flagEntries) {
+ builder.addStatement(
+ "$N.add($L, $L, $S)",
+ variable,
+ hexLiteral(flagEntry.getMask()),
+ hexLiteral(flagEntry.getTarget()),
+ flagEntry.getName());
+ }
+ builder.addStatement(
+ "$N = propertyMapper.mapIntFlag($S, $L, $N::get)",
+ field,
+ property.getName(),
+ generateAttributeId(property),
+ variable);
+
+ return builder.build();
+ }
+
+ /**
+ * Generate a literal attribute ID or reference to {@link android.R.attr}.
+ *
+ * Example: {@code R.attr.value} or {@code 0xdecafbad}.
+ *
+ * @param property A property model
+ * @return A code block containing the attribute ID
+ */
+ @NonNull
+ private CodeBlock generateAttributeId(@NonNull Property property) {
if (property.isAttributeIdInferrableFromR()) {
- builder.add("$T.attr.$L", R_CLASS_NAME, property.getName());
+ return CodeBlock.of("$T.attr.$L", R_CLASS_NAME, property.getName());
} else {
if (property.getAttributeId() == ID_NULL) {
- builder.add("$L", ID_NULL);
+ return CodeBlock.of("$L", ID_NULL);
} else {
- builder.add("$L", hexLiteral(property.getAttributeId()));
+ return CodeBlock.of("$L", hexLiteral(property.getAttributeId()));
}
}
-
- switch (property.getType()) {
- case INT_ENUM:
- builder.add(",$W");
- builder.add(generateIntEnumMappingBuilder(property.getIntEnumEntries()));
- break;
- case INT_FLAG:
- builder.add(",$W");
- builder.add(generateIntFlagMappingBuilder(property.getIntFlagEntries()));
- break;
- }
-
- return builder.add(")").build();
}
/**
- * Generate a check that throws
- * {@link android.view.inspector.InspectionCompanion.UninitializedPropertyMapException}
- * if the properties haven't been initialized.
+ * Generate an implementation of
+ * {@link android.view.inspector.InspectionCompanion#readProperties(Object,
+ * android.view.inspector.PropertyReader)}.
*
+ * Example:
* <pre>
- * if (!mPropertiesMapped) {
- * throw new InspectionCompanion.UninitializedPropertyMapException();
+ * @Override
+ * public void readProperties(MyNode node, PropertyReader propertyReader) {
+ * if (!mPropertiesMapped) {
+ * throw new InspectionCompanion.UninitializedPropertyMapException();
+ * }
+ * propertyReader.readInt(mValueId, node.getValue());
* }
* </pre>
*
- * @return A codeblock containing the property map initialization check
+ * @param properties An ordered list of property models
+ * @param fields A map from properties to their field specs
+ * @param nodeClass The class of the node, used for the parameter type
+ * @return A method definition
*/
- private CodeBlock generatePropertyMapInitializationCheck() {
- return CodeBlock.builder()
- .beginControlFlow("if (!$N)", M_PROPERTIES_MAPPED)
+ @NonNull
+ private MethodSpec generateReadProperties(
+ @NonNull List<Property> properties,
+ @NonNull Map<Property, FieldSpec> fields,
+ @NonNull ClassName nodeClass) {
+ final MethodSpec.Builder builder = MethodSpec.methodBuilder("readProperties")
+ .addAnnotation(Override.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addParameter(nodeClass, "node")
+ .addParameter(PROPERTY_READER, "propertyReader")
+ .beginControlFlow("if (!mPropertiesMapped)")
.addStatement(
"throw new $T()",
INSPECTION_COMPANION.nestedClass("UninitializedPropertyMapException"))
- .endControlFlow()
- .build();
+ .endControlFlow();
+
+ for (Property property : properties) {
+ builder.addStatement(
+ "propertyReader.read$L($N, node.$L)",
+ methodSuffixForPropertyType(property.getType()),
+ fields.get(property),
+ property.getAccessor().invocation());
+ }
+
+ return builder.build();
}
/**
- * Generate an invocation of {@link android.view.inspector.IntEnumMapping.Builder}.
+ * Generate an implementation of
+ * {@link android.view.inspector.InspectionCompanion#getNodeName()}.
*
+ * Example:
* <pre>
- * new IntEnumMapping.Builder()
- * .addValue("ONE", 1)
- * .build()
+ * @Override
+ * public String getNodeName() {
+ * return "nodeName";
+ * }
* </pre>
*
- * @return A codeblock containing the an int enum mapping builder
+ * @param nodeName The name of this node
+ * @return A method definition that returns the node name
*/
- private CodeBlock generateIntEnumMappingBuilder(List<IntEnumEntry> intEnumEntries) {
- final ArrayList<IntEnumEntry> sortedEntries = new ArrayList<>(intEnumEntries);
- sortedEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
-
- final CodeBlock.Builder builder = CodeBlock.builder()
- .add("new $T()$>", INT_ENUM_MAPPING.nestedClass("Builder"));
-
- for (IntEnumEntry entry : sortedEntries) {
- builder.add("\n.addValue($S, $L)", entry.getName(), entry.getValue());
- }
-
- return builder.add("\n.build()$<").build();
- }
-
- private CodeBlock generateIntFlagMappingBuilder(List<IntFlagEntry> intFlagEntries) {
- final ArrayList<IntFlagEntry> sortedEntries = new ArrayList<>(intFlagEntries);
- sortedEntries.sort(Comparator.comparing(IntFlagEntry::getName));
-
- final CodeBlock.Builder builder = CodeBlock.builder()
- .add("new $T()$>", INT_FLAG_MAPPING.nestedClass("Builder"));
-
- for (IntFlagEntry entry : sortedEntries) {
- if (entry.hasMask()) {
- builder.add(
- "\n.addFlag($S, $L, $L)",
- entry.getName(),
- hexLiteral(entry.getTarget()),
- hexLiteral(entry.getMask()));
- } else {
- builder.add(
- "\n.addFlag($S, $L)",
- entry.getName(),
- hexLiteral(entry.getTarget()));
- }
- }
-
- return builder.add("\n.build()$<").build();
+ @NonNull
+ private MethodSpec generateGetNodeName(@NonNull String nodeName) {
+ return MethodSpec.methodBuilder("getNodeName")
+ .addAnnotation(Override.class)
+ .addModifiers(Modifier.PUBLIC)
+ .returns(String.class)
+ .addStatement("return $S", nodeName)
+ .build();
}
/**
@@ -397,14 +480,15 @@ public final class InspectionCompanionGenerator {
*
* The generated class is added to the same package as the source class. If the class in the
* model is a nested class, the nested class names are joined with {@code "$"}. The suffix
- * {@code "$$InspectionCompanion"} is always added the the generated name. E.g.: For modeled
+ * {@code "$InspectionCompanion"} is always added to the generated name. E.g.: For modeled
* class {@code com.example.Outer.Inner}, the generated class name will be
- * {@code com.example.Outer$Inner$$InspectionCompanion}.
+ * {@code com.example.Outer$Inner$InspectionCompanion}.
*
* @param model The model to generate from
* @return A class name for the generated inspection companion class
*/
- private static ClassName generateClassName(InspectableClassModel model) {
+ @NonNull
+ private static ClassName generateClassName(@NonNull InspectableClassModel model) {
final ClassName className = model.getClassName();
return ClassName.get(
@@ -418,7 +502,8 @@ public final class InspectionCompanionGenerator {
* @param type The requested property type
* @return A method suffix
*/
- private static String methodSuffixForPropertyType(Property.Type type) {
+ @NonNull
+ private static String methodSuffixForPropertyType(@NonNull Property.Type type) {
switch (type) {
case BOOLEAN:
return "Boolean";
@@ -453,20 +538,14 @@ public final class InspectionCompanionGenerator {
}
}
- private static String hexLiteral(int value) {
- return String.format("0x%08x", value);
- }
-
/**
- * Value class that holds a {@link Property} and a {@link FieldSpec} for that property.
+ * Format an int as an 8 digit hex literal
+ *
+ * @param value The value to format
+ * @return A string representation of the hex literal
*/
- private static final class PropertyIdField {
- private final FieldSpec mFieldSpec;
- private final Property mProperty;
-
- private PropertyIdField(FieldSpec fieldSpec, Property property) {
- mFieldSpec = fieldSpec;
- mProperty = property;
- }
+ @NonNull
+ private static String hexLiteral(int value) {
+ return String.format("0x%08x", value);
}
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
index 6f522608a9b4..ab38f4c9e1b0 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
@@ -16,6 +16,8 @@
package android.processor.view.inspector;
+import androidx.annotation.NonNull;
+
import javax.lang.model.element.Element;
/**
@@ -28,5 +30,5 @@ public interface ModelProcessor {
* @param element The annotated element to operate on
* @param model The model this element should be merged into
*/
- void process(Element element, InspectableClassModel model);
+ void process(@NonNull Element element, @NonNull InspectableClassModel model);
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index fd142c62e8e3..d9ed1fb9f343 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -18,6 +18,8 @@ package android.processor.view.inspector;
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.annotation.NonNull;
+
import com.squareup.javapoet.ClassName;
import java.io.IOException;
@@ -63,7 +65,9 @@ public final class PlatformInspectableProcessor extends AbstractProcessor {
}
@Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ public boolean process(
+ @NonNull Set<? extends TypeElement> annotations,
+ @NonNull RoundEnvironment roundEnv) {
final Map<String, InspectableClassModel> modelMap = new HashMap<>();
for (TypeElement annotation : annotations) {
@@ -109,9 +113,9 @@ public final class PlatformInspectableProcessor extends AbstractProcessor {
* @param modelMap A map of qualified class names to models
*/
private void runModelProcessor(
- Set<? extends Element> elements,
- ModelProcessor processor,
- Map<String, InspectableClassModel> modelMap) {
+ @NonNull Set<? extends Element> elements,
+ @NonNull ModelProcessor processor,
+ @NonNull Map<String, InspectableClassModel> modelMap) {
for (Element element : elements) {
final Optional<TypeElement> classElement = enclosingClassElement(element);
@@ -149,7 +153,7 @@ public final class PlatformInspectableProcessor extends AbstractProcessor {
* @param typeElement A type element representing the class to check
* @return f the class contains a class named {@code InspectionCompanion}
*/
- private static boolean hasNestedInspectionCompanion(TypeElement typeElement) {
+ private static boolean hasNestedInspectionCompanion(@NonNull TypeElement typeElement) {
for (TypeElement nestedClass : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
if (nestedClass.getSimpleName().toString().equals("InspectionCompanion")) {
return true;
@@ -167,7 +171,8 @@ public final class PlatformInspectableProcessor extends AbstractProcessor {
* @param element An element to search from
* @return A TypeElement of the nearest enclosing class or an empty optional
*/
- private static Optional<TypeElement> enclosingClassElement(Element element) {
+ @NonNull
+ private static Optional<TypeElement> enclosingClassElement(@NonNull Element element) {
Element cursor = element;
while (cursor != null) {
@@ -186,7 +191,7 @@ public final class PlatformInspectableProcessor extends AbstractProcessor {
*
* @param message Message to print
*/
- private void fail(String message) {
+ private void fail(@NonNull String message) {
processingEnv.getMessager().printMessage(ERROR, message);
}
@@ -196,7 +201,7 @@ public final class PlatformInspectableProcessor extends AbstractProcessor {
* @param message Message to print
* @param element The element that failed
*/
- private void fail(String message, Element element) {
+ private void fail(@NonNull String message, @NonNull Element element) {
processingEnv.getMessager().printMessage(ERROR, message, element);
}
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
index b4c6466b2b2f..7389c240049b 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
@@ -18,6 +18,9 @@ package android.processor.view.inspector;
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import javax.annotation.processing.Messager;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
@@ -27,27 +30,30 @@ import javax.lang.model.element.Element;
* Internal exception used to signal an error processing an annotation.
*/
final class ProcessingException extends RuntimeException {
- private final Element mElement;
- private final AnnotationMirror mAnnotationMirror;
- private final AnnotationValue mAnnotationValue;
+ private final @Nullable Element mElement;
+ private final @Nullable AnnotationMirror mAnnotationMirror;
+ private final @Nullable AnnotationValue mAnnotationValue;
- ProcessingException(String message) {
+ ProcessingException(@NonNull String message) {
this(message, null, null, null);
}
- ProcessingException(String message, Element element) {
+ ProcessingException(@NonNull String message, @NonNull Element element) {
this(message, element, null, null);
}
- ProcessingException(String message, Element element, AnnotationMirror annotationMirror) {
+ ProcessingException(
+ @NonNull String message,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
this(message, element, annotationMirror, null);
}
ProcessingException(
- String message,
- Element element,
- AnnotationMirror annotationMirror,
- AnnotationValue annotationValue) {
+ @NonNull String message,
+ @Nullable Element element,
+ @Nullable AnnotationMirror annotationMirror,
+ @Nullable AnnotationValue annotationValue) {
super(message);
mElement = element;
mAnnotationMirror = annotationMirror;
@@ -59,7 +65,7 @@ final class ProcessingException extends RuntimeException {
*
* @param messager A Messager to print to
*/
- void print(Messager messager) {
+ void print(@NonNull Messager messager) {
if (mElement != null) {
if (mAnnotationMirror != null) {
if (mAnnotationValue != null) {
diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
index 4eed5040eb51..3ec620a1a4bf 100644
--- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
+++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
@@ -118,9 +118,9 @@ public class InspectionCompanionGeneratorTest {
Property.Type.INT_ENUM);
property.setIntEnumEntries(Arrays.asList(
- new IntEnumEntry("THREE", 3),
- new IntEnumEntry("TWO", 2),
- new IntEnumEntry("ONE", 1)));
+ new IntEnumEntry(3, "THREE"),
+ new IntEnumEntry(2, "TWO"),
+ new IntEnumEntry(1, "ONE")));
mModel.putProperty(property);
@@ -136,9 +136,9 @@ public class InspectionCompanionGeneratorTest {
property.setAttributeIdInferrableFromR(false);
property.setIntFlagEntries(Arrays.asList(
- new IntFlagEntry("TURBO", 0x1, 0x3),
- new IntFlagEntry("OVERDRIVE", 0x2, 0x3),
- new IntFlagEntry("WARP", 0x4)
+ new IntFlagEntry(0x3, 0x1, "TURBO"),
+ new IntFlagEntry(0x3, 0x2, "OVERDRIVE"),
+ new IntFlagEntry(0x4, "WARP")
));
assertGeneratedFileEquals("IntFlag");
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
index 9a0fe5b76e27..e4a8ba49e63b 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
@@ -14,7 +14,7 @@ import java.lang.Override;
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
index b491de1d63ad..fa9dbfd9a590 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
@@ -1,11 +1,12 @@
package com.android.node;
import android.R;
+import android.util.SparseArray;
import android.view.inspector.InspectionCompanion;
-import android.view.inspector.IntEnumMapping;
import android.view.inspector.PropertyMapper;
import android.view.inspector.PropertyReader;
import java.lang.Override;
+import java.lang.String;
/**
* Inspection companion for {@link TestNode}.
@@ -15,7 +16,7 @@ import java.lang.Override;
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
@@ -26,12 +27,11 @@ public final class TestNode$InspectionCompanion implements InspectionCompanion<T
@Override
public void mapProperties(PropertyMapper propertyMapper) {
- mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty,
- new IntEnumMapping.Builder()
- .addValue("ONE", 1)
- .addValue("TWO", 2)
- .addValue("THREE", 3)
- .build());
+ final SparseArray<String> intEnumPropertyEnumMapping = new SparseArray<>();
+ intEnumPropertyEnumMapping.put(1, "ONE");
+ intEnumPropertyEnumMapping.put(2, "TWO");
+ intEnumPropertyEnumMapping.put(3, "THREE");
+ mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty, intEnumPropertyEnumMapping::get);
mPropertiesMapped = true;
}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
index 7d180580b45e..ed3d8ee40ffb 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
@@ -14,7 +14,7 @@ import java.lang.Override;
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
@@ -25,11 +25,11 @@ public final class TestNode$InspectionCompanion implements InspectionCompanion<T
@Override
public void mapProperties(PropertyMapper propertyMapper) {
- mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, new IntFlagMapping.Builder()
- .addFlag("OVERDRIVE", 0x00000002, 0x00000003)
- .addFlag("TURBO", 0x00000001, 0x00000003)
- .addFlag("WARP", 0x00000004)
- .build());
+ final IntFlagMapping intFlagFlagMapping = new IntFlagMapping();
+ intFlagFlagMapping.add(0x00000003, 0x00000002, "OVERDRIVE");
+ intFlagFlagMapping.add(0x00000003, 0x00000001, "TURBO");
+ intFlagFlagMapping.add(0x00000004, 0x00000004, "WARP");
+ mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, intFlagFlagMapping::get);
mPropertiesMapped = true;
}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
index dc27abbe6fbd..4514ed9ac3dc 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
@@ -13,7 +13,7 @@ import java.lang.Override;
*/
public final class Outer$Inner$InspectionCompanion implements InspectionCompanion<Outer.Inner> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index 738bcd3dab36..563f93dfe560 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -13,7 +13,7 @@ import java.lang.Override;
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
index 82dd66e2597e..ffa1f0be02d4 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
@@ -14,7 +14,7 @@ import java.lang.String;
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
index 08ea69679086..cb85767ee2d3 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
@@ -14,7 +14,7 @@ import java.lang.Override;
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
index 3bfa78ac857f..731d41073810 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
@@ -13,7 +13,7 @@ import java.lang.Override;
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
@@ -24,8 +24,7 @@ public final class TestNode$InspectionCompanion implements InspectionCompanion<T
@Override
public void mapProperties(PropertyMapper propertyMapper) {
- mSuppliedAttributePropertyId = propertyMapper.mapInt("suppliedAttributeProperty",
- 0xdecafbad);
+ mSuppliedAttributePropertyId = propertyMapper.mapInt("suppliedAttributeProperty", 0xdecafbad);
mPropertiesMapped = true;
}