preventing NPE
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / expressions / path / GrMethodCallExpressionImpl.java
blob39c1f33bf59dfc2b42d40c19c78b4bd8dfc0b04f
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.
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;
44 /**
45 * @author ilyas
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) {
85 return result;
86 } else {
87 return ResolveUtil.getListTypeForSpreadOperator(refExpr, result);
91 return null;
95 @Nullable
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);
114 return null;
117 public GrMethodCallExpressionImpl(@NotNull ASTNode node) {
118 super(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;
153 // New argument list
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];
164 } else {
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;
176 return null;
179 @NotNull
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()]);
201 return variants;
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();
211 //todo implement me!
212 return null;