assert (14772)
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / introduceParameter / JavaIntroduceParameterMethodUsagesProcessor.java
blobcc66bbe8c778f465b1bd472fbaed947e5babb4ee
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.refactoring.introduceParameter;
18 import com.intellij.codeInsight.ChangeContextUtil;
19 import com.intellij.lang.Language;
20 import com.intellij.lang.java.JavaLanguage;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.psi.*;
23 import com.intellij.psi.codeStyle.CodeStyleManager;
24 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
25 import com.intellij.psi.javadoc.PsiDocTag;
26 import com.intellij.psi.util.PsiTreeUtil;
27 import com.intellij.psi.util.PsiUtil;
28 import com.intellij.refactoring.util.FieldConflictsResolver;
29 import com.intellij.refactoring.util.RefactoringUtil;
30 import com.intellij.refactoring.util.javadoc.MethodJavaDocHelper;
31 import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
32 import com.intellij.usageView.UsageInfo;
33 import com.intellij.util.IncorrectOperationException;
34 import com.intellij.util.VisibilityUtil;
35 import com.intellij.util.containers.MultiMap;
36 import gnu.trove.TIntArrayList;
37 import gnu.trove.TIntProcedure;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
41 /**
42 * @author Maxim.Medvedev
44 public class JavaIntroduceParameterMethodUsagesProcessor implements IntroduceParameterMethodUsagesProcessor {
45 private static final Logger LOG =
46 Logger.getInstance("#com.intellij.refactoring.introduceParameter.JavaIntroduceParameterMethodUsagesProcessor");
47 private static final JavaLanguage myLanguage = Language.findInstance(JavaLanguage.class);
49 private static boolean isJavaUsage(UsageInfo usage) {
50 PsiElement e = usage.getElement();
51 return e != null && e.getLanguage().is(myLanguage);
54 public boolean isMethodUsage(UsageInfo usage) {
55 return RefactoringUtil.isMethodUsage(usage.getElement()) && isJavaUsage(usage);
58 public boolean processChangeMethodUsage(IntroduceParameterData data, UsageInfo usage, UsageInfo[] usages) throws IncorrectOperationException {
59 if (!isMethodUsage(usage)) return true;
60 final PsiElement ref = usage.getElement();
61 PsiCall callExpression = RefactoringUtil.getCallExpressionByMethodReference(ref);
62 PsiExpressionList argList = RefactoringUtil.getArgumentListByMethodReference(ref);
63 PsiExpression[] oldArgs = argList.getExpressions();
65 final PsiExpression anchor;
66 if (!data.getMethodToSearchFor().isVarArgs()) {
67 anchor = getLast(oldArgs);
69 else {
70 final PsiParameter[] parameters = data.getMethodToSearchFor().getParameterList().getParameters();
71 if (parameters.length > oldArgs.length) {
72 anchor = getLast(oldArgs);
74 else {
75 LOG.assertTrue(parameters.length > 0);
76 final int lastNonVararg = parameters.length - 2;
77 anchor = lastNonVararg >= 0 ? oldArgs[lastNonVararg] : null;
81 //if we insert parameter in method usage which is contained in method in which we insert this parameter too, we must insert parameter name instead of its initializer
82 PsiMethod method = PsiTreeUtil.getParentOfType(argList, PsiMethod.class);
83 if (method != null && isMethodInUsages(data, method, usages)) {
84 argList
85 .addAfter(JavaPsiFacade.getElementFactory(data.getProject()).createExpressionFromText(data.getParameterName(), argList), anchor);
87 else {
88 ChangeContextUtil.encodeContextInfo(data.getParameterInitializer(), true);
89 PsiExpression newArg = (PsiExpression)argList.addAfter(data.getParameterInitializer(), anchor);
90 ChangeContextUtil.decodeContextInfo(newArg, null, null);
91 ChangeContextUtil.clearContextInfo(data.getParameterInitializer());
92 // here comes some postprocessing...
93 new OldReferenceResolver(callExpression, newArg, data.getMethodToReplaceIn(), data.getReplaceFieldsWithGetters(),
94 data.getParameterInitializer()).resolve();
98 final PsiExpressionList argumentList = callExpression.getArgumentList();
99 LOG.assertTrue(argumentList != null, callExpression.getText());
100 removeParametersFromCall(argumentList, data.getParametersToRemove());
101 return false;
104 private static boolean isMethodInUsages(IntroduceParameterData data, PsiMethod method, UsageInfo[] usages) {
105 PsiManager manager = PsiManager.getInstance(data.getProject());
106 for (UsageInfo info : usages) {
107 if (!(info instanceof DefaultConstructorImplicitUsageInfo) && manager.areElementsEquivalent(info.getElement(), method)) {
108 return true;
111 return false;
114 private static void removeParametersFromCall(@NotNull final PsiExpressionList argList, TIntArrayList parametersToRemove) {
115 final PsiExpression[] exprs = argList.getExpressions();
116 parametersToRemove.forEachDescending(new TIntProcedure() {
117 public boolean execute(final int paramNum) {
118 try {
119 exprs[paramNum].delete();
121 catch (IncorrectOperationException e) {
122 LOG.error(e);
124 return true;
129 @Nullable
130 private static PsiExpression getLast(PsiExpression[] oldArgs) {
131 PsiExpression anchor;
132 if (oldArgs.length > 0) {
133 anchor = oldArgs[oldArgs.length - 1];
135 else {
136 anchor = null;
138 return anchor;
142 public void findConflicts(IntroduceParameterData data, UsageInfo[] usages, MultiMap<PsiElement, String> conflicts) {
145 public boolean processChangeMethodSignature(IntroduceParameterData data, UsageInfo usage, UsageInfo[] usages) throws IncorrectOperationException {
146 if (!(usage.getElement() instanceof PsiMethod) || !isJavaUsage(usage)) return true;
147 PsiMethod method = (PsiMethod)usage.getElement();
149 final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(data.getParameterName(), method.getBody());
150 final MethodJavaDocHelper javaDocHelper = new MethodJavaDocHelper(method);
151 PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory();
153 final PsiParameter[] parameters = method.getParameterList().getParameters();
154 data.getParametersToRemove().forEachDescending(new TIntProcedure() {
155 public boolean execute(final int paramNum) {
156 try {
157 PsiParameter param = parameters[paramNum];
158 PsiDocTag tag = javaDocHelper.getTagForParameter(param);
159 if (tag != null) {
160 tag.delete();
162 param.delete();
164 catch (IncorrectOperationException e) {
165 LOG.error(e);
167 return true;
171 PsiParameter parameter = factory.createParameter(data.getParameterName(), data.getForcedType());
172 PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, data.isDeclareFinal());
173 final PsiParameter anchorParameter = getAnchorParameter(method);
174 final PsiParameterList parameterList = method.getParameterList();
175 parameter = (PsiParameter)parameterList.addAfter(parameter, anchorParameter);
176 JavaCodeStyleManager.getInstance(data.getProject()).shortenClassReferences(parameter);
177 final PsiDocTag tagForAnchorParameter = javaDocHelper.getTagForParameter(anchorParameter);
178 javaDocHelper.addParameterAfter(data.getParameterName(), tagForAnchorParameter);
180 fieldConflictsResolver.fix();
182 return false;
185 @Nullable
186 private static PsiParameter getAnchorParameter(PsiMethod methodToReplaceIn) {
187 PsiParameterList parameterList = methodToReplaceIn.getParameterList();
188 final PsiParameter anchorParameter;
189 final PsiParameter[] parameters = parameterList.getParameters();
190 final int length = parameters.length;
191 if (!methodToReplaceIn.isVarArgs()) {
192 anchorParameter = length > 0 ? parameters[length - 1] : null;
194 else {
195 LOG.assertTrue(length > 0);
196 LOG.assertTrue(parameters[length - 1].isVarArgs());
197 anchorParameter = length > 1 ? parameters[length - 2] : null;
199 return anchorParameter;
202 public boolean processAddDefaultConstructor(IntroduceParameterData data, UsageInfo usage, UsageInfo[] usages) {
203 if (!(usage.getElement() instanceof PsiClass) || !isJavaUsage(usage)) return true;
204 PsiClass aClass = (PsiClass)usage.getElement();
205 if (!(aClass instanceof PsiAnonymousClass)) {
206 final PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory();
207 PsiMethod constructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass);
208 constructor = (PsiMethod)CodeStyleManager.getInstance(data.getProject()).reformat(constructor);
209 constructor = (PsiMethod)aClass.add(constructor);
210 PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
211 processAddSuperCall(data, new UsageInfo(constructor), usages);
213 else {
214 return true;
216 return false;
219 public boolean processAddSuperCall(IntroduceParameterData data, UsageInfo usage, UsageInfo[] usages) throws IncorrectOperationException {
220 if (!(usage.getElement() instanceof PsiMethod) || !isJavaUsage(usage)) return true;
221 PsiMethod constructor = (PsiMethod)usage.getElement();
223 if (!constructor.isConstructor()) return true;
225 final PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory();
226 PsiExpressionStatement superCall = (PsiExpressionStatement)factory.createStatementFromText("super();", constructor);
227 superCall = (PsiExpressionStatement)CodeStyleManager.getInstance(data.getProject()).reformat(superCall);
228 PsiCodeBlock body = constructor.getBody();
229 final PsiStatement[] statements = body.getStatements();
230 if (statements.length > 0) {
231 superCall = (PsiExpressionStatement)body.addBefore(superCall, statements[0]);
233 else {
234 superCall = (PsiExpressionStatement)body.add(superCall);
236 processChangeMethodUsage(data, new ExternalUsageInfo(((PsiMethodCallExpression)superCall.getExpression()).getMethodExpression()), usages);
237 return false;