mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
introduce parameter object abstraction
This commit is contained in:
+78
-247
@@ -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<ParameterChunk> parameters;
|
||||
private final int[] paramsToMerge;
|
||||
private final List<PsiTypeParameter> typeParams;
|
||||
private final Set<PsiParameter> paramsNeedingSetters = new HashSet<PsiParameter>();
|
||||
private final Set<PsiParameter> paramsNeedingGetters = new HashSet<PsiParameter>();
|
||||
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<FixableUsageInfo> 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<FixableUsageInfo> usages, String fixedParamName) {
|
||||
final ParamUsageVisitor visitor = new ParamUsageVisitor(overridingMethod, paramsToMerge);
|
||||
overridingMethod.accept(visitor);
|
||||
final Set<PsiReferenceExpression> 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<FixableUsageInfo> 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<PsiReference>() {
|
||||
@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<PsiParameter> 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<PsiParameter> paramsToMerge = new HashSet<PsiParameter>();
|
||||
private final Set<PsiReferenceExpression> parameterUsages = new HashSet<PsiReferenceExpression>(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<PsiReferenceExpression> getParameterUsages() {
|
||||
return parameterUsages;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod existingClassIsCompatible(PsiClass aClass, List<ParameterChunk> 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<ParameterChunk> 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<ParameterChunk> 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;
|
||||
|
||||
|
||||
+132
@@ -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<ParameterChunk> 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<ParameterChunk> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-16
@@ -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<PsiTypeParameter, String>() {
|
||||
@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();
|
||||
|
||||
+98
@@ -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<ParameterChunk> 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;
|
||||
}
|
||||
}
|
||||
+46
-54
@@ -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<PsiParameter> paramsNeedingSetters;
|
||||
private final Set<PsiParameter> paramsNeedingGetters;
|
||||
private final List<IntroduceParameterObjectProcessor.ParameterChunk> parameters;
|
||||
private final PsiParameter myParameter;
|
||||
private final boolean myGetter;
|
||||
private final List<ParameterChunk> parameters;
|
||||
private static final Logger LOGGER = Logger.getInstance("#" + AppendAccessorsUsageInfo.class.getName());
|
||||
|
||||
|
||||
public AppendAccessorsUsageInfo(PsiElement psiClass, boolean generateAccessors, Set<PsiParameter> paramsNeedingGetters,
|
||||
Set<PsiParameter> paramsNeedingSetters, List<IntroduceParameterObjectProcessor.ParameterChunk> parameters) {
|
||||
super(psiClass);
|
||||
public AppendAccessorsUsageInfo(PsiClass existingClass,
|
||||
boolean generateAccessors,
|
||||
PsiParameter parameter,
|
||||
boolean isGetter,
|
||||
List<ParameterChunk> 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<PsiParameter> 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<PsiParameter> 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<PsiParameter, String>() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user