package de.plushnikov.intellij.plugin.provider; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiAnnotation; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMember; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifierList; import de.plushnikov.intellij.plugin.extension.LombokProcessorExtensionPoint; import de.plushnikov.intellij.plugin.processor.Processor; import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil; import de.plushnikov.intellij.plugin.util.PsiClassUtil; import org.jetbrains.annotations.NotNull; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; public class LombokProcessorProvider { public static LombokProcessorProvider getInstance(@NotNull Project project) { return ServiceManager.getService(project, LombokProcessorProvider.class); } private final Map<Class, Collection<Processor>> lombokTypeProcessors; private final Map<String, Collection<Processor>> lombokProcessors; private final Collection<String> registeredAnnotationNames; private PropertiesComponent myPropertiesComponent; private LombokProcessorProvider(@NotNull PropertiesComponent propertiesComponent) { myPropertiesComponent = propertiesComponent; lombokProcessors = new HashMap<String, Collection<Processor>>(); lombokTypeProcessors = new HashMap<Class, Collection<Processor>>(); registeredAnnotationNames = new HashSet<String>(); initProcessors(); } public void initProcessors() { lombokProcessors.clear(); lombokTypeProcessors.clear(); registeredAnnotationNames.clear(); for (Processor processor : getLombokProcessors()) { if (processor.isEnabled(myPropertiesComponent)) { Class<? extends Annotation>[] annotationClasses = processor.getSupportedAnnotationClasses(); for (Class<? extends Annotation> annotationClass : annotationClasses) { putProcessor(lombokProcessors, annotationClass.getName(), processor); putProcessor(lombokProcessors, annotationClass.getSimpleName(), processor); } putProcessor(lombokTypeProcessors, processor.getSupportedClass(), processor); } } registeredAnnotationNames.addAll(lombokProcessors.keySet()); } @NotNull private Processor[] getLombokProcessors() { return LombokProcessorExtensionPoint.EP_NAME_PROCESSOR.getExtensions(); } private <K, V> void putProcessor(final Map<K, Collection<V>> map, final K key, final V value) { Collection<V> valueList = map.get(key); if (null == valueList) { valueList = new HashSet<V>(); map.put(key, valueList); } valueList.add(value); } @NotNull public Collection<Processor> getLombokProcessors(@NotNull Class supportedClass) { final Collection<Processor> result = lombokTypeProcessors.get(supportedClass); return result == null ? Collections.<Processor>emptySet() : result; } @NotNull public Collection<Processor> getProcessors(@NotNull PsiAnnotation psiAnnotation) { final String qualifiedName = psiAnnotation.getQualifiedName(); final Collection<Processor> result = qualifiedName == null ? null : lombokProcessors.get(qualifiedName); return result == null ? Collections.<Processor>emptySet() : result; } private boolean verifyLombokAnnotationPresent(@NotNull PsiClass psiClass) { if (PsiAnnotationSearchUtil.checkAnnotationsSimpleNameExistsIn(psiClass, registeredAnnotationNames)) { return true; } Collection<PsiField> psiFields = PsiClassUtil.collectClassFieldsIntern(psiClass); for (PsiField psiField : psiFields) { if (PsiAnnotationSearchUtil.checkAnnotationsSimpleNameExistsIn(psiField, registeredAnnotationNames)) { return true; } } Collection<PsiMethod> psiMethods = PsiClassUtil.collectClassMethodsIntern(psiClass); for (PsiMethod psiMethod : psiMethods) { if (PsiAnnotationSearchUtil.checkAnnotationsSimpleNameExistsIn(psiMethod, registeredAnnotationNames)) { return true; } } final PsiElement psiClassParent = psiClass.getParent(); if (psiClassParent instanceof PsiClass) { return verifyLombokAnnotationPresent((PsiClass) psiClassParent); } return false; } private boolean verifyLombokAnnotationPresent(@NotNull PsiMember psiMember) { if (PsiAnnotationSearchUtil.checkAnnotationsSimpleNameExistsIn(psiMember, registeredAnnotationNames)) { return true; } final PsiClass psiClass = psiMember.getContainingClass(); return null != psiClass && verifyLombokAnnotationPresent(psiClass); } @NotNull public Collection<LombokProcessorData> getApplicableProcessors(@NotNull PsiMember psiMember) { Collection<LombokProcessorData> result = Collections.emptyList(); if (verifyLombokAnnotationPresent(psiMember)) { result = new ArrayList<LombokProcessorData>(); addApplicableProcessors(psiMember, result); final PsiClass psiClass = psiMember.getContainingClass(); if (null != psiClass) { addApplicableProcessors(psiClass, result); } } return result; } private void addApplicableProcessors(@NotNull PsiMember psiMember, @NotNull Collection<LombokProcessorData> target) { final PsiModifierList psiModifierList = psiMember.getModifierList(); if (null != psiModifierList) { for (PsiAnnotation psiAnnotation : psiModifierList.getAnnotations()) { for (Processor processor : getProcessors(psiAnnotation)) { target.add(new LombokProcessorData(processor, psiAnnotation)); } } } } }