From 555152fa05beab007a4d31242fbe3a3b9f50a46b Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 1 Apr 2016 19:31:01 +0200 Subject: [PATCH] introduce parameter object abstraction --- .../IntroduceParameterObjectProcessor.java | 325 +++++------------- .../JavaIntroduceParameterObjectDelegate.java | 132 +++++++ .../MergeMethodArguments.java | 21 +- .../ParameterChunk.java | 98 ++++++ .../usageInfo/AppendAccessorsUsageInfo.java | 100 +++--- .../IntroduceParameterObjectTest.java | 8 +- 6 files changed, 362 insertions(+), 322 deletions(-) create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterChunk.java diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java index 0b1dbe80533f..825a752022c2 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java @@ -15,7 +15,6 @@ */ package com.intellij.refactoring.introduceparameterobject; -import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.ide.util.PackageUtil; import com.intellij.openapi.diagnostic.Logger; @@ -31,11 +30,10 @@ import com.intellij.psi.impl.source.javadoc.PsiDocParamRef; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.RefactorJBundle; import com.intellij.refactoring.changeSignature.ChangeInfo; @@ -49,11 +47,11 @@ import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewDescriptor; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.Processor; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.HashSet; @@ -67,7 +65,6 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP private final PsiMethod method; private final String className; private final String packageName; - private final boolean keepMethodAsDelegate; private final boolean myUseExistingClass; private final boolean myCreateInnerClass; private final String myNewVisibility; @@ -75,11 +72,10 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP private final List parameters; private final int[] paramsToMerge; private final List typeParams; - private final Set paramsNeedingSetters = new HashSet(); - private final Set paramsNeedingGetters = new HashSet(); private final PsiClass existingClass; private PsiMethod myExistingClassCompatibleConstructor; private ChangeInfo myChangeInfo; + private final String fixedParamName; public IntroduceParameterObjectProcessor(String className, String packageName, @@ -94,7 +90,6 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP this.method = method; this.className = className; this.packageName = packageName; - this.keepMethodAsDelegate = keepMethodAsDelegate; myUseExistingClass = useExistingClass; myCreateInnerClass = createInnerClass; myNewVisibility = newVisibility; @@ -136,6 +131,18 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP final GlobalSearchScope scope = GlobalSearchScope.allScope(myProject); existingClass = JavaPsiFacade.getInstance(myProject).findClass(qualifiedName, scope); + final PsiCodeBlock body = method.getBody(); + final String baseParameterName = StringUtil.decapitalize(className); + + fixedParamName = body != null + ? JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(baseParameterName, body.getLBrace(), true) + : JavaCodeStyleManager.getInstance(myProject).propertyNameToVariableName(baseParameterName, VariableKind.PARAMETER); + + + myChangeInfo = + new MergeMethodArguments(method, className, packageName, fixedParamName, paramsToMerge, typeParams, keepMethodAsDelegate, + myCreateInnerClass ? method.getContainingClass() : null).createChangeInfo(); + } @NotNull @@ -187,34 +194,36 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP public void findUsages(@NotNull List usages) { if (myUseExistingClass && existingClass != null) { - myExistingClassCompatibleConstructor = existingClassIsCompatible(existingClass, parameters); + myExistingClassCompatibleConstructor = JavaIntroduceParameterObjectDelegate.existingClassIsCompatible(existingClass, parameters); } - final PsiCodeBlock body = method.getBody(); - final String baseParameterName = StringUtil.decapitalize(className); - - final String fixedParamName = - body != null - ? JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(baseParameterName, body.getLBrace(), true) - : JavaCodeStyleManager.getInstance(myProject).propertyNameToVariableName(baseParameterName, VariableKind.PARAMETER); - - myChangeInfo = - new MergeMethodArguments(method, className, packageName, fixedParamName, paramsToMerge, typeParams, keepMethodAsDelegate, - myCreateInnerClass ? method.getContainingClass() : null).createChangeInfo(); - for (UsageInfo info : ChangeSignatureProcessorBase.findUsages(myChangeInfo)) { usages.add(new ChangeSignatureUsageWrapper(info)); } - findUsagesForMethod(method, usages, fixedParamName); - - if (myUseExistingClass && existingClass != null && !(paramsNeedingGetters.isEmpty() && paramsNeedingSetters.isEmpty())) { - usages.add(new AppendAccessorsUsageInfo(existingClass, myGenerateAccessors, paramsNeedingGetters, paramsNeedingSetters, parameters)); - } - final PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY); - for (PsiMethod siblingMethod : overridingMethods) { - findUsagesForMethod(siblingMethod, usages, fixedParamName); + for (int i : paramsToMerge) { + final PsiParameter parameterInBase = method.getParameterList().getParameters()[i]; + ParameterChunk parameterChunk = ParameterChunk.getChunkByParameter(parameterInBase, parameters); + assert parameterChunk != null; + @NonNls String getter = parameterChunk.getGetterName(myProject); + @NonNls String setter = parameterChunk.getSetterName(myProject); + + final boolean[] needAccessors = {false, false}; + findUsagesForMethod(method, usages, fixedParamName, i, needAccessors, getter, setter); + + for (PsiMethod siblingMethod : overridingMethods) { + findUsagesForMethod(siblingMethod, usages, fixedParamName, i, needAccessors, getter, setter); + } + + final boolean useExisting = myUseExistingClass && existingClass != null; + + if (needAccessors[0] && parameterChunk.getGetter() == null) { + usages.add(new AppendAccessorsUsageInfo(existingClass, myGenerateAccessors || !useExisting, parameterInBase, true, parameters)); + } + if (needAccessors[1] && parameterChunk.getSetter() == null) { + usages.add(new AppendAccessorsUsageInfo(existingClass, myGenerateAccessors || !useExisting, parameterInBase, false, parameters)); + } } if (myNewVisibility != null) { @@ -222,51 +231,40 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP } } - private void findUsagesForMethod(PsiMethod overridingMethod, List usages, String fixedParamName) { - final ParamUsageVisitor visitor = new ParamUsageVisitor(overridingMethod, paramsToMerge); - overridingMethod.accept(visitor); - final Set values = visitor.getParameterUsages(); - for (PsiReferenceExpression paramUsage : values) { - final PsiParameter parameter = (PsiParameter)paramUsage.resolve(); - assert parameter != null; - final PsiMethod containingMethod = (PsiMethod)parameter.getDeclarationScope(); - final int index = containingMethod.getParameterList().getParameterIndex(parameter); - final PsiParameter replacedParameter = method.getParameterList().getParameters()[index]; - final ParameterChunk parameterChunk = ParameterChunk.getChunkByParameter(parameter, parameters); - - @NonNls String getter = parameterChunk != null ? parameterChunk.getter : null; - final String paramName = parameterChunk != null ? parameterChunk.parameter.name : replacedParameter.getName(); - final PsiType paramType = parameterChunk != null ? parameterChunk.parameter.type : replacedParameter.getType(); - if (getter == null) { - getter = parameterChunk != null && parameterChunk.field != null ? GenerateMembersUtil.suggestGetterName(parameterChunk.field) - : GenerateMembersUtil.suggestGetterName(paramName, paramType, myProject); - paramsNeedingGetters.add(replacedParameter); - } - @NonNls String setter = parameterChunk != null ? parameterChunk.setter : null; - if (setter == null) { - setter = parameterChunk != null && parameterChunk.field != null ? GenerateMembersUtil.suggestSetterName(parameterChunk.field) - : GenerateMembersUtil.suggestSetterName(paramName, paramType, myProject); - } - if (RefactoringUtil.isPlusPlusOrMinusMinus(paramUsage.getParent())) { - usages.add(new ReplaceParameterIncrementDecrement(paramUsage, fixedParamName, setter, getter)); - if (parameterChunk == null || parameterChunk.setter == null) { - paramsNeedingSetters.add(replacedParameter); + private static void findUsagesForMethod(PsiMethod overridingMethod, + List usages, + String fixedParamName, + int i, + final boolean[] needAccessors, String getter, String setter) { + final LocalSearchScope localSearchScope = new LocalSearchScope(overridingMethod); + final PsiParameter[] params = overridingMethod.getParameterList().getParameters(); + final PsiParameter parameter = params[i]; + ReferencesSearch.search(parameter, localSearchScope).forEach(new Processor() { + @Override + public boolean process(PsiReference reference) { + final PsiElement refElement = reference.getElement(); + if (refElement instanceof PsiReferenceExpression) { + final PsiReferenceExpression paramUsage = (PsiReferenceExpression)refElement; + needAccessors[0] = true; + if (RefactoringUtil.isPlusPlusOrMinusMinus(paramUsage.getParent())) { + usages.add(new ReplaceParameterIncrementDecrement(paramUsage, fixedParamName, setter, getter)); + needAccessors[1] = true; + } + else if (RefactoringUtil.isAssignmentLHS(paramUsage)) { + usages.add(new ReplaceParameterAssignmentWithCall(paramUsage, fixedParamName, setter, getter)); + needAccessors[1] = true; + } + else { + usages.add(new ReplaceParameterReferenceWithCall(paramUsage, fixedParamName, getter)); + } } + return true; } - else if (RefactoringUtil.isAssignmentLHS(paramUsage)) { - usages.add(new ReplaceParameterAssignmentWithCall(paramUsage, fixedParamName, setter, getter)); - if (parameterChunk == null || parameterChunk.setter == null) { - paramsNeedingSetters.add(replacedParameter); - } - } - else { - usages.add(new ReplaceParameterReferenceWithCall(paramUsage, fixedParamName, getter)); - } - } + }); } protected void performRefactoring(@NotNull UsageInfo[] usageInfos) { - final PsiClass psiClass = buildClass(); + final PsiClass psiClass = buildClass(usageInfos); if (psiClass != null) { fixJavadocForConstructor(psiClass); super.performRefactoring(usageInfos); @@ -289,10 +287,18 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP } } - private PsiClass buildClass() { + private PsiClass buildClass(UsageInfo[] usageInfos) { if (existingClass != null) { return existingClass; } + + Set paramsWithSetters = new HashSet<>(); + for (UsageInfo info : usageInfos) { + if (info instanceof AppendAccessorsUsageInfo && !((AppendAccessorsUsageInfo)info).isGetter()) { + paramsWithSetters.add(((AppendAccessorsUsageInfo)info).getParameter()); + } + } + final ParameterObjectBuilder beanClassBuilder = new ParameterObjectBuilder(); beanClassBuilder.setVisibility(myCreateInnerClass ? PsiModifier.PRIVATE : PsiModifier.PUBLIC); beanClassBuilder.setProject(myProject); @@ -300,8 +306,8 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP beanClassBuilder.setClassName(className); beanClassBuilder.setPackageName(packageName); for (ParameterChunk parameterChunk : parameters) { - final VariableData parameter = parameterChunk.parameter; - final boolean setterRequired = paramsNeedingSetters.contains(parameter.variable); + final VariableData parameter = parameterChunk.getParameter(); + final boolean setterRequired = paramsWithSetters.contains(parameter.variable); beanClassBuilder.addField((PsiParameter)parameter.variable, parameter.name, parameter.type, setterRequired); } final String classString = beanClassBuilder.buildBeanClass(); @@ -388,181 +394,6 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP } - private static class ParamUsageVisitor extends JavaRecursiveElementVisitor { - private final Set paramsToMerge = new HashSet(); - private final Set parameterUsages = new HashSet(4); - - ParamUsageVisitor(PsiMethod method, int[] paramIndicesToMerge) { - super(); - final PsiParameterList paramList = method.getParameterList(); - final PsiParameter[] parameters = paramList.getParameters(); - for (int i : paramIndicesToMerge) { - paramsToMerge.add(parameters[i]); - } - } - - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement referent = expression.resolve(); - if (!(referent instanceof PsiParameter)) { - return; - } - final PsiParameter parameter = (PsiParameter)referent; - if (paramsToMerge.contains(parameter)) { - parameterUsages.add(expression); - } - } - - public Set getParameterUsages() { - return parameterUsages; - } - } - - @Nullable - private static PsiMethod existingClassIsCompatible(PsiClass aClass, List params) { - if (params.size() == 1) { - final ParameterChunk parameterChunk = params.get(0); - final PsiType paramType = parameterChunk.parameter.type; - if (TypeConversionUtil.isPrimitiveWrapper(aClass.getQualifiedName())) { - parameterChunk.setField(aClass.findFieldByName("value", false)); - parameterChunk.setGetter(paramType.getCanonicalText() + "Value"); - for (PsiMethod constructor : aClass.getConstructors()) { - if (constructorIsCompatible(constructor, params)) return constructor; - } - } - } - final PsiMethod[] constructors = aClass.getConstructors(); - PsiMethod compatibleConstructor = null; - for (PsiMethod constructor : constructors) { - if (constructorIsCompatible(constructor, params)) { - compatibleConstructor = constructor; - break; - } - } - if (compatibleConstructor == null) { - return null; - } - final PsiParameterList parameterList = compatibleConstructor.getParameterList(); - final PsiParameter[] constructorParams = parameterList.getParameters(); - for (int i = 0; i < constructorParams.length; i++) { - final PsiParameter param = constructorParams[i]; - final ParameterChunk parameterChunk = params.get(i); - - final PsiField field = findFieldAssigned(param, compatibleConstructor); - if (field == null) { - return null; - } - - parameterChunk.setField(field); - - final PsiMethod getterForField = PropertyUtil.findGetterForField(field); - if (getterForField != null) { - parameterChunk.setGetter(getterForField.getName()); - } - - final PsiMethod setterForField = PropertyUtil.findSetterForField(field); - if (setterForField != null) { - parameterChunk.setSetter(setterForField.getName()); - } - } - return compatibleConstructor; - } - - private static boolean constructorIsCompatible(PsiMethod constructor, List params) { - final PsiParameterList parameterList = constructor.getParameterList(); - final PsiParameter[] constructorParams = parameterList.getParameters(); - if (constructorParams.length != params.size()) { - return false; - } - for (int i = 0; i < constructorParams.length; i++) { - if (!TypeConversionUtil.isAssignable(constructorParams[i].getType(), params.get(i).parameter.type)) { - return false; - } - } - return true; - } - - public static class ParameterChunk { - private final VariableData parameter; - private PsiField field; - private String getter; - private String setter; - - public ParameterChunk(VariableData parameter) { - this.parameter = parameter; - } - - public void setField(PsiField field) { - this.field = field; - } - - public void setGetter(String getter) { - this.getter = getter; - } - - public void setSetter(String setter) { - this.setter = setter; - } - - @Nullable - public PsiField getField() { - return field; - } - - @Nullable - public static ParameterChunk getChunkByParameter(PsiParameter param, List params) { - for (ParameterChunk chunk : params) { - if (chunk.parameter.variable.equals(param)) { - return chunk; - } - } - return null; - } - } - - private static PsiField findFieldAssigned(PsiParameter param, PsiMethod constructor) { - final ParamAssignmentFinder visitor = new ParamAssignmentFinder(param); - constructor.accept(visitor); - return visitor.getFieldAssigned(); - } - - private static class ParamAssignmentFinder extends JavaRecursiveElementWalkingVisitor { - - private final PsiParameter param; - - private PsiField fieldAssigned = null; - - ParamAssignmentFinder(PsiParameter param) { - this.param = param; - } - - public void visitAssignmentExpression(PsiAssignmentExpression assignment) { - super.visitAssignmentExpression(assignment); - final PsiExpression lhs = assignment.getLExpression(); - final PsiExpression rhs = assignment.getRExpression(); - if (!(lhs instanceof PsiReferenceExpression)) { - return; - } - if (!(rhs instanceof PsiReferenceExpression)) { - return; - } - final PsiElement referent = ((PsiReference)rhs).resolve(); - if (referent == null || !referent.equals(param)) { - return; - } - final PsiElement assigned = ((PsiReference)lhs).resolve(); - if (assigned == null || !(assigned instanceof PsiField)) { - return; - } - fieldAssigned = (PsiField)assigned; - } - - public PsiField getFieldAssigned() { - return fieldAssigned; - } - - } - private static class ChangeSignatureUsageWrapper extends FixableUsageInfo { private final UsageInfo myInfo; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java new file mode 100644 index 000000000000..ee5cecaa827a --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java @@ -0,0 +1,132 @@ +/* + * Copyright 2000-2016 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.introduceparameterobject; + +import com.intellij.psi.*; +import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.TypeConversionUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class JavaIntroduceParameterObjectDelegate { + + @Nullable + static PsiMethod existingClassIsCompatible(PsiClass aClass, List params) { + if (params.size() == 1) { + final ParameterChunk parameterChunk = params.get(0); + final PsiType paramType = parameterChunk.getParameter().type; + if (TypeConversionUtil.isPrimitiveWrapper(aClass.getQualifiedName())) { + parameterChunk.setField(aClass.findFieldByName("value", false)); + parameterChunk.setGetter(paramType.getCanonicalText() + "Value"); + for (PsiMethod constructor : aClass.getConstructors()) { + if (constructorIsCompatible(constructor, params)) return constructor; + } + } + } + final PsiMethod[] constructors = aClass.getConstructors(); + PsiMethod compatibleConstructor = null; + for (PsiMethod constructor : constructors) { + if (constructorIsCompatible(constructor, params)) { + compatibleConstructor = constructor; + break; + } + } + if (compatibleConstructor == null) { + return null; + } + final PsiParameterList parameterList = compatibleConstructor.getParameterList(); + final PsiParameter[] constructorParams = parameterList.getParameters(); + for (int i = 0; i < constructorParams.length; i++) { + final PsiParameter param = constructorParams[i]; + final ParameterChunk parameterChunk = params.get(i); + + final PsiField field = findFieldAssigned(param, compatibleConstructor); + if (field == null) { + return null; + } + + parameterChunk.setField(field); + + final PsiMethod getterForField = PropertyUtil.findGetterForField(field); + if (getterForField != null) { + parameterChunk.setGetter(getterForField.getName()); + } + + final PsiMethod setterForField = PropertyUtil.findSetterForField(field); + if (setterForField != null) { + parameterChunk.setSetter(setterForField.getName()); + } + } + return compatibleConstructor; + } + + private static boolean constructorIsCompatible(PsiMethod constructor, List params) { + final PsiParameterList parameterList = constructor.getParameterList(); + final PsiParameter[] constructorParams = parameterList.getParameters(); + if (constructorParams.length != params.size()) { + return false; + } + for (int i = 0; i < constructorParams.length; i++) { + if (!TypeConversionUtil.isAssignable(constructorParams[i].getType(), params.get(i).getParameter().type)) { + return false; + } + } + return true; + } + + private static PsiField findFieldAssigned(PsiParameter param, PsiMethod constructor) { + final ParamAssignmentFinder visitor = new ParamAssignmentFinder(param); + constructor.accept(visitor); + return visitor.getFieldAssigned(); + } + + private static class ParamAssignmentFinder extends JavaRecursiveElementWalkingVisitor { + + private final PsiParameter param; + + private PsiField fieldAssigned = null; + + ParamAssignmentFinder(PsiParameter param) { + this.param = param; + } + + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + super.visitAssignmentExpression(assignment); + final PsiExpression lhs = assignment.getLExpression(); + final PsiExpression rhs = assignment.getRExpression(); + if (!(lhs instanceof PsiReferenceExpression)) { + return; + } + if (!(rhs instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference)rhs).resolve(); + if (referent == null || !referent.equals(param)) { + return; + } + final PsiElement assigned = ((PsiReference)lhs).resolve(); + if (assigned == null || !(assigned instanceof PsiField)) { + return; + } + fieldAssigned = (PsiField)assigned; + } + + public PsiField getFieldAssigned() { + return fieldAssigned; + } + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/MergeMethodArguments.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/MergeMethodArguments.java index 33da7f6253c9..8f9a93c204d1 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/MergeMethodArguments.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/MergeMethodArguments.java @@ -78,7 +78,8 @@ public class MergeMethodArguments { packageName = this.packageName; } - String text = StringUtil.getQualifiedName(packageName, className); + final String qualifiedName = StringUtil.getQualifiedName(packageName, className); + String text = qualifiedName; if (!typeParams.isEmpty()) { text += "<" + StringUtil.join(typeParams, new Function() { @Override @@ -94,7 +95,7 @@ public class MergeMethodArguments { @Override public PsiExpression getValue(final PsiCallExpression expr) throws IncorrectOperationException { return (PsiExpression)JavaCodeStyleManager.getInstance(project) - .shortenClassReferences(psiFacade.getElementFactory().createExpressionFromText(getMergedParam(expr), expr)); + .shortenClassReferences(psiFacade.getElementFactory().createExpressionFromText(getMergedParam(expr, qualifiedName), expr)); } }; @@ -130,21 +131,9 @@ public class MergeMethodArguments { return false; } - private String getMergedParam(PsiCallExpression call) { + private String getMergedParam(PsiCallExpression call, String qualifiedName) { final PsiExpression[] args = call.getArgumentList().getExpressions(); - StringBuffer newExpression = new StringBuffer(); - final String qualifiedName; - if (myContainingClass != null) { - final String containingClassQName = myContainingClass.getQualifiedName(); - if (containingClassQName != null) { - qualifiedName = containingClassQName + "." + className; - } else { - qualifiedName = className; - } - } - else { - qualifiedName = StringUtil.getQualifiedName(packageName, className); - } + StringBuilder newExpression = new StringBuilder(); newExpression.append("new ").append(qualifiedName); if (!typeParams.isEmpty()) { final JavaResolveResult resolvant = call.resolveMethodGenerics(); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterChunk.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterChunk.java new file mode 100644 index 000000000000..1b3dd41a04ad --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterChunk.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2016 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.introduceparameterobject; + +import com.intellij.codeInsight.generation.GenerateMembersUtil; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiParameter; +import com.intellij.refactoring.util.VariableData; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ParameterChunk { + private final VariableData parameter; + private PsiField field; + private String getter; + private String setter; + + public ParameterChunk(VariableData parameter) { + this.parameter = parameter; + } + + public void setField(PsiField field) { + this.field = field; + } + + public void setGetter(String getter) { + this.getter = getter; + } + + public void setSetter(String setter) { + this.setter = setter; + } + + @Nullable + public PsiField getField() { + return field; + } + + @Nullable + public static ParameterChunk getChunkByParameter(PsiParameter param, List params) { + for (ParameterChunk chunk : params) { + if (chunk.getParameter().variable.equals(param)) { + return chunk; + } + } + return null; + } + + public VariableData getParameter() { + return parameter; + } + + public String getGetter() { + return getter; + } + + public String getSetter() { + return setter; + } + + @NotNull + public String getSetterName(Project project) { + @NonNls String setter = getSetter(); + if (setter == null) { + setter = getField() != null ? GenerateMembersUtil.suggestSetterName(getField()) + : GenerateMembersUtil.suggestSetterName(parameter.name, parameter.type, project); + } + + return setter; + } + + @NotNull + public String getGetterName(Project project) { + @NonNls String getter = getGetter(); + if (getter == null) { + getter = getField() != null ? GenerateMembersUtil.suggestGetterName(getField()) + : GenerateMembersUtil.suggestGetterName(parameter.name, parameter.type, project); + } + return getter; + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java index e862915d8db8..7d3ec5be5d15 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java @@ -22,91 +22,83 @@ package com.intellij.refactoring.introduceparameterobject.usageInfo; import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiField; import com.intellij.psi.PsiParameter; -import com.intellij.refactoring.RefactorJBundle; -import com.intellij.refactoring.introduceparameterobject.IntroduceParameterObjectProcessor; +import com.intellij.refactoring.introduceparameterobject.ParameterChunk; import com.intellij.refactoring.util.FixableUsageInfo; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import java.util.List; -import java.util.Set; public class AppendAccessorsUsageInfo extends FixableUsageInfo{ + private final PsiClass myExistingClass; private final boolean myGenerateAccessors; - private final Set paramsNeedingSetters; - private final Set paramsNeedingGetters; - private final List parameters; + private final PsiParameter myParameter; + private final boolean myGetter; + private final List parameters; private static final Logger LOGGER = Logger.getInstance("#" + AppendAccessorsUsageInfo.class.getName()); - - public AppendAccessorsUsageInfo(PsiElement psiClass, boolean generateAccessors, Set paramsNeedingGetters, - Set paramsNeedingSetters, List parameters) { - super(psiClass); + public AppendAccessorsUsageInfo(PsiClass existingClass, + boolean generateAccessors, + PsiParameter parameter, + boolean isGetter, + List parameters) { + super(parameter); + myExistingClass = existingClass; myGenerateAccessors = generateAccessors; - this.paramsNeedingGetters = paramsNeedingGetters; - this.paramsNeedingSetters = paramsNeedingSetters; + myParameter = parameter; + myGetter = isGetter; this.parameters = parameters; } @Override public void fixUsage() throws IncorrectOperationException { if (myGenerateAccessors) { - appendAccessors(paramsNeedingGetters, true); - appendAccessors(paramsNeedingSetters, false); - } - } - - private void appendAccessors(final Set params, boolean isGetter) { - final PsiElement element = getElement(); - if (element != null) { - for (PsiParameter parameter : params) { - final IntroduceParameterObjectProcessor.ParameterChunk parameterChunk = - IntroduceParameterObjectProcessor.ParameterChunk.getChunkByParameter(parameter, parameters); + if (myExistingClass != null) { + final ParameterChunk parameterChunk = ParameterChunk.getChunkByParameter(myParameter, parameters); LOGGER.assertTrue(parameterChunk != null); final PsiField field = parameterChunk.getField(); if (field != null) { - element.add(isGetter - ? GenerateMembersUtil.generateGetterPrototype(field) - : GenerateMembersUtil.generateSetterPrototype(field)); + myExistingClass.add(myGetter + ? GenerateMembersUtil.generateGetterPrototype(field) + : GenerateMembersUtil.generateSetterPrototype(field)); } - } } } + public boolean isGetter() { + return myGetter; + } + + public PsiParameter getParameter() { + return myParameter; + } + @Override public String getConflictMessage() { - if (!myGenerateAccessors && (!paramsNeedingSetters.isEmpty() || !paramsNeedingGetters.isEmpty())) { - final StringBuffer buf = new StringBuffer(); - appendConflicts(buf, paramsNeedingGetters); - appendConflicts(buf, paramsNeedingSetters); - return RefactorJBundle.message("cannot.perform.the.refactoring") + buf.toString(); + if (!myGenerateAccessors) { + String fieldName = myParameter.getName(); + final ParameterChunk chunk = ParameterChunk.getChunkByParameter(myParameter, parameters); + if (chunk != null) { + final PsiField field = chunk.getField(); + if (field != null) { + fieldName = field.getName(); + } + } + return (myGetter ? "Getter" : "Setter") + " for field \'" + fieldName + "\' is required"; } return null; } - private void appendConflicts(StringBuffer buf, final Set paramsNeeding) { - if (!paramsNeeding.isEmpty()) { - buf.append(paramsNeeding == paramsNeedingGetters ? "Getters" : "Setters"); - buf.append(" for the following fields are required:\n"); - buf.append(StringUtil.join(paramsNeeding, new Function() { - public String fun(PsiParameter psiParameter) { - final IntroduceParameterObjectProcessor.ParameterChunk chunk = - IntroduceParameterObjectProcessor.ParameterChunk.getChunkByParameter(psiParameter, parameters); - if (chunk != null) { - final PsiField field = chunk.getField(); - if (field != null) { - return field.getName(); - } - } - return psiParameter.getName(); - } - }, ", ")); - buf.append(".\n"); - } + @Override + public boolean equals(Object o) { + return super.equals(o) && ((AppendAccessorsUsageInfo)o).isGetter() == isGetter(); + } + + @Override + public int hashCode() { + return super.hashCode() * 29 + (isGetter() ? 1 : 0); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java index fa873a46c801..c822fd62d682 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java @@ -202,9 +202,7 @@ public class IntroduceParameterObjectTest extends MultiFileTestCase{ } public void testIntegerIncremental() throws Exception { - checkExceptionThrown("Integer", "java.lang", "Cannot perform the refactoring.\n" + - "Setters for the following fields are required:\n" + - "value.\n"); + checkExceptionThrown("Integer", "java.lang", "Setter for field 'value' is required"); } private void checkExceptionThrown(String existingClassName, String existingClassPackage, String exceptionMessage) throws Exception { @@ -227,7 +225,7 @@ public class IntroduceParameterObjectTest extends MultiFileTestCase{ } public void testExistingBeanIfNoGeneration() throws Exception { - checkExceptionThrown("Param", "", "Cannot perform the refactoring.\n" + "Setters for the following fields are required:\n" + "i.\n"); + checkExceptionThrown("Param", "", "Setter for field 'i' is required"); } public void testParamNameConflict() throws Exception { @@ -244,6 +242,6 @@ public class IntroduceParameterObjectTest extends MultiFileTestCase{ } public void testWrongBean() throws Exception { - checkExceptionThrown("Param", "", "Cannot perform the refactoring.\n" + "Getters for the following fields are required:\n" + "i.\n"); + checkExceptionThrown("Param", "", "Getter for field 'i' is required"); } }