f2d70c1776aca535c3fd568be7dcae6515a5f464
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / arguments / GrArgumentLabelImpl.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.arguments;
18
19 import com.intellij.lang.ASTNode;
20 import com.intellij.openapi.util.TextRange;
21 import com.intellij.psi.*;
22 import com.intellij.psi.util.PropertyUtil;
23 import com.intellij.util.ArrayUtil;
24 import com.intellij.util.IncorrectOperationException;
25 import org.jetbrains.annotations.NotNull;
26 import org.jetbrains.annotations.Nullable;
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.statements.arguments.GrArgumentLabel;
30 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
31 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
32 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression;
33 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
34 import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiElementImpl;
35 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
36
37 /**
38  * @author ilyas
39  */
40 public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgumentLabel {
41
42   public GrArgumentLabelImpl(@NotNull ASTNode node) {
43     super(node);
44   }
45
46   public void accept(GroovyElementVisitor visitor) {
47     visitor.visitArgumentLabel(this);
48   }
49
50   public String toString() {
51     return "Argument label";
52   }
53
54   public PsiReference getReference() {
55     return this;
56   }
57
58   public String getName() {
59     return getNameElement().getText();
60   }
61
62   public PsiElement getElement() {
63     return this;
64   }
65
66   public TextRange getRangeInElement() {
67     return new TextRange(0, getTextLength());
68   }
69
70   @Nullable
71   public PsiElement resolve() {
72     String propName = getText();
73     String setterName = PropertyUtil.suggestSetterName(propName);
74     PsiElement context = getParent().getParent();
75     if (context instanceof GrArgumentList) {
76       final PsiElement parent = context.getParent();
77       if (parent instanceof GrCallExpression) {
78         final PsiMethod resolvedMethod = ((GrCallExpression) parent).resolveMethod();
79         if (resolvedMethod != null) {
80           final PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters();
81           if (parameters.length > 0) {
82             if (PsiUtil.createMapType(resolvedMethod.getManager(), resolvedMethod.getResolveScope()).isAssignableFrom(parameters[0].getType())) {
83               //call with named argument, not setting property
84               return null;
85             }
86           }
87         }
88       }
89
90       if (parent instanceof GrExpression || parent instanceof GrAnonymousClassDefinition) {
91         PsiType type =
92           parent instanceof GrExpression ? ((GrExpression)parent).getType() : ((GrAnonymousClassDefinition)parent).getBaseClassType();
93         if (type instanceof PsiClassType) {
94           PsiClass clazz = ((PsiClassType) type).resolve();
95           if (clazz != null) {
96             PsiMethod[] byName = clazz.findMethodsByName(setterName, true);
97             if (byName.length > 0) return byName[0];
98             return clazz.findFieldByName(propName, true);
99           }
100         }
101       }
102     }
103     return null;
104   }
105
106   public String getCanonicalText() {
107     PsiElement resolved = resolve();
108     if (resolved instanceof PsiMember && resolved instanceof PsiNamedElement) {
109       PsiClass clazz = ((PsiMember) resolved).getContainingClass();
110       if (clazz != null) {
111         String qName = clazz.getQualifiedName();
112         if (qName != null) {
113           return qName + "." + ((PsiNamedElement) resolved).getName();
114         }
115       }
116     }
117
118     return getText();
119   }
120
121   public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
122     final PsiElement resolved = resolve();
123     if (resolved instanceof PsiMethod) {
124       final PsiMethod method = (PsiMethod) resolved;
125       final String oldName = getNameElement().getText();
126       if (!method.getName().equals(oldName)) { //was property reference to accessor
127         if (PropertyUtil.isSimplePropertySetter(method)) {
128           final String newPropertyName = PropertyUtil.getPropertyName(newElementName);
129           if (newPropertyName != null) {
130             return doHandleElementRename(newPropertyName);
131           } else {
132             //todo encapsulate fields:)
133           }
134         }
135       }
136     }
137     return doHandleElementRename(newElementName);
138   }
139
140   private PsiElement doHandleElementRename(String newElementName) {
141     PsiElement nameElement = getNameElement();
142     ASTNode node = nameElement.getNode();
143     ASTNode newNameNode = GroovyPsiElementFactory.getInstance(getProject()).createReferenceNameFromText(newElementName).getNode();
144     assert newNameNode != null && node != null;
145     node.getTreeParent().replaceChild(node, newNameNode);
146     return this;
147   }
148
149   public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
150     throw new IncorrectOperationException("NIY");
151   }
152
153   public boolean isReferenceTo(PsiElement element) {
154     return (element instanceof PsiMethod || element instanceof PsiField) &&
155         getManager().areElementsEquivalent(element, resolve());
156
157   }
158
159   public Object[] getVariants() {
160     return ArrayUtil.EMPTY_OBJECT_ARRAY;
161   }
162
163   public boolean isSoft() {
164     return false;
165   }
166
167   @NotNull
168   public PsiElement getNameElement() {
169     final PsiElement element = getFirstChild();
170     assert element != null;
171     return element;
172   }
173
174   @Nullable
175   public PsiType getExpectedArgumentType() {
176     final PsiElement resolved = resolve();
177     if (resolved instanceof PsiMethod) {
178       final PsiMethod method = (PsiMethod) resolved;
179       if (PropertyUtil.isSimplePropertyGetter(method))
180         return method.getReturnType();
181       if (PropertyUtil.isSimplePropertySetter(method))
182         return method.getParameterList().getParameters()[0].getType();
183
184     } else if (resolved instanceof PsiField) {
185       return ((PsiField) resolved).getType();
186     }
187
188     return null;
189   }
190 }