Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 350325 - [1.7] String switch statements break conditional breakpoints
Summary: [1.7] String switch statements break conditional breakpoints
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 3.7   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 3.7.1   Edit
Assignee: Michael Rennie CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 349400
  Show dependency tree
 
Reported: 2011-06-24 15:47 EDT by Curtis Windatt CLA
Modified: 2011-07-19 07:42 EDT (History)
4 users (show)

See Also:


Attachments
fix (2.61 KB, patch)
2011-06-27 16:53 EDT, Michael Rennie CLA
no flags Details | Diff
better fix (2.72 KB, patch)
2011-06-27 17:01 EDT, Michael Rennie CLA
no flags Details | Diff
update (2.69 KB, patch)
2011-06-29 13:42 EDT, Michael Rennie CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Curtis Windatt CLA 2011-06-24 15:47:52 EDT
String test = "one";
switch (test) {
case "one":
System.out.println("Accept");
return true;
default:
System.out.println("Fail");
return false;
}

Code such as the following will hit the first case when executed in a java application, but will fall into the default case when used in a conditional breakpoint.
Comment 1 Curtis Windatt CLA 2011-06-24 15:52:08 EDT
This might be something to do with my configuration.  I have the same problems in detail formatters, expressions, etc.
Comment 2 Michael Rennie CLA 2011-06-27 14:21:25 EDT
(In reply to comment #1)
> This might be something to do with my configuration.  I have the same problems
> in detail formatters, expressions, etc.

The problem is coming from our Snippet source generator, we are not correctly detecting that the switch statement is going to return a boolean value, so we end up with the compiled expression as follows:

package a;
public class WatchBug {
  void ___run(  java.lang.String test) throws Throwable {
switch (test) {
case "one":
      System.out.println("Accept");
    return true;
default :
  System.out.println("Fail");
return false;
}
}
Comment 3 Michael Rennie CLA 2011-06-27 16:53:49 EDT
Created attachment 198687 [details]
fix

The problem was actually a bit deeper down in the ASTInstructionCompiler - we had to account for the string literal type in the equals expression to make sure we are comparing the string value rather than the ObjectReference value.
Comment 4 Michael Rennie CLA 2011-06-27 17:01:38 EDT
Created attachment 198688 [details]
better fix

Here is a better fix that also considers the operands equal if their values are null.
Comment 5 Curtis Windatt CLA 2011-06-27 17:20:45 EDT
The patch works well for me, changes seem reasonable.  The patch does not include copyright updates.
Comment 6 Michael Rennie CLA 2011-06-28 11:44:31 EDT
applied fix to the branch (with copyright updates).
Comment 7 Markus Keller CLA 2011-06-28 13:35:13 EDT
This change is not good, since it converts the EqualEqualOperator into an "Object#equals(Object)"-operator.

E.g. the result of this expression was 'false' in 3.7, and that was correct:

    new String("one") == new String("one")


There are 2 caveats with the switch-on-String feature:

1. String comparisons must use equals(Object), not ==. E.g. change comment 0 to use:
    String test = new String("one");

=> works with the patch

2. If the switch expression evaluates to null, the SwitchStatement must throw a NullPointerException. E.g. change comment 0 to use
    String test = null;

=> broken with the patch
Comment 8 Michael Rennie CLA 2011-06-28 16:42:00 EDT
(In reply to comment #7)

> There are 2 caveats with the switch-on-String feature:
> 
> 1. String comparisons must use equals(Object), not ==. E.g. change comment 0 to
> use:
>     String test = new String("one");
> 
> => works with the patch

Prior to this patch the == operator was overloaded to do #equals comparisons when the operands are not IJavaPrimitiveType, so I specialized the operator a bit for comparing strings. We could just as easily push a SendMessage("equals", "()Z", 1, "Ljava.lang.Object", counter) node instead of EqualsEqualsOperator in the switch-on-String case.

> 
> 2. If the switch expression evaluates to null, the SwitchStatement must throw a
> NullPointerException. E.g. change comment 0 to use
>     String test = null;
> 
> => broken with the patch

That makes sense.
Comment 9 Markus Keller CLA 2011-06-29 09:46:28 EDT
> Prior to this patch the == operator was overloaded to do #equals comparisons
> when the operands are not IJavaPrimitiveType [..]

I initially thought the same when I saw
			default :
				equals= leftOperand.equals(rightOperand);

But this only compares IJavaValue objects with equals(..). AFAICS, JDIValue#equals(Object) then uses Value#equals(Object), and that one is implemented by ObjectReferenceImpl#equals(Object), which really compares the JdwpObjectID.

=> I don't think the EqualEqualOperator ever used Object#equals(Object).
Comment 10 Michael Rennie CLA 2011-06-29 13:42:33 EDT
Created attachment 198848 [details]
update

This patch reverts all changes to the EqualsEqualsOperator and properly sends a Object#equals message for comparing the switch cases. If the example is changed in comment #1 to be null, a NullPointerException is now thrown as well.
Comment 11 Michael Rennie CLA 2011-06-29 14:02:35 EDT
applied patch to branch
Comment 12 Ankur Sharma CLA 2011-07-19 07:42:10 EDT
verified in I20110613-1736 with Java7Patch