IDEA-51893: Quick Fix "​Create Field" when using Groovy named parameters
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / arguments / GrArgumentLabelImpl.java
blob01902ba2abf47c4a65f4a222e434d63ec2bad089
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.arguments;
19 import com.intellij.lang.ASTNode;
20 import com.intellij.openapi.util.TextRange;
21 import com.intellij.psi.*;
22 import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
23 import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
24 import com.intellij.psi.util.PropertyUtil;
25 import com.intellij.util.ArrayUtil;
26 import com.intellij.util.IncorrectOperationException;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
30 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
31 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
32 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
33 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
34 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
35 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
36 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression;
37 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
38 import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiElementImpl;
39 import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
40 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
41 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
42 import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
44 /**
45 * @author ilyas
47 public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgumentLabel {
49 public GrArgumentLabelImpl(@NotNull ASTNode node) {
50 super(node);
53 public void accept(GroovyElementVisitor visitor) {
54 visitor.visitArgumentLabel(this);
57 public String toString() {
58 return "Argument label";
61 public PsiReference getReference() {
62 PsiReference[] otherReferences = ReferenceProvidersRegistry.getReferencesFromProviders(this, GrArgumentLabel.class);
63 PsiReference[] thisReference = {this};
64 return new PsiMultiReference(otherReferences.length == 0 ? thisReference : ArrayUtil.mergeArrays(thisReference, otherReferences, PsiReference.class), this);
67 @Nullable
68 public String getName() {
69 final PsiElement element = getNameElement();
70 if (element instanceof GrExpression) {
71 return null;
73 else {
74 return GrStringUtil.removeQuotes(element.getText());
78 public PsiElement getElement() {
79 return this;
82 public TextRange getRangeInElement() {
83 return new TextRange(0, getTextLength());
86 @Nullable
87 public PsiElement resolve() {
88 String propName = getText();
89 String setterName = PropertyUtil.suggestSetterName(propName);
90 PsiElement context = getParent().getParent();
91 if (context instanceof GrArgumentList) {
92 final PsiElement parent = context.getParent();
93 if (parent instanceof GrCallExpression) {
94 final PsiMethod resolvedMethod = ((GrCallExpression) parent).resolveMethod();
95 if (resolvedMethod != null) {
96 final PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters();
97 if (parameters.length > 0) {
98 if (PsiUtil.createMapType(resolvedMethod.getManager(), resolvedMethod.getResolveScope()).isAssignableFrom(parameters[0].getType())) {
99 //call with named argument, not setting property
100 return null;
106 if (parent instanceof GrExpression || parent instanceof GrAnonymousClassDefinition) {
107 PsiType type =
108 parent instanceof GrExpression ? ((GrExpression)parent).getType() : ((GrAnonymousClassDefinition)parent).getBaseClassType();
109 if (type instanceof PsiClassType) {
110 PsiClass clazz = ((PsiClassType) type).resolve();
111 if (clazz != null) {
112 PsiMethod[] byName = clazz.findMethodsByName(setterName, true);
113 if (byName.length > 0) return byName[0];
114 final PsiField field = clazz.findFieldByName(propName, true);
115 if (field != null) return field;
116 final PropertyResolverProcessor processor = new PropertyResolverProcessor(propName, this);
117 ResolveUtil
118 .processNonCodeMethods(JavaPsiFacade.getElementFactory(getProject()).createType(clazz), processor, getProject(), this, false);
119 final GroovyResolveResult[] candidates = processor.getCandidates();
120 if (candidates.length == 0) return null;
121 return candidates[0].getElement();
126 return null;
129 public String getCanonicalText() {
130 PsiElement resolved = resolve();
131 if (resolved instanceof PsiMember && resolved instanceof PsiNamedElement) {
132 PsiClass clazz = ((PsiMember) resolved).getContainingClass();
133 if (clazz != null) {
134 String qName = clazz.getQualifiedName();
135 if (qName != null) {
136 return qName + "." + ((PsiNamedElement) resolved).getName();
141 return getText();
144 public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
145 final PsiElement resolved = resolve();
146 if (resolved instanceof PsiMethod) {
147 final PsiMethod method = (PsiMethod) resolved;
148 final String oldName = getNameElement().getText();
149 if (!method.getName().equals(oldName)) { //was property reference to accessor
150 if (PropertyUtil.isSimplePropertySetter(method)) {
151 final String newPropertyName = PropertyUtil.getPropertyName(newElementName);
152 if (newPropertyName != null) {
153 return doHandleElementRename(newPropertyName);
154 } else {
155 //todo encapsulate fields:)
160 return doHandleElementRename(newElementName);
163 private PsiElement doHandleElementRename(String newElementName) {
164 PsiElement nameElement = getNameElement();
165 ASTNode node = nameElement.getNode();
166 ASTNode newNameNode = GroovyPsiElementFactory.getInstance(getProject()).createReferenceNameFromText(newElementName).getNode();
167 assert newNameNode != null && node != null;
168 node.getTreeParent().replaceChild(node, newNameNode);
169 return this;
172 public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
173 throw new IncorrectOperationException("NIY");
176 public boolean isReferenceTo(PsiElement element) {
177 return (element instanceof PsiMethod || element instanceof PsiField) &&
178 getManager().areElementsEquivalent(element, resolve());
182 @NotNull
183 public Object[] getVariants() {
184 return ArrayUtil.EMPTY_OBJECT_ARRAY;
187 public boolean isSoft() {
188 return false;
191 @NotNull
192 public PsiElement getNameElement() {
193 final PsiElement element = getFirstChild();
194 assert element != null;
195 return element;
198 @Nullable
199 public PsiType getExpectedArgumentType() {
200 final PsiElement resolved = resolve();
201 if (resolved instanceof PsiMethod) {
202 final PsiMethod method = (PsiMethod) resolved;
203 if (PropertyUtil.isSimplePropertyGetter(method))
204 return method.getReturnType();
205 if (PropertyUtil.isSimplePropertySetter(method))
206 return method.getParameterList().getParameters()[0].getType();
208 } else if (resolved instanceof PsiField) {
209 return ((PsiField) resolved).getType();
212 return null;
215 public GrNamedArgument getNamedArgument() {
216 final PsiElement parent = getParent();
217 assert parent instanceof GrNamedArgument;
218 return (GrNamedArgument)parent;