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.
21 package com
.intellij
.refactoring
.extractMethod
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.util
.Pair
;
25 import com
.intellij
.psi
.*;
26 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
27 import com
.intellij
.psi
.codeStyle
.VariableKind
;
28 import com
.intellij
.psi
.controlFlow
.ControlFlow
;
29 import com
.intellij
.psi
.search
.LocalSearchScope
;
30 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
31 import com
.intellij
.psi
.util
.PsiTreeUtil
;
32 import com
.intellij
.refactoring
.util
.ParameterTablePanel
;
33 import com
.intellij
.refactoring
.util
.duplicates
.DuplicatesFinder
;
34 import com
.intellij
.util
.ArrayUtil
;
38 public class InputVariables
{
39 private final List
<ParameterTablePanel
.VariableData
> myInputVariables
;
41 private List
<?
extends PsiVariable
> myInitialParameters
;
42 private final Project myProject
;
43 private final LocalSearchScope myScope
;
45 private ParametersFolder myFolding
;
46 private boolean myFoldingAvailable
;
48 public InputVariables(final List
<?
extends PsiVariable
> inputVariables
,
50 LocalSearchScope scope
,
51 boolean foldingAvailable
) {
52 myInitialParameters
= inputVariables
;
55 myFoldingAvailable
= foldingAvailable
;
56 myFolding
= new ParametersFolder();
57 myInputVariables
= wrapInputVariables(inputVariables
);
63 public InputVariables(List
<ParameterTablePanel
.VariableData
> inputVariables
,
65 LocalSearchScope scope
) {
68 myInputVariables
= new ArrayList
<ParameterTablePanel
.VariableData
>(inputVariables
);
71 public boolean isFoldable() {
72 return myFolding
.isFoldable();
75 public ArrayList
<ParameterTablePanel
.VariableData
> wrapInputVariables(final List
<?
extends PsiVariable
> inputVariables
) {
76 final ArrayList
<ParameterTablePanel
.VariableData
> inputData
= new ArrayList
<ParameterTablePanel
.VariableData
>(inputVariables
.size());
77 for (PsiVariable var
: inputVariables
) {
78 String name
= var
.getName();
79 if (!(var
instanceof PsiParameter
)) {
80 JavaCodeStyleManager codeStyleManager
= JavaCodeStyleManager
.getInstance(myProject
);
81 VariableKind kind
= codeStyleManager
.getVariableKind(var
);
82 name
= codeStyleManager
.variableNameToPropertyName(name
, kind
);
83 name
= codeStyleManager
.propertyNameToVariableName(name
, VariableKind
.PARAMETER
);
85 PsiType type
= var
.getType();
86 if (type
instanceof PsiEllipsisType
) {
87 type
= ((PsiEllipsisType
)type
).toArrayType();
90 ParameterTablePanel
.VariableData data
= new ParameterTablePanel
.VariableData(var
, type
);
92 data
.passAsParameter
= true;
95 if (myFoldingAvailable
) myFolding
.isParameterFoldable(data
, myScope
, inputVariables
);
99 if (myFoldingAvailable
) {
100 final Set
<ParameterTablePanel
.VariableData
> toDelete
= new HashSet
<ParameterTablePanel
.VariableData
>();
101 for (int i
= inputData
.size() - 1; i
>=0; i
--) {
102 final ParameterTablePanel
.VariableData data
= inputData
.get(i
);
103 if (myFolding
.isParameterSafeToDelete(data
, myScope
)) {
107 inputData
.removeAll(toDelete
);
114 public List
<ParameterTablePanel
.VariableData
> getInputVariables() {
115 return myInputVariables
;
118 public PsiExpression
replaceWrappedReferences(PsiElement
[] elements
, PsiExpression expression
) {
119 if (!myFoldingAvailable
) return expression
;
121 boolean update
= elements
[0] == expression
;
122 for (ParameterTablePanel
.VariableData inputVariable
: myInputVariables
) {
123 myFolding
.foldParameterUsagesInBody(inputVariable
, elements
, myScope
);
125 return update ?
(PsiExpression
)elements
[0] : expression
;
128 public boolean toDeclareInsideBody(PsiVariable variable
) {
129 final ArrayList
<ParameterTablePanel
.VariableData
> knownVars
= new ArrayList
<ParameterTablePanel
.VariableData
>(myInputVariables
);
130 for (ParameterTablePanel
.VariableData data
: knownVars
) {
131 if (data
.variable
.equals(variable
)) {
135 return !myFolding
.wasExcluded(variable
);
138 public boolean contains(PsiVariable variable
) {
139 for (ParameterTablePanel
.VariableData data
: myInputVariables
) {
140 if (data
.variable
.equals(variable
)) return true;
145 public void removeParametersUsedInExitsOnly(PsiElement codeFragment
,
146 Collection
<PsiStatement
> exitStatements
,
147 ControlFlow controlFlow
,
150 final LocalSearchScope scope
= new LocalSearchScope(codeFragment
);
152 for (Iterator
<ParameterTablePanel
.VariableData
> iterator
= myInputVariables
.iterator(); iterator
.hasNext();) {
153 final ParameterTablePanel
.VariableData data
= iterator
.next();
154 for (PsiReference ref
: ReferencesSearch
.search(data
.variable
, scope
)) {
155 PsiElement element
= ref
.getElement();
156 int elementOffset
= controlFlow
.getStartOffset(element
);
157 if (elementOffset
>= startOffset
&& elementOffset
<= endOffset
) {
158 if (!isInExitStatements(element
, exitStatements
)) continue Variables
;
165 private static boolean isInExitStatements(PsiElement element
, Collection
<PsiStatement
> exitStatements
) {
166 for (PsiStatement exitStatement
: exitStatements
) {
167 if (PsiTreeUtil
.isAncestor(exitStatement
, element
, false)) return true;
173 public InputVariables
copy() {
174 final InputVariables inputVariables
= new InputVariables(myInputVariables
, myProject
, myScope
);
175 inputVariables
.myFoldingAvailable
= myFoldingAvailable
;
176 inputVariables
.myFolding
= myFolding
;
177 inputVariables
.myInitialParameters
= myInitialParameters
;
178 return inputVariables
;
182 public void appendCallArguments(ParameterTablePanel
.VariableData data
, StringBuilder buffer
) {
183 if (myFoldingAvailable
) {
184 buffer
.append(myFolding
.getGeneratedCallArgument(data
));
186 buffer
.append(data
.variable
.getName());
190 public void setFoldingAvailable(boolean foldingAvailable
) {
191 myFoldingAvailable
= foldingAvailable
;
194 myInputVariables
.clear();
195 myInputVariables
.addAll(wrapInputVariables(myInitialParameters
));
198 public void annotateWithParameter(PsiJavaCodeReferenceElement reference
) {
199 for (ParameterTablePanel
.VariableData data
: myInputVariables
) {
200 final PsiElement element
= reference
.resolve();
201 if (data
.variable
.equals(element
)) {
202 PsiType type
= data
.variable
.getType();
203 final PsiMethodCallExpression methodCallExpression
= PsiTreeUtil
.getParentOfType(reference
, PsiMethodCallExpression
.class);
204 if (methodCallExpression
!= null) {
205 int idx
= ArrayUtil
.find(methodCallExpression
.getArgumentList().getExpressions(), reference
);
207 final PsiMethod psiMethod
= methodCallExpression
.resolveMethod();
208 if (psiMethod
!= null) {
209 final PsiParameter
[] parameters
= psiMethod
.getParameterList().getParameters();
210 if (idx
>= parameters
.length
) { //vararg parameter
211 idx
= parameters
.length
- 1;
212 if (idx
>= 0) { //incomplete code
213 type
= parameters
[idx
].getType();
216 if (type
instanceof PsiEllipsisType
) {
217 type
= ((PsiEllipsisType
)type
).getComponentType();
222 if (!myFoldingAvailable
|| !myFolding
.annotateWithParameter(data
, reference
)) {
223 reference
.putUserData(DuplicatesFinder
.PARAMETER
, Pair
.create(data
.variable
, type
));
229 public boolean isFoldingSelectedByDefault() {
230 return myFolding
.isFoldingSelectedByDefault();