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.
17 package org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.statements
.expressions
.path
;
19 import com
.intellij
.lang
.ASTNode
;
20 import com
.intellij
.psi
.*;
21 import com
.intellij
.psi
.search
.GlobalSearchScope
;
22 import com
.intellij
.util
.Function
;
23 import com
.intellij
.util
.IncorrectOperationException
;
24 import org
.jetbrains
.annotations
.NotNull
;
25 import org
.jetbrains
.annotations
.Nullable
;
26 import org
.jetbrains
.plugins
.groovy
.lang
.lexer
.GroovyTokenTypes
;
27 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyElementVisitor
;
28 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyPsiElementFactory
;
29 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.GroovyResolveResult
;
30 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrVariable
;
31 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.arguments
.GrArgumentList
;
32 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.blocks
.GrClosableBlock
;
33 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrExpression
;
34 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrReferenceExpression
;
35 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.path
.GrMethodCallExpression
;
36 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GrClosureType
;
37 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GroovyPsiManager
;
38 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.statements
.expressions
.TypesUtil
;
39 import org
.jetbrains
.plugins
.groovy
.lang
.resolve
.ResolveUtil
;
41 import java
.util
.ArrayList
;
42 import java
.util
.Arrays
;
47 public class GrMethodCallExpressionImpl
extends GrCallExpressionImpl
implements GrMethodCallExpression
{
48 private static final Function
<GrMethodCallExpressionImpl
, PsiType
> TYPES_CALCULATOR
= new Function
<GrMethodCallExpressionImpl
, PsiType
>() {
49 public PsiType
fun(GrMethodCallExpressionImpl callExpression
) {
50 GrExpression invoked
= callExpression
.getInvokedExpression();
51 if (invoked
instanceof GrReferenceExpression
) {
52 GrReferenceExpression refExpr
= (GrReferenceExpression
) invoked
;
53 final GroovyResolveResult
[] resolveResults
= refExpr
.multiResolve(false);
54 PsiManager manager
= callExpression
.getManager();
55 GlobalSearchScope scope
= callExpression
.getResolveScope();
56 PsiType result
= null;
57 for (GroovyResolveResult resolveResult
: resolveResults
) {
58 PsiElement resolved
= resolveResult
.getElement();
59 PsiType returnType
= null;
60 if (resolved
instanceof PsiMethod
&& !GroovyPsiManager
.getInstance(resolved
.getProject()).isTypeBeingInferred(resolved
)) {
61 PsiMethod method
= (PsiMethod
) resolved
;
62 returnType
= getClosureCallOrCurryReturnType(callExpression
, refExpr
, method
);
63 if (returnType
== null) {
64 returnType
= method
.getReturnType();
66 } else if (resolved
instanceof GrVariable
) {
67 PsiType refType
= refExpr
.getType();
68 final PsiType type
= refType
== null ?
((GrVariable
) resolved
).getTypeGroovy() : refType
;
69 if (type
instanceof GrClosureType
) {
70 returnType
= ((GrClosureType
) type
).getClosureReturnType();
73 if (returnType
== null) return null;
74 returnType
= resolveResult
.getSubstitutor().substitute(returnType
);
75 returnType
= TypesUtil
.boxPrimitiveType(returnType
, manager
, scope
);
77 if (result
== null || returnType
.isAssignableFrom(result
)) result
= returnType
;
78 else if (!result
.isAssignableFrom(returnType
))
79 result
= TypesUtil
.getLeastUpperBound(result
, returnType
, manager
);
82 if (result
== null) return null;
84 if (refExpr
.getDotTokenType() != GroovyTokenTypes
.mSPREAD_DOT
) {
87 return ResolveUtil
.getListTypeForSpreadOperator(refExpr
, result
);
96 private static PsiType
getClosureCallOrCurryReturnType(GrMethodCallExpressionImpl callExpression
,
97 GrReferenceExpression refExpr
, PsiMethod resolved
) {
98 PsiClass clazz
= resolved
.getContainingClass();
99 if (clazz
!= null && GrClosableBlock
.GROOVY_LANG_CLOSURE
.equals(clazz
.getQualifiedName())) {
100 if ("call".equals(resolved
.getName()) || "curry".equals(resolved
.getName())) {
101 GrExpression qualifier
= refExpr
.getQualifierExpression();
102 if (qualifier
!= null) {
103 PsiType qType
= qualifier
.getType();
104 if (qType
instanceof GrClosureType
) {
105 if ("call".equals(resolved
.getName())) {
106 return ((GrClosureType
) qType
).getClosureReturnType();
107 } else if ("curry".equals(resolved
.getName())) {
108 return ((GrClosureType
) qType
).curry(callExpression
.getExpressionArguments().length
);
117 public GrMethodCallExpressionImpl(@NotNull ASTNode node
) {
121 public String
toString() {
122 return "Method call";
125 public void accept(GroovyElementVisitor visitor
) {
126 visitor
.visitMethodCallExpression(this);
129 public PsiType
getType() {
130 return GroovyPsiManager
.getInstance(getProject()).getType(this, TYPES_CALCULATOR
);
133 public GrExpression
getInvokedExpression() {
134 return findChildByClass(GrExpression
.class);
137 public GrExpression
replaceClosureArgument(@NotNull GrClosableBlock closure
, @NotNull GrExpression newExpr
) throws IncorrectOperationException
{
139 ASTNode parentNode
= this.getParent().getNode();
140 if (!(newExpr
instanceof GrClosableBlock
)) {
141 ArrayList
<GrExpression
> allArgs
= new ArrayList
<GrExpression
>();
142 // Collecting all arguments
143 allArgs
.addAll(Arrays
.asList(getExpressionArguments()));
144 ArrayList
<GrExpression
> closureArgs
= new ArrayList
<GrExpression
>();
145 for (GrExpression closArg
: getClosureArguments()) {
146 if (closArg
.equals(closure
)) break;
147 closureArgs
.add(closArg
);
149 allArgs
.addAll(closureArgs
);
150 allArgs
.add(newExpr
);
151 int refIndex
= allArgs
.size() - 1;
154 GrArgumentList newArgList
= GroovyPsiElementFactory
.getInstance(getProject()).createExpressionArgumentList(allArgs
.toArray(GrExpression
.EMPTY_ARRAY
));
155 while (closure
.getNode().getTreePrev() != null &&
156 !(closure
.getNode().getTreePrev().getPsi() instanceof GrArgumentList
)) {
157 parentNode
.removeChild(closure
.getNode().getTreePrev());
159 parentNode
.removeChild(closure
.getNode());
160 getArgumentList().replaceWithArgumentList(newArgList
);
161 GrExpression
[] arguments
= getArgumentList().getExpressionArguments();
162 assert arguments
.length
== refIndex
+ 1;
163 return arguments
[refIndex
];
165 return closure
.replaceWithExpression(newExpr
, true);
169 public PsiMethod
resolveMethod() {
170 final GrExpression methodExpr
= getInvokedExpression();
171 if (methodExpr
instanceof GrReferenceExpression
) {
172 final PsiElement resolved
= ((GrReferenceExpression
) methodExpr
).resolve();
173 return resolved
instanceof PsiMethod ?
(PsiMethod
) resolved
: null;
180 public GroovyResolveResult
[] getMethodVariants() {
181 final GrExpression invoked
= getInvokedExpression();
182 if (!(invoked
instanceof GrReferenceExpression
)) return GroovyResolveResult
.EMPTY_ARRAY
;
183 final ArrayList
<GroovyResolveResult
> res
= new ArrayList
<GroovyResolveResult
>();
185 final GroovyResolveResult
[] variants
= ((GrReferenceExpression
)invoked
).getSameNameVariants();
186 if (variants
.length
== 0) {
187 final PsiReference
[] refs
= invoked
.getReferences();
188 for (PsiReference ref
: refs
) {
189 if (ref
instanceof PsiPolyVariantReference
) {
190 PsiPolyVariantReference reference
= (PsiPolyVariantReference
)ref
;
191 final ResolveResult
[] results
= reference
.multiResolve(false);
192 for (ResolveResult result
: results
) {
193 if (result
instanceof GroovyResolveResult
) {
194 res
.add((GroovyResolveResult
)result
);
199 return res
.toArray(new GroovyResolveResult
[res
.size()]);
205 public PsiElement addNamedArgument(final GrNamedArgument argument) {
206 final GrArgumentList argList = getArgumentList();
207 if (argList != null) {
208 return argList.addNamedArgument(argument);
210 final GrClosableBlock[] clArgs = getClosureArguments();