diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/AppendChainPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/AppendChainPredicate.java new file mode 100644 index 000000000000..c57a407e59c0 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/AppendChainPredicate.java @@ -0,0 +1,38 @@ +package com.siyeh.ipp.concatenation; + +import com.intellij.psi.*; +import com.siyeh.ipp.base.PsiElementPredicate; + +class AppendChainPredicate implements PsiElementPredicate{ + public boolean satisfiedBy(PsiElement element){ + if(!(element instanceof PsiMethodCallExpression)){ + return false; + } + final PsiMethodCallExpression call = (PsiMethodCallExpression) element; + if(!AppendUtil.isAppend(call)) + { + return false; + } + final PsiReferenceExpression methodExpression = + call.getMethodExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if(!(qualifier instanceof PsiMethodCallExpression)){ + return false; + } + final PsiMethodCallExpression qualifierCall = (PsiMethodCallExpression) element; + if(!AppendUtil.isAppend(qualifierCall)){ + return false; + } + final PsiElement parent = element.getParent(); + if(parent instanceof PsiExpressionStatement) + return true; + if(parent instanceof PsiLocalVariable && parent.getParent() instanceof PsiDeclarationStatement && + ( (PsiDeclarationStatement)(parent.getParent())).getDeclaredElements().length == 1) + return true; + if(parent instanceof PsiAssignmentExpression && + parent.getParent() instanceof PsiExpressionStatement) + return true; + return false; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/AppendUtil.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/AppendUtil.java new file mode 100644 index 000000000000..689327e7c93d --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/AppendUtil.java @@ -0,0 +1,32 @@ +package com.siyeh.ipp.concatenation; + +import com.intellij.psi.PsiMethodCallExpression; +import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiClass; + +public class AppendUtil{ + public static boolean isAppend(PsiMethodCallExpression call) + { + final PsiReferenceExpression methodExpression = + call.getMethodExpression(); + if(methodExpression == null){ + return false; + } + final String callName = methodExpression.getReferenceName(); + if(!"append".equals(callName)){ + return false; + } + final PsiMethod method = call.resolveMethod(); + if(method == null){ + return false; + } + final PsiClass containingClass = method.getContainingClass(); + if(containingClass == null){ + return false; + } + final String name = containingClass.getQualifiedName(); + return "java.lang.StringBuffer".equals(name)|| + "java.lang.StringBuilder".equals(name); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/MakeAppendChainIntoAppendSequenceIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/MakeAppendChainIntoAppendSequenceIntention.java new file mode 100644 index 000000000000..df7552e3a2d1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/MakeAppendChainIntoAppendSequenceIntention.java @@ -0,0 +1,107 @@ +package com.siyeh.ipp.concatenation; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.base.Intention; +import com.siyeh.ipp.base.PsiElementPredicate; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class MakeAppendChainIntoAppendSequenceIntention extends Intention{ + protected PsiElementPredicate getElementPredicate(){ + return new AppendChainPredicate(); + } + + public String getText(){ + return "Make .append() chain into .append() sequence"; + } + + public String getFamilyName(){ + return "Make Append Chain Into Append Sequence"; + } + + public void invoke(Project project, Editor editor, PsiFile file) + throws IncorrectOperationException{ + if(isFileReadOnly(project, file)){ + return; + } + + PsiExpression call = + (PsiExpression) findMatchingElement(file, editor); + final List argsList = new ArrayList(); + PsiExpression currentCall = call; + while(currentCall instanceof PsiMethodCallExpression && + AppendUtil.isAppend((PsiMethodCallExpression) currentCall)){ + final PsiExpressionList args = + ((PsiMethodCallExpression) currentCall).getArgumentList(); + final String argText = args.getText(); + argsList.add(argText); + final PsiReferenceExpression methodExpression = + ((PsiMethodCallExpression) currentCall).getMethodExpression(); + currentCall = methodExpression.getQualifierExpression(); + } + final String targetText; + final String firstTargetText; + final PsiManager mgr = PsiManager.getInstance(project); + final PsiElementFactory factory = mgr.getElementFactory(); + final CodeStyleManager codeStyleManager = mgr.getCodeStyleManager(); + final PsiStatement statement; + final String firstStatementPreamble; + if(call.getParent() instanceof PsiExpressionStatement){ + targetText = currentCall.getText(); + firstTargetText = currentCall.getText(); + statement = (PsiStatement) call.getParent(); + firstStatementPreamble = ""; + } else if(call.getParent() instanceof PsiAssignmentExpression && + call.getParent() + .getParent() instanceof PsiExpressionStatement){ + statement = (PsiStatement) call.getParent().getParent(); + final PsiAssignmentExpression assignment = + (PsiAssignmentExpression) call.getParent(); + targetText = assignment.getLExpression().getText(); + firstTargetText = currentCall.getText(); + firstStatementPreamble = + assignment.getLExpression().getText() + + assignment.getOperationSign().getText(); + } else{ + statement = (PsiStatement) call.getParent().getParent(); + final PsiDeclarationStatement declaration = + (PsiDeclarationStatement) statement; + final PsiVariable variable = + (PsiVariable) declaration.getDeclaredElements()[0]; + targetText = variable.getName(); + firstTargetText = currentCall.getText(); + if(variable.hasModifierProperty(PsiModifier.FINAL)){ + firstStatementPreamble = "final " + + variable.getType().getPresentableText() + + ' ' + variable.getName() + '='; + } else{ + firstStatementPreamble = + variable.getType().getPresentableText() + + ' ' + variable.getName() + '='; + } + } + + for(Iterator iterator = argsList.iterator(); iterator.hasNext();){ + final String arg = (String) iterator.next(); + final String append; + if(iterator.hasNext()){ + append = targetText + ".append" + arg + ';'; + } else{ + append = firstStatementPreamble + + firstTargetText + ".append" + arg + ';'; + } + final PsiStatement newCall = + factory.createStatementFromText(append, null); + final PsiElement insertedElement = statement.getParent() + .addAfter(newCall, statement); + codeStyleManager.reformat(insertedElement); + } + statement.delete(); + } +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/after.java.template new file mode 100644 index 000000000000..c01ad8e932ba --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/after.java.template @@ -0,0 +1,7 @@ +public class X { + void f(String a, String b) { + StringBuffer buffer = new StringBuffer + buffer.append(a); + buffer.append(b); + } +}} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/before.java.template new file mode 100644 index 000000000000..bc0c2d52b0aa --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/before.java.template @@ -0,0 +1,6 @@ +public class X { + void f(String a, String b) { + StringBuffer buffer = new StringBuffer + buffer.append(a).append(b); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/description.html new file mode 100644 index 000000000000..7808d4034e10 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Make Append Chain Into Append Sequence/description.html @@ -0,0 +1,10 @@ + + +This intention chains of StringBuffer.append() calls with equivalent + sequences of call statements.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/ManualTestClass.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/ManualTestClass.java index 232afad2f8c4..069607022f17 100644 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/ManualTestClass.java +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/ManualTestClass.java @@ -1216,6 +1216,15 @@ public class ManualTestClass buffer.append("foo" + "bar" + "baz"); } + public void testStringBufferSequencing() + { + StringBuffer buf = new StringBuffer(); + buf.append("foo").append("bar").append("baz"); + StringBuffer buf2; + buf2 = new StringBuffer().append("foo").append("bar").append("baz"); + final StringBuffer buf3 = new StringBuffer().append("foo").append("bar").append("baz"); + } + public boolean testExpandBoolean() { boolean foo = true;