change signature: propagate params/exceptions to implicit constructors

This commit is contained in:
anna
2010-01-28 16:22:12 +03:00
parent fca2bf3729
commit 365ed16a15
17 changed files with 213 additions and 56 deletions

View File

@@ -26,6 +26,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
@@ -182,11 +183,16 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor {
result.add(new UsageInfo(ref.getElement()));
}
else if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) {
DefaultConstructorImplicitUsageInfo implicitUsageInfo = new DefaultConstructorImplicitUsageInfo((PsiMethod)element, method);
DefaultConstructorImplicitUsageInfo implicitUsageInfo = new DefaultConstructorImplicitUsageInfo((PsiMethod)element,
((PsiMethod)element).getContainingClass(), method);
result.add(implicitUsageInfo);
}
else if(element instanceof PsiClass) {
result.add(new NoConstructorClassUsageInfo((PsiClass)element));
LOG.assertTrue(method.isConstructor());
final PsiClass psiClass = (PsiClass)element;
if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateParametersMethods)) continue;
if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateExceptionsMethods)) continue;
result.add(new NoConstructorClassUsageInfo(psiClass));
}
else if (ref instanceof PsiCallReference) {
result.add(new CallReferenceUsageInfo((PsiCallReference) ref));
@@ -223,6 +229,16 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor {
return overridingMethods;
}
private static boolean shouldPropagateToNonPhysicalMethod(PsiMethod method, ArrayList<UsageInfo> result, PsiClass containingClass, final Set<PsiMethod> propagateMethods) {
for (PsiMethod psiMethod : propagateMethods) {
if (!psiMethod.isPhysical() && Comparing.strEqual(psiMethod.getName(), containingClass.getName())) {
result.add(new DefaultConstructorImplicitUsageInfo(psiMethod, containingClass, method));
return true;
}
}
return false;
}
private void findUsagesInCallers(final ArrayList<UsageInfo> usages) {
for (PsiMethod caller : myPropagateParametersMethods) {
usages.add(new CallerUsageInfo(caller, true, myPropagateExceptionsMethods.contains(caller)));
@@ -512,7 +528,17 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor {
if (usage instanceof DefaultConstructorImplicitUsageInfo) {
final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage;
addSuperCall(defConstructorUsage.getConstructor(), defConstructorUsage.getBaseConstructor(),usages);
PsiMethod constructor = defConstructorUsage.getConstructor();
if (!constructor.isPhysical()) {
final boolean toPropagate = myPropagateParametersMethods.remove(constructor);
final PsiClass containingClass = defConstructorUsage.getContainingClass();
constructor = (PsiMethod)containingClass.add(constructor);
PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true);
if (toPropagate) {
myPropagateParametersMethods.add(constructor);
}
}
addSuperCall(constructor, defConstructorUsage.getBaseConstructor(),usages);
}
else if (usage instanceof NoConstructorClassUsageInfo) {
addDefaultConstructor(((NoConstructorClassUsageInfo)usage).getPsiClass(),usages);

View File

@@ -136,7 +136,7 @@ public abstract class CallerChooser extends DialogWrapper {
final PsiMethod caller = node.getMethod();
final PsiMethod callee = parentNode != null ? parentNode.getMethod() : null;
if (caller != null && callee != null) {
if (caller != null && caller.isPhysical() && callee != null) {
HighlightManager highlighter = HighlightManager.getInstance(myProject);
EditorColorsManager colorManager = EditorColorsManager.getInstance();
TextAttributes attributes = colorManager.getGlobalScheme().getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES);
@@ -162,9 +162,12 @@ public abstract class CallerChooser extends DialogWrapper {
if (method == null) return "";
final PsiFile file = method.getContainingFile();
Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
final int start = document.getLineStartOffset(document.getLineNumber(method.getTextRange().getStartOffset()));
final int end = document.getLineEndOffset(document.getLineNumber(method.getTextRange().getEndOffset()));
return document.getText().substring(start, end);
if (document != null) {
final int start = document.getLineStartOffset(document.getLineNumber(method.getTextRange().getStartOffset()));
final int end = document.getLineEndOffset(document.getLineNumber(method.getTextRange().getEndOffset()));
return document.getText().substring(start, end);
}
return "";
}
private int getStartOffset (@NotNull final PsiMethod method) {

View File

@@ -103,6 +103,9 @@ public class MethodNode extends CheckedTreeNode {
if (enclosingContext instanceof PsiMethod &&
!myMethod.equals(enclosingContext) && !myCalled.contains(myMethod)) { //do not add recursive methods
callers.add((PsiMethod) enclosingContext);
} else if (element instanceof PsiClass) {
final PsiClass aClass = (PsiClass)element;
callers.add(JavaPsiFacade.getElementFactory(project).createMethodFromText(aClass.getName() + "(){}", aClass));
}
}
}
@@ -137,8 +140,10 @@ public class MethodNode extends CheckedTreeNode {
SimpleTextAttributes.EXCLUDED_ATTRIBUTES;
renderer.append(buffer.toString(), attributes);
final String packageName = getPackageName(myMethod.getContainingClass());
renderer.append(" (" + packageName + ")", new SimpleTextAttributes(SimpleTextAttributes.STYLE_ITALIC, Color.GRAY));
if (containingClass != null) {
final String packageName = getPackageName(containingClass);
renderer.append(" (" + packageName + ")", new SimpleTextAttributes(SimpleTextAttributes.STYLE_ITALIC, Color.GRAY));
}
}
@Nullable

View File

@@ -152,7 +152,7 @@ public class IntroduceParameterProcessor extends BaseRefactoringProcessor implem
PsiElement ref = ref1.getElement();
if (ref instanceof PsiMethod && ((PsiMethod)ref).isConstructor()) {
DefaultConstructorImplicitUsageInfo implicitUsageInfo =
new DefaultConstructorImplicitUsageInfo((PsiMethod)ref, myMethodToSearchFor);
new DefaultConstructorImplicitUsageInfo((PsiMethod)ref, ((PsiMethod)ref).getContainingClass(), myMethodToSearchFor);
result.add(implicitUsageInfo);
}
else if (ref instanceof PsiClass) {

View File

@@ -23,11 +23,13 @@ import com.intellij.usageView.UsageInfo;
*/
public class DefaultConstructorImplicitUsageInfo extends UsageInfo {
private final PsiMethod myOverridingConstructor;
private final PsiClass myContainingClass;
private final PsiMethod myBaseConstructor;
public DefaultConstructorImplicitUsageInfo(PsiMethod overridingConstructor, PsiMethod baseConstructor) {
public DefaultConstructorImplicitUsageInfo(PsiMethod overridingConstructor, PsiClass containingClass, PsiMethod baseConstructor) {
super(overridingConstructor);
myOverridingConstructor = overridingConstructor;
myContainingClass = containingClass;
myBaseConstructor = baseConstructor;
}
@@ -38,4 +40,8 @@ public class DefaultConstructorImplicitUsageInfo extends UsageInfo {
public PsiMethod getBaseConstructor() {
return myBaseConstructor;
}
public PsiClass getContainingClass() {
return myContainingClass;
}
}

View File

@@ -1,38 +0,0 @@
/*
* 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.
*/
package com.intellij.refactoring.util.usageInfo;
import com.intellij.psi.*;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.usageView.UsageInfo;
import java.util.ArrayList;
public class DefaultConstructorUsageCollector implements RefactoringUtil.ImplicitConstructorUsageVisitor {
private final ArrayList<UsageInfo> myUsages;
public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) {
myUsages.add(new DefaultConstructorImplicitUsageInfo(constructor, baseConstructor));
}
public void visitClassWithoutConstructors(PsiClass aClass) {
myUsages.add(new NoConstructorClassUsageInfo(aClass));
}
public DefaultConstructorUsageCollector(ArrayList<UsageInfo> result) {
myUsages = result;
}
}

View File

@@ -0,0 +1,9 @@
public class P {
public P<caret>() {
}
}
class PP extends P {
public PP(){
}
}

View File

@@ -0,0 +1,10 @@
public class P {
public P() throws Exception {
}
}
class PP extends P {
public PP() throws Exception {
super();
}
}

View File

@@ -0,0 +1,7 @@
public class P {
public P<caret>() {
}
}
class PP extends P {
}

View File

@@ -0,0 +1,10 @@
public class P {
public P() throws Exception {
}
}
class PP extends P {
PP() throws Exception {
super();
}
}

View File

@@ -0,0 +1,9 @@
public class P {
public P<caret>() {
}
}
class PP extends P {
public PP(){
}
}

View File

@@ -0,0 +1,10 @@
public class P {
public P(Class clazz) {
}
}
class PP extends P {
public PP(Class clazz){
super(clazz);
}
}

View File

@@ -0,0 +1,14 @@
public class P {
public P<caret>() {
}
}
class PP extends P {
public PP(){
}
}
class PPP extends P {
public PPP(){
}
}

View File

@@ -0,0 +1,16 @@
public class P {
public P(Class clazz) {
}
}
class PP extends P {
public PP(Class clazz){
super(clazz);
}
}
class PPP extends P {
public PPP(Class clazz){
super(clazz);
}
}

View File

@@ -0,0 +1,7 @@
public class P {
public P<caret>() {
}
}
class PP extends P {
}

View File

@@ -0,0 +1,10 @@
public class P {
public P(Class clazz) {
}
}
class PP extends P {
PP(Class clazz) {
super(clazz);
}
}

View File

@@ -4,12 +4,15 @@ import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
import com.intellij.refactoring.changeSignature.ThrownExceptionInfo;
import com.intellij.refactoring.util.CanonicalTypes;
import com.intellij.testFramework.LightCodeInsightTestCase;
import com.intellij.util.containers.HashSet;
import junit.framework.Assert;
import java.util.Arrays;
import java.util.Set;
@@ -34,21 +37,71 @@ public class ChangeSignaturePropagationTest extends LightCodeInsightTestCase {
exceptionPropagationTest();
}
public void testParamWithNoConstructor() throws Exception {
final PsiMethod method = getPrimaryMethod();
parameterPropagationTest(method, collectNonPhysicalMethodsToPropagate(method));
}
public void testExceptionWithNoConstructor() throws Exception {
final PsiMethod method = getPrimaryMethod();
exceptionPropagationTest(method, collectNonPhysicalMethodsToPropagate(method));
}
private static HashSet<PsiMethod> collectNonPhysicalMethodsToPropagate(PsiMethod method) {
final HashSet<PsiMethod> methodsToPropagate = new HashSet<PsiMethod>();
final PsiReference[] references =
MethodReferencesSearch.search(method, GlobalSearchScope.allScope(getProject()), true).toArray(PsiReference.EMPTY_ARRAY);
for (PsiReference reference : references) {
final PsiElement element = reference.getElement();
Assert.assertTrue(element instanceof PsiClass);
PsiClass containingClass = (PsiClass)element;
methodsToPropagate.add(JavaPsiFacade.getElementFactory(getProject()).createMethodFromText(containingClass.getName() + "(){}", containingClass));
}
return methodsToPropagate;
}
public void testParamWithImplicitConstructor() throws Exception {
final PsiMethod method = getPrimaryMethod();
parameterPropagationTest(method, collectDefaultConstructorsToPropagate(method));
}
public void testParamWithImplicitConstructors() throws Exception {
final PsiMethod method = getPrimaryMethod();
parameterPropagationTest(method, collectDefaultConstructorsToPropagate(method));
}
public void testExceptionWithImplicitConstructor() throws Exception {
final PsiMethod method = getPrimaryMethod();
exceptionPropagationTest(method, collectDefaultConstructorsToPropagate(method));
}
private static HashSet<PsiMethod> collectDefaultConstructorsToPropagate(PsiMethod method) {
final HashSet<PsiMethod> methodsToPropagate = new HashSet<PsiMethod>();
for (PsiClass inheritor : ClassInheritorsSearch.search(method.getContainingClass())) {
methodsToPropagate.add(inheritor.getConstructors()[0]);
}
return methodsToPropagate;
}
private void parameterPropagationTest() throws Exception {
PsiMethod method = getPrimaryMethod();
PsiClass aClass = method.getContainingClass();
final PsiMethod method = getPrimaryMethod();
parameterPropagationTest(method, new HashSet<PsiMethod>(Arrays.asList(method.getContainingClass().getMethods())));
}
private void parameterPropagationTest(final PsiMethod method, final HashSet<PsiMethod> psiMethods) throws Exception {
PsiType newParamType = JavaPsiFacade.getElementFactory(getProject()).createTypeByFQClassName("java.lang.Class", GlobalSearchScope.allScope(getProject()));
final ParameterInfoImpl[] newParameters = new ParameterInfoImpl[]{new ParameterInfoImpl(-1, "clazz", newParamType, "null")};
final Set<PsiMethod> methodsToPropagateParameters = new HashSet<PsiMethod>(Arrays.asList(aClass.getMethods()));
doTest(newParameters, new ThrownExceptionInfo[0], methodsToPropagateParameters, null, method);
doTest(newParameters, new ThrownExceptionInfo[0], psiMethods, null, method);
}
private void exceptionPropagationTest() throws Exception {
PsiMethod method = getPrimaryMethod();
PsiClass aClass = method.getContainingClass();
final PsiMethod method = getPrimaryMethod();
exceptionPropagationTest(method, new HashSet<PsiMethod>(Arrays.asList(method.getContainingClass().getMethods())));
}
private void exceptionPropagationTest(final PsiMethod method, final Set<PsiMethod> methodsToPropagateExceptions) throws Exception {
PsiClassType newExceptionType = JavaPsiFacade.getElementFactory(getProject()).createTypeByFQClassName("java.lang.Exception", GlobalSearchScope.allScope(getProject()));
final ThrownExceptionInfo[] newExceptions = new ThrownExceptionInfo[]{new ThrownExceptionInfo(-1, newExceptionType)};
final Set<PsiMethod> methodsToPropagateExceptions = new HashSet<PsiMethod>(Arrays.asList(aClass.getMethods()));
doTest(new ParameterInfoImpl[0], newExceptions, null, methodsToPropagateExceptions, method);
}