Bug 36350 - [quick assist] convert to StringBuffer
Summary: [quick assist] convert to StringBuffer
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 2.1   Edit
Hardware: All All
: P4 enhancement with 1 vote (vote)
Target Milestone: 3.4 M4   Edit
Assignee: Martin Aeschlimann CLA
QA Contact:
URL:
Whiteboard:
Keywords: contributed
: 48240 163960 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-04-10 10:19 EDT by Randy Giffen CLA
Modified: 2009-06-16 12:39 EDT (History)
8 users (show)

See Also:


Attachments
Convert to StringBuffer quickfix (24.53 KB, patch)
2007-10-26 19:34 EDT, Benjamin Muskalla CLA
no flags Details | Diff
updated patch (31.47 KB, patch)
2007-10-31 22:59 EDT, Benjamin Muskalla CLA
no flags Details | Diff
updated patch (33.05 KB, patch)
2007-11-03 11:31 EDT, Benjamin Muskalla CLA
no flags Details | Diff
updated tests (17.05 KB, patch)
2007-11-13 18:44 EST, Benjamin Muskalla CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Randy Giffen CLA 2003-04-10 10:19:28 EDT
Convert

setFileName("ComponentWiring" + nameSuffix + "." + 
CWEditor.MODEL_FILE_EXTENSION);  //$NON-NLS-2$//$NON-NLS-1$

To

StringBuffer buf = new StringBuffer();
buf.append("ComponentWiring"); //$NON-NLS-1$
buf.append(nameSuffix);
buf.append("."); //$NON-NLS-1$
buf.append(CWEditor.MODEL_FILE_EXTENSION);
setFileName(buf.toString());
Comment 1 Dirk Baeumer CLA 2003-04-10 10:23:33 EDT
Good suggestion. Should consider for 2.2
Comment 2 Dirk Baeumer CLA 2003-04-24 12:24:05 EDT
Most compilers (javac, eclipse) do this optimization when generating byte code.
Comment 3 Alex Blewitt CLA 2004-04-06 22:10:33 EDT
The suggestion to convert to string buffer is also useful in loops:

String data = "";

for(int i=0;i<args.length;i++) {
  data += args[i];
}

I don't believe these kind of loops will be picked up by the compiler, but I could be wrong.
Comment 4 Dirk Baeumer CLA 2004-12-22 05:37:54 EST
This is now more a quick assist than a refactoring.

Comment 5 Dirk Baeumer CLA 2004-12-22 05:38:21 EST
Currently no action planned for 3.1
Comment 6 Martin Aeschlimann CLA 2006-11-10 06:12:46 EST
*** Bug 163960 has been marked as a duplicate of this bug. ***
Comment 7 Martin Aeschlimann CLA 2006-11-10 06:13:35 EST
reopen
Comment 8 Martin Aeschlimann CLA 2006-11-10 06:14:46 EST
*** Bug 154199 has been marked as a duplicate of this bug. ***
Comment 9 Martin Aeschlimann CLA 2007-10-11 04:05:51 EDT
*** Bug 48240 has been marked as a duplicate of this bug. ***
Comment 10 Benjamin Muskalla CLA 2007-10-26 19:34:47 EDT
Created attachment 81312 [details]
Convert to StringBuffer quickfix

Hi,

attached is a patch for a new quickfix to convert concatenated strings into a string buffer. As this is the first time for me hacking JDT it would be really great to have some feedback how to improve the implementation.

Thanks in advance!
Comment 11 Martin Aeschlimann CLA 2007-10-29 05:10:27 EDT
Hi Benjamin,
looks good! From a quick look at the code, I saw the following:
- resolveBinding can be null, if there are compile errors
- a statement can be in a if body (if (x) statement();). Test this with:
ASTNodes.isControlStatementBody(statement.getLocationInParent())
In that case you have to introduce a block.
- For variable name suggestions use:  StubUtility.getVariableNameSuggestions. 
- Use ASTRewrite.createCopyPlaceholder when copying nodes. You shouldn't be copying trees here. If it is a tree, wouldn't it be necessary to traverse all children?
- Add a test case for the following scenario:  foo("Hello" + "World")
Comment 12 Benjamin Muskalla CLA 2007-10-31 22:59:13 EDT
Created attachment 81817 [details]
updated patch

 (In reply to comment #11)
> Hi Benjamin,
> looks good! From a quick look at the code, I saw the following:
First, thanks for the good hints :)

> - resolveBinding can be null, if there are compile errors
Done

> - a statement can be in a if body (if (x) statement();). Test this with:
> ASTNodes.isControlStatementBody(statement.getLocationInParent())
> In that case you have to introduce a block.
Done - after a bit struggeling ;)

> - For variable name suggestions use:  StubUtility.getVariableNameSuggestions.
I thought that there has to be something like that but could not find it :)

> - Use ASTRewrite.createCopyPlaceholder when copying nodes. You shouldn't be
> copying trees here. If it is a tree, wouldn't it be necessary to traverse all
> children?
Done

> - Add a test case for the following scenario:  foo("Hello" + "World")
Done

I also added a testcase for NLS-comment handling but I think this could be done as an additional step.
Martin, what do you think of Alex comment #3 - should be also support this case? I think this you get a little tricky (at least for me :) ).
Comment 13 Benjamin Muskalla CLA 2007-11-03 11:31:06 EDT
Created attachment 82032 [details]
updated patch

Just saw that i forgot the NLS test (I commented it out as this is not yet implemented - waiting for response of Martin).
Some thoughts about the two missing features:
* NLS support: I could use NLSUtil.createNLSEdit to do the work but it will only give me a TextEdit which I am not able to apply to the resulting AST (afaik). One idea would be to implement a CompositeProposal which manages two proposals as one (the ASTRewritePropsal used for the rewrite itself and one to add the TextEdit computed by the NLS stuff. Or should the whole thing be done by duplicating the NLS stuff and have an AST-conform way? Or is there maybe already something like this somewhere? ;)
* Loops: I think this could be done and would be a good thing but it could get a bit complex as far as I can see. I'm willing to contribute this too in an additional step when the initial support is accepted.

Have a nice weekend!
Comment 14 Martin Aeschlimann CLA 2007-11-05 12:08:24 EST
I'll have a look as I soon as I find time for it. Thanks Benjamin.
For NLS: None of our quick fixes or refactoring tries to preserve the NON_NLS comments. So no need for that here.

Comment 15 Martin Aeschlimann CLA 2007-11-08 06:18:03 EST
I simplified the patch a bit, in particular the evaluation how the InfixExpression is found. Released the code, but not the tests> 20070811. Thanks Benjamin!

Can you have a look at the following outstanding issues:

For the tests you used ConvertIterableLoopQuickFixTest as example. Unfortunately this is a bad one, as I just realized now. Can you have a look at the other quick fix tests, for example AssistQuickFixTest
- use spaces, no tabs in example code. Make sure that the example results are in a good format. It doesn't make sense to test for badly indented code... :-)
- Use 'assertExpectedExistInProposals' to test that the StringBuffer proposal is in the list.
- I wouldn't mind to include the StringBuffer tests in AssistQuickFixTest. 

Comment 16 Benjamin Muskalla CLA 2007-11-13 18:44:45 EST
Created attachment 82822 [details]
updated tests

Martin, here are the updated test cases. Any other things to do?
Comment 17 Martin Aeschlimann CLA 2007-11-15 09:52:32 EST
tests released (removed some IMO redundant tests) > 20071115
Thanks Benjamin!

I think we're done with everthibg. If you're interested in adding some improvement, you're welcome!
Interesting could be:

a. 'Convert to MessageFormat' (bug 29562)
   String s= "Hello" + name + "!";
   ->
   MessageFormat.format("Hello {0}!", new Object[] { name });
b. look at multiple assignments
   String s= "Hello"
   s+= " World";
   s= s + "!";

Please open a new bug if you're interested in tackle this.
Comment 18 Mike Haller CLA 2007-11-16 18:04:09 EST
How about support for transforming constructs like
"Foo: " + foo + " and bar is " + bar
into String.format("Foo: %s and bar is %s",foo,bar)
Comment 19 Mohamed ZERGAOUI CLA 2007-11-17 04:44:50 EST
Is this use case which was in Bug 48240 covered ?

<pre>
...
String s = "";
for(int i = 0; i < MAX; i++) {
  switch (i % 3) {
    case 0 :
      s += "a";
      break;
    case 1 :
      s += "b";
      break;
    case 2 :
    default :
      s = "c" + s;   
  }
}
System.out.println(s);
...
</pre>
and when you select "s" and choose the quick assist "convert to StringBuffer"
or "convert to StringBuilder" (for 1.5)
you'll have
<pre>
...
StringBuffer s = new StringBuffer("");
for(int i = 0; i < MAX; i++) {
  switch (i % 3) {
    case 0 :
      s.append("a");
      break;
    case 1 :
      s.append("b");
      break;
    case 2 :
    default :
      s.insert(0, "c");   
  }
}
System.out.println(s);
...
</pre>
Comment 20 Mohamed ZERGAOUI CLA 2007-11-17 04:51:52 EST
Don't need to open a new bug for MessageFormat, it already exists here Bug 29562

May be it should be extended to handle Java 5 java.util.Formatter and by the way java.lang.String.format()
Comment 21 Mohamed ZERGAOUI CLA 2007-11-17 05:13:11 EST
Do you think it is worth adding a getConvertToStringBuilderProposal based on getConvertToStringBufferProposal which could be available for 1.5 and upper ?
Comment 22 Martin Aeschlimann CLA 2007-11-19 04:29:38 EST
Maybe it would make sense to automatically StringBuilder when in 1.5.
The quick assist could set up a the linked mode with proposals where it is possible to choose between StringBuilder and StringBuffer.

I'm fine with adding 1 or two more variants, but I think we should be careful to keep the number of proposals small.
Comment 23 Genady Beryozkin CLA 2007-12-15 18:52:54 EST
IMHO StringBuilder should be used if the lib&class compatibility are 5.0, especially because the compiler internally converts similar concatenations to StringBuilder.
Comment 24 Aaron Digulla CLA 2007-12-18 04:58:25 EST
Re StringBuilder: Either reopen this bug or delete the duplicate mark on bug 154199, to allow to track the "StringBuilder" code assist.