From 30ec0ba899f7829600d9bba1dfdda14287f3ac0e Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 29 May 2008 15:08:41 +0400 Subject: [PATCH] IDEADEV-26737 --- .../ig/performance/TailRecursionInspection.java | 171 ++++++++++++++++----- .../performance/TailRecursionInspection.java | 47 ++++++ 2 files changed, 181 insertions(+), 37 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TailRecursionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TailRecursionInspection.java index 3e84bdccbb..2b90bae25d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TailRecursionInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TailRecursionInspection.java @@ -89,29 +89,26 @@ public class TailRecursionInspection extends BaseInspection { } final StringBuilder builder = new StringBuilder(); builder.append('{'); + final PsiClass containingClass = method.getContainingClass(); final String thisVariableName; - if (!method.hasModifierProperty(PsiModifier.STATIC)) { - final PsiType returnType = method.getReturnType(); - final PsiClass containingClass = method.getContainingClass(); - if (returnType instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)returnType; - final PsiClass aClass = classType.resolve(); - if (aClass != null && aClass.equals(containingClass)) { - builder.append(containingClass.getName()); - final JavaCodeStyleManager styleManager = - JavaCodeStyleManager.getInstance(project); - thisVariableName = - styleManager.suggestUniqueVariableName( - "result", method, false); - builder.append(' '); - builder.append(thisVariableName); - builder.append(" = this;"); - } else { - thisVariableName = null; - } - } else { - thisVariableName = null; - } + final JavaCodeStyleManager styleManager = + JavaCodeStyleManager.getInstance(project); + if (methodReturnsContainingClassType(method, containingClass)) { + builder.append(containingClass.getName()); + thisVariableName = + styleManager.suggestUniqueVariableName( + "result", method, false); + builder.append(' '); + builder.append(thisVariableName); + builder.append(" = this;"); + } else if (methodContainsCallOnOtherInstance(method)) { + builder.append(containingClass.getName()); + thisVariableName = + styleManager.suggestUniqueVariableName( + "other", method, false); + builder.append(' '); + builder.append(thisVariableName); + builder.append(" = this;"); } else { thisVariableName = null; } @@ -139,6 +136,79 @@ public class TailRecursionInspection extends BaseInspection { codeStyleManager.reformat(method); } + private static boolean methodReturnsContainingClassType( + PsiMethod method, PsiClass containingClass) { + if (containingClass == null) { + return false; + } + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!(returnType instanceof PsiClassType)) { + return false; + } + final PsiClassType classType = (PsiClassType)returnType; + final PsiClass aClass = classType.resolve(); + return containingClass.equals(aClass); + } + + private static boolean methodContainsCallOnOtherInstance( + PsiMethod method) { + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return false; + } + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return false; + } + final PsiClass aClass = method.getContainingClass(); + final MethodContainsCallOnOtherInstanceVisitor visitor = + new MethodContainsCallOnOtherInstanceVisitor(aClass); + body.accept(visitor); + return visitor.containsCallOnOtherInstance(); + } + + private static class MethodContainsCallOnOtherInstanceVisitor + extends JavaRecursiveElementVisitor { + + private boolean containsCallOnOtherInstance = false; + private final PsiClass aClass; + + public MethodContainsCallOnOtherInstanceVisitor( + PsiClass aClass) { + this.aClass = aClass; + } + + @Override + public void visitMethodCallExpression( + PsiMethodCallExpression expression) { + if (containsCallOnOtherInstance) { + return; + } + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = + expression.getMethodExpression(); + final PsiExpression qualifier = + methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (aClass.equals(containingClass)) { + containsCallOnOtherInstance = true; + } + } + + public boolean containsCallOnOtherInstance() { + return containsCallOnOtherInstance; + } + } + private static void replaceTailCalls( PsiElement element, PsiMethod method, @Nullable String thisVariableName, @@ -195,11 +265,17 @@ public class TailRecursionInspection extends BaseInspection { out.append(';'); } if (thisVariableName != null) { - out.append(thisVariableName); - out.append(" = "); - replaceTailCalls(call, method, thisVariableName, - tailCallIsContainedInLoop, out); - out.append(';'); + final PsiReferenceExpression methodExpression = + call.getMethodExpression(); + final PsiExpression qualifier = + methodExpression.getQualifierExpression(); + if (qualifier != null) { + out.append(thisVariableName); + out.append(" = "); + replaceTailCalls(qualifier, method, thisVariableName, + tailCallIsContainedInLoop, out); + out.append(';'); + } } final PsiCodeBlock body = method.getBody(); assert body != null; @@ -235,16 +311,31 @@ public class TailRecursionInspection extends BaseInspection { if (containingMethod.hasModifierProperty(PsiModifier.STATIC)) { return false; } - if (!(element instanceof PsiMethodCallExpression)) { + if (element instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression methodCallExpression = + (PsiMethodCallExpression) element; + final PsiReferenceExpression methodExpression = + methodCallExpression.getMethodExpression(); + final PsiExpression qualifierExpression = + methodExpression.getQualifierExpression(); + return qualifierExpression == null; + } else if (element instanceof PsiReferenceExpression) { + PsiReferenceExpression referenceExpression = + (PsiReferenceExpression) element; + final PsiElement parent = referenceExpression.getParent(); + if (parent instanceof PsiMethodCallExpression) { + return false; + } + final PsiExpression qualifier = + referenceExpression.getQualifierExpression(); + if (qualifier != null) { + return false; + } + final PsiElement target = referenceExpression.resolve(); + return target instanceof PsiField; + } else { return false; } - final PsiMethodCallExpression methodCallExpression = - (PsiMethodCallExpression)element; - final PsiReferenceExpression methodExpression = - methodCallExpression.getMethodExpression(); - final PsiExpression qualifierExpression = - methodExpression.getQualifierExpression(); - return qualifierExpression == null; } private static boolean isTailCallReturn(PsiElement element, @@ -278,14 +369,20 @@ public class TailRecursionInspection extends BaseInspection { if (!(returnValue instanceof PsiMethodCallExpression)) { return; } + final PsiMethodCallExpression returnCall = + (PsiMethodCallExpression)returnValue; final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(statement, PsiMethod.class); if (containingMethod == null) { return; } - final PsiMethodCallExpression returnCall = - (PsiMethodCallExpression)returnValue; + final PsiReferenceExpression methodExpression = + returnCall.getMethodExpression(); + final String name = containingMethod.getName(); + if (!name.equals(methodExpression.getReferenceName())) { + return; + } final PsiMethod method = returnCall.resolveMethod(); if (method == null) { return; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/TailRecursionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/TailRecursionInspection.java index e224d24306..71498a3ea7 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/TailRecursionInspection.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/TailRecursionInspection.java @@ -39,4 +39,51 @@ public class TailRecursionInspection { return hasParent(child.getParent(), parent); } + + private TailRecursionInspection getRootSO() { + if (getParent() instanceof TailRecursionInspection) + { + return ((TailRecursionInspection) getParent()).getRootSO(); + } + return this; + } + + public Object getParent() { + return null; + } +} +class TailRecursion +{ + private boolean duplicate; + private Something something; + private TailRecursion original; + + public Something getSomething() { + if (something == null) { + if (isDuplicate()) { + final TailRecursion recursion = getOriginal(); + return recursion.getSomething(); + } else { + something = new Something(); + } + } + return something; + } + + public Something foo() { + if (!duplicate) { + return something; + } else { + return getOriginal().foo(); + } + } + + private TailRecursion getOriginal() { + return original; + } + private boolean isDuplicate() { + return duplicate; + } + + public static class Something {} } \ No newline at end of file -- 2.11.4.GIT