optimize show popup for multiple selection: minimize classes processing to detect test cases (IDEA-144401)

This commit is contained in:
Anna Kozlova
2015-09-01 12:14:27 +03:00
parent f2dd324d9e
commit 564bdc40dc
2 changed files with 93 additions and 54 deletions
@@ -26,12 +26,11 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.PsiElementProcessor;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.*;
public abstract class AbstractAddToTestsPatternAction<T extends ModuleBasedConfiguration> extends AnAction {
@NotNull protected abstract AbstractPatternBasedConfigurationProducer<T> getPatternBasedProducer();
@@ -46,7 +45,9 @@ public abstract class AbstractAddToTestsPatternAction<T extends ModuleBasedConfi
public void actionPerformed(AnActionEvent e) {
final DataContext dataContext = e.getDataContext();
final PsiElement[] psiElements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
final Set<PsiElement> classes = getPatternBasedProducer().collectTestMembers(psiElements, true);
final LinkedHashSet<PsiElement> classes = new LinkedHashSet<PsiElement>();
PsiElementProcessor.CollectElements<PsiElement> processor = new PsiElementProcessor.CollectElements<PsiElement>(classes);
getPatternBasedProducer().collectTestMembers(psiElements, true, true, processor);
final Project project = CommonDataKeys.PROJECT.getData(dataContext);
final List<T> patternConfigurations = collectPatternConfigurations(classes, project);
@@ -86,11 +87,13 @@ public abstract class AbstractAddToTestsPatternAction<T extends ModuleBasedConfi
final DataContext dataContext = e.getDataContext();
final PsiElement[] psiElements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
if (psiElements != null) {
final Set<PsiElement> foundMembers = getPatternBasedProducer().collectTestMembers(psiElements, true);
if (foundMembers.isEmpty()) return;
PsiElementProcessor.CollectElementsWithLimit<PsiElement> processor = new PsiElementProcessor.CollectElementsWithLimit<PsiElement>(2);
getPatternBasedProducer().collectTestMembers(psiElements, false, false, processor);
Collection<PsiElement> collection = processor.getCollection();
if (collection.isEmpty()) return;
final Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (project != null) {
final List<T> foundConfigurations = collectPatternConfigurations(foundMembers, project);
final List<T> foundConfigurations = collectPatternConfigurations(collection, project);
if (!foundConfigurations.isEmpty()) {
presentation.setVisible(true);
if (foundConfigurations.size() == 1) {
@@ -101,7 +104,7 @@ public abstract class AbstractAddToTestsPatternAction<T extends ModuleBasedConfi
}
}
private List<T> collectPatternConfigurations(Set<PsiElement> foundClasses, Project project) {
private List<T> collectPatternConfigurations(Collection<PsiElement> foundClasses, Project project) {
final List<RunConfiguration> configurations = RunManager.getInstance(project).getConfigurationsList(getConfigurationType());
final List<T> foundConfigurations = new ArrayList<T>();
for (RunConfiguration configuration : configurations) {
@@ -26,10 +26,12 @@ import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.util.ClassUtil;
import java.util.ArrayList;
@@ -55,18 +57,27 @@ public abstract class AbstractPatternBasedConfigurationProducer<T extends Module
}
public boolean isMultipleElementsSelected(ConfigurationContext context) {
if (TestsUIUtil.isMultipleSelectionImpossible(context.getDataContext())) return false;
final DataContext dataContext = context.getDataContext();
if (TestsUIUtil.isMultipleSelectionImpossible(dataContext)) return false;
final LinkedHashSet<String> classes = new LinkedHashSet<String>();
final PsiElement[] elements = collectPatternElements(context, classes);
if (elements != null && collectTestMembers(elements, false).size() > 1) {
return true;
final PsiElementProcessor.CollectElementsWithLimit<PsiElement> processor = new PsiElementProcessor.CollectElementsWithLimit<PsiElement>(2);
final PsiElement[] locationElements = collectLocationElements(classes, dataContext);
if (locationElements != null) {
collectTestMembers(locationElements, false, false, processor);
}
return false;
else {
collectContextElements(dataContext, false, false, classes, processor);
}
return processor.getCollection().size() > 1;
}
public boolean isConfiguredFromContext(ConfigurationContext context, Set<String> patterns) {
final LinkedHashSet<String> classes = new LinkedHashSet<String>();
collectPatternElements(context, classes);
final DataContext dataContext = context.getDataContext();
final PsiElement[] locationElements = collectLocationElements(classes, dataContext);
if (locationElements == null) {
collectContextElements(dataContext, true, false, classes, new PsiElementProcessor.CollectElements<PsiElement>());
}
if (Comparing.equal(classes, patterns)) {
return true;
}
@@ -74,43 +85,91 @@ public abstract class AbstractPatternBasedConfigurationProducer<T extends Module
}
public PsiElement checkPatterns(ConfigurationContext context, LinkedHashSet<String> classes) {
PsiElement[] elements = collectPatternElements(context, classes);
if (elements == null || collectTestMembers(elements, false).size() <= 1) {
PsiElement[] result;
final DataContext dataContext = context.getDataContext();
final PsiElement[] locationElements = collectLocationElements(classes, dataContext);
PsiElementProcessor.CollectElements<PsiElement> processor = new PsiElementProcessor.CollectElements<PsiElement>();
if (locationElements != null) {
collectTestMembers(locationElements, false, true, processor);
result = processor.toArray();
}
else if (collectContextElements(dataContext, true, true, classes, processor)) {
result = processor.toArray();
}
else {
return null;
}
return elements[0];
if (result.length <= 1) {
return null;
}
return result[0];
}
public Set<PsiElement> collectTestMembers(PsiElement[] psiElements, boolean checkAbstract) {
final Set<PsiElement> foundMembers = new LinkedHashSet<PsiElement>();
public void collectTestMembers(PsiElement[] psiElements,
boolean checkAbstract,
boolean checkIsTest,
PsiElementProcessor.CollectElements<PsiElement> collectingProcessor) {
for (PsiElement psiElement : psiElements) {
if (psiElement instanceof PsiClassOwner) {
final PsiClass[] classes = ((PsiClassOwner)psiElement).getClasses();
for (PsiClass aClass : classes) {
if (isTestClass(aClass)) {
foundMembers.add(aClass);
if ((!checkIsTest || isTestClass(aClass)) && !collectingProcessor.execute(aClass)) {
return;
}
}
} else if (psiElement instanceof PsiClass) {
if (isTestClass((PsiClass)psiElement)) {
foundMembers.add(psiElement);
if ((!checkIsTest || isTestClass((PsiClass)psiElement)) && !collectingProcessor.execute(psiElement)) {
return;
}
} else if (psiElement instanceof PsiMethod) {
if (isTestMethod(checkAbstract, psiElement)) {
foundMembers.add(psiElement);
if ((!checkIsTest || isTestMethod(checkAbstract, psiElement)) && !collectingProcessor.execute(psiElement)) {
return;
}
} else if (psiElement instanceof PsiDirectory) {
final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory)psiElement);
if (aPackage != null) {
foundMembers.add(aPackage);
if (aPackage != null && !collectingProcessor.execute(aPackage)) {
return;
}
}
}
return foundMembers;
}
private PsiElement[] collectPatternElements(ConfigurationContext context, LinkedHashSet<String> classes) {
final DataContext dataContext = context.getDataContext();
private boolean collectContextElements(DataContext dataContext,
boolean checkAbstract,
boolean checkIsTest,
LinkedHashSet<String> classes,
PsiElementProcessor.CollectElements<PsiElement> processor) {
PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
if (elements != null) {
collectTestMembers(elements, checkAbstract, checkIsTest, processor);
for (PsiElement psiClass : processor.getCollection()) {
classes.add(getQName(psiClass));
}
return true;
}
else {
final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
if (files != null) {
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (project != null) {
final PsiManager psiManager = PsiManager.getInstance(project);
for (VirtualFile file : files) {
final PsiFile psiFile = psiManager.findFile(file);
if (psiFile instanceof PsiClassOwner) {
collectTestMembers(((PsiClassOwner)psiFile).getClasses(), checkAbstract, checkIsTest, processor);
for (PsiElement psiMember : processor.getCollection()) {
classes.add(((PsiClass)psiMember).getQualifiedName());
}
}
}
return true;
}
}
}
return false;
}
private static PsiElement[] collectLocationElements(LinkedHashSet<String> classes, DataContext dataContext) {
final Location<?>[] locations = Location.DATA_KEYS.getData(dataContext);
if (locations != null) {
List<PsiElement> elements = new ArrayList<PsiElement>();
@@ -121,29 +180,6 @@ public abstract class AbstractPatternBasedConfigurationProducer<T extends Module
}
return elements.toArray(new PsiElement[elements.size()]);
}
PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
if (elements != null) {
for (PsiElement psiClass : collectTestMembers(elements, true)) {
classes.add(getQName(psiClass));
}
return elements;
} else {
final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
if (files != null) {
final List<PsiFile> psiFiles = new ArrayList<PsiFile>();
final PsiManager psiManager = PsiManager.getInstance(context.getProject());
for (VirtualFile file : files) {
final PsiFile psiFile = psiManager.findFile(file);
if (psiFile instanceof PsiClassOwner) {
for (PsiElement psiMember : collectTestMembers(((PsiClassOwner)psiFile).getClasses(), true)) {
classes.add(((PsiClass)psiMember).getQualifiedName());
}
psiFiles.add(psiFile);
}
}
return psiFiles.toArray(new PsiElement[psiFiles.size()]);
}
}
return null;
}