constructor reference: don't ignore constructor parameters during method reference...
[idea/community.git] / java / java-impl / src / com / intellij / testIntegration / JavaTestFinder.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
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 package com.intellij.testIntegration;
17
18 import com.intellij.codeInsight.TestFrameworks;
19 import com.intellij.openapi.module.Module;
20 import com.intellij.openapi.roots.ProjectFileIndex;
21 import com.intellij.openapi.roots.ProjectRootManager;
22 import com.intellij.openapi.util.Pair;
23 import com.intellij.openapi.util.text.StringUtil;
24 import com.intellij.openapi.vfs.VirtualFile;
25 import com.intellij.psi.PsiClass;
26 import com.intellij.psi.PsiElement;
27 import com.intellij.psi.PsiNamedElement;
28 import com.intellij.psi.codeStyle.*;
29 import com.intellij.psi.search.GlobalSearchScope;
30 import com.intellij.psi.search.PsiShortNamesCache;
31 import com.intellij.psi.util.PsiUtilCore;
32 import com.intellij.util.Processor;
33 import com.intellij.util.Processors;
34 import com.intellij.util.containers.ContainerUtil;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
37
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.List;
42
43 public class JavaTestFinder implements TestFinder {
44   @Override
45   public PsiClass findSourceElement(@NotNull PsiElement element) {
46     return TestIntegrationUtils.findOuterClass(element);
47   }
48
49   @Override
50   @NotNull
51   public Collection<PsiElement> findClassesForTest(@NotNull PsiElement element) {
52     PsiClass klass = findSourceElement(element);
53     if (klass == null) return Collections.emptySet();
54
55     GlobalSearchScope scope = getSearchScope(element, true);
56
57     PsiShortNamesCache cache = PsiShortNamesCache.getInstance(element.getProject());
58
59     List<Pair<? extends PsiNamedElement, Integer>> classesWithWeights = new ArrayList<>();
60     for (Pair<String, Integer> eachNameWithWeight : TestFinderHelper.collectPossibleClassNamesWithWeights(klass.getName())) {
61       for (PsiClass eachClass : cache.getClassesByName(eachNameWithWeight.first, scope)) {
62         if (isTestSubjectClass(eachClass)) {
63           classesWithWeights.add(Pair.create(eachClass, eachNameWithWeight.second));
64         }
65       }
66     }
67
68     return TestFinderHelper.getSortedElements(classesWithWeights, false);
69   }
70
71   protected GlobalSearchScope getSearchScope(PsiElement element, boolean dependencies) {
72     final Module module = getModule(element);
73     if (module != null) {
74       return dependencies ? GlobalSearchScope.moduleWithDependenciesScope(module)
75                           : GlobalSearchScope.moduleWithDependentsScope(module);
76     }
77     else {
78       return GlobalSearchScope.projectScope(element.getProject());
79     }
80   }
81
82   protected boolean isTestSubjectClass(PsiClass klass) {
83     if (klass.isAnnotationType() ||
84         TestFrameworks.getInstance().isTestClass(klass) ||
85         !klass.isPhysical()) {
86       return false;
87     }
88     return true;
89   }
90
91   @Override
92   @NotNull
93   public Collection<PsiElement> findTestsForClass(@NotNull PsiElement element) {
94     PsiClass klass = findSourceElement(element);
95     if (klass == null) return Collections.emptySet();
96
97     List<Pair<? extends PsiNamedElement, Integer>> classesWithProximities = new ArrayList<>();
98     Processor<Pair<? extends PsiNamedElement, Integer>> processor =
99       Processors.cancelableCollectProcessor(classesWithProximities);
100     collectTests(klass, processor);
101
102     return TestFinderHelper.getSortedElements(classesWithProximities, true);
103   }
104
105   private void collectTests(PsiClass klass, Processor<? super Pair<? extends PsiNamedElement, Integer>> processor) {
106     GlobalSearchScope scope = getSearchScope(klass, false);
107
108     PsiShortNamesCache cache = PsiShortNamesCache.getInstance(klass.getProject());
109
110     String klassName = klass.getName();
111     assert klassName != null;
112     klassName = StringUtil.trimStart(klassName, JavaCodeStyleSettings.getInstance(klass.getContainingFile()).SUBCLASS_NAME_PREFIX);
113     klassName = StringUtil.trimEnd(klassName, JavaCodeStyleSettings.getInstance(klass.getContainingFile()).SUBCLASS_NAME_SUFFIX);
114     if (klassName.isEmpty()) {
115       klassName = klass.getName();
116     }
117     MinusculeMatcher matcher = NameUtil.buildMatcher("*" + klassName, NameUtil.MatchingCaseSensitivity.NONE);
118     for (String eachName : ContainerUtil.newHashSet(cache.getAllClassNames())) {
119       if (matcher.matches(eachName)) {
120         for (PsiClass eachClass : cache.getClassesByName(eachName, scope)) {
121           if (isTestClass(eachClass, klass) && !processor.process(Pair.create(eachClass, TestFinderHelper.calcTestNameProximity(klassName, eachName)))) {
122             return;
123           }
124         }
125       }
126     }
127   }
128
129   protected boolean isTestClass(PsiClass eachClass, PsiClass klass) {
130     final TestFrameworks frameworks = TestFrameworks.getInstance();
131     return eachClass.isPhysical() && (frameworks.isTestClass(eachClass) || eachClass != klass && frameworks.isPotentialTestClass(eachClass));
132   }
133
134   @Nullable
135   private static Module getModule(PsiElement element) {
136     ProjectFileIndex index = ProjectRootManager.getInstance(element.getProject()).getFileIndex();
137     VirtualFile file = PsiUtilCore.getVirtualFile(element);
138     return file == null ? null : index.getModuleForFile(file);
139   }
140
141   @Override
142   public boolean isTest(@NotNull PsiElement element) {
143     return TestIntegrationUtils.isTest(element);
144   }
145 }