inline superclass: process default/implicit constructors (IDEADEV-41326)

This commit is contained in:
anna
2009-11-12 19:06:31 +03:00
parent d9831b2c91
commit 11373491d2
12 changed files with 148 additions and 9 deletions
@@ -34,13 +34,13 @@ import com.intellij.refactoring.memberPushDown.PushDownProcessor;
import com.intellij.refactoring.util.DocCommentPolicy;
import com.intellij.refactoring.util.FixableUsageInfo;
import com.intellij.refactoring.util.FixableUsagesRefactoringProcessor;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.refactoring.util.classMembers.MemberInfoStorage;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashMap;
import com.intellij.util.Processor;import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
@@ -79,6 +79,7 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
final JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject);
final PsiElementFactory elementFactory = facade.getElementFactory();
final PsiResolveHelper resolveHelper = facade.getResolveHelper();
ReferencesSearch.search(mySuperClass).forEach(new Processor<PsiReference>() {
public boolean process(final PsiReference reference) {
final PsiElement element = reference.getElement();
@@ -134,12 +135,14 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
for (PsiReference reference : ReferencesSearch.search(member, member.getUseScope(), true)) {
final PsiElement element = reference.getElement();
if (element instanceof PsiReferenceExpression &&
((PsiReferenceExpression)element).getQualifierExpression() instanceof PsiSuperExpression && PsiTreeUtil.isAncestor(
targetClass, element, false)) {
((PsiReferenceExpression)element).getQualifierExpression() instanceof PsiSuperExpression &&
PsiTreeUtil.isAncestor(targetClass, element, false)) {
usages.add(new RemoveQualifierUsageInfo((PsiReferenceExpression)element));
}
}
}
final PsiMethod[] superConstructors = mySuperClass.getConstructors();
for (PsiMethod constructor : targetClass.getConstructors()) {
final PsiCodeBlock constrBody = constructor.getBody();
LOG.assertTrue(constrBody != null);
@@ -154,11 +157,30 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
final PsiMethod superConstructor = ((PsiMethodCallExpression)expression).resolveMethod();
if (superConstructor != null && superConstructor.getBody() != null) {
usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression)expression));
continue;
}
}
}
}
}
//insert implicit call to super
for (PsiMethod superConstructor : superConstructors) {
if (superConstructor.getParameterList().getParametersCount() == 0) {
final PsiExpression expression = JavaPsiFacade.getElementFactory(myProject).createExpressionFromText("super()", constructor);
usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression)expression, constrBody));
}
}
}
if (targetClass.getConstructors().length == 0) {
//copy default constructor
for (PsiMethod superConstructor : superConstructors) {
if (superConstructor.getParameterList().getParametersCount() == 0) {
usages.add(new CopyDefaultConstructorUsageInfo(targetClass, superConstructor));
break;
}
}
}
}
}
@@ -191,7 +213,25 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
}
}.run();
replaceInnerTypeUsages();
super.performRefactoring(usages);
RefactoringUtil.sortDepthFirstRightLeftOrder(usages);
for (UsageInfo usageInfo : usages) {
if (!(usageInfo instanceof ReplaceExtendsListUsageInfo)) {
try {
((FixableUsageInfo)usageInfo).fixUsage();
}
catch (IncorrectOperationException e) {
LOG.info(e);
}
}
}
//postpone broken hierarchy
for (UsageInfo usage : usages) {
if (usage instanceof ReplaceExtendsListUsageInfo) {
((ReplaceExtendsListUsageInfo)usage).fixUsage();
}
}
try {
mySuperClass.delete();
}
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* User: anna
* Date: 27-Aug-2008
*/
package com.intellij.refactoring.inlineSuperClass.usageInfo;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiMethod;
import com.intellij.refactoring.util.FixableUsageInfo;
import com.intellij.util.IncorrectOperationException;
public class CopyDefaultConstructorUsageInfo extends FixableUsageInfo{
private final PsiClass myTargetClass;
private final PsiMethod myConstructor;
public CopyDefaultConstructorUsageInfo(PsiClass targetClass, PsiMethod constructor) {
super(targetClass);
myTargetClass = targetClass;
myConstructor = constructor;
}
public void fixUsage() throws IncorrectOperationException {
final PsiCodeBlock body = myConstructor.getBody();
assert body != null;
if (body.getFirstBodyElement() != null) { //do not copy empty constructor
myTargetClass.add(myConstructor.copy());
}
}
}
@@ -34,14 +34,25 @@ import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
public class InlineSuperCallUsageInfo extends FixableUsageInfo {
private PsiCodeBlock myConstrBody;
public InlineSuperCallUsageInfo(PsiMethodCallExpression methodCallExpression) {
super(methodCallExpression);
}
public InlineSuperCallUsageInfo(PsiMethodCallExpression methodCallExpression, PsiCodeBlock constrBody) {
super(methodCallExpression);
myConstrBody = constrBody;
}
@Override
public void fixUsage() throws IncorrectOperationException {
final PsiElement element = getElement();
PsiElement element = getElement();
if (element != null && myConstrBody != null) {
assert !element.isPhysical();
final PsiStatement statement = JavaPsiFacade.getElementFactory(getProject()).createStatementFromText("super();", myConstrBody);
element = ((PsiExpressionStatement)myConstrBody.addBefore(statement, myConstrBody.getFirstBodyElement())).getExpression();
}
if (element instanceof PsiMethodCallExpression) {
PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)element).getMethodExpression();
final PsiMethod superConstructor = (PsiMethod)methodExpression.resolve();
@@ -0,0 +1,6 @@
class Test {
Test() {
System.out.println("Super");
System.out.println("Test");
}
}
@@ -0,0 +1,5 @@
class Super {
Super() {
System.out.println("Super");
}
}
@@ -0,0 +1,5 @@
class Test extends Super{
Test() {
System.out.println("Test");
}
}
@@ -1,5 +1,6 @@
class Test {
Test(String s){super(s);}
Test(String s){
}
void foo() {
Test s = new Test("");
@@ -0,0 +1,6 @@
class Test {
Test() {
System.out.println("");
}
}
@@ -0,0 +1,5 @@
class Super {
Super() {
System.out.println("");
}
}
@@ -0,0 +1,3 @@
class Test extends Super{
}
@@ -2,8 +2,10 @@ class Test {
String s;
Test(String s){
super(s);
System.out.println("hello");
if (s != null) {
this.s = s;
}
System.out.println("hello");
}
void foo() {
@@ -147,6 +147,14 @@ public class InlineSuperClassTest extends MultiFileTestCase {
doTest();
}
public void testChildConstructorImplicitlyCallsSuper() throws Exception {
doTest();
}
public void testNoChildConstructorCallsSuperDefault() throws Exception {
doTest();
}
public void testMultipleSubclasses() throws Exception {
doTest(new PerformAction() {
public void performAction(final VirtualFile rootDir, final VirtualFile rootAfter) throws Exception {