Bug 38393

Summary: bytecode generated for evaluation with parentheses is wrong
Product: [Eclipse Project] JDT Reporter: Chris Tait <chris_tait>
Component: CoreAssignee: Philipe Mulet <philippe_mulet>
Status: VERIFIED FIXED QA Contact:
Severity: normal    
Priority: P3    
Version: 2.1   
Target Milestone: 3.0 M2   
Hardware: PC   
OS: Windows 2000   
Whiteboard:

Description Chris Tait CLA 2003-06-03 19:02:56 EDT
Expression evaluation should occur from left to right, but when parentheses are 
added to the right hand side of an expression, the bytecode generated by the 
JDT dictates that the RHS evaluation is first.

Consider the following java code:
public class EvalTest
{
	private static String n = null;
	
	public static void test1()
	{
		if (n == null || n.equals("") || true)
			System.out.println("null or \"\"");
		else
			System.out.println("other");
	}
	
	public static void test2()
	{
		if (n == null || (n.equals("") || true))  // *** note - extra 
set of parentheses in this line
			System.out.println("null or \"\"");
		else
			System.out.println("other");
	}
	
	public static void main(String[] args)
	{
		System.out.println("test1:");
		test1();
		System.out.println("test2:");
		test2();
	}
}

I would expect both of the above methods to evaluate the 'n == null' test first 
and since that evaluation returns true, they shouldn't evaluate the rest.  If I 
compile the above class using JAVAC then it works that way (the bytecode for 
test1 and test2 are identical).  If I compile it using the eclipse JDT then the 
bytecode for test1 is different to test2.  The test2 bytecode evaluates 
the 'n.equals("")' test first, which generates a NullPointerException.

Here's the bytecode produced by eclipse for the test1 and test2 methods:
Method void test1()
   0 getstatic #11 <Field java.lang.String n>
   3 ifnull 15
   6 getstatic #11 <Field java.lang.String n>
   9 ldc #21 <String "">
  11 invokevirtual #27 <Method boolean equals(java.lang.Object)>
  14 pop
  15 getstatic #33 <Field java.io.PrintStream out>
  18 ldc #35 <String "null or """>
  20 invokevirtual #41 <Method void println(java.lang.String)>
  23 return

Method void test2()
   0 getstatic #11 <Field java.lang.String n>
   3 ldc #21 <String "">
   5 invokevirtual #27 <Method boolean equals(java.lang.Object)>
   8 pop
   9 getstatic #33 <Field java.io.PrintStream out>
  12 ldc #35 <String "null or """>
  14 invokevirtual #41 <Method void println(java.lang.String)>
  17 return
Comment 1 Philipe Mulet CLA 2003-06-05 08:06:30 EDT
Given Java is left associate,

(n == null || n.equals("") || true)

is strictly equivalent to

((n == null || n.equal("")) || true)

however, I agree we have a bug, since in the end it shouldn't make a difference 
on this very example. The nuance however explains why we have this bug in this 
case (and in this case only).
Comment 2 Philipe Mulet CLA 2003-06-05 08:52:57 EDT
Similar defect on:

(n != null && (n.equal("")) && false))


Fix under testing.
Comment 3 Philipe Mulet CLA 2003-06-05 10:46:50 EDT
Fixed (will release after 3.0M1 is declared)
Comment 4 David Audel CLA 2003-07-16 06:50:57 EDT
Verified.