[groovy] tweak isEquivalentTo() in accessors and light variables
[idea/community.git] / plugins / groovy / groovy-psi / src / org / jetbrains / plugins / groovy / lang / psi / impl / synthetic / GrAccessorMethodImpl.java
1 /*
2  * Copyright 2000-2016 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 package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.util.text.StringUtil;
20 import com.intellij.psi.PsiElement;
21 import com.intellij.psi.PsiModifier;
22 import com.intellij.psi.PsiType;
23 import com.intellij.psi.impl.light.LightMethodBuilder;
24 import com.intellij.psi.impl.light.LightModifierList;
25 import com.intellij.psi.impl.light.LightParameterListBuilder;
26 import icons.JetgroovyIcons;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29 import org.jetbrains.plugins.groovy.GroovyLanguage;
30 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
31 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
32 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
33 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
34 import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil;
35
36 import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.GET_PREFIX;
37
38 /**
39  * @author ven
40  */
41 public class GrAccessorMethodImpl extends LightMethodBuilder implements GrAccessorMethod {
42   public static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrAccessorMethodImpl");
43   @NotNull private final GrField myProperty;
44
45   private final boolean myIsSetter;
46
47   public GrAccessorMethodImpl(@NotNull GrField property, boolean isSetter, String name) {
48     super(property.getManager(), GroovyLanguage.INSTANCE, name,
49           new LightParameterListBuilder(property.getManager(), GroovyLanguage.INSTANCE),
50           new LightModifierList(property.getManager()) {
51             @Override
52             public String getText() {
53               final String[] modifiers = getModifiers();
54               if (modifiers.length == 0) return "";
55               if (modifiers.length == 1) return modifiers[0];
56
57               return StringUtil.join(modifiers, " ");
58             }
59           });
60     myProperty = property;
61     myIsSetter = isSetter;
62
63     if (myIsSetter) {
64       PsiType type = myProperty.getDeclaredType();
65       if (type == null) {
66         type = TypesUtil.getJavaLangObject(myProperty);
67       }
68       addParameter(myProperty.getName(), type);
69     }
70
71     setMethodReturnType(myIsSetter ? PsiType.VOID : myProperty.getType());
72
73     addModifier(PsiModifier.PUBLIC);
74     if (myProperty.hasModifierProperty(PsiModifier.STATIC)) {
75       addModifier(PsiModifier.STATIC);
76     }
77     else if (myProperty.hasModifierProperty(PsiModifier.FINAL)) { //don't add final modifier to static method
78       addModifier(PsiModifier.FINAL);
79     }
80
81     if (myProperty.hasModifierProperty(PsiModifier.ABSTRACT) && GrTraitUtil.isTrait(myProperty.getContainingClass())) {
82       addModifier(PsiModifier.ABSTRACT);
83     }
84
85     setNavigationElement(property);
86     setBaseIcon(JetgroovyIcons.Groovy.Property);
87
88     setContainingClass(myProperty.getContainingClass());
89     setMethodKind("AccessorMethod");
90     setOriginInfo("synthetic accessor for '"+myProperty.getName()+"'");
91   }
92
93   @Override
94   @Nullable
95   public PsiType getInferredReturnType() {
96     if (myIsSetter) return PsiType.VOID;
97     return myProperty.getTypeGroovy();
98   }
99
100   @Override
101   public boolean isSetter() {
102     return myIsSetter;
103   }
104
105
106   @Override
107   public PsiElement copy() {
108     //return new GrAccessorMethodImpl(myProperty, myIsSetter, getName());
109     //rename refactoring may create a copy using this method, add it to a class to check for conflicts, and then remove this copy.
110     final String modifiers = getModifierList().getText();
111     final String params;
112     if (myIsSetter) {
113       params="("+myProperty.getName()+")";
114     }
115     else {
116       params="()";
117     }
118     return GroovyPsiElementFactory.getInstance(getProject()).createMethodFromText(modifiers+" "+getName()+params+"{}");
119   }
120
121   @Override
122   @NotNull
123   public GrField getProperty() {
124     return myProperty;
125   }
126
127   @Override
128   public boolean isEquivalentTo(PsiElement another) {
129     if (another == this) return true;
130     if (!(another instanceof GrAccessorMethod)) return false;
131
132     GrAccessorMethod anotherAccessor = (GrAccessorMethod)another;
133     if (isSetter()) {
134       if (!anotherAccessor.isSetter()) return false;
135     }
136     else {
137       if (!getName().startsWith(GET_PREFIX) == anotherAccessor.getName().startsWith(GET_PREFIX)) return false;
138     }
139     return getManager().areElementsEquivalent(myProperty, anotherAccessor.getProperty());
140   }
141
142   @NotNull
143   @Override
144   public PsiElement getPrototype() {
145     return getProperty();
146   }
147
148   @Override
149   public boolean hasModifierProperty(@NotNull String name) {
150     if (GrTraitUtil.isTrait(getContainingClass())) {
151       if (PsiModifier.ABSTRACT.equals(name)) return true;
152       if (PsiModifier.FINAL.equals(name)) return false;
153     }
154     return super.hasModifierProperty(name);
155   }
156 }