Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 350285 - ASTRewrite destroys formatting on CatchClause#setBody(copyTarget)
Summary: ASTRewrite destroys formatting on CatchClause#setBody(copyTarget)
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: 3.8 M3   Edit
Assignee: Satyam Kandula CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-06-24 11:57 EDT by Markus Keller CLA
Modified: 2011-10-25 05:39 EDT (History)
4 users (show)

See Also:
Olivier_Thomann: review+


Attachments
Proposed patch (9.75 KB, patch)
2011-10-04 01:39 EDT, Satyam Kandula CLA
no flags Details | Diff
Proposed patch (11.21 KB, text/plain)
2011-10-04 22:14 EDT, Satyam Kandula CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2011-06-24 11:57:11 EDT
BETA_JAVA7, but most probably not Java 7 related

The new Quick Fix to convert a multi-catch to separate catch blocks tried to use

    newCatchClause.setBody(
            (Block) rewrite.createCopyTarget(catchClause.getBody()));

in QuickAssistProcessor#getUnrollMultiCatchProposals(..), but this mangled e.g.

public class E {
    void foo() {
        try {
            System.out.println("foo");
        } catch (IllegalArgumentException | NullPointerException ex) {
            ex.printStackTrace();
        }
    }
}

into

    void foo() {
        try {
            System.out.println("foo");
        } catch (IllegalArgumentException ex) {
    ex.printStackTrace();
} catch (NullPointerException ex) {
    ex.printStackTrace();
}
    }

As a workaround, we now copy statement-by-statement, but this should not be necessary, and it can lose comments if they are separated by newlines.

UI tests are in AssistQuickFixTest17.
Comment 1 Olivier Thomann CLA 2011-06-24 13:43:55 EDT
Satyam, please take a look.
Comment 2 Markus Keller CLA 2011-07-07 08:55:15 EDT
I've extracted our workarounds into QuickAssistProcessor#setCatchClauseBody(CatchClause, ASTRewrite, CatchClause).

This would be nice to have for BETA_JAVA7 (though we can also ship 3.7.1 with the workaround).
Comment 3 Markus Keller CLA 2011-09-13 13:08:36 EDT
Bug 110059 is probably a similar problem.
Comment 4 Satyam Kandula CLA 2011-10-04 01:20:26 EDT
(In reply to comment #3)
> Bug 110059 is probably a similar problem.
They are slightly different. 

Reason for this bug: Blocks like catch clauses needs a prefix like try to be given to the formatter to format. Formatter doesn't format the prefix. If the string that follows the prefix lies on the same line, that line is not formatted and thus the indentation will not be correct. 

Reason for bug 110059: In the original string, the line where the blocks starts has an indentation of 4. In the modified string, the line where the block starts has an indentation of 2. Thus, the indentation logic thinks that the code needs to be moved left by 2 and so the problem.
Comment 5 Satyam Kandula CLA 2011-10-04 01:39:50 EDT
Created attachment 204486 [details]
Proposed patch
Comment 6 Satyam Kandula CLA 2011-10-04 01:40:24 EDT
Olivier, Can you please review this patch?
Comment 7 Olivier Thomann CLA 2011-10-04 10:36:26 EDT
I think this goes into the right direction, but I think we should find a way to prevent the iteration over the source more than once (inside isFirstLine(..) and getCurrentLine(..)).
If isFirstLine(..) returns the position inside the current line, this could prevent iterating the same string again to find the same position.
So we should rename it with a name that shows it returns a position and then check that position. If position == 0, then this should be seen as the first line. Doing that, it should not do more work than it used too.
Comment 8 Satyam Kandula CLA 2011-10-04 22:14:56 EDT
Created attachment 204560 [details]
Proposed patch

Here is an improved version. This can be optimized further by calling the formatter only if the line start differs from the previous start. Do you think it is worth?
Comment 9 Satyam Kandula CLA 2011-10-04 22:17:52 EDT
(In reply to comment #8)
> Created attachment 204560 [details]
> Proposed patch
> 
> Here is an improved version. This can be optimized further by calling the
> formatter only if the line start differs from the previous start. Do you think
> it is worth?
Forgot to add - In this patch, I have modified the other place where getCurrentLine() is being called so that getCurrentLine() can be removed.
Comment 10 Olivier Thomann CLA 2011-10-06 16:22:56 EDT
Looks good to me.
Comment 11 Satyam Kandula CLA 2011-10-10 02:52:44 EDT
Thanks Olivier. 
Release the patch in HEAD. 
commit 6e51f9fbccbd96945f6930d913a998a8346308ac
Comment 12 Deepak Azad CLA 2011-10-10 05:19:07 EDT
Not yet perfect :)

Things work nicely in the following case - all exceptions are on one line
-------------------------------------------------------------------------------
	void foo(String s) throws Exception {
		try {
			if (s == null)
				throw new NullPointerException();
			else if (s.length() == 0)
				throw new IllegalArgumentException();
			else
				throw new Exception();
		} catch (NullPointerException | IllegalArgumentException e) {
			e.printStackTrace();
		}
	}
-------------------------------------------------------------------------------

However, in the following case, where all exceptions are not on one line to begin with, the formatting is still bad
-------------------------------------------------------------------------------
	void foo2(String s) throws Exception {
		try {
			if (s == null)
				throw new NullPointerException();
			else if (s.length() == 0)
				throw new IllegalArgumentException();
			else
				throw new Exception();
		} catch (NullPointerException
				| IllegalArgumentException e) {
			e.printStackTrace();
		}
	}
-------------------------------------------------------------------------------

Steps to reproduce
- Uncomment line 1627 in  org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessor.setCatchClauseBody(CatchClause, ASTRewrite, CatchClause)
- Comment lines 1630-1633 in the same method.
- Try 'Use separate catch blocks' quick assist on above mentioned foo2(String)
Comment 13 Satyam Kandula CLA 2011-10-10 06:35:43 EDT
(In reply to comment #12)
This is similar to bug 110059. Hence, I will keep this resolved and fix the other part there.
Comment 14 Srikanth Sankaran CLA 2011-10-25 05:39:08 EDT
(In reply to comment #12)
> Steps to reproduce
> - Uncomment line 1627 in 
> org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessor.setCatchClauseBody(CatchClause,
> ASTRewrite, CatchClause)
> - Comment lines 1630-1633 in the same method.
> - Try 'Use separate catch blocks' quick assist on above mentioned foo2(String)

Thanks for the instructions. 
Verified for 3.8 M3 using build id: N20111022-2000.