| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.psi.util; |
| |
| import com.intellij.codeInsight.NullableNotNullManager; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.CodeStyleManager; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.codeStyle.VariableKind; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.IncorrectOperationException; |
| import com.intellij.util.containers.ContainerUtil; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.beans.Introspector; |
| import java.util.*; |
| |
| /** |
| * @author Mike |
| */ |
| public class PropertyUtil { |
| @NonNls private static final String IS_PREFIX = "is"; |
| private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.PropertyUtil"); |
| |
| private PropertyUtil() { |
| } |
| |
| public static boolean isSimplePropertyGetter(PsiMethod method) { |
| return hasGetterName(method) && method.getParameterList().getParametersCount() == 0; |
| } |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| public static boolean hasGetterName(final PsiMethod method) { |
| if (method == null) return false; |
| |
| if (method.isConstructor()) return false; |
| |
| String methodName = method.getName(); |
| int methodNameLength = methodName.length(); |
| if (methodName.startsWith("get") && methodNameLength > "get".length()) { |
| if (Character.isLowerCase(methodName.charAt("get".length())) |
| && (methodNameLength == "get".length() + 1 || Character.isLowerCase(methodName.charAt("get".length() + 1)))) { |
| return false; |
| } |
| PsiType returnType = method.getReturnType(); |
| if (returnType != null && PsiType.VOID.equals(returnType)) return false; |
| } |
| else if (methodName.startsWith(IS_PREFIX) && methodNameLength > IS_PREFIX.length()) { |
| if (Character.isLowerCase(methodName.charAt(IS_PREFIX.length())) |
| && (methodNameLength == IS_PREFIX.length() + 1 || Character.isLowerCase(methodName.charAt(IS_PREFIX.length() + 1)))) { |
| return false; |
| } |
| PsiType returnType = method.getReturnType(); |
| return isBoolean(returnType); |
| } |
| else { |
| return false; |
| } |
| return true; |
| } |
| |
| @SuppressWarnings("HardCodedStringLiteral") |
| public static boolean isSimplePropertySetter(@Nullable PsiMethod method) { |
| if (method == null) return false; |
| |
| if (method.isConstructor()) return false; |
| |
| String methodName = method.getName(); |
| |
| if (!(methodName.startsWith("set") && methodName.length() > "set".length())) return false; |
| if (Character.isLowerCase(methodName.charAt("set".length())) |
| && (methodName.length() == "set".length() + 1 || Character.isLowerCase(methodName.charAt("set".length() + 1)))) return false; |
| |
| if (method.getParameterList().getParametersCount() != 1) { |
| return false; |
| } |
| |
| final PsiType returnType = method.getReturnType(); |
| |
| if (returnType == null || PsiType.VOID.equals(returnType)) { |
| return true; |
| } |
| |
| return Comparing.equal(PsiUtil.resolveClassInType(TypeConversionUtil.erasure(returnType)), method.getContainingClass()); |
| } |
| |
| @Nullable public static String getPropertyName(PsiMethod method) { |
| if (isSimplePropertyGetter(method)) { |
| return getPropertyNameByGetter(method); |
| } |
| else if (isSimplePropertySetter(method)) { |
| return getPropertyNameBySetter(method); |
| } |
| else { |
| return null; |
| } |
| } |
| |
| @NotNull |
| public static String getPropertyNameByGetter(PsiMethod getterMethod) { |
| @NonNls String methodName = getterMethod.getName(); |
| return methodName.startsWith("get") ? |
| StringUtil.decapitalize(methodName.substring(3)) : |
| StringUtil.decapitalize(methodName.substring(2)); |
| } |
| |
| @NotNull |
| public static String getPropertyNameBySetter(PsiMethod setterMethod) { |
| String methodName = setterMethod.getName(); |
| return Introspector.decapitalize(methodName.substring(3)); |
| } |
| |
| @NotNull |
| public static Map<String, PsiMethod> getAllProperties(@NotNull final PsiClass psiClass, final boolean acceptSetters, final boolean acceptGetters) { |
| return getAllProperties(psiClass, acceptSetters, acceptGetters, true); |
| } |
| |
| @NotNull |
| public static Map<String, PsiMethod> getAllProperties(@NotNull final PsiClass psiClass, |
| final boolean acceptSetters, |
| final boolean acceptGetters, |
| final boolean includeSuperClass) { |
| return getAllProperties(acceptSetters, acceptGetters, includeSuperClass ? psiClass.getAllMethods() : psiClass.getMethods()); |
| } |
| |
| @NotNull |
| public static Map<String, PsiMethod> getAllProperties(final boolean acceptSetters, |
| final boolean acceptGetters, PsiMethod[] methods) { |
| final Map<String, PsiMethod> map = new HashMap<String, PsiMethod>(); |
| |
| for (PsiMethod method : methods) { |
| if (filterMethods(method)) continue; |
| if (acceptSetters && isSimplePropertySetter(method)|| |
| acceptGetters && isSimplePropertyGetter(method)) { |
| map.put(getPropertyName(method), method); |
| } |
| } |
| return map; |
| } |
| |
| |
| private static boolean filterMethods(final PsiMethod method) { |
| if(method.hasModifierProperty(PsiModifier.STATIC) || !method.hasModifierProperty(PsiModifier.PUBLIC)) return true; |
| |
| PsiClass psiClass = method.getContainingClass(); |
| if (psiClass == null) return false; |
| final String className = psiClass.getQualifiedName(); |
| return className != null && className.equals(CommonClassNames.JAVA_LANG_OBJECT); |
| } |
| |
| @NotNull |
| public static List<PsiMethod> getSetters(@NotNull final PsiClass psiClass, final String propertyName) { |
| final String setterName = suggestSetterName(propertyName); |
| final PsiMethod[] psiMethods = psiClass.findMethodsByName(setterName, true); |
| final ArrayList<PsiMethod> list = new ArrayList<PsiMethod>(psiMethods.length); |
| for (PsiMethod method : psiMethods) { |
| if (filterMethods(method)) continue; |
| if (isSimplePropertySetter(method)) { |
| list.add(method); |
| } |
| } |
| return list; |
| } |
| |
| @NotNull |
| public static List<PsiMethod> getGetters(@NotNull final PsiClass psiClass, final String propertyName) { |
| final String[] names = suggestGetterNames(propertyName); |
| final ArrayList<PsiMethod> list = new ArrayList<PsiMethod>(); |
| for (String name : names) { |
| final PsiMethod[] psiMethods = psiClass.findMethodsByName(name, true); |
| for (PsiMethod method : psiMethods) { |
| if (filterMethods(method)) continue; |
| if (isSimplePropertyGetter(method)) { |
| list.add(method); |
| } |
| } |
| } |
| return list; |
| } |
| @NotNull |
| public static List<PsiMethod> getAccessors(@NotNull final PsiClass psiClass, final String propertyName) { |
| return ContainerUtil.concat(getGetters(psiClass, propertyName), getSetters(psiClass, propertyName)); |
| } |
| |
| @Nullable |
| public static PsiMethod findPropertyGetter(PsiClass aClass, |
| String propertyName, |
| boolean isStatic, |
| boolean checkSuperClasses) { |
| if (aClass == null) return null; |
| PsiMethod[] methods; |
| if (checkSuperClasses) { |
| methods = aClass.getAllMethods(); |
| } |
| else { |
| methods = aClass.getMethods(); |
| } |
| |
| for (PsiMethod method : methods) { |
| if (method.hasModifierProperty(PsiModifier.STATIC) != isStatic) continue; |
| |
| if (isSimplePropertyGetter(method)) { |
| if (getPropertyNameByGetter(method).equals(propertyName)) { |
| return method; |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| @Nullable |
| public static PsiMethod findPropertyGetterWithType(String propertyName, boolean isStatic, PsiType type, Iterator<PsiMethod> methods) { |
| while (methods.hasNext()) { |
| PsiMethod method = methods.next(); |
| if (method.hasModifierProperty(PsiModifier.STATIC) != isStatic) continue; |
| if (isSimplePropertyGetter(method)) { |
| if (getPropertyNameByGetter(method).equals(propertyName)) { |
| if (type.equals(method.getReturnType())) return method; |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static boolean isSimplePropertyAccessor(PsiMethod method) { |
| return isSimplePropertyGetter(method) || isSimplePropertySetter(method); |
| } |
| |
| @Nullable public static PsiMethod findPropertySetter(PsiClass aClass, |
| String propertyName, |
| boolean isStatic, |
| boolean checkSuperClasses) { |
| if (aClass == null) return null; |
| PsiMethod[] methods; |
| if (checkSuperClasses) { |
| methods = aClass.getAllMethods(); |
| } |
| else { |
| methods = aClass.getMethods(); |
| } |
| |
| for (PsiMethod method : methods) { |
| if (method.hasModifierProperty(PsiModifier.STATIC) != isStatic) continue; |
| |
| if (isSimplePropertySetter(method)) { |
| if (getPropertyNameBySetter(method).equals(propertyName)) { |
| return method; |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| @Nullable |
| public static PsiMethod findPropertySetterWithType(String propertyName, boolean isStatic, PsiType type, Iterator<PsiMethod> methods) { |
| while (methods.hasNext()) { |
| PsiMethod method = methods.next(); |
| if (method.hasModifierProperty(PsiModifier.STATIC) != isStatic) continue; |
| |
| if (isSimplePropertySetter(method)) { |
| if (getPropertyNameBySetter(method).equals(propertyName)) { |
| PsiType methodType = method.getParameterList().getParameters()[0].getType(); |
| if (type.equals(methodType)) return method; |
| } |
| } |
| } |
| return null; |
| } |
| |
| @Nullable public static PsiField findPropertyField(PsiClass aClass, String propertyName, boolean isStatic) { |
| PsiField[] fields = aClass.getAllFields(); |
| |
| for (PsiField field : fields) { |
| if (field.hasModifierProperty(PsiModifier.STATIC) != isStatic) continue; |
| if (propertyName.equals(suggestPropertyName(field))) return field; |
| } |
| |
| return null; |
| } |
| |
| @Nullable public static String getPropertyName(@NonNls String methodName) { |
| return StringUtil.getPropertyName(methodName); |
| } |
| |
| public static String suggestGetterName(@NonNls @NotNull String propertyName, @Nullable PsiType propertyType) { |
| return suggestGetterName(propertyName, propertyType, null); |
| } |
| |
| public static String suggestGetterName(@NotNull String propertyName, @Nullable PsiType propertyType, @NonNls String existingGetterName) { |
| @NonNls StringBuilder name = new StringBuilder(StringUtil.capitalizeWithJavaBeanConvention(propertyName)); |
| if (isBoolean(propertyType)) { |
| if (existingGetterName == null || !existingGetterName.startsWith("get")) { |
| name.insert(0, IS_PREFIX); |
| } |
| else { |
| name.insert(0, "get"); |
| } |
| } |
| else { |
| name.insert(0, "get"); |
| } |
| |
| return name.toString(); |
| } |
| |
| private static boolean isBoolean(@Nullable PsiType propertyType) { |
| return PsiType.BOOLEAN.equals(propertyType); |
| } |
| |
| @NonNls |
| public static String[] suggestGetterNames(String propertyName) { |
| final String str = StringUtil.capitalizeWithJavaBeanConvention(propertyName); |
| return new String[] { IS_PREFIX + str, "get" + str }; |
| } |
| |
| public static String suggestSetterName(@NonNls String propertyName) { |
| @NonNls StringBuilder name = new StringBuilder(StringUtil.capitalizeWithJavaBeanConvention(propertyName)); |
| name.insert(0, "set"); |
| return name.toString(); |
| } |
| |
| public static String[] getReadableProperties(PsiClass aClass, boolean includeSuperClass) { |
| List<String> result = new ArrayList<String>(); |
| |
| PsiMethod[] methods; |
| if (includeSuperClass) { |
| methods = aClass.getAllMethods(); |
| } |
| else { |
| methods = aClass.getMethods(); |
| } |
| |
| for (PsiMethod method : methods) { |
| if (CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName())) continue; |
| |
| if (isSimplePropertyGetter(method)) { |
| result.add(getPropertyName(method)); |
| } |
| } |
| |
| return ArrayUtil.toStringArray(result); |
| } |
| |
| public static String[] getWritableProperties(PsiClass aClass, boolean includeSuperClass) { |
| List<String> result = new ArrayList<String>(); |
| |
| PsiMethod[] methods; |
| |
| if (includeSuperClass) { |
| methods = aClass.getAllMethods(); |
| } |
| else { |
| methods = aClass.getMethods(); |
| } |
| |
| for (PsiMethod method : methods) { |
| if (CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName())) continue; |
| |
| if (isSimplePropertySetter(method)) { |
| result.add(getPropertyName(method)); |
| } |
| } |
| |
| return ArrayUtil.toStringArray(result); |
| } |
| |
| /** |
| * Consider using {@link com.intellij.codeInsight.generation.GenerateMembersUtil#generateGetterPrototype(com.intellij.psi.PsiField)} |
| * to add @Override annotation |
| */ |
| @Nullable |
| public static PsiMethod generateGetterPrototype(@NotNull PsiField field) { |
| PsiElementFactory factory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory(); |
| Project project = field.getProject(); |
| String name = field.getName(); |
| String getName = suggestGetterName(field); |
| try { |
| PsiMethod getMethod = factory.createMethod(getName, field.getType()); |
| PsiUtil.setModifierProperty(getMethod, PsiModifier.PUBLIC, true); |
| if (field.hasModifierProperty(PsiModifier.STATIC)) { |
| PsiUtil.setModifierProperty(getMethod, PsiModifier.STATIC, true); |
| } |
| |
| annotateWithNullableStuff(field, factory, getMethod); |
| |
| PsiCodeBlock body = factory.createCodeBlockFromText("{\nreturn " + name + ";\n}", null); |
| getMethod.getBody().replace(body); |
| getMethod = (PsiMethod)CodeStyleManager.getInstance(project).reformat(getMethod); |
| return getMethod; |
| } |
| catch (IncorrectOperationException e) { |
| LOG.error(e); |
| return null; |
| } |
| } |
| |
| /** |
| * Consider using {@link com.intellij.codeInsight.generation.GenerateMembersUtil#generateSetterPrototype(com.intellij.psi.PsiField)} |
| * to add @Override annotation |
| */ |
| @Nullable |
| public static PsiMethod generateSetterPrototype(PsiField field) { |
| return generateSetterPrototype(field, field.getContainingClass()); |
| } |
| |
| /** |
| * Consider using {@link com.intellij.codeInsight.generation.GenerateMembersUtil#generateSetterPrototype(com.intellij.psi.PsiField)} |
| * to add @Override annotation |
| */ |
| @Nullable |
| public static PsiMethod generateSetterPrototype(PsiField field, final PsiClass containingClass) { |
| return generateSetterPrototype(field, containingClass, false); |
| } |
| |
| /** |
| * Consider using {@link com.intellij.codeInsight.generation.GenerateMembersUtil#generateSetterPrototype(com.intellij.psi.PsiField)} |
| * to add @Override annotation |
| */ |
| @Nullable |
| public static PsiMethod generateSetterPrototype(PsiField field, final PsiClass containingClass, boolean returnSelf) { |
| Project project = field.getProject(); |
| JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); |
| PsiElementFactory factory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory(); |
| |
| String name = field.getName(); |
| boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); |
| VariableKind kind = codeStyleManager.getVariableKind(field); |
| String propertyName = codeStyleManager.variableNameToPropertyName(name, kind); |
| String setName = suggestSetterName(field); |
| try { |
| PsiMethod setMethod = factory.createMethodFromText(factory.createMethod(setName, returnSelf ? factory.createType(containingClass) : PsiType.VOID).getText(), field); |
| String parameterName = codeStyleManager.propertyNameToVariableName(propertyName, VariableKind.PARAMETER); |
| PsiParameter param = factory.createParameter(parameterName, field.getType()); |
| |
| annotateWithNullableStuff(field, factory, param); |
| |
| setMethod.getParameterList().add(param); |
| PsiUtil.setModifierProperty(setMethod, PsiModifier.PUBLIC, true); |
| PsiUtil.setModifierProperty(setMethod, PsiModifier.STATIC, isStatic); |
| |
| @NonNls StringBuilder buffer = new StringBuilder(); |
| buffer.append("{\n"); |
| if (name.equals(parameterName)) { |
| if (!isStatic) { |
| buffer.append("this."); |
| } |
| else { |
| String className = containingClass.getName(); |
| if (className != null) { |
| buffer.append(className); |
| buffer.append("."); |
| } |
| } |
| } |
| buffer.append(name); |
| buffer.append("="); |
| buffer.append(parameterName); |
| buffer.append(";\n"); |
| if (returnSelf) { |
| buffer.append("return this;\n"); |
| } |
| buffer.append("}"); |
| PsiCodeBlock body = factory.createCodeBlockFromText(buffer.toString(), null); |
| setMethod.getBody().replace(body); |
| setMethod = (PsiMethod)CodeStyleManager.getInstance(project).reformat(setMethod); |
| return setMethod; |
| } |
| catch (IncorrectOperationException e) { |
| LOG.error(e); |
| return null; |
| } |
| } |
| |
| private static void annotateWithNullableStuff(final PsiModifierListOwner field, final PsiElementFactory factory, final PsiModifierListOwner listOwner) |
| throws IncorrectOperationException { |
| final NullableNotNullManager manager = NullableNotNullManager.getInstance(field.getProject()); |
| final String notNull = manager.getNotNull(field); |
| if (notNull != null) { |
| annotate(factory, listOwner, notNull); |
| } |
| else { |
| final String nullable = manager.getNullable(field); |
| if (nullable != null) { |
| annotate(factory, listOwner, nullable); |
| } |
| } |
| } |
| |
| private static void annotate(final PsiElementFactory factory, final PsiModifierListOwner listOwner, final String annotationQName) |
| throws IncorrectOperationException { |
| final PsiModifierList modifierList = listOwner.getModifierList(); |
| LOG.assertTrue(modifierList != null); |
| modifierList.addAfter(factory.createAnnotationFromText("@" + annotationQName, listOwner), null); |
| } |
| |
| public static String suggestPropertyName(@NotNull PsiField field) { |
| return suggestPropertyName(field, field.getName()); |
| } |
| |
| public static String suggestPropertyName(@NotNull PsiField field, @NotNull String fieldName) { |
| JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(field.getProject()); |
| VariableKind kind = codeStyleManager.getVariableKind(field); |
| String name = codeStyleManager.variableNameToPropertyName(fieldName, kind); |
| if (!field.hasModifierProperty(PsiModifier.STATIC) && isBoolean(field.getType())) { |
| if (name.startsWith(IS_PREFIX) && name.length() > IS_PREFIX.length() && Character.isUpperCase(name.charAt(IS_PREFIX.length()))) { |
| name = Introspector.decapitalize(name.substring(IS_PREFIX.length())); |
| } |
| } |
| return name; |
| } |
| |
| public static String suggestGetterName(PsiField field) { |
| String propertyName = suggestPropertyName(field); |
| return suggestGetterName(propertyName, field.getType()); |
| } |
| |
| public static String suggestSetterName(PsiField field) { |
| String propertyName = suggestPropertyName(field); |
| return suggestSetterName(propertyName); |
| } |
| |
| @Nullable |
| public static String getPropertyName(final PsiMember member) { |
| if (member instanceof PsiMethod) { |
| return getPropertyName((PsiMethod)member); |
| } |
| else if (member instanceof PsiField) { |
| return member.getName(); |
| } |
| else return null; |
| } |
| |
| @Nullable |
| public static PsiType getPropertyType(final PsiMember member) { |
| if (member instanceof PsiField) { |
| return ((PsiField)member).getType(); |
| } |
| else if (member instanceof PsiMethod) { |
| final PsiMethod psiMethod = (PsiMethod)member; |
| if (isSimplePropertyGetter(psiMethod)) { |
| return psiMethod.getReturnType(); |
| } |
| else if (isSimplePropertySetter(psiMethod)) { |
| return psiMethod.getParameterList().getParameters()[0].getType(); |
| } |
| } |
| return null; |
| } |
| |
| @Nullable |
| public static PsiTypeElement getPropertyTypeElement(final PsiMember member) { |
| if (member instanceof PsiField) { |
| return ((PsiField)member).getTypeElement(); |
| } |
| else if (member instanceof PsiMethod) { |
| final PsiMethod psiMethod = (PsiMethod)member; |
| if (isSimplePropertyGetter(psiMethod)) { |
| return psiMethod.getReturnTypeElement(); |
| } |
| else if (isSimplePropertySetter(psiMethod)) { |
| return psiMethod.getParameterList().getParameters()[0].getTypeElement(); |
| } |
| } |
| return null; |
| } |
| |
| @Nullable |
| public static PsiIdentifier getPropertyNameIdentifier(final PsiMember member) { |
| if (member instanceof PsiField) { |
| return ((PsiField)member).getNameIdentifier(); |
| } |
| else if (member instanceof PsiMethod) { |
| return ((PsiMethod)member).getNameIdentifier(); |
| } |
| return null; |
| } |
| |
| @Nullable |
| public static PsiField findPropertyFieldByMember(final PsiMember psiMember) { |
| if (psiMember instanceof PsiField) { |
| return (PsiField)psiMember; |
| } |
| else if (psiMember instanceof PsiMethod) { |
| final PsiMethod psiMethod = (PsiMethod)psiMember; |
| final PsiType returnType = psiMethod.getReturnType(); |
| if (returnType == null) return null; |
| final PsiCodeBlock body = psiMethod.getBody(); |
| final PsiStatement[] statements = body == null? null : body.getStatements(); |
| final PsiStatement statement = statements == null || statements.length != 1? null : statements[0]; |
| final PsiElement target; |
| if (PsiType.VOID.equals(returnType)) { |
| final PsiExpression expression = |
| statement instanceof PsiExpressionStatement ? ((PsiExpressionStatement)statement).getExpression() : null; |
| target = expression instanceof PsiAssignmentExpression ? ((PsiAssignmentExpression)expression).getLExpression() : null; |
| } |
| else { |
| target = statement instanceof PsiReturnStatement ? ((PsiReturnStatement)statement).getReturnValue() : null; |
| } |
| final PsiElement resolved = target instanceof PsiReferenceExpression ? ((PsiReferenceExpression)target).resolve() : null; |
| if (resolved instanceof PsiField) { |
| final PsiField field = (PsiField)resolved; |
| if (psiMember.getContainingClass() == field.getContainingClass() || |
| psiMember.getContainingClass().isInheritor(field.getContainingClass(), true)) return field; |
| } |
| } |
| return null; |
| } |
| |
| public static PsiMethod findSetterForField(PsiField field) { |
| final PsiClass containingClass = field.getContainingClass(); |
| final String propertyName = suggestPropertyName(field); |
| final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); |
| return findPropertySetter(containingClass, propertyName, isStatic, true); |
| } |
| |
| public static PsiMethod findGetterForField(PsiField field) { |
| final PsiClass containingClass = field.getContainingClass(); |
| final String propertyName = suggestPropertyName(field); |
| final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); |
| return findPropertyGetter(containingClass, propertyName, isStatic, true); |
| } |
| |
| /** |
| * If the name of the method looks like a getter and the body consists of a single return statement, |
| * returns the returned expression. Otherwise, returns null. |
| * |
| * @param method the method to check |
| * @return the return value, or null if it doesn't match the condotions. |
| */ |
| @Nullable |
| public static PsiExpression getGetterReturnExpression(PsiMethod method) { |
| return method != null && hasGetterSignature(method) ? getSingleReturnValue(method) : null; |
| } |
| |
| private static boolean hasGetterSignature(@NotNull PsiMethod method) { |
| return isSimplePropertyGetter(method) && !method.hasModifierProperty(PsiModifier.SYNCHRONIZED); |
| } |
| |
| @Nullable |
| public static PsiExpression getSingleReturnValue(@NotNull PsiMethod method) { |
| final PsiCodeBlock body = method.getBody(); |
| if (body == null) { |
| return null; |
| } |
| final PsiStatement[] statements = body.getStatements(); |
| final PsiStatement statement = statements.length != 1 ? null : statements[0]; |
| return statement instanceof PsiReturnStatement ? ((PsiReturnStatement)statement).getReturnValue() : null; |
| } |
| |
| @Nullable |
| public static PsiField getFieldOfGetter(PsiMethod method) { |
| PsiField field = getSimplyReturnedField(method, getGetterReturnExpression(method)); |
| if (field != null) { |
| final PsiType returnType = method.getReturnType(); |
| if (returnType != null && field.getType().equalsToText(returnType.getCanonicalText())) { |
| return field; |
| } |
| } |
| return null; |
| } |
| |
| @Nullable |
| public static PsiField getSimplyReturnedField(PsiMethod method, @Nullable PsiExpression value) { |
| if (!(value instanceof PsiReferenceExpression)) { |
| return null; |
| } |
| |
| final PsiReferenceExpression reference = (PsiReferenceExpression)value; |
| if (hasSubstantialQualifier(reference)) { |
| return null; |
| } |
| |
| final PsiElement referent = reference.resolve(); |
| if (!(referent instanceof PsiField)) { |
| return null; |
| } |
| |
| final PsiField field = (PsiField)referent; |
| return InheritanceUtil.isInheritorOrSelf(method.getContainingClass(), field.getContainingClass(), true) ? field : null; |
| } |
| |
| private static boolean hasSubstantialQualifier(PsiReferenceExpression reference) { |
| final PsiExpression qualifier = reference.getQualifierExpression(); |
| if (qualifier == null) return false; |
| |
| if (qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) { |
| return false; |
| } |
| |
| if (qualifier instanceof PsiReferenceExpression) { |
| return !(((PsiReferenceExpression)qualifier).resolve() instanceof PsiClass); |
| } |
| return true; |
| } |
| |
| public static boolean isSimpleGetter(PsiMethod method) { |
| return getFieldOfGetter(method) != null; |
| } |
| |
| @Nullable |
| public static PsiField getFieldOfSetter(PsiMethod method) { |
| if (method == null) { |
| return null; |
| } |
| final PsiParameterList parameterList = method.getParameterList(); |
| if (parameterList.getParametersCount() != 1) { |
| return null; |
| } |
| @NonNls final String name = method.getName(); |
| if (!name.startsWith("set")) { |
| return null; |
| } |
| if (method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { |
| return null; |
| } |
| final PsiCodeBlock body = method.getBody(); |
| if (body == null) { |
| return null; |
| } |
| final PsiStatement[] statements = body.getStatements(); |
| if (statements.length != 1) { |
| return null; |
| } |
| final PsiStatement statement = statements[0]; |
| if (!(statement instanceof PsiExpressionStatement)) { |
| return null; |
| } |
| final PsiExpressionStatement possibleAssignmentStatement = (PsiExpressionStatement)statement; |
| final PsiExpression possibleAssignment = possibleAssignmentStatement.getExpression(); |
| if (!(possibleAssignment instanceof PsiAssignmentExpression)) { |
| return null; |
| } |
| final PsiAssignmentExpression assignment = (PsiAssignmentExpression)possibleAssignment; |
| if (!JavaTokenType.EQ.equals(assignment.getOperationTokenType())) { |
| return null; |
| } |
| final PsiExpression lhs = assignment.getLExpression(); |
| if (!(lhs instanceof PsiReferenceExpression)) { |
| return null; |
| } |
| final PsiReferenceExpression reference = (PsiReferenceExpression)lhs; |
| final PsiExpression qualifier = reference.getQualifierExpression(); |
| if (qualifier instanceof PsiReferenceExpression) { |
| final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier; |
| final PsiElement target = referenceExpression.resolve(); |
| if (!(target instanceof PsiClass)) { |
| return null; |
| } |
| } |
| else if (qualifier != null && !(qualifier instanceof PsiThisExpression) && !(qualifier instanceof PsiSuperExpression)) { |
| return null; |
| } |
| final PsiElement referent = reference.resolve(); |
| if (referent == null) { |
| return null; |
| } |
| if (!(referent instanceof PsiField)) { |
| return null; |
| } |
| final PsiField field = (PsiField)referent; |
| final PsiClass fieldContainingClass = field.getContainingClass(); |
| final PsiClass methodContainingClass = method.getContainingClass(); |
| if (!InheritanceUtil.isInheritorOrSelf(methodContainingClass, fieldContainingClass, true)) { |
| return null; |
| } |
| final PsiExpression rhs = assignment.getRExpression(); |
| if (!(rhs instanceof PsiReferenceExpression)) { |
| return null; |
| } |
| final PsiReferenceExpression rReference = (PsiReferenceExpression)rhs; |
| final PsiExpression rQualifier = rReference.getQualifierExpression(); |
| if (rQualifier != null) { |
| return null; |
| } |
| final PsiElement rReferent = rReference.resolve(); |
| if (rReferent == null) { |
| return null; |
| } |
| if (!(rReferent instanceof PsiParameter)) { |
| return null; |
| } |
| final PsiType fieldType = field.getType(); |
| final PsiType parameterType = ((PsiVariable)rReferent).getType(); |
| if (fieldType.equalsToText(parameterType.getCanonicalText())) { |
| return field; |
| } |
| else { |
| return null; |
| } |
| } |
| |
| public static boolean isSimpleSetter(PsiMethod method) { |
| return getFieldOfSetter(method) != null; |
| } |
| |
| @Nullable |
| public static PsiMethod getReversePropertyMethod(PsiMethod propertyMethod) { |
| if (propertyMethod == null) { |
| return null; |
| } |
| final PsiClass aClass = propertyMethod.getContainingClass(); |
| if (aClass == null) { |
| return null; |
| } |
| final String methodName = propertyMethod.getName(); |
| final String prefix; |
| if (methodName.startsWith("get")) { |
| prefix = "get"; |
| } |
| else if (methodName.startsWith(IS_PREFIX)) { |
| prefix = IS_PREFIX; |
| } |
| else if (methodName.startsWith("set")) { |
| prefix = "set"; |
| } |
| else { |
| return null; |
| } |
| final String name = methodName.substring(prefix.length()); |
| final PsiField field; |
| if (prefix.equals("set")) { |
| field = getFieldOfSetter(propertyMethod); |
| } |
| else { |
| field = getFieldOfGetter(propertyMethod); |
| } |
| if (field == null) { |
| return null; |
| } |
| if (prefix.equals("set")) { |
| final PsiMethod result = findPropertyMethod(aClass, "get", name, field); |
| if (result != null) { |
| return result; |
| } |
| return findPropertyMethod(aClass, IS_PREFIX, name, field); |
| } |
| else { |
| return findPropertyMethod(aClass, "set", name, field); |
| } |
| } |
| |
| private static PsiMethod findPropertyMethod(@NotNull PsiClass aClass, @NotNull String prefix, @NotNull String propertyName, @NotNull PsiField field1) { |
| final PsiMethod[] methods = aClass.findMethodsByName(prefix + propertyName, true); |
| for (PsiMethod method : methods) { |
| final PsiField field2; |
| if (prefix.equals("set")) { |
| field2 = getFieldOfSetter(method); |
| } |
| else { |
| field2 = getFieldOfGetter(method); |
| } |
| if (field1.equals(field2)) { |
| return method; |
| } |
| } |
| return null; |
| } |
| } |