1 /* 2 * Copyright (C) 2021 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen.processingstep; 18 19 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectAssistedParameters; 20 21 import androidx.room.compiler.processing.XConstructorElement; 22 import androidx.room.compiler.processing.XMessager; 23 import androidx.room.compiler.processing.XType; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableSet; 26 import com.squareup.javapoet.ClassName; 27 import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedParameter; 28 import dagger.internal.codegen.javapoet.TypeNames; 29 import dagger.internal.codegen.validation.InjectValidator; 30 import dagger.internal.codegen.validation.ValidationReport; 31 import java.util.HashSet; 32 import java.util.Set; 33 import javax.inject.Inject; 34 35 /** An annotation processor for {@link dagger.assisted.AssistedInject}-annotated elements. */ 36 final class AssistedInjectProcessingStep extends TypeCheckingProcessingStep<XConstructorElement> { 37 private final XMessager messager; 38 private final InjectValidator injectValidator; 39 40 @Inject AssistedInjectProcessingStep(XMessager messager, InjectValidator injectValidator)41 AssistedInjectProcessingStep(XMessager messager, InjectValidator injectValidator) { 42 this.messager = messager; 43 this.injectValidator = injectValidator; 44 } 45 46 @Override annotationClassNames()47 public ImmutableSet<ClassName> annotationClassNames() { 48 return ImmutableSet.of(TypeNames.ASSISTED_INJECT); 49 } 50 51 @Override process( XConstructorElement assistedInjectElement, ImmutableSet<ClassName> annotations)52 protected void process( 53 XConstructorElement assistedInjectElement, ImmutableSet<ClassName> annotations) { 54 // The InjectValidator has already run and reported its errors in InjectProcessingStep, so no 55 // need to report its errors. However, the AssistedInjectValidator relies on the InjectValidator 56 // returning a clean report, so we check that first before running AssistedInjectValidator. This 57 // shouldn't be expensive since InjectValidator caches its results after validating. 58 if (injectValidator.validate(assistedInjectElement.getEnclosingElement()).isClean()) { 59 new AssistedInjectValidator().validate(assistedInjectElement).printMessagesTo(messager); 60 } 61 } 62 63 private final class AssistedInjectValidator { validate(XConstructorElement constructor)64 ValidationReport validate(XConstructorElement constructor) { 65 ValidationReport.Builder report = ValidationReport.about(constructor); 66 67 XType assistedInjectType = constructor.getEnclosingElement().getType(); 68 ImmutableList<AssistedParameter> assistedParameters = 69 assistedInjectAssistedParameters(assistedInjectType); 70 71 Set<AssistedParameter> uniqueAssistedParameters = new HashSet<>(); 72 for (AssistedParameter assistedParameter : assistedParameters) { 73 if (!uniqueAssistedParameters.add(assistedParameter)) { 74 report.addError( 75 String.format( 76 "@AssistedInject constructor has duplicate @Assisted type: %s. Consider setting" 77 + " an identifier on the parameter by using @Assisted(\"identifier\") in both" 78 + " the factory and @AssistedInject constructor", 79 assistedParameter), 80 assistedParameter.element()); 81 } 82 } 83 84 return report.build(); 85 } 86 } 87 } 88