From 2d2239dda357b8dade477a53d2361cb94f799ffc Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 9 Apr 2026 12:49:32 +0200 Subject: [PATCH 1/2] Fix fragile use of TypeMirror#toString in SpecElementTypeDeterminator https://github.com/facebook/litho/issues/1083 --- .../SpecElementTypeDeterminatorTest.java | 4 ++-- .../processor/SpecElementTypeDeterminator.java | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/litho-it/src/test/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminatorTest.java b/litho-it/src/test/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminatorTest.java index 062c90b1d45..a241d30f4c0 100644 --- a/litho-it/src/test/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminatorTest.java +++ b/litho-it/src/test/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminatorTest.java @@ -20,9 +20,9 @@ import com.facebook.litho.specmodels.model.SpecElementType; import com.google.testing.compile.CompilationRule; -import javax.annotation.Nullable; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; +import org.jetbrains.annotations.NotNull; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -38,7 +38,7 @@ public class SpecElementTypeDeterminatorTest { * for. */ public static class FakeKotlinSingleton { - @Nullable public static final FakeKotlinSingleton INSTANCE = null; + @NotNull public static final FakeKotlinSingleton INSTANCE = null; } @Test diff --git a/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java b/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java index 5e5ae00418f..0135ef9c95f 100644 --- a/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java +++ b/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java @@ -22,28 +22,29 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; public class SpecElementTypeDeterminator { static boolean isKotlinSingleton(TypeElement element) { - final String className = element.getQualifiedName().toString(); return element.getKind() == ElementKind.CLASS && element.getEnclosedElements().stream() .anyMatch( e -> isPublicStaticFinalElement(e) - && isElementWithTypeName(e, className) + && isElementWithType(e, element) && e.getSimpleName().contentEquals("INSTANCE")); } static boolean isKotlinClass(TypeElement element) { - final String companionClassName = element.getQualifiedName().toString() + ".Companion"; return element.getKind() == ElementKind.CLASS /* should contain a companion static field instance */ && element.getEnclosedElements().stream() .anyMatch( e -> isPublicStaticFinalElement(e) - && isElementWithTypeName(e, companionClassName) + && isElementWithType(e, element) && e.getSimpleName().contentEquals("Companion")) /* should contain a Companion class declaration. */ && element.getEnclosedElements().stream() @@ -71,7 +72,9 @@ static boolean isPublicStaticFinalElement(Element e) { .containsAll(ImmutableList.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)); } - static boolean isElementWithTypeName(Element e, String name) { - return e.asType().toString().equals(name); + static boolean isElementWithType(Element e, TypeElement typeElement) { + TypeMirror type = e.asType(); + return type.getKind() == TypeKind.DECLARED + && ((DeclaredType) type).asElement().equals(typeElement); } } From f63c8202bb6199fd8a4f05ef14a50db33e474910 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 9 Apr 2026 13:29:36 +0200 Subject: [PATCH 2/2] Fix Companion class test --- .../processor/SpecElementTypeDeterminator.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java b/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java index 0135ef9c95f..5701122cc05 100644 --- a/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java +++ b/litho-processor/src/main/java/com/facebook/litho/specmodels/processor/SpecElementTypeDeterminator.java @@ -28,23 +28,25 @@ public class SpecElementTypeDeterminator { static boolean isKotlinSingleton(TypeElement element) { + final String className = element.getQualifiedName().toString(); return element.getKind() == ElementKind.CLASS && element.getEnclosedElements().stream() .anyMatch( e -> isPublicStaticFinalElement(e) - && isElementWithType(e, element) + && isElementWithTypeName(e, className) && e.getSimpleName().contentEquals("INSTANCE")); } static boolean isKotlinClass(TypeElement element) { + final String companionClassName = element.getQualifiedName().toString() + ".Companion"; return element.getKind() == ElementKind.CLASS /* should contain a companion static field instance */ && element.getEnclosedElements().stream() .anyMatch( e -> isPublicStaticFinalElement(e) - && isElementWithType(e, element) + && isElementWithTypeName(e, companionClassName) && e.getSimpleName().contentEquals("Companion")) /* should contain a Companion class declaration. */ && element.getEnclosedElements().stream() @@ -72,9 +74,9 @@ static boolean isPublicStaticFinalElement(Element e) { .containsAll(ImmutableList.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)); } - static boolean isElementWithType(Element e, TypeElement typeElement) { + static boolean isElementWithTypeName(Element e, String name) { TypeMirror type = e.asType(); return type.getKind() == TypeKind.DECLARED - && ((DeclaredType) type).asElement().equals(typeElement); + && ((TypeElement) ((DeclaredType) type).asElement()).getQualifiedName().contentEquals(name); } }