IDEA-52789: Groovy map literals should have LinkedHashMap type
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / expressions / path / GrIndexPropertyImpl.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path;
18
19 import com.intellij.lang.ASTNode;
20 import com.intellij.psi.*;
21 import com.intellij.psi.util.InheritanceUtil;
22 import com.intellij.psi.util.PsiUtil;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
25 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
26 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
27 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
28 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
29 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
30 import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
31 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl;
32 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
33
34 /**
35  * @author ilyas
36  */
37 public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProperty {
38
39   public GrIndexPropertyImpl(@NotNull ASTNode node) {
40     super(node);
41   }
42
43   public void accept(GroovyElementVisitor visitor) {
44     visitor.visitIndexProperty(this);
45   }
46
47   public String toString() {
48     return "Property by index";
49   }
50
51   @NotNull
52   public GrExpression getSelectedExpression() {
53     GrExpression result = findChildByClass(GrExpression.class);
54     assert result != null;
55     return result;
56   }
57
58   public GrArgumentList getArgumentList() {
59     return findChildByClass(GrArgumentList.class);
60   }
61
62   public PsiType getType() {
63     GrExpression selected = getSelectedExpression();
64     PsiType thisType = selected.getType();
65
66     if (thisType != null) {
67       GrArgumentList argList = getArgumentList();
68       if (argList != null) {
69         GrExpression[] arguments = argList.getExpressionArguments();
70         PsiType[] argTypes = new PsiType[arguments.length];
71         for (int i = 0; i < arguments.length; i++) {
72           PsiType argType = arguments[i].getType();
73           if (argType == null) argType = TypesUtil.getJavaLangObject(argList);
74           argTypes[i] = argType;
75         }
76
77         if (thisType instanceof GrTupleType) {
78           PsiType[] types = ((GrTupleType)thisType).getParameters();
79           return types.length == 1 ? types[0] : null;
80         }
81
82         PsiType overloadedOperatorType = null;
83         final GroovyResolveResult[] candidates = TypesUtil.getOverloadedOperatorCandidates(thisType, "getAt", this, argTypes);
84         if (candidates.length == 1) {
85           final PsiElement element = candidates[0].getElement();
86           if (element instanceof PsiMethod) {
87             overloadedOperatorType = candidates[0].getSubstitutor().substitute(((PsiMethod)element).getReturnType());
88             if (overloadedOperatorType != null && !(element instanceof GrGdkMethod)) {   //gdk 'getAt' methods don't have information about type parameters
89               return overloadedOperatorType;
90             }
91           }
92         }
93
94         if (thisType instanceof PsiArrayType) {
95           PsiType componentType = ((PsiArrayType)thisType).getComponentType();
96           return TypesUtil.boxPrimitiveType(componentType, getManager(), getResolveScope());
97         }
98
99         if (InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_LIST)) {
100           PsiType iterType = PsiUtil.extractIterableTypeParameter(thisType, true);
101           if (iterType != null) return iterType;
102         }
103
104         if (InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_MAP)) {
105           return PsiUtil.substituteTypeParameter(thisType, CommonClassNames.JAVA_UTIL_MAP, 1, true);
106         }
107
108         return overloadedOperatorType;
109       }
110     }
111     return null;
112   }
113 }