Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 128861

Summary: [compiler][null][correlation] variables correlation (lack of)
Product: [Eclipse Project] JDT Reporter: Eugene Kuleshov <ekuleshov>
Component: CoreAssignee: Ayushman Jain <amj87.iitr>
Status: CLOSED DUPLICATE QA Contact:
Severity: enhancement    
Priority: P5 CC: bugzilla, stephan.herrmann
Version: 3.2Keywords: helpwanted
Target Milestone: 4.7 M1   
Hardware: PC   
OS: All   
Whiteboard:

Description Eugene Kuleshov CLA 2006-02-21 13:28:54 EST
Null reference analyzer in 3.2M5 reports that variables o1 and o2 may be null in the following code (last conditional branch).

    public int compare(Object o1, Object o2) {
      int rv = 0;
      if (o1 == null && o2 != null) {
        rv = -1;
      } else if (o1 == null && o2 == null) {
        rv = 0;
      } else if (o1 != null && o2 == null) {
        rv = 1;
      } else {
        int lhs = ((ExecutionCacheStatistics) o1).numHits();  // may be null
        int rhs = ((ExecutionCacheStatistics) o2).numHits();
        rv = lhs - rhs;
      }
      return rv;
    }

The same false positive reported if retun is used in first 3 conditional branches.
Comment 1 Eugene Kuleshov CLA 2006-02-22 16:46:09 EST
Here is another case for false positives:

  private void aa() {
    Object o = null;
    while(o==null) {
      o = getSomething();
      if (o != null) return;
    }
  }

  private Object getSomething() {
    return null;
  }

Variable o in "while" condition reported as "can only be null", but it is too general assumption because method getSomething() can return different values on every next call (especially ifhere is some multithreading envolved).
Comment 2 Maxime Daniel CLA 2006-02-23 01:28:59 EST
(In reply to comment #1)
> Here is another case for false positives:
>   private void aa() {
>     Object o = null;
>     while(o==null) {
>       o = getSomething();
>       if (o != null) return;
>     }
>   }
>   private Object getSomething() {
>     return null;
>   }
> Variable o in "while" condition reported as "can only be null", but it is too
> general assumption because method getSomething() can return different values on
> every next call (especially ifhere is some multithreading envolved).
But whenever getSomething returns a non null, you return, never seing the while condition again. Which implies that o is always null when you hit the while condition.

Comment 3 Eugene Kuleshov CLA 2006-02-23 01:34:10 EST
(In reply to comment #2)
> But whenever getSomething returns a non null, you return, never seing the while
> condition again. Which implies that o is always null when you hit the while
> condition.

The thing is that getSomething() could return null on first call and non-null on a second. You ca'nt assume that getSomething() always return the same value. Such assumption probably would work for if statement but here is a "while" loop.
Comment 4 Maxime Daniel CLA 2006-02-23 01:42:49 EST
(In reply to comment #3)
> (In reply to comment #2)
> The thing is that getSomething() could return null on first call and non-null
> on a second. You ca'nt assume that getSomething() always return the same value.
> Such assumption probably would work for if statement but here is a "while"
> loop.

Because of the return, there is a twist though.
Stepping through it with null, then non null results, numbering the lines as:
1    Object o = null;
2    while(o==null) {
3      o = getSomething();
4      if (o != null) return;
5    }
6

start at line 1, set o to null
2 - o is null, goto 3
3 - o gets null per first call
4 - o is null, goto 5
5 - goto 2
2 - o is null, goto 3
3 - o gets non null per second call
4 - o is non null, return

Hence line 3 always sees o as null... or do I miss something?
Comment 5 Eugene Kuleshov CLA 2006-02-23 01:49:50 EST
(In reply to comment #4)
> Because of the return, there is a twist though.
> Stepping through it with null, then non null results, numbering the lines as:
> 1    Object o = null;
> 2    while(o==null) {
> 3      o = getSomething();
> 4      if (o != null) return;
> 5    }
> 6
> 
> start at line 1, set o to null
> 2 - o is null, goto 3
> 3 - o gets null per first call
> 4 - o is null, goto 5
> 5 - goto 2
> 2 - o is null, goto 3
> 3 - o gets non null per second call
> 4 - o is non null, return
> 
> Hence line 3 always sees o as null... or do I miss something?

Ahh. I see what are you mean. The condition in a where clasuse could be replaced with "true". So, it would be nice if error message would try to point that out. It should probably say that "condition is always true" or something like that.
Comment 6 Eugene Kuleshov CLA 2006-02-23 16:38:56 EST
Here is another one I don't understand.

  private void aa() {
    for(int i = 0; i < 10; i++) {
      String s = get();
      if(s != null) {
        for(int j = 0; j < 1; j++) {
          break;
        }
        s.length();
      }
    }
  }

  private String get() {
    return null;
  }

Eclipse is reporting "The variable s may be null" at s.lenght() and it seems has something todo with "break"...
Comment 7 Maxime Daniel CLA 2006-02-24 01:12:10 EST
Reproduced. Would you please file a separate bug?
Comment 8 Eugene Kuleshov CLA 2006-02-24 12:09:08 EST
(In reply to comment #7)
> Reproduced. Would you please file a separate bug?

Here it is https://bugs.eclipse.org/bugs/show_bug.cgi?id=129371
Comment 9 Maxime Daniel CLA 2006-03-22 04:40:37 EST
Coming back to the initial description.
Avoiding the false reports would involve variables correlation, which is not in scope for 3.2. We may consider this again afterwards.

A workaround gets rid of the extraneous messages though:
    public int compare(Object o1, Object o2) {
      int rv = 0;
      if (o1 == null && o2 == null) {
        rv = 0;
      } else if (o1 == null) { // o2 != null implied
        rv = -1;
      } else if (o2 == null) { // o1 != null implied
        rv = 1;
      } else {
        int lhs = ((ExecutionCacheStatistics) o1).numHits();
        int rhs = ((ExecutionCacheStatistics) o2).numHits();
        rv = lhs - rhs;
      }
      return rv;
    }

Added NullReferenceTest #337 (that won't pass until we implement variables correlation) and #338 (workaround).
Comment 10 Maxime Daniel CLA 2007-06-19 08:06:15 EDT
Reopening as P5 (since RESOLVED LATER is deprecated).
Comment 11 Rob Prime CLA 2008-08-17 15:28:59 EDT
I encountered another similar problem in Ganymedes yesterday.

InputStream is = new FileInputStream(file);
ZipInputStream zis = new ZipInputStream(is);
Database database = null;
try
{
    database = getDatabaseConnection(); // can throw SQLException, but not return null
    ZipEntry entry;
    while ((entry = zis.getNextEntry()) != null) // can throw IOException
    {
        String name = entry.getName();
        if (name.toLowerCase().endsWith(".csv"))
        {
            name = name.substring(0, name.length() - 4);
        }
        IVRTable table = (IVRTable)tables.get(name);
        if (table == null)
        {
            throw new IOException(name + " is not a valid table");
        }
        table.open(zis); // can throw IOException
        database.deleteAll(table); // can throw SQLException
        database.insertAll(table); // can throw SQLException and IOException
    }
    database.commit(); // can throw SQLException
}
catch (IOException e)
{
    if (database != null) // PROBLEM!! according to Eclipse, database is always null
    {
        database.rollback();
    }
    throw e;
}
catch (SQLException e)
{
    if (database != null)
    {
        database.rollback();
    }
    throw e;
}
finally
{
    if (database != null)
    {
        database.disconnect();
    }
    zis.close();
}

Now I've checked this for 15 minutes, but I'm quite possitive that at that position, database will in fact never be null if getDatabaseConnection() never returns null. If not, it can both be null and non-null, so the check is valid.
See also the reply by Mark Vedder in this thread at JavaRanch:
http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=33&t=027838&p=1
Comment 12 Stephan Herrmann CLA 2016-06-28 17:17:10 EDT
Bulk closing all compiler bugs tagged [null][correlation], because we have no plans to add such a feature: it would be a tremendous implementation effort, beyond our current man power, and may be impossible to achieve within the desired performance bounds.

If s.o. has a viable strategy or even implementation for such a feature, I'm all ears.
Comment 13 Sasikanth Bharadwaj CLA 2016-08-02 04:43:02 EDT
Verified for 4.7 M1
Comment 14 Stephan Herrmann CLA 2018-08-30 10:37:02 EDT
I created a new umbrella RFE outlining what would be needed to address this issue.

*** This bug has been marked as a duplicate of bug 538421 ***