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.params;
19 import com.intellij.lang.ASTNode;
20 import com.intellij.psi.*;
21 import com.intellij.psi.search.LocalSearchScope;
22 import com.intellij.psi.search.SearchScope;
23 import com.intellij.psi.util.InheritanceUtil;
24 import com.intellij.psi.util.PsiTreeUtil;
25 import com.intellij.psi.util.PsiUtil;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
28 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
29 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocCommentOwner;
30 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
31 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
32 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
33 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrCatchClause;
34 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
35 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
36 import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClause;
37 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
38 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression;
39 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
40 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.arithmetic.GrRangeExpression;
41 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
42 import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
43 import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList;
44 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
45 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
46 import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
47 import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
48 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.GrVariableImpl;
49 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
52 * @author: Dmitry.Krasilschikov
55 public class GrParameterImpl extends GrVariableImpl implements GrParameter {
56 public GrParameterImpl(@NotNull ASTNode node) {
60 public void accept(GroovyElementVisitor visitor) {
61 visitor.visitParameter(this);
64 public String toString() {
69 public PsiType getTypeGroovy() {
70 GrTypeElement typeElement = getTypeElementGroovy();
71 if (typeElement != null) {
72 PsiType type = typeElement.getType();
77 return new PsiEllipsisType(type);
80 PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
82 PsiClassType type = factory.createTypeByFQClassName("java.lang.Object", getResolveScope());
83 return new PsiEllipsisType(type);
85 PsiElement parent = getParent();
86 if (parent instanceof GrForInClause) {
87 GrExpression iteratedExpression = ((GrForInClause)parent).getIteratedExpression();
88 if (iteratedExpression instanceof GrRangeExpression) {
89 return factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_INTEGER, getResolveScope());
91 else if (iteratedExpression != null) {
92 PsiType result = findTypeForCollection(iteratedExpression, factory, this);
97 } else if (parent instanceof GrCatchClause) {
98 return factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, getResolveScope());
101 String argumentName = getElementToCompare();
102 GrClosableBlock closure = findClosureWithArgument(parent);
104 return findClosureParameterType(closure, argumentName, factory, this);
108 public static PsiType findClosureParameterType(GrClosableBlock closure,
110 PsiElementFactory factory,
111 PsiElement context) {
112 if (closure != null && closure.getParent() instanceof GrMethodCallExpression) {
113 GrMethodCallExpression methodCall = (GrMethodCallExpression)closure.getParent();
114 String methodName = findMethodName(methodCall);
115 //final GrExpression invokedExpression = methodCall.getInvokedExpression();
116 //PsiType type = findQualifierType(methodCall);
118 GrExpression expression = methodCall.getInvokedExpression();
119 if (!(expression instanceof GrReferenceExpression)) return null;
121 GrExpression qualifier = ((GrReferenceExpression)expression).getQualifierExpression();
122 if (qualifier == null) return null;
123 PsiType type = qualifier.getType();
125 GrParameter[] params = closure.getParameters();
130 if ("each".equals(methodName) ||
131 "every".equals(methodName) ||
132 "collect".equals(methodName) ||
133 "find".equals(methodName) ||
134 "findAll".equals(methodName) ||
135 "findIndexOf".equals(methodName)) {
136 PsiType res = findTypeForCollection(qualifier, factory, context);
137 if (closure.getParameters().length <= 1 && res != null) {
141 if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) {
142 if (closure.getParameters().length <= 1) {
143 return getEntryForMap(type, factory, context);
145 if (closure.getParameters().length == 2) {
146 if (argumentName.equals(params[0].getName())) {
147 return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 0, true);
149 return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 1, true);
153 else if ("with".equals(methodName) && closure.getParameters().length <= 1) {
156 else if ("eachWithIndex".equals(methodName)) {
157 PsiType res = findTypeForCollection(qualifier, factory, context);
158 if (closure.getParameters().length == 2 && res != null) {
159 if (argumentName.equals(params[0].getName())) {
162 return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, context);
164 if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) {
165 if (params.length == 2) {
166 if (argumentName.equals(params[0].getName())) {
167 return getEntryForMap(type, factory, context);
169 return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, context);
171 if (params.length == 3) {
172 if (argumentName.equals(params[0].getName())) {
173 return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 0, true);
175 if (argumentName.equals(params[1].getName())) {
176 return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 1, true);
178 return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, context);
182 else if ("inject".equals(methodName) && params.length == 2) {
183 if (argumentName.equals(params[0].getName())) {
184 return factory.createTypeFromText(CommonClassNames.JAVA_LANG_OBJECT, context);
187 PsiType res = findTypeForCollection(qualifier, factory, context);
191 if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) {
192 return getEntryForMap(type, factory, context);
200 private static PsiType getEntryForMap(PsiType map, PsiElementFactory factory, PsiElement context) {
201 PsiType key = PsiUtil.substituteTypeParameter(map, CommonClassNames.JAVA_UTIL_MAP, 0, true);
202 PsiType value = PsiUtil.substituteTypeParameter(map, CommonClassNames.JAVA_UTIL_MAP, 1, true);
203 if (key != null && value != null) {
204 return factory.createTypeFromText("java.util.Map.Entry<" + key.getCanonicalText() + ", " + value.getCanonicalText() + ">", context);
210 private static PsiType findTypeForCollection(GrExpression qualifier, PsiElementFactory factory, PsiElement context) {
211 PsiType iterType = qualifier.getType();
212 if (iterType == null) return null;
213 if (iterType instanceof PsiArrayType) {
214 return ((PsiArrayType)iterType).getComponentType();
216 if (iterType instanceof GrTupleType) {
217 PsiType[] types = ((GrTupleType)iterType).getParameters();
218 return types.length == 1 ? types[0] : null;
221 if (factory.createTypeFromText("groovy.lang.IntRange", context).isAssignableFrom(iterType)) {
222 return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, context);
224 if (factory.createTypeFromText("groovy.lang.ObjectRange", context).isAssignableFrom(iterType)) {
225 PsiElement element = qualifier;
226 element = removeBrackets(element);
227 if (element instanceof GrReferenceExpression) {
228 GrReferenceExpression ref = (GrReferenceExpression)element;
229 element = removeBrackets(ref.resolve());
231 if (element instanceof GrRangeExpression) {
232 return getRangeElementType((GrRangeExpression)element);
237 PsiType res = PsiUtil.extractIterableTypeParameter(iterType, true);
242 if (iterType.equalsToText(CommonClassNames.JAVA_LANG_STRING) || iterType.equalsToText("java.io.File")) {
243 return factory.createTypeFromText(CommonClassNames.JAVA_LANG_STRING, context);
248 private static PsiElement removeBrackets(PsiElement element) {
249 while (element instanceof GrParenthesizedExpression) {
250 element = ((GrParenthesizedExpression)element).getOperand();
256 private static PsiType getRangeElementType(GrRangeExpression range) {
257 GrExpression left = range.getLeftOperand();
258 GrExpression right = range.getRightOperand();
260 final PsiType leftType = left.getType();
261 final PsiType rightType = right.getType();
262 if (leftType != null && rightType != null) {
263 return TypesUtil.getLeastUpperBound(leftType, rightType, range.getManager());
270 private static String findMethodName(@NotNull GrMethodCallExpression methodCall) {
271 GrExpression expression = methodCall.getInvokedExpression();
272 if (expression instanceof GrReferenceExpression) {
273 return ((GrReferenceExpression)expression).getReferenceName();
279 private static GrClosableBlock findClosureWithArgument(@NotNull PsiElement parent) {
280 if (parent instanceof GrParameterList) {
281 GrParameterList list = (GrParameterList)parent;
282 if (list.getParent() instanceof GrClosableBlock) {
283 return (GrClosableBlock)list.getParent();
290 public PsiType getType() {
291 /*PsiType type = getTypeGroovy();
292 if (type == null) type = super.getType();*/
293 PsiType type = super.getType();
295 return new PsiEllipsisType(type);
297 else if (isMainMethodFirstUntypedParameter()) {
298 PsiClassType stringType =
299 JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeByFQClassName("java.lang.String", getResolveScope());
300 return stringType.createArrayType();
307 private boolean isMainMethodFirstUntypedParameter() {
308 if (getTypeElementGroovy() != null) return false;
310 if (getParent() instanceof GrParameterList) {
311 GrParameterList parameterList = (GrParameterList)getParent();
312 GrParameter[] params = parameterList.getParameters();
313 if (params.length != 1 || this != params[0]) return false;
315 if (parameterList.getParent() instanceof GrMethod) {
316 GrMethod method = (GrMethod)parameterList.getParent();
317 return PsiImplUtil.isMainMethod(method);
323 public void setType(@Nullable PsiType type) {
324 throw new RuntimeException("NIY");
328 public GrTypeElement getTypeElementGroovy() {
329 return findChildByClass(GrTypeElement.class);
333 public GrExpression getDefaultInitializer() {
334 return findChildByClass(GrExpression.class);
337 public boolean isOptional() {
338 return getDefaultInitializer() != null;
342 public SearchScope getUseScope() {
344 final PsiFile file = getContainingFile();
345 final PsiElement context = file.getContext();
346 if (context != null) return new LocalSearchScope(context);
347 return super.getUseScope();
350 final PsiElement scope = getDeclarationScope();
351 if (scope instanceof GrDocCommentOwner) {
352 GrDocCommentOwner owner = (GrDocCommentOwner)scope;
353 final GrDocComment comment = owner.getDocComment();
354 if (comment != null) {
355 return new LocalSearchScope(new PsiElement[]{scope, comment});
359 return new LocalSearchScope(scope);
363 public String getName() {
364 return getNameIdentifierGroovy().getText();
367 public int getTextOffset() {
368 return getNameIdentifierGroovy().getTextRange().getStartOffset();
372 public GrModifierList getModifierList() {
373 return findChildByClass(GrModifierList.class);
377 public PsiElement getDeclarationScope() {
378 final GrParametersOwner owner = PsiTreeUtil.getParentOfType(this, GrParametersOwner.class);
379 assert owner != null;
380 if (owner instanceof GrForInClause) return owner.getParent();
384 public boolean isVarArgs() {
385 PsiElement dots = findChildByType(GroovyTokenTypes.mTRIPLE_DOT);
390 public PsiAnnotation[] getAnnotations() {
391 return PsiAnnotation.EMPTY_ARRAY;
395 public PsiType getDeclaredType() {
396 PsiType type = super.getDeclaredType();
398 type = getTypeGroovy();