From e9a202cedf44ed9db2f2135ec21d74c1d9a3e9be Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Tue, 25 Oct 2016 14:08:31 +0200 Subject: [PATCH] check annotations if they contain given meta annotations --- .../intellij/execution/junit/JUnitUtil.java | 67 ++----------------- .../codeInsight/MetaAnnotationUtil.java | 52 ++++++++++++-- 2 files changed, 52 insertions(+), 67 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index 5d715ed42399..edfc1563123b 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -16,6 +16,7 @@ package com.intellij.execution.junit; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.MetaAnnotationUtil; import com.intellij.codeInsight.TestFrameworks; import com.intellij.execution.*; import com.intellij.execution.junit2.info.MethodLocation; @@ -25,22 +26,17 @@ import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.*; import com.intellij.testIntegration.JavaTestFramework; import com.intellij.testIntegration.TestFramework; -import com.intellij.util.ConcurrencyUtil; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.ConcurrentMap; @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) public class JUnitUtil { @@ -225,11 +221,11 @@ public class JUnitUtil { if (module != null) { for (final PsiMethod method : psiClass.getAllMethods()) { ProgressManager.checkCanceled(); - if (isMetaAnnotated(method, TEST5_ANNOTATIONS)) return true; + if (MetaAnnotationUtil.isMetaAnnotated(method, TEST5_ANNOTATIONS)) return true; } for (PsiClass aClass : psiClass.getInnerClasses()) { - if (isMetaAnnotated(aClass, Collections.singleton(JUNIT5_NESTED))) return true; + if (MetaAnnotationUtil.isMetaAnnotated(aClass, Collections.singleton(JUNIT5_NESTED))) return true; } } @@ -262,64 +258,9 @@ public class JUnitUtil { return true; } - return isMetaAnnotated(method, TEST5_ANNOTATIONS); + return MetaAnnotationUtil.isMetaAnnotated(method, TEST5_ANNOTATIONS); } - private static final ConcurrentMap> annotationsKeyForProvider = ContainerUtil.newConcurrentMap(); - @NotNull - private static Key> getKeyForAnnotations(Collection annotations) { - String name = StringUtil.join(annotations, ", "); - Key key = annotationsKeyForProvider.get(name); - if (key == null) { - key = ConcurrencyUtil.cacheOrGet(annotationsKeyForProvider, name, Key.create(name)); - } - //noinspection unchecked - return (Key)key; - } - - private static boolean isMetaAnnotated(PsiModifierListOwner listOwner, final Collection annotations) { - if (AnnotationUtil.isAnnotated(listOwner, annotations, false)) { - return true; - } - PsiModifierList modifierList = listOwner.getModifierList(); - if (modifierList != null) { - for (PsiAnnotation annotation : modifierList.getApplicableAnnotations()) { - PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement(); - if (nameReferenceElement != null) { - PsiElement resolve = nameReferenceElement.resolve(); - if (resolve instanceof PsiClass) { - Boolean annotated = CachedValuesManager.getManager(listOwner.getProject()).getCachedValue(resolve, getKeyForAnnotations(annotations), () -> new CachedValueProvider.Result<>( - isTestAnnotatedAnnotation((PsiClass)resolve, new HashSet<>(), annotations), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT), false); - if (annotated != null && annotated) return true; - } - } - } - } - return false; - } - - - private static boolean isTestAnnotatedAnnotation(PsiClass aClass, final Set visited, final Collection annotations) { - if (AnnotationUtil.isAnnotated(aClass, annotations, false)) { - return true; - } - PsiModifierList modifierList = aClass.getModifierList(); - if (modifierList != null) { - for (PsiAnnotation psiAnnotation : modifierList.getApplicableAnnotations()) { - PsiJavaCodeReferenceElement nameReferenceElement = psiAnnotation.getNameReferenceElement(); - if (nameReferenceElement != null) { - PsiElement resolve = nameReferenceElement.resolve(); - if (resolve instanceof PsiClass && visited.add((PsiClass)resolve) && - ((PsiClass)resolve).isAnnotationType() && - isTestAnnotatedAnnotation((PsiClass)resolve, visited, annotations)) { - return true; - } - } - } - } - - return false; - } @Nullable private static PsiClass getTestCaseClassOrNull(final Location location) { diff --git a/java/openapi/src/com/intellij/codeInsight/MetaAnnotationUtil.java b/java/openapi/src/com/intellij/codeInsight/MetaAnnotationUtil.java index c1df8fcd33b5..a4d17439333f 100644 --- a/java/openapi/src/com/intellij/codeInsight/MetaAnnotationUtil.java +++ b/java/openapi/src/com/intellij/codeInsight/MetaAnnotationUtil.java @@ -21,10 +21,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiAnnotation; -import com.intellij.psi.PsiClass; +import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.AnnotatedElementsSearch; import com.intellij.psi.search.searches.DirectClassInheritorsSearch; @@ -148,4 +145,51 @@ public class MetaAnnotationUtil { } } } + + /** + * Check if listOwner is annotated with annotations or listOwner's annotations contain given annotations + */ + public static boolean isMetaAnnotated(@NotNull PsiModifierListOwner listOwner, @NotNull final Collection annotations) { + if (AnnotationUtil.isAnnotated(listOwner, annotations, false)) { + return true; + } + + final List resolvedAnnotations = getResolvedClassesInAnnotationsList(listOwner); + for (String annotationFQN : annotations) { + for (PsiClass psiClass : resolvedAnnotations) { + ConcurrentFactoryMap cachedValue = CachedValuesManager.getCachedValue(psiClass, () -> + new CachedValueProvider.Result<>(ConcurrentFactoryMap.createConcurrentMap(anno -> isMetaAnnotated(psiClass, anno, new HashSet<>())), + PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT)); + if (cachedValue.getOrDefault(annotationFQN, false)) return true; + } + } + + return false; + } + + private static boolean isMetaAnnotated(PsiClass aClass, final String annotation, final Set visited) { + if (AnnotationUtil.isAnnotated(aClass, annotation, false)) { + return true; + } + List resolvedAnnotations = getResolvedClassesInAnnotationsList(aClass); + for (PsiClass resolvedAnnotation : resolvedAnnotations) { + if (visited.add(resolvedAnnotation) && isMetaAnnotated(resolvedAnnotation, annotation, visited)) { + return true; + } + } + + return false; + } + + private static List getResolvedClassesInAnnotationsList(PsiModifierListOwner owner) { + PsiModifierList modifierList = owner.getModifierList(); + if (modifierList != null) { + return ContainerUtil.mapNotNull(modifierList.getApplicableAnnotations(), psiAnnotation -> { + PsiJavaCodeReferenceElement nameReferenceElement = psiAnnotation.getNameReferenceElement(); + PsiElement resolve = nameReferenceElement != null ? nameReferenceElement.resolve() : null; + return resolve instanceof PsiClass && ((PsiClass)resolve).isAnnotationType() ? (PsiClass)resolve : null; + }); + } + return Collections.emptyList(); + } }