1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2021 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.internal.codegen; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static com.google.common.truth.Truth.assertThat; 20*f585d8a3SJacky Wang import static org.junit.Assert.assertThrows; 21*f585d8a3SJacky Wang 22*f585d8a3SJacky Wang import androidx.room.compiler.processing.XConstructorElement; 23*f585d8a3SJacky Wang import androidx.room.compiler.processing.XElement; 24*f585d8a3SJacky Wang import androidx.room.compiler.processing.XMethodElement; 25*f585d8a3SJacky Wang import androidx.room.compiler.processing.XProcessingEnv; 26*f585d8a3SJacky Wang import androidx.room.compiler.processing.XProcessingStep; 27*f585d8a3SJacky Wang import androidx.room.compiler.processing.XTypeElement; 28*f585d8a3SJacky Wang import androidx.room.compiler.processing.XVariableElement; 29*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source; 30*f585d8a3SJacky Wang import com.google.common.base.Joiner; 31*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList; 32*f585d8a3SJacky Wang import com.google.common.collect.ImmutableSet; 33*f585d8a3SJacky Wang import dagger.BindsInstance; 34*f585d8a3SJacky Wang import dagger.Component; 35*f585d8a3SJacky Wang import dagger.internal.codegen.base.DaggerSuperficialValidation; 36*f585d8a3SJacky Wang import dagger.internal.codegen.base.DaggerSuperficialValidation.ValidationException; 37*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests; 38*f585d8a3SJacky Wang import java.util.Map; 39*f585d8a3SJacky Wang import java.util.Set; 40*f585d8a3SJacky Wang import javax.inject.Singleton; 41*f585d8a3SJacky Wang import org.junit.Test; 42*f585d8a3SJacky Wang import org.junit.runner.RunWith; 43*f585d8a3SJacky Wang import org.junit.runners.Parameterized; 44*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters; 45*f585d8a3SJacky Wang 46*f585d8a3SJacky Wang @RunWith(Parameterized.class) 47*f585d8a3SJacky Wang public class DaggerSuperficialValidationTest { 48*f585d8a3SJacky Wang enum SourceKind { 49*f585d8a3SJacky Wang JAVA, 50*f585d8a3SJacky Wang KOTLIN 51*f585d8a3SJacky Wang } 52*f585d8a3SJacky Wang 53*f585d8a3SJacky Wang @Parameters(name = "sourceKind={0}") parameters()54*f585d8a3SJacky Wang public static ImmutableList<Object[]> parameters() { 55*f585d8a3SJacky Wang return ImmutableList.of(new Object[] {SourceKind.JAVA}, new Object[] {SourceKind.KOTLIN}); 56*f585d8a3SJacky Wang } 57*f585d8a3SJacky Wang 58*f585d8a3SJacky Wang private final SourceKind sourceKind; 59*f585d8a3SJacky Wang DaggerSuperficialValidationTest(SourceKind sourceKind)60*f585d8a3SJacky Wang public DaggerSuperficialValidationTest(SourceKind sourceKind) { 61*f585d8a3SJacky Wang this.sourceKind = sourceKind; 62*f585d8a3SJacky Wang } 63*f585d8a3SJacky Wang 64*f585d8a3SJacky Wang private static final Joiner NEW_LINES = Joiner.on("\n "); 65*f585d8a3SJacky Wang 66*f585d8a3SJacky Wang @Test missingReturnType()67*f585d8a3SJacky Wang public void missingReturnType() { 68*f585d8a3SJacky Wang runTest( 69*f585d8a3SJacky Wang CompilerTests.javaSource( 70*f585d8a3SJacky Wang "test.TestClass", 71*f585d8a3SJacky Wang "package test;", 72*f585d8a3SJacky Wang "", 73*f585d8a3SJacky Wang "abstract class TestClass {", 74*f585d8a3SJacky Wang " abstract MissingType blah();", 75*f585d8a3SJacky Wang "}"), 76*f585d8a3SJacky Wang CompilerTests.kotlinSource( 77*f585d8a3SJacky Wang "test.TestClass.kt", 78*f585d8a3SJacky Wang "package test", 79*f585d8a3SJacky Wang "", 80*f585d8a3SJacky Wang "abstract class TestClass {", 81*f585d8a3SJacky Wang " abstract fun blah(): MissingType", 82*f585d8a3SJacky Wang "}"), 83*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 84*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 85*f585d8a3SJacky Wang ValidationException exception = 86*f585d8a3SJacky Wang assertThrows( 87*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 88*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 89*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 90*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 91*f585d8a3SJacky Wang assertThat(exception) 92*f585d8a3SJacky Wang .hasMessageThat() 93*f585d8a3SJacky Wang .contains( 94*f585d8a3SJacky Wang String.format( 95*f585d8a3SJacky Wang NEW_LINES.join( 96*f585d8a3SJacky Wang "Validation trace:", 97*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 98*f585d8a3SJacky Wang " => element (METHOD): blah()", 99*f585d8a3SJacky Wang " => type (ERROR return type): %1$s"), 100*f585d8a3SJacky Wang isJavac ? "MissingType" : "error.NonExistentClass")); 101*f585d8a3SJacky Wang }); 102*f585d8a3SJacky Wang } 103*f585d8a3SJacky Wang 104*f585d8a3SJacky Wang @Test missingGenericReturnType()105*f585d8a3SJacky Wang public void missingGenericReturnType() { 106*f585d8a3SJacky Wang runTest( 107*f585d8a3SJacky Wang CompilerTests.javaSource( 108*f585d8a3SJacky Wang "test.TestClass", 109*f585d8a3SJacky Wang "package test;", 110*f585d8a3SJacky Wang "", 111*f585d8a3SJacky Wang "abstract class TestClass {", 112*f585d8a3SJacky Wang " abstract MissingType<?> blah();", 113*f585d8a3SJacky Wang "}"), 114*f585d8a3SJacky Wang CompilerTests.kotlinSource( 115*f585d8a3SJacky Wang "test.TestClass.kt", 116*f585d8a3SJacky Wang "package test", 117*f585d8a3SJacky Wang "", 118*f585d8a3SJacky Wang "abstract class TestClass {", 119*f585d8a3SJacky Wang " abstract fun blah(): MissingType<*>", 120*f585d8a3SJacky Wang "}"), 121*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 122*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 123*f585d8a3SJacky Wang ValidationException exception = 124*f585d8a3SJacky Wang assertThrows( 125*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 126*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 127*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 128*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 129*f585d8a3SJacky Wang assertThat(exception) 130*f585d8a3SJacky Wang .hasMessageThat() 131*f585d8a3SJacky Wang .contains( 132*f585d8a3SJacky Wang String.format( 133*f585d8a3SJacky Wang NEW_LINES.join( 134*f585d8a3SJacky Wang "Validation trace:", 135*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 136*f585d8a3SJacky Wang " => element (METHOD): blah()", 137*f585d8a3SJacky Wang " => type (ERROR return type): %1$s"), 138*f585d8a3SJacky Wang isJavac ? "<any>" : "error.NonExistentClass")); 139*f585d8a3SJacky Wang }); 140*f585d8a3SJacky Wang } 141*f585d8a3SJacky Wang 142*f585d8a3SJacky Wang @Test missingReturnTypeTypeParameter()143*f585d8a3SJacky Wang public void missingReturnTypeTypeParameter() { 144*f585d8a3SJacky Wang runTest( 145*f585d8a3SJacky Wang CompilerTests.javaSource( 146*f585d8a3SJacky Wang "test.TestClass", 147*f585d8a3SJacky Wang "package test;", 148*f585d8a3SJacky Wang "", 149*f585d8a3SJacky Wang "import java.util.Map;", 150*f585d8a3SJacky Wang "import java.util.Set;", 151*f585d8a3SJacky Wang "", 152*f585d8a3SJacky Wang "abstract class TestClass {", 153*f585d8a3SJacky Wang " abstract Map<Set<?>, MissingType<?>> blah();", 154*f585d8a3SJacky Wang "}"), 155*f585d8a3SJacky Wang CompilerTests.kotlinSource( 156*f585d8a3SJacky Wang "test.TestClass.kt", 157*f585d8a3SJacky Wang "package test", 158*f585d8a3SJacky Wang "", 159*f585d8a3SJacky Wang "abstract class TestClass {", 160*f585d8a3SJacky Wang " abstract fun blah(): Map<Set<*>, MissingType<*>>", 161*f585d8a3SJacky Wang "}"), 162*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 163*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 164*f585d8a3SJacky Wang ValidationException exception = 165*f585d8a3SJacky Wang assertThrows( 166*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 167*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 168*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 169*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 170*f585d8a3SJacky Wang assertThat(exception) 171*f585d8a3SJacky Wang .hasMessageThat() 172*f585d8a3SJacky Wang .contains( 173*f585d8a3SJacky Wang String.format( 174*f585d8a3SJacky Wang NEW_LINES.join( 175*f585d8a3SJacky Wang "Validation trace:", 176*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 177*f585d8a3SJacky Wang " => element (METHOD): blah()", 178*f585d8a3SJacky Wang " => type (DECLARED return type): " 179*f585d8a3SJacky Wang + "java.util.Map<java.util.Set<?>,%1$s>", 180*f585d8a3SJacky Wang " => type (ERROR type argument): %1$s"), 181*f585d8a3SJacky Wang isJavac ? "<any>" : "error.NonExistentClass")); 182*f585d8a3SJacky Wang }); 183*f585d8a3SJacky Wang } 184*f585d8a3SJacky Wang 185*f585d8a3SJacky Wang @Test missingTypeParameter()186*f585d8a3SJacky Wang public void missingTypeParameter() { 187*f585d8a3SJacky Wang runTest( 188*f585d8a3SJacky Wang CompilerTests.javaSource( 189*f585d8a3SJacky Wang "test.TestClass", // 190*f585d8a3SJacky Wang "package test;", 191*f585d8a3SJacky Wang "", 192*f585d8a3SJacky Wang "class TestClass<T extends MissingType> {}"), 193*f585d8a3SJacky Wang CompilerTests.kotlinSource( 194*f585d8a3SJacky Wang "test.TestClass.kt", // 195*f585d8a3SJacky Wang "package test", 196*f585d8a3SJacky Wang "", 197*f585d8a3SJacky Wang "class TestClass<T : MissingType>"), 198*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 199*f585d8a3SJacky Wang if (isKAPT(processingEnv)) { 200*f585d8a3SJacky Wang // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT. 201*f585d8a3SJacky Wang return; 202*f585d8a3SJacky Wang } 203*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 204*f585d8a3SJacky Wang ValidationException exception = 205*f585d8a3SJacky Wang assertThrows( 206*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 207*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 208*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 209*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 210*f585d8a3SJacky Wang assertThat(exception) 211*f585d8a3SJacky Wang .hasMessageThat() 212*f585d8a3SJacky Wang .contains( 213*f585d8a3SJacky Wang String.format( 214*f585d8a3SJacky Wang NEW_LINES.join( 215*f585d8a3SJacky Wang "Validation trace:", 216*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 217*f585d8a3SJacky Wang " => element (TYPE_PARAMETER): T", 218*f585d8a3SJacky Wang " => type (ERROR bound type): %s"), 219*f585d8a3SJacky Wang isJavac ? "MissingType" : "error.NonExistentClass")); 220*f585d8a3SJacky Wang }); 221*f585d8a3SJacky Wang } 222*f585d8a3SJacky Wang 223*f585d8a3SJacky Wang @Test missingParameterType()224*f585d8a3SJacky Wang public void missingParameterType() { 225*f585d8a3SJacky Wang runTest( 226*f585d8a3SJacky Wang CompilerTests.javaSource( 227*f585d8a3SJacky Wang "test.TestClass", 228*f585d8a3SJacky Wang "package test;", 229*f585d8a3SJacky Wang "", 230*f585d8a3SJacky Wang "abstract class TestClass {", 231*f585d8a3SJacky Wang " abstract void foo(MissingType param);", 232*f585d8a3SJacky Wang "}"), 233*f585d8a3SJacky Wang CompilerTests.kotlinSource( 234*f585d8a3SJacky Wang "test.TestClass.kt", 235*f585d8a3SJacky Wang "package test", 236*f585d8a3SJacky Wang "", 237*f585d8a3SJacky Wang "abstract class TestClass {", 238*f585d8a3SJacky Wang " abstract fun foo(param: MissingType);", 239*f585d8a3SJacky Wang "}"), 240*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 241*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 242*f585d8a3SJacky Wang ValidationException exception = 243*f585d8a3SJacky Wang assertThrows( 244*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 245*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 246*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 247*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 248*f585d8a3SJacky Wang assertThat(exception) 249*f585d8a3SJacky Wang .hasMessageThat() 250*f585d8a3SJacky Wang .contains( 251*f585d8a3SJacky Wang String.format( 252*f585d8a3SJacky Wang NEW_LINES.join( 253*f585d8a3SJacky Wang "Validation trace:", 254*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 255*f585d8a3SJacky Wang " => element (METHOD): foo(%1$s)", 256*f585d8a3SJacky Wang " => element (PARAMETER): param", 257*f585d8a3SJacky Wang " => type (ERROR parameter type): %1$s"), 258*f585d8a3SJacky Wang isJavac ? "MissingType" : "error.NonExistentClass")); 259*f585d8a3SJacky Wang }); 260*f585d8a3SJacky Wang } 261*f585d8a3SJacky Wang 262*f585d8a3SJacky Wang @Test missingAnnotation()263*f585d8a3SJacky Wang public void missingAnnotation() { 264*f585d8a3SJacky Wang runTest( 265*f585d8a3SJacky Wang CompilerTests.javaSource( 266*f585d8a3SJacky Wang "test.TestClass", // 267*f585d8a3SJacky Wang "package test;", 268*f585d8a3SJacky Wang "", 269*f585d8a3SJacky Wang "@MissingAnnotation", 270*f585d8a3SJacky Wang "class TestClass {}"), 271*f585d8a3SJacky Wang CompilerTests.kotlinSource( 272*f585d8a3SJacky Wang "test.TestClass.kt", // 273*f585d8a3SJacky Wang "package test", 274*f585d8a3SJacky Wang "", 275*f585d8a3SJacky Wang "@MissingAnnotation", 276*f585d8a3SJacky Wang "class TestClass"), 277*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 278*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 279*f585d8a3SJacky Wang ValidationException exception = 280*f585d8a3SJacky Wang assertThrows( 281*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 282*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 283*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 284*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 285*f585d8a3SJacky Wang assertThat(exception) 286*f585d8a3SJacky Wang .hasMessageThat() 287*f585d8a3SJacky Wang .contains( 288*f585d8a3SJacky Wang String.format( 289*f585d8a3SJacky Wang NEW_LINES.join( 290*f585d8a3SJacky Wang "Validation trace:", 291*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 292*f585d8a3SJacky Wang " => annotation type: MissingAnnotation", 293*f585d8a3SJacky Wang " => type (ERROR annotation type): %s"), 294*f585d8a3SJacky Wang isJavac ? "MissingAnnotation" : "error.NonExistentClass")); 295*f585d8a3SJacky Wang }); 296*f585d8a3SJacky Wang } 297*f585d8a3SJacky Wang 298*f585d8a3SJacky Wang @Test handlesRecursiveTypeParams()299*f585d8a3SJacky Wang public void handlesRecursiveTypeParams() { 300*f585d8a3SJacky Wang runSuccessfulTest( 301*f585d8a3SJacky Wang CompilerTests.javaSource( 302*f585d8a3SJacky Wang "test.TestClass", // 303*f585d8a3SJacky Wang "package test;", 304*f585d8a3SJacky Wang "", 305*f585d8a3SJacky Wang "class TestClass<T extends Comparable<T>> {}"), 306*f585d8a3SJacky Wang CompilerTests.kotlinSource( 307*f585d8a3SJacky Wang "test.TestClass.kt", // 308*f585d8a3SJacky Wang "package test", 309*f585d8a3SJacky Wang "", 310*f585d8a3SJacky Wang "class TestClass<T : Comparable<T>>"), 311*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> 312*f585d8a3SJacky Wang superficialValidation.validateElement(processingEnv.findTypeElement("test.TestClass"))); 313*f585d8a3SJacky Wang } 314*f585d8a3SJacky Wang 315*f585d8a3SJacky Wang @Test handlesRecursiveType()316*f585d8a3SJacky Wang public void handlesRecursiveType() { 317*f585d8a3SJacky Wang runSuccessfulTest( 318*f585d8a3SJacky Wang CompilerTests.javaSource( 319*f585d8a3SJacky Wang "test.TestClass", 320*f585d8a3SJacky Wang "package test;", 321*f585d8a3SJacky Wang "", 322*f585d8a3SJacky Wang "abstract class TestClass {", 323*f585d8a3SJacky Wang " abstract TestClass foo(TestClass x);", 324*f585d8a3SJacky Wang "}"), 325*f585d8a3SJacky Wang CompilerTests.kotlinSource( 326*f585d8a3SJacky Wang "test.TestClass.kt", 327*f585d8a3SJacky Wang "package test", 328*f585d8a3SJacky Wang "", 329*f585d8a3SJacky Wang "abstract class TestClass {", 330*f585d8a3SJacky Wang " abstract fun foo(x: TestClass): TestClass", 331*f585d8a3SJacky Wang "}"), 332*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> 333*f585d8a3SJacky Wang superficialValidation.validateElement(processingEnv.findTypeElement("test.TestClass"))); 334*f585d8a3SJacky Wang } 335*f585d8a3SJacky Wang 336*f585d8a3SJacky Wang @Test missingWildcardBound()337*f585d8a3SJacky Wang public void missingWildcardBound() { 338*f585d8a3SJacky Wang runTest( 339*f585d8a3SJacky Wang CompilerTests.javaSource( 340*f585d8a3SJacky Wang "test.TestClass", 341*f585d8a3SJacky Wang "package test;", 342*f585d8a3SJacky Wang "", 343*f585d8a3SJacky Wang "import java.util.Set;", 344*f585d8a3SJacky Wang "", 345*f585d8a3SJacky Wang "class TestClass {", 346*f585d8a3SJacky Wang " static final class Foo<T> {}", 347*f585d8a3SJacky Wang "", 348*f585d8a3SJacky Wang " Foo<? extends MissingType> extendsTest() {", 349*f585d8a3SJacky Wang " return null;", 350*f585d8a3SJacky Wang " }", 351*f585d8a3SJacky Wang "", 352*f585d8a3SJacky Wang " Foo<? super MissingType> superTest() {", 353*f585d8a3SJacky Wang " return null;", 354*f585d8a3SJacky Wang " }", 355*f585d8a3SJacky Wang "}"), 356*f585d8a3SJacky Wang CompilerTests.kotlinSource( 357*f585d8a3SJacky Wang "test.TestClass.kt", 358*f585d8a3SJacky Wang "package test", 359*f585d8a3SJacky Wang "", 360*f585d8a3SJacky Wang "class TestClass {", 361*f585d8a3SJacky Wang " class Foo<T>", 362*f585d8a3SJacky Wang "", 363*f585d8a3SJacky Wang " fun extendsTest(): Foo<out MissingType> = TODO()", 364*f585d8a3SJacky Wang "", 365*f585d8a3SJacky Wang " fun superTest(): Foo<in MissingType> = TODO()", 366*f585d8a3SJacky Wang "}"), 367*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 368*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 369*f585d8a3SJacky Wang ValidationException exception = 370*f585d8a3SJacky Wang assertThrows( 371*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 372*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 373*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 374*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 375*f585d8a3SJacky Wang assertThat(exception) 376*f585d8a3SJacky Wang .hasMessageThat() 377*f585d8a3SJacky Wang .contains( 378*f585d8a3SJacky Wang String.format( 379*f585d8a3SJacky Wang NEW_LINES.join( 380*f585d8a3SJacky Wang "Validation trace:", 381*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 382*f585d8a3SJacky Wang " => element (METHOD): extendsTest()", 383*f585d8a3SJacky Wang " => type (DECLARED return type): test.TestClass.Foo<? extends %1$s>", 384*f585d8a3SJacky Wang " => type (WILDCARD type argument): ? extends %1$s", 385*f585d8a3SJacky Wang " => type (ERROR extends bound type): %1$s"), 386*f585d8a3SJacky Wang isJavac ? "MissingType" : "error.NonExistentClass")); 387*f585d8a3SJacky Wang }); 388*f585d8a3SJacky Wang } 389*f585d8a3SJacky Wang 390*f585d8a3SJacky Wang @Test missingIntersection()391*f585d8a3SJacky Wang public void missingIntersection() { 392*f585d8a3SJacky Wang runTest( 393*f585d8a3SJacky Wang CompilerTests.javaSource( 394*f585d8a3SJacky Wang "test.TestClass", 395*f585d8a3SJacky Wang "package test;", 396*f585d8a3SJacky Wang "", 397*f585d8a3SJacky Wang "class TestClass<T extends Number & Missing> {}"), 398*f585d8a3SJacky Wang CompilerTests.kotlinSource( 399*f585d8a3SJacky Wang "test.TestClass.kt", 400*f585d8a3SJacky Wang "package test", 401*f585d8a3SJacky Wang "", 402*f585d8a3SJacky Wang "class TestClass<T> where T: Number, T: Missing"), 403*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 404*f585d8a3SJacky Wang if (isKAPT(processingEnv)) { 405*f585d8a3SJacky Wang // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT. 406*f585d8a3SJacky Wang return; 407*f585d8a3SJacky Wang } 408*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass"); 409*f585d8a3SJacky Wang ValidationException exception = 410*f585d8a3SJacky Wang assertThrows( 411*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 412*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 413*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 414*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 415*f585d8a3SJacky Wang assertThat(exception) 416*f585d8a3SJacky Wang .hasMessageThat() 417*f585d8a3SJacky Wang .contains( 418*f585d8a3SJacky Wang String.format( 419*f585d8a3SJacky Wang NEW_LINES.join( 420*f585d8a3SJacky Wang "Validation trace:", 421*f585d8a3SJacky Wang " => element (CLASS): test.TestClass", 422*f585d8a3SJacky Wang " => element (TYPE_PARAMETER): T", 423*f585d8a3SJacky Wang " => type (ERROR bound type): %s"), 424*f585d8a3SJacky Wang isJavac ? "Missing" : "error.NonExistentClass")); 425*f585d8a3SJacky Wang }); 426*f585d8a3SJacky Wang } 427*f585d8a3SJacky Wang 428*f585d8a3SJacky Wang @Test invalidAnnotationValue()429*f585d8a3SJacky Wang public void invalidAnnotationValue() { 430*f585d8a3SJacky Wang runTest( 431*f585d8a3SJacky Wang CompilerTests.javaSource( 432*f585d8a3SJacky Wang "test.Outer", 433*f585d8a3SJacky Wang "package test;", 434*f585d8a3SJacky Wang "", 435*f585d8a3SJacky Wang "final class Outer {", 436*f585d8a3SJacky Wang " @interface TestAnnotation {", 437*f585d8a3SJacky Wang " Class[] classes();", 438*f585d8a3SJacky Wang " }", 439*f585d8a3SJacky Wang "", 440*f585d8a3SJacky Wang " @TestAnnotation(classes = MissingType.class)", 441*f585d8a3SJacky Wang " static class TestClass {}", 442*f585d8a3SJacky Wang "}"), 443*f585d8a3SJacky Wang CompilerTests.kotlinSource( 444*f585d8a3SJacky Wang "test.Outer.kt", 445*f585d8a3SJacky Wang "package test", 446*f585d8a3SJacky Wang "", 447*f585d8a3SJacky Wang "class Outer {", 448*f585d8a3SJacky Wang " annotation class TestAnnotation(", 449*f585d8a3SJacky Wang " val classes: Array<kotlin.reflect.KClass<*>>", 450*f585d8a3SJacky Wang " )", 451*f585d8a3SJacky Wang "", 452*f585d8a3SJacky Wang " @TestAnnotation(classes = [MissingType::class])", 453*f585d8a3SJacky Wang " class TestClass {}", 454*f585d8a3SJacky Wang "}"), 455*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 456*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.Outer.TestClass"); 457*f585d8a3SJacky Wang if (processingEnv.getBackend() == XProcessingEnv.Backend.KSP 458*f585d8a3SJacky Wang && sourceKind == SourceKind.KOTLIN) { 459*f585d8a3SJacky Wang // TODO(b/269364338): When using kotlin source with KSP the MissingType annotation value 460*f585d8a3SJacky Wang // appears to be missing so validating this element does not cause the expected failure. 461*f585d8a3SJacky Wang superficialValidation.validateElement(testClassElement); 462*f585d8a3SJacky Wang return; 463*f585d8a3SJacky Wang } 464*f585d8a3SJacky Wang ValidationException exception = 465*f585d8a3SJacky Wang assertThrows( 466*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 467*f585d8a3SJacky Wang () -> superficialValidation.validateElement(testClassElement)); 468*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 469*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 470*f585d8a3SJacky Wang assertThat(exception) 471*f585d8a3SJacky Wang .hasMessageThat() 472*f585d8a3SJacky Wang .contains( 473*f585d8a3SJacky Wang String.format( 474*f585d8a3SJacky Wang NEW_LINES.join( 475*f585d8a3SJacky Wang "Validation trace:", 476*f585d8a3SJacky Wang " => element (CLASS): test.Outer.TestClass", 477*f585d8a3SJacky Wang " => annotation type: test.Outer.TestAnnotation", 478*f585d8a3SJacky Wang " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})", 479*f585d8a3SJacky Wang " => annotation value (TYPE_ARRAY): classes={<%1$s>}", 480*f585d8a3SJacky Wang " => annotation value (TYPE): classes=<%1$s>"), 481*f585d8a3SJacky Wang isJavac ? "error" : "Error")); 482*f585d8a3SJacky Wang }); 483*f585d8a3SJacky Wang } 484*f585d8a3SJacky Wang 485*f585d8a3SJacky Wang @Test invalidAnnotationValueOnParameter()486*f585d8a3SJacky Wang public void invalidAnnotationValueOnParameter() { 487*f585d8a3SJacky Wang runTest( 488*f585d8a3SJacky Wang CompilerTests.javaSource( 489*f585d8a3SJacky Wang "test.Outer", 490*f585d8a3SJacky Wang "package test;", 491*f585d8a3SJacky Wang "", 492*f585d8a3SJacky Wang "final class Outer {", 493*f585d8a3SJacky Wang " @interface TestAnnotation {", 494*f585d8a3SJacky Wang " Class[] classes();", 495*f585d8a3SJacky Wang " }", 496*f585d8a3SJacky Wang "", 497*f585d8a3SJacky Wang " static class TestClass {", 498*f585d8a3SJacky Wang " TestClass(@TestAnnotation(classes = MissingType.class) String strParam) {}", 499*f585d8a3SJacky Wang " }", 500*f585d8a3SJacky Wang "}"), 501*f585d8a3SJacky Wang CompilerTests.kotlinSource( 502*f585d8a3SJacky Wang "test.Outer.kt", 503*f585d8a3SJacky Wang "package test", 504*f585d8a3SJacky Wang "", 505*f585d8a3SJacky Wang "class Outer {", 506*f585d8a3SJacky Wang " annotation class TestAnnotation(", 507*f585d8a3SJacky Wang " val classes: Array<kotlin.reflect.KClass<*>>", 508*f585d8a3SJacky Wang " )", 509*f585d8a3SJacky Wang "", 510*f585d8a3SJacky Wang " class TestClass(", 511*f585d8a3SJacky Wang " @TestAnnotation(classes = [MissingType::class]) strParam: String", 512*f585d8a3SJacky Wang " )", 513*f585d8a3SJacky Wang "}"), 514*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 515*f585d8a3SJacky Wang if (sourceKind == SourceKind.KOTLIN) { 516*f585d8a3SJacky Wang // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT. 517*f585d8a3SJacky Wang // TODO(b/269364338): When using kotlin source the MissingType annotation value appears 518*f585d8a3SJacky Wang // to be missing so validating this element does not cause the expected failure. 519*f585d8a3SJacky Wang return; 520*f585d8a3SJacky Wang } 521*f585d8a3SJacky Wang XTypeElement testClassElement = processingEnv.findTypeElement("test.Outer.TestClass"); 522*f585d8a3SJacky Wang XConstructorElement constructor = testClassElement.getConstructors().get(0); 523*f585d8a3SJacky Wang XVariableElement parameter = constructor.getParameters().get(0); 524*f585d8a3SJacky Wang ValidationException exception = 525*f585d8a3SJacky Wang assertThrows( 526*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 527*f585d8a3SJacky Wang () -> superficialValidation.validateElement(parameter)); 528*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 529*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 530*f585d8a3SJacky Wang assertThat(exception) 531*f585d8a3SJacky Wang .hasMessageThat() 532*f585d8a3SJacky Wang .contains( 533*f585d8a3SJacky Wang String.format( 534*f585d8a3SJacky Wang NEW_LINES.join( 535*f585d8a3SJacky Wang "Validation trace:", 536*f585d8a3SJacky Wang " => element (CLASS): test.Outer.TestClass", 537*f585d8a3SJacky Wang " => element (CONSTRUCTOR): TestClass(java.lang.String)", 538*f585d8a3SJacky Wang " => element (PARAMETER): strParam", 539*f585d8a3SJacky Wang " => annotation type: test.Outer.TestAnnotation", 540*f585d8a3SJacky Wang " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})", 541*f585d8a3SJacky Wang " => annotation value (TYPE_ARRAY): classes={<%1$s>}", 542*f585d8a3SJacky Wang " => annotation value (TYPE): classes=<%1$s>"), 543*f585d8a3SJacky Wang isJavac ? "error" : "Error")); 544*f585d8a3SJacky Wang }); 545*f585d8a3SJacky Wang } 546*f585d8a3SJacky Wang 547*f585d8a3SJacky Wang @Test invalidSuperclassInTypeHierarchy()548*f585d8a3SJacky Wang public void invalidSuperclassInTypeHierarchy() { 549*f585d8a3SJacky Wang runTest( 550*f585d8a3SJacky Wang CompilerTests.javaSource( 551*f585d8a3SJacky Wang "test.Outer", 552*f585d8a3SJacky Wang "package test;", 553*f585d8a3SJacky Wang "", 554*f585d8a3SJacky Wang "final class Outer {", 555*f585d8a3SJacky Wang " Child<Long> getChild() { return null; }", 556*f585d8a3SJacky Wang " static class Child<T> extends Parent<T> {}", 557*f585d8a3SJacky Wang " static class Parent<T> extends MissingType<T> {}", 558*f585d8a3SJacky Wang "}"), 559*f585d8a3SJacky Wang CompilerTests.kotlinSource( 560*f585d8a3SJacky Wang "test.Outer.kt", 561*f585d8a3SJacky Wang "package test", 562*f585d8a3SJacky Wang "", 563*f585d8a3SJacky Wang "class Outer {", 564*f585d8a3SJacky Wang " fun getChild(): Child<Long> = TODO()", 565*f585d8a3SJacky Wang " class Child<T> : Parent<T>", 566*f585d8a3SJacky Wang " open class Parent<T> : MissingType<T>", 567*f585d8a3SJacky Wang "}"), 568*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 569*f585d8a3SJacky Wang XTypeElement outerElement = processingEnv.findTypeElement("test.Outer"); 570*f585d8a3SJacky Wang XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0); 571*f585d8a3SJacky Wang ValidationException exception = 572*f585d8a3SJacky Wang assertThrows( 573*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 574*f585d8a3SJacky Wang () -> 575*f585d8a3SJacky Wang superficialValidation.validateTypeHierarchyOf( 576*f585d8a3SJacky Wang "return type", getChildMethod, getChildMethod.getReturnType())); 577*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 578*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 579*f585d8a3SJacky Wang assertThat(exception) 580*f585d8a3SJacky Wang .hasMessageThat() 581*f585d8a3SJacky Wang .contains( 582*f585d8a3SJacky Wang String.format( 583*f585d8a3SJacky Wang NEW_LINES.join( 584*f585d8a3SJacky Wang "Validation trace:", 585*f585d8a3SJacky Wang " => element (CLASS): test.Outer", 586*f585d8a3SJacky Wang " => element (METHOD): getChild()", 587*f585d8a3SJacky Wang " => type (DECLARED return type): test.Outer.Child<java.lang.Long>", 588*f585d8a3SJacky Wang " => type (DECLARED supertype): test.Outer.Parent<java.lang.Long>", 589*f585d8a3SJacky Wang " => type (ERROR supertype): %s"), 590*f585d8a3SJacky Wang isJavac ? "MissingType<T>" : "error.NonExistentClass")); 591*f585d8a3SJacky Wang }); 592*f585d8a3SJacky Wang } 593*f585d8a3SJacky Wang 594*f585d8a3SJacky Wang @Test invalidSuperclassTypeParameterInTypeHierarchy()595*f585d8a3SJacky Wang public void invalidSuperclassTypeParameterInTypeHierarchy() { 596*f585d8a3SJacky Wang runTest( 597*f585d8a3SJacky Wang CompilerTests.javaSource( 598*f585d8a3SJacky Wang "test.Outer", 599*f585d8a3SJacky Wang "package test;", 600*f585d8a3SJacky Wang "", 601*f585d8a3SJacky Wang "final class Outer {", 602*f585d8a3SJacky Wang " Child getChild() { return null; }", 603*f585d8a3SJacky Wang " static class Child extends Parent<MissingType> {}", 604*f585d8a3SJacky Wang " static class Parent<T> {}", 605*f585d8a3SJacky Wang "}"), 606*f585d8a3SJacky Wang CompilerTests.kotlinSource( 607*f585d8a3SJacky Wang "test.Outer.kt", 608*f585d8a3SJacky Wang "package test", 609*f585d8a3SJacky Wang "", 610*f585d8a3SJacky Wang "class Outer {", 611*f585d8a3SJacky Wang " fun getChild(): Child = TODO()", 612*f585d8a3SJacky Wang " class Child : Parent<MissingType>()", 613*f585d8a3SJacky Wang " open class Parent<T>", 614*f585d8a3SJacky Wang "}"), 615*f585d8a3SJacky Wang (processingEnv, superficialValidation) -> { 616*f585d8a3SJacky Wang XTypeElement outerElement = processingEnv.findTypeElement("test.Outer"); 617*f585d8a3SJacky Wang XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0); 618*f585d8a3SJacky Wang if (isKAPT(processingEnv)) { 619*f585d8a3SJacky Wang // https://youtrack.jetbrains.com/issue/KT-34193/Kapt-CorrectErrorTypes-doesnt-work-for-generics 620*f585d8a3SJacky Wang // There's no way to work around this bug in KAPT so validation doesn't catch this case. 621*f585d8a3SJacky Wang superficialValidation.validateTypeHierarchyOf( 622*f585d8a3SJacky Wang "return type", getChildMethod, getChildMethod.getReturnType()); 623*f585d8a3SJacky Wang return; 624*f585d8a3SJacky Wang } 625*f585d8a3SJacky Wang ValidationException exception = 626*f585d8a3SJacky Wang assertThrows( 627*f585d8a3SJacky Wang ValidationException.KnownErrorType.class, 628*f585d8a3SJacky Wang () -> 629*f585d8a3SJacky Wang superficialValidation.validateTypeHierarchyOf( 630*f585d8a3SJacky Wang "return type", getChildMethod, getChildMethod.getReturnType())); 631*f585d8a3SJacky Wang // TODO(b/248552462): Javac and KSP should match once this bug is fixed. 632*f585d8a3SJacky Wang boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; 633*f585d8a3SJacky Wang assertThat(exception) 634*f585d8a3SJacky Wang .hasMessageThat() 635*f585d8a3SJacky Wang .contains( 636*f585d8a3SJacky Wang String.format( 637*f585d8a3SJacky Wang NEW_LINES.join( 638*f585d8a3SJacky Wang "Validation trace:", 639*f585d8a3SJacky Wang " => element (CLASS): test.Outer", 640*f585d8a3SJacky Wang " => element (METHOD): getChild()", 641*f585d8a3SJacky Wang " => type (DECLARED return type): test.Outer.Child", 642*f585d8a3SJacky Wang " => type (DECLARED supertype): test.Outer.Parent<%1$s>", 643*f585d8a3SJacky Wang " => type (ERROR type argument): %1$s"), 644*f585d8a3SJacky Wang isJavac ? "MissingType" : "error.NonExistentClass")); 645*f585d8a3SJacky Wang }); 646*f585d8a3SJacky Wang } 647*f585d8a3SJacky Wang runTest( Source.JavaSource javaSource, Source.KotlinSource kotlinSource, AssertionHandler assertionHandler)648*f585d8a3SJacky Wang private void runTest( 649*f585d8a3SJacky Wang Source.JavaSource javaSource, 650*f585d8a3SJacky Wang Source.KotlinSource kotlinSource, 651*f585d8a3SJacky Wang AssertionHandler assertionHandler) { 652*f585d8a3SJacky Wang CompilerTests.daggerCompiler(sourceKind == SourceKind.JAVA ? javaSource : kotlinSource) 653*f585d8a3SJacky Wang .withProcessingSteps(() -> new AssertingStep(assertionHandler)) 654*f585d8a3SJacky Wang // We're expecting compiler errors that we assert on in the assertionHandler. 655*f585d8a3SJacky Wang .compile(subject -> subject.hasError()); 656*f585d8a3SJacky Wang } 657*f585d8a3SJacky Wang runSuccessfulTest( Source.JavaSource javaSource, Source.KotlinSource kotlinSource, AssertionHandler assertionHandler)658*f585d8a3SJacky Wang private void runSuccessfulTest( 659*f585d8a3SJacky Wang Source.JavaSource javaSource, 660*f585d8a3SJacky Wang Source.KotlinSource kotlinSource, 661*f585d8a3SJacky Wang AssertionHandler assertionHandler) { 662*f585d8a3SJacky Wang CompilerTests.daggerCompiler(sourceKind == SourceKind.JAVA ? javaSource : kotlinSource) 663*f585d8a3SJacky Wang .withProcessingSteps(() -> new AssertingStep(assertionHandler)) 664*f585d8a3SJacky Wang .compile(subject -> subject.hasErrorCount(0)); 665*f585d8a3SJacky Wang } 666*f585d8a3SJacky Wang isKAPT(XProcessingEnv processingEnv)667*f585d8a3SJacky Wang private boolean isKAPT(XProcessingEnv processingEnv) { 668*f585d8a3SJacky Wang return processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC 669*f585d8a3SJacky Wang && sourceKind == SourceKind.KOTLIN; 670*f585d8a3SJacky Wang } 671*f585d8a3SJacky Wang 672*f585d8a3SJacky Wang private interface AssertionHandler { runAssertions( XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation)673*f585d8a3SJacky Wang void runAssertions( 674*f585d8a3SJacky Wang XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation); 675*f585d8a3SJacky Wang } 676*f585d8a3SJacky Wang 677*f585d8a3SJacky Wang private static final class AssertingStep implements XProcessingStep { 678*f585d8a3SJacky Wang private final AssertionHandler assertionHandler; 679*f585d8a3SJacky Wang private boolean processed = false; 680*f585d8a3SJacky Wang AssertingStep(AssertionHandler assertionHandler)681*f585d8a3SJacky Wang AssertingStep(AssertionHandler assertionHandler) { 682*f585d8a3SJacky Wang this.assertionHandler = assertionHandler; 683*f585d8a3SJacky Wang } 684*f585d8a3SJacky Wang 685*f585d8a3SJacky Wang @Override annotations()686*f585d8a3SJacky Wang public final ImmutableSet<String> annotations() { 687*f585d8a3SJacky Wang return ImmutableSet.of("*"); 688*f585d8a3SJacky Wang } 689*f585d8a3SJacky Wang 690*f585d8a3SJacky Wang @Override process( XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation)691*f585d8a3SJacky Wang public ImmutableSet<XElement> process( 692*f585d8a3SJacky Wang XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) { 693*f585d8a3SJacky Wang if (!processed) { 694*f585d8a3SJacky Wang processed = true; // only process once. 695*f585d8a3SJacky Wang TestComponent component = 696*f585d8a3SJacky Wang DaggerDaggerSuperficialValidationTest_TestComponent.factory().create(env); 697*f585d8a3SJacky Wang assertionHandler.runAssertions(env, component.superficialValidation()); 698*f585d8a3SJacky Wang } 699*f585d8a3SJacky Wang return ImmutableSet.of(); 700*f585d8a3SJacky Wang } 701*f585d8a3SJacky Wang 702*f585d8a3SJacky Wang @Override processOver( XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation)703*f585d8a3SJacky Wang public void processOver( 704*f585d8a3SJacky Wang XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) {} 705*f585d8a3SJacky Wang } 706*f585d8a3SJacky Wang 707*f585d8a3SJacky Wang @Singleton 708*f585d8a3SJacky Wang @Component(modules = ProcessingEnvironmentModule.class) 709*f585d8a3SJacky Wang interface TestComponent { superficialValidation()710*f585d8a3SJacky Wang DaggerSuperficialValidation superficialValidation(); 711*f585d8a3SJacky Wang 712*f585d8a3SJacky Wang @Component.Factory 713*f585d8a3SJacky Wang interface Factory { create(@indsInstance XProcessingEnv processingEnv)714*f585d8a3SJacky Wang TestComponent create(@BindsInstance XProcessingEnv processingEnv); 715*f585d8a3SJacky Wang } 716*f585d8a3SJacky Wang } 717*f585d8a3SJacky Wang } 718