mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Inline inner: show error message as soon as possible (IDEA-39083)
This commit is contained in:
+55
-1
@@ -20,6 +20,8 @@ import com.intellij.lang.StdLanguages;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.patterns.PlatformPatterns;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
@@ -38,6 +40,11 @@ import java.util.Collection;
|
||||
* @author yole
|
||||
*/
|
||||
public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
|
||||
static final ElementPattern ourCatchClausePattern = PlatformPatterns.psiElement(PsiTypeElement.class).withParent(PlatformPatterns.psiElement(PsiParameter.class).withParent(
|
||||
PlatformPatterns.psiElement(PsiCatchSection.class)));
|
||||
static final ElementPattern ourThrowsClausePattern = PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(PsiReferenceList.class).withFirstChild(
|
||||
PlatformPatterns.psiElement().withText(PsiKeyword.THROWS)));
|
||||
|
||||
@Override
|
||||
public boolean isEnabledOnElement(PsiElement element) {
|
||||
return element instanceof PsiMethod || element instanceof PsiClass;
|
||||
@@ -240,7 +247,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return getCannotInlineDueToUsagesMessage(psiClass);
|
||||
}
|
||||
|
||||
static boolean isRedundantImplements(final PsiClass superClass, final PsiClassType interfaceType) {
|
||||
@@ -266,6 +273,53 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
|
||||
return stmt.get();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getCannotInlineDueToUsagesMessage(final PsiClass aClass) {
|
||||
boolean hasUsages = false;
|
||||
for(PsiReference reference : ReferencesSearch.search(aClass)) {
|
||||
final PsiElement element = reference.getElement();
|
||||
if (element == null) continue;
|
||||
if (!PsiTreeUtil.isAncestor(aClass, element, false)) {
|
||||
hasUsages = true;
|
||||
}
|
||||
final PsiElement parentElement = element.getParent();
|
||||
if (parentElement != null) {
|
||||
if (parentElement.getParent() instanceof PsiClassObjectAccessExpression) {
|
||||
return "Class cannot be inlined because it has usages of its class literal";
|
||||
}
|
||||
if (ourCatchClausePattern.accepts(parentElement)) {
|
||||
return "Class cannot be inlined because it is used in a 'catch' clause";
|
||||
}
|
||||
}
|
||||
if (ourThrowsClausePattern.accepts(element)) {
|
||||
return "Class cannot be inlined because it is used in a 'throws' clause";
|
||||
}
|
||||
if (parentElement instanceof PsiThisExpression) {
|
||||
return "Class cannot be inlined because it is used as a 'this' qualifier";
|
||||
}
|
||||
if (parentElement instanceof PsiNewExpression) {
|
||||
final PsiNewExpression newExpression = (PsiNewExpression)parentElement;
|
||||
final PsiMethod[] constructors = aClass.getConstructors();
|
||||
if (constructors.length == 0) {
|
||||
PsiExpressionList newArgumentList = newExpression.getArgumentList();
|
||||
if (newArgumentList != null && newArgumentList.getExpressions().length > 0) {
|
||||
return "Class cannot be inlined because a call to its constructor is unresolved";
|
||||
}
|
||||
}
|
||||
else {
|
||||
final JavaResolveResult resolveResult = newExpression.resolveMethodGenerics();
|
||||
if (!resolveResult.isValidResult()) {
|
||||
return "Class cannot be inlined because a call to its constructor is unresolved";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasUsages) {
|
||||
return RefactoringBundle.message("class.is.never.used");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class AllowedUsagesProcessor implements Processor<PsiReference> {
|
||||
private final PsiElement myPsiElement;
|
||||
|
||||
|
||||
+1
-62
@@ -19,8 +19,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.patterns.PlatformPatterns;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
@@ -29,7 +27,6 @@ import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.rename.NonCodeUsageInfoFactory;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.TextOccurrencesUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
@@ -52,11 +49,6 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
|
||||
private final boolean mySearchInComments;
|
||||
private final boolean mySearchInNonJavaFiles;
|
||||
|
||||
private final ElementPattern ourCatchClausePattern = PlatformPatterns.psiElement(PsiTypeElement.class).withParent(PlatformPatterns.psiElement(PsiParameter.class).withParent(
|
||||
PlatformPatterns.psiElement(PsiCatchSection.class)));
|
||||
private final ElementPattern ourThrowsClausePattern = PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(PsiReferenceList.class).withFirstChild(
|
||||
PlatformPatterns.psiElement().withText(PsiKeyword.THROWS)));
|
||||
|
||||
protected InlineToAnonymousClassProcessor(Project project,
|
||||
PsiClass psiClass,
|
||||
@Nullable final PsiCall callToInline,
|
||||
@@ -134,13 +126,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
|
||||
}
|
||||
|
||||
protected boolean preprocessUsages(final Ref<UsageInfo[]> refUsages) {
|
||||
UsageInfo[] usages = refUsages.get();
|
||||
String s = getPreprocessUsagesMessage(usages);
|
||||
if (s != null) {
|
||||
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("inline.to.anonymous.refactoring"), s, null, myClass.getProject());
|
||||
return false;
|
||||
}
|
||||
MultiMap<PsiElement, String> conflicts = getConflicts(usages);
|
||||
MultiMap<PsiElement, String> conflicts = getConflicts(refUsages.get());
|
||||
if (!conflicts.isEmpty()) {
|
||||
return showConflicts(conflicts);
|
||||
}
|
||||
@@ -280,51 +266,4 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
|
||||
return RefactoringBundle.message("inline.to.anonymous.command.name", myClass.getQualifiedName());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPreprocessUsagesMessage(final UsageInfo[] usages) {
|
||||
boolean hasUsages = false;
|
||||
for(UsageInfo usage: usages) {
|
||||
final PsiElement element = usage.getElement();
|
||||
if (element == null) continue;
|
||||
if (!PsiTreeUtil.isAncestor(myClass, element, false)) {
|
||||
hasUsages = true;
|
||||
}
|
||||
final PsiElement parentElement = element.getParent();
|
||||
if (parentElement != null) {
|
||||
if (parentElement.getParent() instanceof PsiClassObjectAccessExpression) {
|
||||
return "Class cannot be inlined because it has usages of its class literal";
|
||||
}
|
||||
if (ourCatchClausePattern.accepts(parentElement)) {
|
||||
return "Class cannot be inlined because it is used in a 'catch' clause";
|
||||
}
|
||||
}
|
||||
if (ourThrowsClausePattern.accepts(element)) {
|
||||
return "Class cannot be inlined because it is used in a 'throws' clause";
|
||||
}
|
||||
if (parentElement instanceof PsiThisExpression) {
|
||||
return "Class cannot be inlined because it is used as a 'this' qualifier";
|
||||
}
|
||||
if (parentElement instanceof PsiNewExpression) {
|
||||
final PsiNewExpression newExpression = (PsiNewExpression)parentElement;
|
||||
final PsiMethod[] constructors = myClass.getConstructors();
|
||||
if (constructors.length == 0) {
|
||||
PsiExpressionList newArgumentList = newExpression.getArgumentList();
|
||||
if (newArgumentList != null && newArgumentList.getExpressions().length > 0) {
|
||||
return "Class cannot be inlined because a call to its constructor is unresolved";
|
||||
}
|
||||
}
|
||||
else {
|
||||
final JavaResolveResult resolveResult = newExpression.resolveMethodGenerics();
|
||||
if (!resolveResult.isValidResult()) {
|
||||
return "Class cannot be inlined because a call to its constructor is unresolved";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasUsages) {
|
||||
return RefactoringBundle.message("class.is.never.used");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import java.lang.Exception;
|
||||
|
||||
public class Simple extends Exception{}
|
||||
|
||||
class Usage {
|
||||
void foo() throws Simple {
|
||||
throw new Si<caret>mple();
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -348,9 +348,12 @@ public class InlineToAnonymousClassTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
|
||||
private void doTestPreprocessUsages(final String expectedMessage) throws Exception {
|
||||
final InlineToAnonymousClassProcessor processor = prepareProcessor();
|
||||
String message = processor.getPreprocessUsagesMessage(processor.findUsages());
|
||||
assertEquals(expectedMessage, message);
|
||||
configureByFile("/refactoring/inlineToAnonymousClass/" + getTestName(false) + ".java");
|
||||
PsiElement element = TargetElementUtilBase.findTargetElement(myEditor, TargetElementUtilBase
|
||||
.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED);
|
||||
assertInstanceOf(element, PsiClass.class);
|
||||
final PsiClass psiClass = (PsiClass)element;
|
||||
assertEquals(expectedMessage, InlineToAnonymousClassHandler.getCannotInlineMessage(psiClass));
|
||||
}
|
||||
|
||||
private InlineToAnonymousClassProcessor prepareProcessor() throws Exception {
|
||||
@@ -415,10 +418,6 @@ public class InlineToAnonymousClassTest extends LightCodeInsightTestCase {
|
||||
doTestCanBeInvokedOnReference(true);
|
||||
}
|
||||
|
||||
public void testCantBeInvokedOnReferenceThrowStatement() throws Exception {
|
||||
doTestCanBeInvokedOnReference(false);
|
||||
}
|
||||
|
||||
private void doTestCanBeInvokedOnReference(boolean canBeInvokedOnReference) throws Exception {
|
||||
configureByFile("/refactoring/inlineToAnonymousClass/" + getTestName(false) + ".java");
|
||||
PsiElement element = TargetElementUtilBase
|
||||
|
||||
Reference in New Issue
Block a user