Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
Alexey Pegov
2011-04-22 18:40:05 +04:00
10 changed files with 177 additions and 217 deletions
@@ -18,9 +18,7 @@ package com.intellij.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
@@ -44,10 +42,8 @@ import java.util.*;
/**
* @author peter
*/
public class CreateClassOrPackageFix implements IntentionAction, LocalQuickFix {
public class CreateClassOrPackageFix extends LocalQuickFixAndIntentionActionOnPsiElement {
private final List<PsiDirectory> myWritableDirectoryList;
private final PsiElement myContext;
private final String myPresentation;
@Nullable private final ClassKind myClassKind;
@@ -92,17 +88,17 @@ public class CreateClassOrPackageFix implements IntentionAction, LocalQuickFix {
return createFix(qualifiedName, context.getResolveScope(), context, null, kind, superClass, null);
}
private CreateClassOrPackageFix(final List<PsiDirectory> writableDirectoryList,
final PsiElement context,
final String presentation,
final String redPart,
private CreateClassOrPackageFix(@NotNull List<PsiDirectory> writableDirectoryList,
@NotNull PsiElement context,
@NotNull String presentation,
@NotNull String redPart,
@Nullable ClassKind kind,
@Nullable String superClass,
@Nullable final String templateName) {
super(context);
myRedPart = redPart;
myTemplateName = templateName;
myWritableDirectoryList = writableDirectoryList;
myContext = context;
myClassKind = kind;
mySuperClass = superClass;
myPresentation = presentation;
@@ -111,13 +107,8 @@ public class CreateClassOrPackageFix implements IntentionAction, LocalQuickFix {
@NotNull
public String getText() {
return QuickFixBundle.message(
myClassKind == ClassKind.INTERFACE ? "create.interface.text" : myClassKind != null ? "create.class.text" : "create.package.text",
myPresentation);
}
@NotNull
public String getName() {
return getText();
myClassKind == ClassKind.INTERFACE ? "create.interface.text" : myClassKind != null ? "create.class.text" : "create.package.text",
myPresentation);
}
@NotNull
@@ -125,19 +116,28 @@ public class CreateClassOrPackageFix implements IntentionAction, LocalQuickFix {
return getText();
}
public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) {
final PsiFile file = descriptor.getPsiElement().getContainingFile();
@Override
public void invoke(@NotNull final Project project,
@NotNull final PsiFile file,
@Nullable("is null when called from inspection") Editor editor,
@NotNull final PsiElement startElement,
@NotNull PsiElement endElement) {
if (isAvailable(project, null, file)) {
new WriteCommandAction(project) {
protected void run(Result result) throws Throwable {
invoke(project, null, file);
final PsiDirectory directory = chooseDirectory(project, file);
if (directory == null) return;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
doCreate(directory, startElement);
}
});
}
}.execute();
}
}
private static boolean checkCreateClassOrPackage(final boolean createJavaClass, final PsiDirectory directory, final String name) {
try {
if (createJavaClass) {
JavaDirectoryService.getInstance().checkCreateClass(directory, name);
@@ -152,21 +152,6 @@ public class CreateClassOrPackageFix implements IntentionAction, LocalQuickFix {
}
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
public void invoke(@NotNull Project project, Editor editor, PsiFile file) {
final PsiDirectory directory = chooseDirectory(project, file);
if (directory == null) return;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
doCreate(directory);
}
});
}
@Nullable
private PsiDirectory chooseDirectory(final Project project, final PsiFile file) {
PsiDirectory preferredDirectory = myWritableDirectoryList.isEmpty() ? null : myWritableDirectoryList.get(0);
@@ -192,7 +177,7 @@ public class CreateClassOrPackageFix implements IntentionAction, LocalQuickFix {
return preferredDirectory;
}
private void doCreate(final PsiDirectory baseDirectory) {
private void doCreate(final PsiDirectory baseDirectory, PsiElement myContext) {
final PsiManager manager = baseDirectory.getManager();
PsiDirectory directory = baseDirectory;
String lastName;
@@ -20,12 +20,12 @@ import com.intellij.codeInspection.*;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.JavaTemplateUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -108,41 +108,33 @@ class CatchBodyVisitor extends JavaRecursiveElementWalkingVisitor {
Pair<? extends PsiElement, ? extends PsiElement> range = DefaultFileTemplateUsageInspection.getInteriorRange(catchBlock);
final String description = InspectionsBundle.message("default.file.template.description");
ProblemDescriptor descriptor = myManager.createProblemDescriptor(range.first, range.second, description, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
myOnTheFly, createQuickFix(section));
myOnTheFly, createQuickFix());
myProblemDescriptors.add(descriptor);
}
private static LocalQuickFix[] createQuickFix(final PsiCatchSection section) {
private static LocalQuickFix[] createQuickFix() {
FileTemplate template = FileTemplateManager.getInstance().getCodeTemplate(JavaTemplateUtil.TEMPLATE_CATCH_BODY);
final Runnable runnable = new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
final PsiParameter parameter = section.getParameter();
if (parameter == null) return;
PsiCodeBlock catchBlock = section.getCatchBlock();
if (catchBlock == null) return;
PsiType type = parameter.getType();
if (!(type instanceof PsiClassType)) return;
final PsiJavaParserFacade elementFactory = JavaPsiFacade.getInstance(section.getProject()).getParserFacade();
try {
PsiCatchSection sectionTemplate = elementFactory.createCatchSection((PsiClassType)type, parameter.getName(), parameter);
section.replace(sectionTemplate);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
});
}
};
ReplaceWithFileTemplateFix replaceWithFileTemplateFix = new ReplaceWithFileTemplateFix() {
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
runnable.run();
public void applyFix(@NotNull Project project, @NotNull final ProblemDescriptor descriptor) {
final PsiCatchSection section = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiCatchSection.class);
if (section == null) return;
final PsiParameter parameter = section.getParameter();
if (parameter == null) return;
PsiCodeBlock catchBlock = section.getCatchBlock();
if (catchBlock == null) return;
PsiType type = parameter.getType();
if (!(type instanceof PsiClassType)) return;
final PsiJavaParserFacade elementFactory = JavaPsiFacade.getInstance(section.getProject()).getParserFacade();
try {
PsiCatchSection sectionTemplate = elementFactory.createCatchSection((PsiClassType)type, parameter.getName(), parameter);
section.replace(sectionTemplate);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
};
LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, runnable);
LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceWithFileTemplateFix);
if (template.isDefault()) {
return new LocalQuickFix[]{editFileTemplateFix};
}
@@ -15,17 +15,14 @@
*/
package com.intellij.codeInspection.defaultFileTemplateUsage;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.*;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.impl.FileTemplateConfigurable;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -85,7 +82,7 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT
break;
}
int end;
for (end=children.length-1; start<end;end--) {
for (end=children.length-1; end > start;end--) {
PsiElement child = children[end];
if (child instanceof PsiWhiteSpace) continue;
if (child instanceof PsiJavaToken && ((PsiJavaToken)child).getTokenType() == JavaTokenType.RBRACE) continue;
@@ -122,15 +119,15 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT
return new InspectionOptions(this).getComponent();
}
public static LocalQuickFix createEditFileTemplateFix(final FileTemplate templateToEdit, final Runnable replaceTemplateFix) {
public static LocalQuickFix createEditFileTemplateFix(final FileTemplate templateToEdit, final ReplaceWithFileTemplateFix replaceTemplateFix) {
return new MyLocalQuickFix(templateToEdit, replaceTemplateFix);
}
private static class MyLocalQuickFix implements LocalQuickFix, IntentionAction {
private static class MyLocalQuickFix implements LocalQuickFix {
private final FileTemplate myTemplateToEdit;
private final Runnable myReplaceTemplateFix;
private final ReplaceWithFileTemplateFix myReplaceTemplateFix;
public MyLocalQuickFix(FileTemplate templateToEdit, Runnable replaceTemplateFix) {
public MyLocalQuickFix(FileTemplate templateToEdit, ReplaceWithFileTemplateFix replaceTemplateFix) {
myTemplateToEdit = templateToEdit;
myReplaceTemplateFix = replaceTemplateFix;
}
@@ -146,22 +143,6 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
invoke(project, null, null);
}
@NotNull
@Override
public String getText() {
return getName();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
final FileTemplateConfigurable configurable = new FileTemplateConfigurable();
SwingUtilities.invokeLater(new Runnable(){
public void run() {
@@ -170,14 +151,9 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT
});
boolean ok = ShowSettingsUtil.getInstance().editConfigurable(project, configurable);
if (ok) {
myReplaceTemplateFix.run();
myReplaceTemplateFix.applyFix(project, descriptor);
FileTemplateManager.getInstance().saveAll();
}
}
@Override
public boolean startInWriteAction() {
return false;
}
}
}
@@ -19,7 +19,6 @@ import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInspection.*;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
@@ -76,7 +75,7 @@ public class FileHeaderChecker {
});
PsiDocComment element = docComment.get();
if (element == null) return null;
LocalQuickFix[] quickFix = createQuickFix(element, matcher, offsetToProperty);
LocalQuickFix[] quickFix = createQuickFix(matcher, offsetToProperty);
final String description = InspectionsBundle.message("default.file.template.description");
return manager.createProblemDescriptor(element, description, onTheFly, quickFix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
@@ -98,55 +97,46 @@ public class FileHeaderChecker {
return properties;
}
private static LocalQuickFix[] createQuickFix(final PsiDocComment element,
final Matcher matcher,
final TIntObjectHashMap<String> offsetToProperty) {
private static LocalQuickFix[] createQuickFix(final Matcher matcher,
final TIntObjectHashMap<String> offsetToProperty) {
final FileTemplate template = FileTemplateManager.getInstance().getPattern(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME);
final Runnable runnable = new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
if (!element.isValid()) return;
if (!CodeInsightUtil.preparePsiElementsForWrite(element)) return;
String newText;
try {
newText = template.getText(computeProperties(matcher, offsetToProperty));
}
catch (IOException e) {
LOG.error(e);
return;
}
try {
int offset = element.getTextRange().getStartOffset();
PsiFile psiFile = element.getContainingFile();
if (psiFile == null) return;
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiFile.getProject());
Document document = documentManager.getDocument(psiFile);
if (document == null) return;
element.delete();
documentManager.doPostponedOperationsAndUnblockDocument(document);
documentManager.commitDocument(document);
document.insertString(offset, newText);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
catch (IllegalStateException e) {
LOG.error("Cannot create doc comment from text: '" + newText + "'", e);
}
}
});
}
};
final ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() {
public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) {
runnable.run();
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (element == null || !element.isValid()) return;
if (!CodeInsightUtil.preparePsiElementsForWrite(element)) return;
String newText;
try {
newText = template.getText(computeProperties(matcher, offsetToProperty));
}
catch (IOException e) {
LOG.error(e);
return;
}
try {
int offset = element.getTextRange().getStartOffset();
PsiFile psiFile = element.getContainingFile();
if (psiFile == null) return;
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiFile.getProject());
Document document = documentManager.getDocument(psiFile);
if (document == null) return;
element.delete();
documentManager.doPostponedOperationsAndUnblockDocument(document);
documentManager.commitDocument(document);
document.insertString(offset, newText);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
catch (IllegalStateException e) {
LOG.error("Cannot create doc comment from text: '" + newText + "'", e);
}
}
};
final LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, runnable);
final LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix);
if (template.isDefault()) {
return new LocalQuickFix[]{editFileTemplateFix};
}
@@ -23,7 +23,6 @@ import com.intellij.codeInspection.*;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.JavaTemplateUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
@@ -32,6 +31,7 @@ import com.intellij.openapi.util.UserDataHolderEx;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ConcurrentHashMap;
import org.jetbrains.annotations.NotNull;
@@ -169,40 +169,33 @@ public class MethodBodyChecker {
return null;
}
final Runnable runnable = new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
PsiType returnType = method.getReturnType();
if (method.isConstructor() || returnType == null) return;
PsiCodeBlock body = method.getBody();
if (body == null) return;
if (!CodeInsightUtil.preparePsiElementsForWrite(body)) return;
PsiClass aClass = method.getContainingClass();
if (aClass == null) return;
List<HierarchicalMethodSignature> superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures();
try {
PsiMethod templateMethod = JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createMethod("x", returnType);
setupMethodBody(superSignatures, templateMethod, aClass, false);
final PsiCodeBlock templateBody = templateMethod.getBody();
if (templateBody == null) return;
PsiElement newBody = body.replace(templateBody);
CodeStyleManager.getInstance(aClass.getManager()).reformat(newBody);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
});
}
};
final ReplaceWithFileTemplateFix replaceWithFileTemplateFix = new ReplaceWithFileTemplateFix() {
public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) {
runnable.run();
PsiMethod method = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethod.class);
if (method == null) return;
PsiType returnType = method.getReturnType();
if (method.isConstructor() || returnType == null) return;
PsiCodeBlock body = method.getBody();
if (body == null) return;
if (!CodeInsightUtil.preparePsiElementsForWrite(body)) return;
PsiClass aClass = method.getContainingClass();
if (aClass == null) return;
List<HierarchicalMethodSignature> superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures();
try {
PsiMethod templateMethod = JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createMethod("x", returnType);
setupMethodBody(superSignatures, templateMethod, aClass, false);
final PsiCodeBlock templateBody = templateMethod.getBody();
if (templateBody == null) return;
PsiElement newBody = body.replace(templateBody);
CodeStyleManager.getInstance(aClass.getManager()).reformat(newBody);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
};
LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, runnable);
LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceWithFileTemplateFix);
if (template != null && template.isDefault()) {
return new LocalQuickFix[]{editFileTemplateFix};
}
@@ -27,19 +27,15 @@ import org.jetbrains.annotations.NotNull;
public class AdjustPackageNameFix implements LocalQuickFix {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.wrongPackageStatement.AdjustPackageNameFix");
private final PsiJavaFile myFile;
private final PsiPackageStatement myStatement;
private final PsiPackage myTargetPackage;
private final String myName;
public AdjustPackageNameFix(PsiJavaFile file, PsiPackageStatement statement, PsiPackage targetPackage) {
myFile = file;
myStatement = statement;
myTargetPackage = targetPackage;
public AdjustPackageNameFix(String targetPackage) {
myName = targetPackage;
}
@NotNull
public String getName() {
return QuickFixBundle.message("adjust.package.text", myTargetPackage.getQualifiedName());
return QuickFixBundle.message("adjust.package.text", myName);
}
@NotNull
@@ -47,21 +43,21 @@ public class AdjustPackageNameFix implements LocalQuickFix {
return QuickFixBundle.message("adjust.package.family");
}
public boolean isAvailable() {
return myFile != null
&& myFile.isValid()
&& myFile.getManager().isInProject(myFile)
&& myTargetPackage != null
&& myTargetPackage.isValid()
&& (myStatement == null || myStatement.isValid())
;
}
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (element == null) return;
PsiFile myFile = element.getContainingFile();
if (!CodeInsightUtilBase.prepareFileForWrite(myFile)) return;
PsiDirectory directory = myFile.getContainingDirectory();
if (directory == null) return;
PsiPackage myTargetPackage = JavaDirectoryService.getInstance().getPackage(directory);
if (myTargetPackage == null) return;
try {
PsiElementFactory factory = JavaPsiFacade.getInstance(myFile.getProject()).getElementFactory();
PsiPackageStatement myStatement = ((PsiJavaFile)myFile).getPackageStatement();
if (myTargetPackage.getQualifiedName().length() == 0) {
if (myStatement != null) {
myStatement.delete();
@@ -56,7 +56,7 @@ public class WrongPackageStatementInspection extends BaseJavaLocalInspectionTool
String description = JavaErrorMessages.message("missing.package.statement", packageName);
return new ProblemDescriptor[]{manager.createProblemDescriptor(classes[0].getNameIdentifier(), description,
new AdjustPackageNameFix(javaFile, null, dirPackage),
new AdjustPackageNameFix(packageName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly)};
}
if (packageStatement != null) {
@@ -64,10 +64,10 @@ public class WrongPackageStatementInspection extends BaseJavaLocalInspectionTool
PsiPackage classPackage = (PsiPackage)packageReference.resolve();
List<LocalQuickFix> availableFixes = new ArrayList<LocalQuickFix>();
if (classPackage == null) {
availableFixes.add(new AdjustPackageNameFix(javaFile, packageStatement, dirPackage));
availableFixes.add(new AdjustPackageNameFix(packageName));
}
else if (!Comparing.equal(dirPackage.getQualifiedName(), packageReference.getText(), true)) {
availableFixes.add(new AdjustPackageNameFix(javaFile, packageStatement, dirPackage));
availableFixes.add(new AdjustPackageNameFix(packageName));
MoveToPackageFix moveToPackageFix = new MoveToPackageFix(classPackage.getQualifiedName());
if (moveToPackageFix.isAvailable(file)) {
availableFixes.add(moveToPackageFix);
@@ -21,23 +21,22 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.util.Function;
import com.intellij.reference.SoftReference;
import com.intellij.util.Processor;
import com.intellij.util.Query;
import com.intellij.util.QueryExecutor;
import com.intellij.util.containers.Stack;
import gnu.trove.TObjectHashingStrategy;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.lang.ref.Reference;
import java.util.Set;
/**
@@ -154,9 +153,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
@NotNull final PsiClass baseClass,
@NotNull final SearchScope searchScope,
@NotNull final SearchParameters parameters) {
if (baseClass instanceof PsiAnonymousClass) return true;
if (isFinal(baseClass)) return true;
if (baseClass instanceof PsiAnonymousClass || isFinal(baseClass)) return true;
final String qname = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
public String compute() {
@@ -173,25 +170,26 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
return aClass.getQualifiedName();
}
});
if (CommonClassNames.JAVA_LANG_OBJECT.equals(qname1)) {
return true;
}
return consumer.process(aClass);
return CommonClassNames.JAVA_LANG_OBJECT.equals(qname1) || consumer.process(aClass);
}
});
}
final Ref<PsiClass> currentBase = Ref.create(null);
final Stack<PsiClass> stack = new Stack<PsiClass>();
final Set<PsiClass> processed = new HashSet<PsiClass>();
final Stack<Pair<Reference<PsiClass>, String>> stack = new Stack<Pair<Reference<PsiClass>, String>>();
// there are two sets for memory optimization: it's cheaper to hold FQN than PsiClass
final Set<String> processedFqns = new THashSet<String>(); // FQN of processed classes if the class has one
final Set<PsiClass> processed = new THashSet<PsiClass>(); // processed classes without FQN (e.g. anonymous)
final Processor<PsiClass> processor = new Processor<PsiClass>() {
public boolean process(final PsiClass candidate) {
ProgressManager.checkCanceled();
final Ref<Boolean> result = new Ref<Boolean>();
final String[] fqn = new String[1];
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
fqn[0] = candidate.getQualifiedName();
if (parameters.isCheckInheritance() || parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass)) {
if (!candidate.isInheritor(currentBase.get(), false)) {
result.set(true);
@@ -213,27 +211,53 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
if (!result.isNull()) return result.get().booleanValue();
if (parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass) && !isFinal(candidate)) {
stack.push(candidate);
Reference<PsiClass> ref = fqn[0] == null ? createHardReference(candidate) : new SoftReference<PsiClass>(candidate);
stack.push(Pair.create(ref, fqn[0]));
}
return true;
}
};
stack.push(baseClass);
final GlobalSearchScope scope = GlobalSearchScope.allScope(baseClass.getProject());
stack.push(Pair.create(createHardReference(baseClass), qname));
final GlobalSearchScope projectScope = GlobalSearchScope.allScope(baseClass.getProject());
final JavaPsiFacade facade = JavaPsiFacade.getInstance(projectScope.getProject());
while (!stack.isEmpty()) {
ProgressManager.checkCanceled();
final PsiClass psiClass = stack.pop();
if (!processed.add(psiClass)) continue;
Pair<Reference<PsiClass>, String> pair = stack.pop();
PsiClass psiClass = pair.getFirst().get();
final String fqn = pair.getSecond();
if (psiClass == null) {
psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
public PsiClass compute() {
return facade.findClass(fqn, projectScope);
}
});
if (psiClass == null) continue;
}
if (fqn == null) {
if (!processed.add(psiClass)) continue;
}
else {
if (!processedFqns.add(fqn)) continue;
}
currentBase.set(psiClass);
if (!DirectClassInheritorsSearch.search(psiClass, scope, parameters.isIncludeAnonymous()).forEach(processor)) return false;
if (!DirectClassInheritorsSearch.search(psiClass, projectScope, parameters.isIncludeAnonymous()).forEach(processor)) return false;
}
return true;
}
private static boolean isFinal(final PsiClass baseClass) {
private static Reference<PsiClass> createHardReference(final PsiClass candidate) {
return new SoftReference<PsiClass>(candidate){
@Override
public PsiClass get() {
return candidate;
}
};
}
private static boolean isFinal(@NotNull final PsiClass baseClass) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
return Boolean.valueOf(baseClass.hasModifierProperty(PsiModifier.FINAL));
@@ -199,6 +199,9 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
assert destFile.mkdirs() : destFile;
}
else {
if (!fromFile.exists()) {
fail("Cannot find source file: '"+sourceFilePath+"'. getTestDataPath()='"+getTestDataPath()+"'. getHomePath()='"+getHomePath()+"'.");
}
try {
FileUtil.copy(fromFile, destFile);
}
@@ -189,6 +189,7 @@ public class TestMethodWithoutAssertionInspection extends BaseInspection {
}
private boolean containsAssertion(PsiElement element) {
if (element == null) return false;
final ContainsAssertionVisitor visitor =
new ContainsAssertionVisitor();
element.accept(visitor);