package com.squareup.ideaplugin.dagger; import com.intellij.psi.PsiAnnotationMemberValue; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiParameter; import com.intellij.psi.PsiType; import com.intellij.usages.Usage; import com.intellij.usages.UsageInfo2UsageAdapter; import com.intellij.usages.UsageTarget; import java.util.List; import java.util.Set; import static com.squareup.ideaplugin.dagger.DaggerConstants.CLASS_INJECT; import static com.squareup.ideaplugin.dagger.DaggerConstants.CLASS_PROVIDES; import static com.squareup.ideaplugin.dagger.DaggerConstants.SET_TYPE; public interface Decider { boolean shouldShow(UsageTarget target, Usage usage); /** Construct with a PsiMethod from a Provider to find where this is injected. */ public class ProvidesMethodDecider implements Decider { private final PsiClass returnType; private final Set<String> qualifierAnnotations; private final List<PsiType> typeParameters; public ProvidesMethodDecider(PsiMethod psiMethod) { this.returnType = PsiConsultantImpl.getReturnClassFromMethod(psiMethod, true); this.qualifierAnnotations = PsiConsultantImpl.getQualifierAnnotations(psiMethod); this.typeParameters = PsiConsultantImpl.getTypeParameters(psiMethod); } @Override public boolean shouldShow(UsageTarget target, Usage usage) { PsiElement element = ((UsageInfo2UsageAdapter) usage).getElement(); PsiField field = PsiConsultantImpl.findField(element); if (field != null // && PsiConsultantImpl.hasAnnotation(field, CLASS_INJECT) // && PsiConsultantImpl.hasQuailifierAnnotations(field, qualifierAnnotations) && PsiConsultantImpl.hasTypeParameters(field, typeParameters)) { return true; } PsiMethod method = PsiConsultantImpl.findMethod(element); if (method != null && (PsiConsultantImpl.hasAnnotation(method, CLASS_INJECT) || PsiConsultantImpl.hasAnnotation(method, CLASS_PROVIDES))) { for (PsiParameter parameter : method.getParameterList().getParameters()) { PsiClass parameterClass = PsiConsultantImpl.checkForLazyOrProvider(parameter); if (parameterClass.equals(returnType) && PsiConsultantImpl.hasQuailifierAnnotations( parameter, qualifierAnnotations) && PsiConsultantImpl.hasTypeParameters(parameter, typeParameters)) { return true; } } } return false; } } /** * Construct with a PsiParameter from an @Inject constructor and then use this to ensure the * usage fits. */ public class ConstructorParameterInjectDecider extends IsAProviderDecider { public ConstructorParameterInjectDecider(PsiParameter psiParameter) { super(psiParameter); } } public class CollectionElementParameterInjectDecider extends IsAProviderDecider { public CollectionElementParameterInjectDecider(PsiElement psiParameter) { super(psiParameter); } @Override public boolean shouldShow(UsageTarget target, Usage usage) { PsiElement element = ((UsageInfo2UsageAdapter) usage).getElement(); PsiMethod psimethod = PsiConsultantImpl.findMethod(element); PsiAnnotationMemberValue attribValue = PsiConsultantImpl .findTypeAttributeOfProvidesAnnotation(psimethod); // Is it a @Provides method? return psimethod != null // Ensure it has an @Provides. && PsiConsultantImpl.hasAnnotation(psimethod, CLASS_PROVIDES) // Check for Qualifier annotations. && PsiConsultantImpl.hasQuailifierAnnotations(psimethod, qualifierAnnotations) // Right return type. && PsiConsultantImpl.getReturnClassFromMethod(psimethod, false) .getName() .equals(target.getName()) // Right type parameters. && PsiConsultantImpl.hasTypeParameters(psimethod, typeParameters) // @Provides(type=SET) && attribValue != null && attribValue.textMatches(SET_TYPE); } } /** * Construct with a PsiField annotated w/ @Inject and then use this to ensure the * usage fits. */ public class FieldInjectDecider extends IsAProviderDecider { public FieldInjectDecider(PsiField psiField) { super(psiField); } } class IsAProviderDecider implements Decider { protected final Set<String> qualifierAnnotations; protected final List<PsiType> typeParameters; public IsAProviderDecider(PsiElement element) { this.qualifierAnnotations = PsiConsultantImpl.getQualifierAnnotations(element); this.typeParameters = PsiConsultantImpl.getTypeParameters(element); } @Override public boolean shouldShow(UsageTarget target, Usage usage) { PsiElement element = ((UsageInfo2UsageAdapter) usage).getElement(); PsiMethod psimethod = PsiConsultantImpl.findMethod(element); // For constructors annotated w/ @Inject, this is searched first before committing to the usage search. // Is it a @Provides method? return psimethod != null // Ensure it has an @Provides. && PsiConsultantImpl.hasAnnotation(psimethod, CLASS_PROVIDES) // Check for Qualifier annotations. && PsiConsultantImpl.hasQuailifierAnnotations(psimethod, qualifierAnnotations) // Right return type. && PsiConsultantImpl.getReturnClassFromMethod(psimethod, false) .getName() .equals(target.getName()) // Right type parameters. && PsiConsultantImpl.hasTypeParameters(psimethod, typeParameters); } } }