diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/TailRecursionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/TailRecursionInspection.java index 0bdcde162261..44f49d583426 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/TailRecursionInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/TailRecursionInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,16 +21,23 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; +import com.intellij.util.graph.CachingSemiGraph; +import com.intellij.util.graph.DFSTBuilder; +import com.intellij.util.graph.Graph; +import com.intellij.util.graph.GraphGenerator; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.ControlFlowUtils; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.*; + public class TailRecursionInspection extends BaseInspection { @Override @@ -42,8 +49,7 @@ public class TailRecursionInspection extends BaseInspection { @Override @NotNull protected String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "tail.recursion.problem.descriptor"); + return InspectionGadgetsBundle.message("tail.recursion.problem.descriptor"); } @Override @@ -57,8 +63,10 @@ public class TailRecursionInspection extends BaseInspection { } private static boolean mayBeReplacedByIterativeMethod(PsiMethod containingMethod) { - final PsiParameterList parameterList = containingMethod.getParameterList(); - final PsiParameter[] parameters = parameterList.getParameters(); + if (containingMethod.isVarArgs()) { + return false; + } + final PsiParameter[] parameters = containingMethod.getParameterList().getParameters(); for (final PsiParameter parameter : parameters) { if (parameter.hasModifierProperty(PsiModifier.FINAL)) { return false; @@ -72,15 +80,14 @@ public class TailRecursionInspection extends BaseInspection { @Override @NotNull public String getFamilyName() { - return InspectionGadgetsBundle.message( - "tail.recursion.replace.quickfix"); + return InspectionGadgetsBundle.message("tail.recursion.replace.quickfix"); } @Override - public void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { + public void doFix(Project project, ProblemDescriptor descriptor) { final PsiElement tailCallToken = descriptor.getPsiElement(); - final PsiMethod method = PsiTreeUtil.getParentOfType(tailCallToken, PsiMethod.class, true, PsiClass.class, PsiLambdaExpression.class); + final PsiMethod method = + PsiTreeUtil.getParentOfType(tailCallToken, PsiMethod.class, true, PsiClass.class, PsiLambdaExpression.class); if (method == null) { return; } @@ -99,16 +106,12 @@ public class TailRecursionInspection extends BaseInspection { if (methodReturnsContainingClassType(method, containingClass)) { builder.append(containingClass.getName()); thisVariableName = styleManager.suggestUniqueVariableName("result", method, false); - builder.append(' '); - builder.append(thisVariableName); - builder.append(" = this;"); + builder.append(' ').append(thisVariableName).append(" = this;"); } else if (methodContainsCallOnOtherInstance(method)) { builder.append(containingClass.getName()); thisVariableName = styleManager.suggestUniqueVariableName("other", method, false); - builder.append(' '); - builder.append(thisVariableName); - builder.append(" = this;"); + builder.append(' ').append(thisVariableName).append(" = this;"); } else { thisVariableName = null; @@ -116,22 +119,17 @@ public class TailRecursionInspection extends BaseInspection { final boolean tailCallIsContainedInLoop; if (ControlFlowUtils.isInLoop(tailCallToken)) { tailCallIsContainedInLoop = true; - builder.append(method.getName()); - builder.append(':'); + builder.append(method.getName()).append(':'); } else { tailCallIsContainedInLoop = false; } builder.append("while(true)"); - final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); replaceTailCalls(body, method, thisVariableName, tailCallIsContainedInLoop, builder); builder.append('}'); - @NonNls final String replacementText = builder.toString(); - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - final PsiElementFactory elementFactory = psiFacade.getElementFactory(); - final PsiCodeBlock block = elementFactory.createCodeBlockFromText(replacementText, method); + final PsiCodeBlock block = JavaPsiFacade.getElementFactory(project).createCodeBlockFromText(builder.toString(), method); body.replace(block); - codeStyleManager.reformat(method); + CodeStyleManager.getInstance(project).reformat(method); } private static boolean methodReturnsContainingClassType(PsiMethod method, PsiClass containingClass) { @@ -169,7 +167,7 @@ public class TailRecursionInspection extends BaseInspection { private boolean containsCallOnOtherInstance; private final PsiClass aClass; - private MethodContainsCallOnOtherInstanceVisitor(PsiClass aClass) { + MethodContainsCallOnOtherInstanceVisitor(PsiClass aClass) { this.aClass = aClass; } @@ -194,25 +192,22 @@ public class TailRecursionInspection extends BaseInspection { } } - private boolean containsCallOnOtherInstance() { + boolean containsCallOnOtherInstance() { return containsCallOnOtherInstance; } } private static void replaceTailCalls(PsiElement element, PsiMethod method, @Nullable String thisVariableName, boolean tailCallIsContainedInLoop, @NonNls StringBuilder out) { - final String text = element.getText(); if (isImplicitCallOnThis(element, method)) { if (thisVariableName != null) { - out.append(thisVariableName); - out.append('.'); + out.append(thisVariableName).append('.'); } - out.append(text); + out.append(element.getText()); } - else if (element instanceof PsiThisExpression || - element instanceof PsiSuperExpression) { + else if (element instanceof PsiThisExpression || element instanceof PsiSuperExpression) { if (thisVariableName == null) { - out.append(text); + out.append(element.getText()); } else { out.append(thisVariableName); @@ -220,38 +215,59 @@ public class TailRecursionInspection extends BaseInspection { } else if (isTailCallReturn(element, method)) { final PsiReturnStatement returnStatement = (PsiReturnStatement)element; - final PsiMethodCallExpression call = (PsiMethodCallExpression)returnStatement.getReturnValue(); + final PsiMethodCallExpression call = (PsiMethodCallExpression)ParenthesesUtils.stripParentheses(returnStatement.getReturnValue()); assert call != null; - final PsiExpressionList argumentList = call.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - final PsiParameterList parameterList = method.getParameterList(); - final PsiParameter[] parameters = parameterList.getParameters(); + final PsiExpression[] arguments = call.getArgumentList().getExpressions(); + final PsiParameter[] parameters = method.getParameterList().getParameters(); final boolean isInBlock = returnStatement.getParent() instanceof PsiCodeBlock; if (!isInBlock) { out.append('{'); } - for (int i = 0; i < parameters.length; i++) { - final PsiParameter parameter = parameters[i]; - final PsiExpression argument = arguments[i]; - final String parameterName = parameter.getName(); - if (parameterName == null) { - continue; + final Graph graph = buildGraph(parameters, arguments); + final DFSTBuilder builder = new DFSTBuilder<>(graph); + final Collection> componentOrdering = builder.getComponents(); + final Set seen = new HashSet<>(); + final Map replacements = new HashMap<>(); + for (Collection component : componentOrdering) { + for (Integer index : component) { + final Iterator in = graph.getIn(index); + final PsiParameter parameter = parameters[index]; + final String parameterName = parameter.getName(); + assert parameterName != null; + final PsiExpression argument = ParenthesesUtils.stripParentheses(arguments[index]); + assert argument != null; + if (argument instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)argument; + if (parameter.equals(referenceExpression.resolve())) { + continue; + } + } + boolean copy = false; + while (in.hasNext()) { + if (!seen.contains(in.next())) { + // if 'in' was some collection instead of an iterator this would have been a nice containsAll expression + copy = true; + break; + } + } + if (copy) { + final String variableName = + JavaCodeStyleManager.getInstance(method.getProject()).suggestUniqueVariableName(parameterName, element, false); + out.append(parameter.getType().getCanonicalText()).append(' ').append(variableName).append('='); + out.append(parameterName).append(';'); + replacements.put(parameter, variableName); + } + out.append(parameterName).append('='); + buildText(argument, replacements, out); + out.append(';'); + seen.add(index); } - final String argumentText = argument.getText(); - if (parameterName.equals(argumentText)) { - continue; - } - out.append(parameterName); - out.append(" = "); - out.append(argumentText); - out.append(';'); } if (thisVariableName != null) { final PsiReferenceExpression methodExpression = call.getMethodExpression(); final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (qualifier != null) { - out.append(thisVariableName); - out.append(" = "); + out.append(thisVariableName).append('='); replaceTailCalls(qualifier, method, thisVariableName, tailCallIsContainedInLoop, out); out.append(';'); } @@ -262,10 +278,7 @@ public class TailRecursionInspection extends BaseInspection { //don't do anything, as the continue is unnecessary } else if (tailCallIsContainedInLoop) { - final String methodName = method.getName(); - out.append("continue "); - out.append(methodName); - out.append(';'); + out.append("continue ").append(method.getName()).append(';'); } else { out.append("continue;"); @@ -277,7 +290,7 @@ public class TailRecursionInspection extends BaseInspection { else { final PsiElement[] children = element.getChildren(); if (children.length == 0) { - out.append(text); + out.append(element.getText()); } else { for (final PsiElement child : children) { @@ -287,8 +300,54 @@ public class TailRecursionInspection extends BaseInspection { } } - private static boolean isImplicitCallOnThis(PsiElement element, - PsiMethod containingMethod) { + private static void buildText(PsiElement element, Map replacements, StringBuilder out) { + if (element instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)element; + final PsiElement target = referenceExpression.resolve(); + final String replacement = replacements.get(target); + out.append(replacement != null ? replacement : element.getText()); + return; + } + final PsiElement[] children = element.getChildren(); + if (children.length > 0) { + for (PsiElement child : children) { + buildText(child, replacements, out); + } + } + else { + out.append(element.getText()); + } + } + + private static Graph buildGraph(PsiParameter[] parameters, PsiExpression[] arguments) { + final GraphGenerator.SemiGraph graph = new GraphGenerator.SemiGraph() { + + @Override + public Collection getNodes() { + final List result = new ArrayList<>(); + for (int i = 0; i < parameters.length; i++) { + result.add(i); + } + return result; + } + + @Override + public Iterator getIn(Integer n) { + final List result = new ArrayList<>(); + final PsiParameter target = parameters[n]; + for (int i = 0, length = arguments.length; i < length; i++) { + if (i == n) continue; + if (VariableAccessUtils.variableIsUsed(target, arguments[i])) { + result.add(i); + } + } + return result.iterator(); + } + }; + return GraphGenerator.create(CachingSemiGraph.create(graph)); + } + + private static boolean isImplicitCallOnThis(PsiElement element, PsiMethod containingMethod) { if (containingMethod.hasModifierProperty(PsiModifier.STATIC)) { return false; } @@ -316,13 +375,12 @@ public class TailRecursionInspection extends BaseInspection { } } - private static boolean isTailCallReturn(PsiElement element, - PsiMethod containingMethod) { + private static boolean isTailCallReturn(PsiElement element, PsiMethod containingMethod) { if (!(element instanceof PsiReturnStatement)) { return false; } final PsiReturnStatement returnStatement = (PsiReturnStatement)element; - final PsiExpression returnValue = returnStatement.getReturnValue(); + final PsiExpression returnValue = ParenthesesUtils.stripParentheses(returnStatement.getReturnValue()); if (!(returnValue instanceof PsiMethodCallExpression)) { return false; } @@ -342,25 +400,18 @@ public class TailRecursionInspection extends BaseInspection { @Override public void visitReturnStatement(@NotNull PsiReturnStatement statement) { super.visitReturnStatement(statement); - final PsiExpression returnValue = statement.getReturnValue(); + final PsiExpression returnValue = ParenthesesUtils.stripParentheses(statement.getReturnValue()); if (!(returnValue instanceof PsiMethodCallExpression)) { return; } final PsiMethodCallExpression returnCall = (PsiMethodCallExpression)returnValue; - final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, true, PsiClass.class, PsiLambdaExpression.class); + final PsiMethod containingMethod = + PsiTreeUtil.getParentOfType(statement, PsiMethod.class, true, PsiClass.class, PsiLambdaExpression.class); if (containingMethod == null) { return; } - 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; - } - if (!method.equals(containingMethod)) { + final JavaResolveResult resolveResult = returnCall.resolveMethodGenerics(); + if (!resolveResult.isValidResult() || !containingMethod.equals(resolveResult.getElement())) { return; } registerMethodCallError(returnCall, containingMethod); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance1.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance1.after.java new file mode 100644 index 000000000000..b4058a46337d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance1.after.java @@ -0,0 +1,30 @@ +class CallOnOtherInstance1 { + private boolean duplicate; + private Something something; + private CallOnOtherInstance1 original; + + public Something getSomething() { + CallOnOtherInstance1 other = this; + while (true) { + if (other.something == null) { + if (other.isDuplicate()) { + final CallOnOtherInstance1 recursion = other.getOriginal(); + other = recursion; + continue; + } else { + other.something = new Something(); + } + } + return other.something; + } + } + + private CallOnOtherInstance1 getOriginal() { + return original; + } + private boolean isDuplicate() { + return duplicate; + } + + public static class Something {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance1.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance1.java new file mode 100644 index 000000000000..3492a2655ff6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance1.java @@ -0,0 +1,26 @@ +class CallOnOtherInstance1 { + private boolean duplicate; + private Something something; + private CallOnOtherInstance1 original; + + public Something getSomething() { + if (something == null) { + if (isDuplicate()) { + final CallOnOtherInstance1 recursion = getOriginal(); + return recursion.getSomething(); + } else { + something = new Something(); + } + } + return something; + } + + private CallOnOtherInstance1 getOriginal() { + return original; + } + private boolean isDuplicate() { + return duplicate; + } + + public static class Something {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance2.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance2.after.java new file mode 100644 index 000000000000..4a2f5d31d053 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance2.after.java @@ -0,0 +1,25 @@ +class CallOnOtherInstance2 { + private boolean duplicate; + private Something something; + private CallOnOtherInstance2 original; + + public Something foo() { + CallOnOtherInstance2 other = this; + while (true) { + if (!other.duplicate) { + return other.something; + } else { + other = other.getOriginal(); + } + } + } + + private CallOnOtherInstance2 getOriginal() { + return original; + } + private boolean isDuplicate() { + return duplicate; + } + + public static class Something {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance2.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance2.java new file mode 100644 index 000000000000..3ec60f888640 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/CallOnOtherInstance2.java @@ -0,0 +1,22 @@ +class CallOnOtherInstance2 { + private boolean duplicate; + private Something something; + private CallOnOtherInstance2 original; + + public Something foo() { + if (!duplicate) { + return something; + } else { + return getOriginal().foo(); + } + } + + private CallOnOtherInstance2 getOriginal() { + return original; + } + private boolean isDuplicate() { + return duplicate; + } + + public static class Something {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency1.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency1.after.java new file mode 100644 index 000000000000..1e25ca9af978 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency1.after.java @@ -0,0 +1,17 @@ +class Dependency1 { + + public int factorial(int val) { + return factorial(val, 1); + } + + private int factorial(int val, int runningVal) { + while (true) { + if (val == 1) { + return runningVal; + } else { + runningVal = runningVal * val; + val = val - 1; + } + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency1.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency1.java new file mode 100644 index 000000000000..0e226a9a3128 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency1.java @@ -0,0 +1,14 @@ +class Dependency1 { + + public int factorial(int val) { + return factorial(val, 1); + } + + private int factorial(int val, int runningVal) { + if (val == 1) { + return runningVal; + } else { + return (factorial(val - 1, runningVal * val)); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency2.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency2.after.java new file mode 100644 index 000000000000..a457069adb1a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency2.after.java @@ -0,0 +1,17 @@ +class Dependency2 { + + private static boolean intersect(@NotNull Set ids1, @NotNull Set ids2) { + while (true) { + if (ids1.size() > ids2.size()) { + Set ids11 = ids1; + ids1 = ids2; + ids2 = ids11; + continue; + } + for (String id : ids1) { + if (ids2.contains(id)) return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency2.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency2.java new file mode 100644 index 000000000000..15231c1328ff --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/Dependency2.java @@ -0,0 +1,10 @@ +class Dependency2 { + + private static boolean intersect(@NotNull Set ids1, @NotNull Set ids2) { + if (ids1.size() > ids2.size()) return intersect(ids2, ids1); + for (String id : ids1) { + if (ids2.contains(id)) return true; + } + return false; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/ThisVariable.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/ThisVariable.after.java new file mode 100644 index 000000000000..42218b7febe2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/ThisVariable.after.java @@ -0,0 +1,17 @@ +class ThisVariable { + + private ThisVariable getRoot() { + ThisVariable result = this; + while (true) { + if (result.getParent() instanceof ThisVariable) { + result = ((ThisVariable) result.getParent()); + continue; + } + return result; + } + } + + public Object getParent() { + return null; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/ThisVariable.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/ThisVariable.java new file mode 100644 index 000000000000..bc380ea127c8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/ThisVariable.java @@ -0,0 +1,14 @@ +class ThisVariable { + + private ThisVariable getRoot() { + if (getParent() instanceof ThisVariable) + { + return ((ThisVariable) getParent()).getRoot(); + } + return this; + } + + public Object getParent() { + return null; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/UnmodifiedParameter.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/UnmodifiedParameter.after.java new file mode 100644 index 000000000000..077dec36672c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/UnmodifiedParameter.after.java @@ -0,0 +1,22 @@ +import java.awt.*; + +class UnmodifiedParameter { + + private static boolean hasAncestor(Container child, Container ancestor) { + while (true) { + if (child == null) { + return false; + } + + if (ancestor == null) { + return true; + } + + if (child.getParent() == ancestor) { + return true; + } + + child = child.getParent(); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/UnmodifiedParameter.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/UnmodifiedParameter.java new file mode 100644 index 000000000000..3653f60eaa8e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/tail_recursion/UnmodifiedParameter.java @@ -0,0 +1,20 @@ +import java.awt.*; + +class UnmodifiedParameter { + + private static boolean hasAncestor(Container child, Container ancestor) { + if (child == null) { + return false; + } + + if (ancestor == null) { + return true; + } + + if (child.getParent() == ancestor) { + return true; + } + + return hasAncestor(child.getParent(), ancestor); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/RemoveTailRecursionFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/RemoveTailRecursionFixTest.java new file mode 100644 index 000000000000..2e51e727e61e --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/RemoveTailRecursionFixTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2016 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.siyeh.ig.fixes.performance; + +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.IGQuickFixesTestCase; +import com.siyeh.ig.performance.TailRecursionInspection; + +/** + * @author Bas Leijdekkers + */ +public class RemoveTailRecursionFixTest extends IGQuickFixesTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + myFixture.enableInspections(new TailRecursionInspection()); + myRelativePath = "performance/tail_recursion"; + myDefaultHint = InspectionGadgetsBundle.message("tail.recursion.replace.quickfix"); + } + + public void testCallOnOtherInstance1() { doTest(); } + public void testCallOnOtherInstance2() { doTest(); } + public void testDependency1() { doTest(); } + public void testDependency2() { doTest(); } + public void testThisVariable() { doTest(); } + public void testUnmodifiedParameter() { doTest(); } +}