From 76a33eeaf09aae8296e2828a9d1b3de5bd52cab6 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Thu, 16 Feb 2017 12:30:12 -0800 Subject: [PATCH] Fix errors and add back autovalue check (#130) --- .../java/com/airbnb/epoxy/EpoxyProcessor.java | 15 ++-- .../com/airbnb/epoxy/HashCodeValidator.java | 23 +++++- .../java/com/airbnb/epoxy/ConfigTest.java | 71 +++++++++++-------- ...lRequiresHashCodeAutoValueClassPasses.java | 20 ++++++ 4 files changed, 94 insertions(+), 35 deletions(-) create mode 100644 epoxy-processortest/src/test/resources/ModelRequiresHashCodeAutoValueClassPasses.java diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/EpoxyProcessor.java b/epoxy-processor/src/main/java/com/airbnb/epoxy/EpoxyProcessor.java index 5be2c998a4..05afe9dd6c 100755 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/EpoxyProcessor.java +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/EpoxyProcessor.java @@ -165,13 +165,16 @@ public boolean process(Set annotations, RoundEnvironment validateAttributesImplementHashCode(modelClassMap.values()); - // We wait until the very end to log errors so that all the generated classes are still created. - // Otherwise the compiler error output is clogged with lots of errors from the generated classes - // not existing, which makes it hard to see the actual errors. - for (Exception loggedException : loggedExceptions) { - messager.printMessage(Diagnostic.Kind.ERROR, loggedException.toString()); + if (roundEnv.processingOver()) { + + // We wait until the very end to log errors so that all the generated classes are still + // created. + // Otherwise the compiler error output is clogged with lots of errors from the generated + // classes not existing, which makes it hard to see the actual errors. + for (Exception loggedException : loggedExceptions) { + messager.printMessage(Diagnostic.Kind.ERROR, loggedException.toString()); + } } - loggedExceptions.clear(); // Let any other annotation processors use our annotations if they want to return false; diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/HashCodeValidator.java b/epoxy-processor/src/main/java/com/airbnb/epoxy/HashCodeValidator.java index aa3fb35376..9b58e13499 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/HashCodeValidator.java +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/HashCodeValidator.java @@ -6,6 +6,7 @@ import java.util.Arrays; import java.util.List; +import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; @@ -17,6 +18,7 @@ import static com.airbnb.epoxy.ProcessorUtils.getMethodOnClass; import static com.airbnb.epoxy.ProcessorUtils.isIterableType; +import static com.airbnb.epoxy.ProcessorUtils.isSubtypeOfType; import static com.airbnb.epoxy.ProcessorUtils.throwError; /** Validates that an attribute implements hashCode. */ @@ -73,6 +75,10 @@ private void validateImplementsHashCode(TypeMirror mirror) throws EpoxyProcessor return; } + if (isAutoValueType(element)) { + return; + } + if (isWhiteListedType(element)) { return; } @@ -127,11 +133,26 @@ private void validateIterableType(DeclaredType declaredType) throws EpoxyProcess private boolean isWhiteListedType(Element element) { for (String whiteListedType : WHITE_LISTED_TYPES) { - if (ProcessorUtils.isSubtypeOfType(element.asType(), whiteListedType)) { + if (isSubtypeOfType(element.asType(), whiteListedType)) { return true; } } return false; } + + /** + * Only works for classes in the module since AutoValue has a retention of Source so it is + * discarded after compilation. + */ + private boolean isAutoValueType(Element element) { + for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + boolean isAutoValue = isSubtypeOfType(annotationType, "com.google.auto.value.AutoValue"); + if (isAutoValue) { + return true; + } + } + return false; + } } diff --git a/epoxy-processortest/src/test/java/com/airbnb/epoxy/ConfigTest.java b/epoxy-processortest/src/test/java/com/airbnb/epoxy/ConfigTest.java index 6c19b277f6..755db0b57f 100644 --- a/epoxy-processortest/src/test/java/com/airbnb/epoxy/ConfigTest.java +++ b/epoxy-processortest/src/test/java/com/airbnb/epoxy/ConfigTest.java @@ -7,6 +7,7 @@ import javax.tools.JavaFileObject; import static com.google.common.truth.Truth.assert_; +import static com.google.testing.compile.JavaFileObjects.forResource; import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources; import static java.util.Arrays.asList; @@ -41,8 +42,8 @@ public void testSubPackageOverridesParent() { + "\n" + "import com.airbnb.epoxy.PackageEpoxyConfig;"); - JavaFileObject model = JavaFileObjects - .forResource("ModelConfigSubPackageOverridesParent.java"); + JavaFileObject model = + forResource("ModelConfigSubPackageOverridesParent.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model, subPackageConfig)) @@ -69,8 +70,8 @@ public void testPackageWithNoConfigInheritsNearestParentConfig() { + "\n" + "import com.airbnb.epoxy.PackageEpoxyConfig;"); - JavaFileObject model = JavaFileObjects - .forResource("ModelPackageWithNoConfigInheritsNearestParentConfig.java"); + JavaFileObject model = + forResource("ModelPackageWithNoConfigInheritsNearestParentConfig.java"); assert_().about(javaSources()) .that(asList(topLevelParentConfig, secondLevelParentConfig, model)) @@ -81,8 +82,8 @@ public void testPackageWithNoConfigInheritsNearestParentConfig() { @Test public void testConfigRequireHashCode() { - JavaFileObject model = JavaFileObjects - .forResource("ModelRequiresHashCodeFailsBasicObject.java"); + JavaFileObject model = + forResource("ModelRequiresHashCodeFailsBasicObject.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -93,8 +94,8 @@ public void testConfigRequireHashCode() { @Test public void testConfigRequireHashCodeIterableFails() { - JavaFileObject model = JavaFileObjects - .forResource("ModelRequiresHashCodeIterableFails.java"); + JavaFileObject model = + forResource("ModelRequiresHashCodeIterableFails.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -105,8 +106,8 @@ public void testConfigRequireHashCodeIterableFails() { @Test public void testConfigRequireHashCodeIterablePasses() { - JavaFileObject model = JavaFileObjects - .forResource("ModelRequiresHashCodeIterableSucceeds.java"); + JavaFileObject model = + forResource("ModelRequiresHashCodeIterableSucceeds.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -116,8 +117,8 @@ public void testConfigRequireHashCodeIterablePasses() { @Test public void testConfigRequireHashCodeArrayFails() { - JavaFileObject model = JavaFileObjects - .forResource("ModelRequiresHashCodeArrayFails.java"); + JavaFileObject model = + forResource("ModelRequiresHashCodeArrayFails.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -128,8 +129,8 @@ public void testConfigRequireHashCodeArrayFails() { @Test public void testConfigRequireHashCodeArrayPasses() { - JavaFileObject model = JavaFileObjects - .forResource("ModelRequiresHashCodeArraySucceeds.java"); + JavaFileObject model = + forResource("ModelRequiresHashCodeArraySucceeds.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -140,8 +141,8 @@ public void testConfigRequireHashCodeArrayPasses() { @Test public void testConfigRequireHashCodeEnumAttributePasses() { // Verify that enum attributes pass the hashcode requirement - JavaFileObject model = JavaFileObjects - .forResource("ModelRequiresHashCodeEnumPasses.java"); + JavaFileObject model = + forResource("ModelRequiresHashCodeEnumPasses.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -152,8 +153,8 @@ public void testConfigRequireHashCodeEnumAttributePasses() { @Test public void testConfigRequireHashCodeCharSequencePasses() { // Verify that AutoValue class attributes pass the hashcode requirement - JavaFileObject model = JavaFileObjects - .forResource("ModelConfigRequireHashCodeCharSequencePasses.java"); + JavaFileObject model = + forResource("ModelConfigRequireHashCodeCharSequencePasses.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -164,8 +165,8 @@ public void testConfigRequireHashCodeCharSequencePasses() { @Test public void testConfigRequireHashCodeInterfaceWithHashCodePasses() { // Verify that AutoValue class attributes pass the hashcode requirement - JavaFileObject model = JavaFileObjects - .forResource("ModelConfigRequireHashCodeInterfaceWithHashCodePasses.java"); + JavaFileObject model = + forResource("ModelConfigRequireHashCodeInterfaceWithHashCodePasses.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) @@ -174,10 +175,24 @@ public void testConfigRequireHashCodeInterfaceWithHashCodePasses() { } @Test - public void testConfigRequireAbstractModelPassesClassWithAttribute() { + public void testConfigRequireHashCodeAutoValueAttributePasses() { // Verify that AutoValue class attributes pass the hashcode requirement JavaFileObject model = JavaFileObjects - .forResource("RequireAbstractModelPassesClassWithAttribute.java"); + .forResource("ModelRequiresHashCodeAutoValueClassPasses.java"); + + assert_().about(javaSources()) + .that(asList(CONFIG_CLASS_REQUIRE_HASH, model)) + .processedWith(new EpoxyProcessor()) + .compilesWithoutError(); + } + + @Test + public void testConfigRequireAbstractModelPassesClassWithAttribute() { + // Verify that AutoValue class attributes pass the hashcode requirement. Only works for + // classes in the module since AutoValue has a retention of Source so it is discarded after + // compilation + JavaFileObject model = + forResource("RequireAbstractModelPassesClassWithAttribute.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_ABSTRACT, model)) @@ -188,8 +203,8 @@ public void testConfigRequireAbstractModelPassesClassWithAttribute() { @Test public void testConfigRequireAbstractModelFailsClassWithAttribute() { // Verify that AutoValue class attributes pass the hashcode requirement - JavaFileObject model = JavaFileObjects - .forResource("RequireAbstractModelFailsClassWithAttribute.java"); + JavaFileObject model = + forResource("RequireAbstractModelFailsClassWithAttribute.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_ABSTRACT, model)) @@ -202,8 +217,8 @@ public void testConfigRequireAbstractModelFailsClassWithAttribute() { @Test public void testConfigRequireAbstractModelPassesEpoxyModelClass() { // Verify that AutoValue class attributes pass the hashcode requirement - JavaFileObject model = JavaFileObjects - .forResource("RequireAbstractModelPassesEpoxyModelClass.java"); + JavaFileObject model = + forResource("RequireAbstractModelPassesEpoxyModelClass.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_ABSTRACT, model)) @@ -214,8 +229,8 @@ public void testConfigRequireAbstractModelPassesEpoxyModelClass() { @Test public void testConfigRequireAbstractModelFailsEpoxyModelClass() { // Verify that AutoValue class attributes pass the hashcode requirement - JavaFileObject model = JavaFileObjects - .forResource("RequireAbstractModelFailsEpoxyModelClass.java"); + JavaFileObject model = + forResource("RequireAbstractModelFailsEpoxyModelClass.java"); assert_().about(javaSources()) .that(asList(CONFIG_CLASS_REQUIRE_ABSTRACT, model)) diff --git a/epoxy-processortest/src/test/resources/ModelRequiresHashCodeAutoValueClassPasses.java b/epoxy-processortest/src/test/resources/ModelRequiresHashCodeAutoValueClassPasses.java new file mode 100644 index 0000000000..8603b0f8b5 --- /dev/null +++ b/epoxy-processortest/src/test/resources/ModelRequiresHashCodeAutoValueClassPasses.java @@ -0,0 +1,20 @@ +package com.airbnb.epoxy.configtest; + +import com.airbnb.epoxy.EpoxyAttribute; +import com.airbnb.epoxy.EpoxyModel; +import com.google.auto.value.AutoValue; + +public class ModelRequiresHashCodeAutoValueClassPasses extends EpoxyModel { + + @AutoValue + public static abstract class AutoValueClass { + + } + + @EpoxyAttribute AutoValueClass autoValueClass; + + @Override + protected int getDefaultLayout() { + return 0; + } +} \ No newline at end of file