Bug 20520 - Refactor - expression detection incorrect
Summary: Refactor - expression detection incorrect
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 2.0 F4   Edit
Assignee: Jerome Lanneluc CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-06-17 17:38 EDT by Peter Burka CLA
Modified: 2002-06-24 04:58 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Burka CLA 2002-06-17 17:38:33 EDT
Build F3

Enter the following class into a Java editor:

1: public class Foo {
2:	public Object foo() {
3:		if ( ((Object)null).toString() == null ) {
4:			return (Object)null;
5:		}
6:		return null;
7:	}
8: }

If you select "(Object)null" on line 3, and choose 'Refactor'->'Extract Local 
Variable', the action complains that "An expression must be selected to 
activate this refactoring.

If you select the same expression on line 4, the refactoring is allowed.

If you select "((Object)null)" on line 3, the refactoring is alos allowed.

All three of these are identical expressions, and should all be permitted.
Comment 1 Jerome Lanneluc CLA 2002-06-18 06:37:27 EDT
Moving to JDT/UI as they own  refactor.
Comment 2 Adam Kiezun CLA 2002-06-18 07:37:58 EDT
AST problem
the ifStatement.toString is as follows

if ((Object)null.toString()==null) {return (Object)null;}

note the missing brackets around (Object)null in the infix (==) expression
the brackets are lost somewhere during AST creation so the code that finds the 
selected expression gets confused
Comment 3 Jerome Lanneluc CLA 2002-06-18 09:19:47 EDT
Adam, why do you need the toString() to be correct? Don't you just need correct 
positions?
Comment 4 Adam Kiezun CLA 2002-06-18 09:30:30 EDT
toString just ilustrates the bug
i do not need it to be correct (it would not hurt but it's P5 for me)

the bug is that a ParenthesizedExpression node is missing around the 
CastExpression node
Comment 5 Olivier Thomann CLA 2002-06-18 09:35:20 EDT
I will investigate.
Comment 6 Adam Kiezun CLA 2002-06-18 09:43:37 EDT
i must've gotten tootoo much sun on my head today: quite naturally, once the 
ParenthesizedExpression is there, there should be no toString problem.
Comment 7 David Audel CLA 2002-06-18 09:50:19 EDT
The problem is in ASTConverter#convert
(org.eclipse.jdt.internal.compiler.ast.Expression 
expression). 'checkForParenthesis' must be done before convert the class cast 
expression.
Comment 8 Olivier Thomann CLA 2002-06-18 10:08:35 EDT
This is not a good fix. Now code like:
  void foo() {
    char x;
    x = (char)3;
  }

doesn't work anymore, because the (char) is converted to a parenthesis
expression. But you are right, the fix is in this area. I think we need to check
if we have a parenthesis AND if the expression is not a cast expression.
I will investigate a fix and I post it very soon.
Comment 9 Olivier Thomann CLA 2002-06-18 11:17:28 EDT
The right fix is to change two things:
1) Instead of:
if (expression instanceof org.eclipse.jdt.internal.compiler.ast.CastExpression) {
return convert((org.eclipse.jdt.internal.compiler.ast.CastExpression) expression);
}
if (checkForParenthesis(expression)) {
  return convertToParenthesizedExpression(expression);
}
it should be:
if (checkForParenthesis(expression)) {
	return convertToParenthesizedExpression(expression);
}
if (expression instanceof org.eclipse.jdt.internal.compiler.ast.CastExpression) {
return convert((org.eclipse.jdt.internal.compiler.ast.CastExpression) expression);
}
You were right for that, David :-).
But in the checkForParenthesis(...) method we should replace:
return (scanner.currentPosition >= end) && (rightParentCount == leftParentCount);
with:
return (scanner.currentPosition > end) && (rightParentCount == leftParentCount);
>= instead of > makes a big difference. This method is supposed to check if an
expression is surrounded with parenthesis. So:
((char) 3) is fine but:
(char) 3 is not.
If you keep the >= both will say they are parenthesis expressions. An expression
is a parenthesis expression iff:
- there is the same number of opening and closing parenthesis
- the first token is a opening parenthesis
- the last token is a closing parenthesis.
The > is checking the last condition. The last token means that the
scanner.currentPosition is beyond the end of the source range. Then the next
token would be an EOF.
I can release this fix if necessary. It is trivial. All regression tests are green.
Comment 10 Philipe Mulet CLA 2002-06-18 19:06:14 EDT
DOM AST is wrong, we should fix it for F4, all the more as it breaks 
refactoring.
Comment 11 Philipe Mulet CLA 2002-06-18 19:19:50 EDT
Olivier - shouldn't rather the AstConverter#checkForParenthesis rather check 
that the last token read before EOF was a closing parenthesis, no matter about 
its position. Your fix is probably ok, but you rely on the fact that the 
scanner will jump out of bounds when reaching EOF, which is more vulnerable IMO.

Something like:

	private boolean checkForParenthesis
(org.eclipse.jdt.internal.compiler.ast.Expression expression) {
		/*
		 * We need to handle multiple parenthesis
		 */
		int start = expression.sourceStart;
		int end = expression.sourceEnd;
		scanner.resetTo(start, end);
		int dangling = 0, token;
		boolean first = true;
		try {
			while (true) {
				token = scanner.getNextToken();
				switch (token) {
					case Scanner.TokenNameLPAREN :
						dangling ++;
						break;
					case Scanner.TokenNameRPAREN :
						if (first) return false;
						dangling --;
						break;
					case Scanner.TokenNameEOF :
						if (first) return false;
						return dangling == 0;
					default :
						if (first) return false;
						if (dangling == 0) return false;
				}
				first = false;
			}
		} catch (InvalidInputException e){
		}
		return false;
	}	
Comment 12 Olivier Thomann CLA 2002-06-19 11:05:47 EDT
If you prefer your code, fine. You can release it.
Comment 13 Olivier Thomann CLA 2002-06-19 11:10:16 EDT
I ran the regression tests with this new version and everything is green.
Comment 14 Erich Gamma CLA 2002-06-20 11:23:58 EDT
Adam, we will get a patch from philippe so that we can run our refactoring test 
suite to get confidence in the fix. 
Comment 15 Philipe Mulet CLA 2002-06-21 06:52:17 EDT
From Adam, regarding to refactoring test suites:

our tests run smoothly
i activated the prevously disabled tests for 
20693 Finding references to variables does not find all occurances 
20520 Refactor - expression detection incorrect 
Comment 16 Philipe Mulet CLA 2002-06-21 07:18:10 EDT
Fix got approved, releasing into 20020621
Comment 17 David Audel CLA 2002-06-24 04:58:23 EDT
Verified.