028940bb46af7abbce793f18809e0cecbe748faf
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / util / GroovyPropertyUtils.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 package org.jetbrains.plugins.groovy.lang.psi.util;
17
18 import com.intellij.openapi.project.Project;
19 import com.intellij.openapi.util.text.StringUtil;
20 import com.intellij.psi.*;
21 import com.intellij.psi.util.PropertyUtil;
22 import com.intellij.util.ArrayUtil;
23 import org.jetbrains.annotations.NonNls;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
27 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
28 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
29
30 import java.beans.Introspector;
31
32 /**
33  * @author ilyas
34  */
35 public class GroovyPropertyUtils {
36   private static final String IS_PREFIX = "is";
37   private static final String GET_PREFIX = "get";
38   private static final String SET_PREFIX = "set";
39
40   private GroovyPropertyUtils() {
41   }
42
43   @Nullable
44   public static PsiMethod findSetterForField(PsiField field) {
45     final PsiClass containingClass = field.getContainingClass();
46     final Project project = field.getProject();
47     final String propertyName = PropertyUtil.suggestPropertyName(project, field);
48     final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC);
49     return findPropertySetter(containingClass, propertyName, isStatic, true);
50   }
51
52   @Nullable
53   public static PsiMethod findGetterForField(PsiField field) {
54     final PsiClass containingClass = field.getContainingClass();
55     final Project project = field.getProject();
56     final String propertyName = PropertyUtil.suggestPropertyName(project, field);
57     final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC);
58     return PropertyUtil.findPropertyGetter(containingClass, propertyName, isStatic, true);
59   }
60
61   @Nullable
62   public static PsiMethod findPropertySetter(PsiClass aClass, String propertyName, boolean isStatic, boolean checkSuperClasses) {
63     if (aClass == null) return null;
64     PsiMethod[] methods;
65     if (checkSuperClasses) {
66       methods = aClass.getAllMethods();
67     }
68     else {
69       methods = aClass.getMethods();
70     }
71
72     for (PsiMethod method : methods) {
73       if (method.hasModifierProperty(PsiModifier.STATIC) != isStatic) continue;
74
75       if (isSimplePropertySetter(method)) {
76         if (propertyName.equals(getPropertyNameBySetter(method))) {
77           return method;
78         }
79       }
80     }
81
82     return null;
83   }
84
85   @Nullable
86   public static PsiMethod findPropertyGetter(PsiClass aClass, String propertyName, boolean isStatic, boolean checkSuperClasses) {
87     if (aClass == null) return null;
88     PsiMethod[] methods;
89     if (checkSuperClasses) {
90       methods = aClass.getAllMethods();
91     }
92     else {
93       methods = aClass.getMethods();
94     }
95
96     for (PsiMethod method : methods) {
97       if (method.hasModifierProperty(PsiModifier.STATIC) != isStatic) continue;
98
99       if (isSimplePropertyGetter(method)) {
100         if (propertyName.equals(getPropertyNameByGetter(method))) {
101           return method;
102         }
103       }
104     }
105
106     return null;
107   }
108
109   public static boolean isSimplePropertyAccessor(PsiMethod method) {
110     return isSimplePropertyGetter(method) || isSimplePropertySetter(method);
111   }//do not check return type
112
113   public static boolean isSimplePropertyGetter(PsiMethod method) {
114     return isSimplePropertyGetter(method, null);
115   }//do not check return type
116
117   public static boolean isSimplePropertyGetter(PsiMethod method, String propertyName) {
118     if (method == null || method.isConstructor()) return false;
119     if (method.getParameterList().getParametersCount() != 0) return false;
120     if (!isGetterName(method.getName())) return false;
121     if (method.getName().startsWith(IS_PREFIX) && !PsiType.BOOLEAN.equals(method.getReturnType())) {
122       return false;
123     }
124     return (propertyName == null || propertyName.equals(getPropertyNameByGetter(method))) && method.getReturnType() != PsiType.VOID;
125   }
126
127   public static boolean isSimplePropertySetter(PsiMethod method) {
128     return isSimplePropertySetter(method, null);
129   }
130
131   public static boolean isSimplePropertySetter(PsiMethod method, String propertyName) {
132     if (method == null || method.isConstructor()) return false;
133     if (method.getParameterList().getParametersCount() != 1) return false;
134     if (!isSetterName(method.getName())) return false;
135     return propertyName == null || propertyName.equals(getPropertyNameBySetter(method));
136   }
137
138   @Nullable
139   public static String getPropertyNameByGetter(PsiMethod getterMethod) {
140     if (getterMethod instanceof GrAccessorMethod) {
141       return ((GrAccessorMethod)getterMethod).getProperty().getName();
142     }
143
144     @NonNls String methodName = getterMethod.getName();
145     final boolean isPropertyBoolean = PsiType.BOOLEAN.equals(getterMethod.getReturnType());
146     return getPropertyNameByGetterName(methodName, isPropertyBoolean);
147   }
148
149   @Nullable
150   public static String getPropertyNameByGetterName(String methodName, boolean canBeBoolean) {
151     if (methodName.startsWith(GET_PREFIX) && methodName.length() > 3) {
152       return decapitalize(methodName.substring(3));
153     }
154     if (canBeBoolean && methodName.startsWith(IS_PREFIX) && methodName.length() > 2) {
155       return decapitalize(methodName.substring(2));
156     }
157     return null;
158   }
159
160   @Nullable
161   public static String getPropertyNameBySetter(PsiMethod setterMethod) {
162     if (setterMethod instanceof GrAccessorMethod) {
163       return ((GrAccessorMethod)setterMethod).getProperty().getName();
164     }
165
166     @NonNls String methodName = setterMethod.getName();
167     return getPropertyNameBySetterName(methodName);
168   }
169
170   @Nullable
171   public static String getPropertyNameBySetterName(String methodName) {
172     if (methodName.startsWith(SET_PREFIX) && methodName.length() > 3) {
173       return StringUtil.decapitalize(methodName.substring(3));
174     }
175     else {
176       return null;
177     }
178   }
179
180   @Nullable
181   public static String getPropertyNameByAccessorName(String accessorName) {
182     if (isGetterName(accessorName)) {
183       return getPropertyNameByGetterName(accessorName, true);
184     }
185     else if (isSetterName(accessorName)) {
186       return getPropertyNameBySetterName(accessorName);
187     }
188     return null;
189   }
190
191   @Nullable
192   public static String getPropertyName(PsiMethod accessor) {
193     if (isSimplePropertyGetter(accessor)) return getPropertyNameByGetter(accessor);
194     if (isSimplePropertySetter(accessor)) return getPropertyNameBySetter(accessor);
195     return null;
196   }
197
198   public static boolean isGetterName(@NotNull String name) {
199     if (name.startsWith(GET_PREFIX) && name.length() > 3 && isUpperCase(name.charAt(3))) return true;
200     if (name.startsWith(IS_PREFIX) && name.length() > 2 && isUpperCase(name.charAt(2))) return true;
201     return false;
202   }
203
204   /**
205    * Returns getter names in priority order
206    *
207    * @param name property name
208    * @return getter names
209    */
210   public static String[] suggestGettersName(@NotNull String name) {
211     return new String[]{IS_PREFIX + capitalize(name), GET_PREFIX + capitalize(name)};
212   }
213
214   public static String[] suggestSettersName(@NotNull String name) {
215     return new String[]{SET_PREFIX + capitalize(name)};
216   }
217
218   public static boolean isSetterName(String name) {
219     return name != null && name.startsWith(SET_PREFIX) && name.length() > 3 && isUpperCase(name.charAt(3));
220   }
221
222   public static boolean isProperty(@Nullable PsiClass aClass, @Nullable String propertyName, boolean isStatic) {
223     if (aClass == null || propertyName == null) return false;
224     final PsiField field = aClass.findFieldByName(propertyName, true);
225     if (field instanceof GrField && ((GrField)field).isProperty() && field.hasModifierProperty(PsiModifier.STATIC) == isStatic) return true;
226
227     final PsiMethod getter = findPropertyGetter(aClass, propertyName, isStatic, true);
228     if (getter != null && getter.hasModifierProperty(PsiModifier.PUBLIC)) return true;
229
230     final PsiMethod setter = findPropertySetter(aClass, propertyName, isStatic, true);
231     return setter != null && setter.hasModifierProperty(PsiModifier.PUBLIC);
232   }
233
234   public static boolean isProperty(GrField field) {
235     final PsiClass clazz = field.getContainingClass();
236     return isProperty(clazz, field.getName(), field.hasModifierProperty(PsiModifier.STATIC));
237   }
238
239   private static boolean isUpperCase(char c) {
240     return Character.toUpperCase(c) == c;
241   }
242
243   /*public static boolean canBePropertyName(String name) {
244     return !(name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isLowerCase(name.charAt(0)));
245   }*/
246
247   public static String capitalize(String s) {
248     if (s.length() == 0) return s;
249     if (s.length() == 1) return s.toUpperCase();
250     if (Character.isUpperCase(s.charAt(1))) return s;
251     final char[] chars = s.toCharArray();
252     chars[0] = Character.toUpperCase(chars[0]);
253     return new String(chars);
254   }
255
256   public static String decapitalize(String s) {
257     return Introspector.decapitalize(s);
258   }
259
260   @Nullable
261   public static PsiField findFieldForAccessor(PsiMethod accessor, boolean checkSuperClasses) {
262     final PsiClass psiClass = accessor.getContainingClass();
263     if (psiClass == null) return null;
264     PsiField field = null;
265     if (!checkSuperClasses) {
266       field = psiClass.findFieldByName(getPropertyNameByAccessorName(accessor.getName()), true);
267     }
268     else {
269       final String name = getPropertyNameByAccessorName(accessor.getName());
270       assert name != null;
271       final PsiField[] allFields = psiClass.getAllFields();
272       for (PsiField psiField : allFields) {
273         if (name.equals(psiField.getName())) {
274           field = psiField;
275           break;
276         }
277       }
278     }
279     if (field == null) return null;
280     if (field.hasModifierProperty(GrModifier.STATIC) == accessor.hasModifierProperty(GrModifier.STATIC)) {
281       return field;
282     }
283     return null;
284   }
285
286   @Nullable
287   public static String getGetterPrefix(PsiMethod getter) {
288     final String name = getter.getName();
289     if (name.startsWith(GET_PREFIX)) return GET_PREFIX;
290     if (name.startsWith(IS_PREFIX)) return IS_PREFIX;
291
292     return null;
293   }
294
295   @Nullable
296   public static String getSetterPrefix(PsiMethod setter) {
297     if (setter.getName().startsWith(SET_PREFIX)) return SET_PREFIX;
298     return null;
299   }
300
301   @Nullable
302   public static String getAccessorPrefix(PsiMethod method) {
303     final String prefix = getGetterPrefix(method);
304     if (prefix != null) return prefix;
305
306     return getSetterPrefix(method);
307   }
308
309   public static boolean isAccessorFor(PsiMethod accessor, PsiField field) {
310     final String accessorName = accessor.getName();
311     final String fieldName = field.getName();
312     if (!ArrayUtil.contains(accessorName, suggestGettersName(fieldName)) &&
313         !ArrayUtil.contains(accessorName, suggestSettersName(fieldName))) {
314       return false;
315     }
316     final PsiClass accessorClass = accessor.getContainingClass();
317     final PsiClass fieldClass = field.getContainingClass();
318     if (!field.getManager().areElementsEquivalent(accessorClass, fieldClass)) return false;
319     return accessor.hasModifierProperty(GrModifier.STATIC) == field.hasModifierProperty(GrModifier.STATIC);
320   }
321 }