inline super: don't search for inheritors (may be only this should be replaced: IDEA-152522); dialog layout simplified (IDEA-152474)

This commit is contained in:
Anna Kozlova
2016-03-04 17:00:37 +01:00
parent 84f7bc13b8
commit e847d166f5
4 changed files with 45 additions and 53 deletions
@@ -21,16 +21,11 @@
package com.intellij.refactoring.inlineSuperClass;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.refactoring.JavaRefactoringSettings;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.inline.InlineOptionsDialog;
import com.intellij.refactoring.ui.DocCommentPanel;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.util.Function;
import com.intellij.util.ui.JBDimension;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,15 +35,13 @@ import java.awt.*;
public class InlineSuperClassRefactoringDialog extends InlineOptionsDialog {
private final PsiClass mySuperClass;
private final PsiClass myCurrentInheritor;
private final PsiClass[] myTargetClasses;
private final DocCommentPanel myDocPanel;
protected InlineSuperClassRefactoringDialog(@NotNull Project project, PsiClass superClass, PsiClass currentInheritor, final PsiClass... targetClasses) {
protected InlineSuperClassRefactoringDialog(@NotNull Project project, PsiClass superClass, PsiClass currentInheritor) {
super(project, false, superClass);
mySuperClass = superClass;
myCurrentInheritor = currentInheritor;
myInvokedOnReference = currentInheritor != null;
myTargetClasses = targetClasses;
myDocPanel = new DocCommentPanel("JavaDoc for inlined members");
myDocPanel.setPolicy(JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC);
init();
@@ -60,7 +53,7 @@ public class InlineSuperClassRefactoringDialog extends InlineOptionsDialog {
if(myRbInlineThisOnly.isEnabled() && myRbInlineAll.isEnabled()) {
settings.INLINE_SUPER_CLASS_THIS = isInlineThisOnly();
}
invokeRefactoring(new InlineSuperClassRefactoringProcessor(getProject(), isInlineThisOnly() ? myCurrentInheritor : null, mySuperClass, myDocPanel.getPolicy(), myTargetClasses));
invokeRefactoring(new InlineSuperClassRefactoringProcessor(getProject(), isInlineThisOnly() ? myCurrentInheritor : null, mySuperClass, myDocPanel.getPolicy()));
}
@Override
@@ -76,31 +69,15 @@ public class InlineSuperClassRefactoringDialog extends InlineOptionsDialog {
@NotNull
protected JComponent createCenterPanel() {
final JLabel label = new JLabel("<html>Super class \'" +
mySuperClass.getQualifiedName() +
"\' inheritors: " +
(myTargetClasses.length > 1 ? " <br>&nbsp;&nbsp;&nbsp;\'" : "\'") +
StringUtil.join(myTargetClasses, new Function<PsiClass, String>() {
public String fun(final PsiClass psiClass) {
return psiClass.getQualifiedName();
}
}, "\',<br>&nbsp;&nbsp;&nbsp;\'") +
"\'</html>");
label.setVerticalAlignment(SwingConstants.TOP);
final JPanel panel = new JPanel(new GridBagLayout());
final GridBagConstraints gc =
new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
panel.add(myDocPanel, gc);
JScrollPane pane = ScrollPaneFactory.createScrollPane(label);
pane.setBorder(IdeBorderFactory.createEmptyBorder(5, 5, 5, 5));
pane.setMinimumSize(JBDimension.create(new Dimension(-1, 100)));
panel.add(super.createCenterPanel(), gc);
gc.weighty = 1;
gc.fill = GridBagConstraints.BOTH;
panel.add(pane, gc);
gc.weighty = 0;
gc.fill = GridBagConstraints.HORIZONTAL;
panel.add(super.createCenterPanel(), gc);
panel.add(Box.createVerticalGlue(), gc);
return panel;
}
@@ -24,9 +24,11 @@ import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.lang.StdLanguages;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceList;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.inline.JavaInlineActionHandler;
import com.intellij.refactoring.util.CommonRefactoringUtil;
@@ -49,23 +51,11 @@ public class InlineSuperClassRefactoringHandler extends JavaInlineActionHandler
public void inlineElement(final Project project, final Editor editor, final PsiElement element) {
PsiClass superClass = (PsiClass) element;
Collection<PsiClass> inheritors = DirectClassInheritorsSearch.search((PsiClass)element).findAll();
if (!superClass.getManager().isInProject(superClass)) {
CommonRefactoringUtil.showErrorHint(project, editor, "Cannot inline non-project class", REFACTORING_NAME, null);
return;
}
for (PsiClass inheritor : inheritors) {
if (PsiTreeUtil.isAncestor(superClass, inheritor, false)) {
CommonRefactoringUtil.showErrorHint(project, editor, "Cannot inline into the inner class. Move \'" + inheritor.getName() + "\' to upper level", REFACTORING_NAME, null);
return;
}
if (inheritor instanceof PsiAnonymousClass) {
CommonRefactoringUtil.showErrorHint(project, editor, "Cannot inline into anonymous class.", REFACTORING_NAME, null);
return;
}
}
PsiClass chosen = null;
PsiReference reference = editor != null ? TargetElementUtil.findReference(editor, editor.getCaretModel().getOffset()) : null;
if (reference != null) {
@@ -76,13 +66,13 @@ public class InlineSuperClassRefactoringHandler extends JavaInlineActionHandler
final PsiElement parent = referenceElement.getParent();
if (parent instanceof PsiReferenceList) {
final PsiElement gParent = parent.getParent();
if (gParent instanceof PsiClass && inheritors.contains(gParent)) {
if (gParent instanceof PsiClass) {
chosen = (PsiClass)gParent;
}
}
}
}
}
new InlineSuperClassRefactoringDialog(project, superClass, chosen, inheritors.toArray(new PsiClass[inheritors.size()])).show();
new InlineSuperClassRefactoringDialog(project, superClass, chosen).show();
}
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
@@ -51,6 +52,7 @@ import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -60,15 +62,14 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
private final PsiClass myCurrentInheritor;
private final PsiClass mySuperClass;
private final int myPolicy;
private final PsiClass[] myTargetClasses;
private PsiClass[] myTargetClasses;
private final MemberInfo[] myMemberInfos;
public InlineSuperClassRefactoringProcessor(Project project, PsiClass currentInheritor, PsiClass superClass, int policy, final PsiClass... targetClasses) {
public InlineSuperClassRefactoringProcessor(Project project, PsiClass currentInheritor, PsiClass superClass, int policy) {
super(project);
myCurrentInheritor = currentInheritor;
mySuperClass = superClass;
myPolicy = policy;
myTargetClasses = currentInheritor != null ? new PsiClass[] {currentInheritor} : targetClasses;
MemberInfoStorage memberInfoStorage = new MemberInfoStorage(mySuperClass, new MemberInfo.Filter<PsiMember>() {
public boolean includeMember(PsiMember element) {
return !(element instanceof PsiClass) || PsiTreeUtil.isAncestor(mySuperClass, element, true);
@@ -92,6 +93,14 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
final PsiElementFactory elementFactory = facade.getElementFactory();
final PsiResolveHelper resolveHelper = facade.getResolveHelper();
if (myCurrentInheritor != null) {
myTargetClasses = new PsiClass[] {myCurrentInheritor};
}
else {
Collection<PsiClass> inheritors = DirectClassInheritorsSearch.search(mySuperClass).findAll();
myTargetClasses = inheritors.toArray(new PsiClass[inheritors.size()]);
}
ReferencesSearch.search(mySuperClass).forEach(new Processor<PsiReference>() {
public boolean process(final PsiReference reference) {
final PsiElement element = reference.getElement();
@@ -157,6 +166,10 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
}
});
for (PsiClass targetClass : myTargetClasses) {
if (skipTargetClass(targetClass)) {
continue;
}
for (MemberInfo memberInfo : myMemberInfos) {
final PsiMember member = memberInfo.getMember();
for (PsiReference reference : ReferencesSearch.search(member, member.getUseScope(), true)) {
@@ -220,11 +233,19 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
final PushDownConflicts pushDownConflicts = new PushDownConflicts(mySuperClass, myMemberInfos, conflicts);
for (PsiClass targetClass : myTargetClasses) {
for (MemberInfo info : myMemberInfos) {
final PsiMember member = info.getMember();
pushDownConflicts.checkMemberPlacementInTargetClassConflict(targetClass, member);
if (targetClass instanceof PsiAnonymousClass) {
conflicts.putValue(targetClass, "Cannot inline into anonymous class.");
}
else if (PsiTreeUtil.isAncestor(mySuperClass, targetClass, false)) {
conflicts.putValue(targetClass, "Cannot inline into the inner class. Move \'" + targetClass.getName() + "\' to upper level");
}
else {
for (MemberInfo info : myMemberInfos) {
final PsiMember member = info.getMember();
pushDownConflicts.checkMemberPlacementInTargetClassConflict(targetClass, member);
}
//todo check accessibility conflicts
}
}
if (myCurrentInheritor != null) {
ReferencesSearch.search(myCurrentInheritor).forEach(new Processor<PsiReference>() {
@@ -249,6 +270,11 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
return showConflicts(conflicts, refUsages.get());
}
private boolean skipTargetClass(PsiClass targetClass) {
return targetClass instanceof PsiAnonymousClass ||
PsiTreeUtil.isAncestor(mySuperClass, targetClass, false);
}
@Nullable
private static PsiType getPlaceExpectedType(PsiElement parent) {
PsiType type = PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent);
@@ -346,6 +372,7 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
final PsiResolveHelper resolveHelper = facade.getResolveHelper();
final Map<UsageInfo, PsiElement> replacementMap = new HashMap<UsageInfo, PsiElement>();
for (final PsiClass targetClass : myTargetClasses) {
if (skipTargetClass(targetClass)) continue;
final PsiSubstitutor superClassSubstitutor =
TypeConversionUtil.getSuperClassSubstitutor(mySuperClass, targetClass, PsiSubstitutor.EMPTY);
final PsiClassType targetClassType = elementFactory.createType(targetClass, superClassSubstitutor);
@@ -87,7 +87,7 @@ public class InlineSuperClassTest extends MultiFileTestCase {
PsiClass superClass = myJavaFacade.findClass("Super", scope);
if (superClass == null) superClass = myJavaFacade.findClass("p1.Super", scope);
assertNotNull("Class Super not found", superClass);
new InlineSuperClassRefactoringProcessor(myProject, inlineOne ? aClass : null, superClass, DocCommentPolicy.ASIS, aClass).run();
new InlineSuperClassRefactoringProcessor(myProject, inlineOne ? aClass : null, superClass, DocCommentPolicy.ASIS).run();
});
}
catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
@@ -109,9 +109,7 @@ public class InlineSuperClassTest extends MultiFileTestCase {
PsiClass superClass = myJavaFacade.findClass("Super", scope);
if (superClass == null) superClass = myJavaFacade.findClass("p1.Super", scope);
assertNotNull("Class Super not found", superClass);
PsiClass target1 = myJavaFacade.findClass("Test", scope);
PsiClass target2 = myJavaFacade.findClass("Test1", scope);
new InlineSuperClassRefactoringProcessor(myProject, null, superClass, DocCommentPolicy.ASIS, target1, target2).run();
new InlineSuperClassRefactoringProcessor(myProject, null, superClass, DocCommentPolicy.ASIS).run();
});
}
}