Bug 560213 - [null] Bogus warning about @NonNullByDefault enum when accessed as BTB
Summary: [null] Bogus warning about @NonNullByDefault enum when accessed as BTB
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.15   Edit
Hardware: PC Mac OS X
: P3 normal (vote)
Target Milestone: 4.15 M3   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords: regression
Depends on:
Blocks:
 
Reported: 2020-02-17 04:29 EST by Till Brychcy CLA
Modified: 2020-02-19 02:17 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Till Brychcy CLA 2020-02-17 04:29:39 EST
Given the following code:

package nullEnumSort;

import java.util.Collections;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;

@NonNullByDefault
public class EnumProblem {
    void f(List<MyEnum> list) {
        Collections.sort(list);
    }
}

----
package nullEnumSort;

import org.eclipse.jdt.annotation.NonNullByDefault;

@NonNullByDefault
enum MyEnum {
    x
}

a bogus warning appears at the "Collections.sort" invocation if EnumProblem is edited and saved (so MyEnum is accessed as BinaryTypeBinding):

Null constraint mismatch: The type '@NonNull MyEnum' is not a valid substitute for the type parameter 'T extends Comparable<? super T>'


happens since 26442c4da93bb37c148503ede232875b5244e58f for bug 482242
Comment 1 Stephan Herrmann CLA 2020-02-17 18:46:27 EST
Thanks for catching. I'll have a look for RC1.

First guess: perhaps s.t. relating to whether or not the implicit "extends Enum<MyEnum>" should annotate that type argument?

In that case bug 482242 would simply bring to light an inconsistency that has always existed?
Comment 2 Michael Keppler CLA 2020-02-18 03:19:13 EST
I'm also seeing this bug several hundred times in production code, since switching to 2020-03 M2. Just saying, so you are aware this is not a corner case, and effectively prohibits upgrading on projects that have null analysis set to severity error.

Not sure if it helps you in the analysis: If the enum is moved as nested class into the caller class (instead of being a top level class itself), then the error goes away. However, in real world code that workaround is not possible in most cases.
Comment 3 Stephan Herrmann CLA 2020-02-18 09:45:55 EST
Observations;

In the source case, type "@NonNull MyEnum" has this superclass:
  - Enum<MyEnum>

In the binary case it's:
  - Enum<@NonNull MyEnum>

The problem detected by NAM.analyse has severity UNCHECKED_TO_UNANNOTATED, so *if* a problem is to be reported, then it should be the new info
   Unsafe null type conversion (type annotations): The value of type 'List<@NonNull MyEnum>' is made accessible using the less-annotated type 'List<MyEnum>'

To check whether the problem is justified, let's try to trigger NPE. E.g.:

@NonNullByDefault
public class EnumProblem {
    void f(List<MyEnum> list) {
    	MyCollections.sort(list);
    }
}

class MyCollections {
    static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.add(null);
    }	
}

Here we succeed to feed 'null' into the list and if subsequently code in f() dereferences list elements without a null check, then we'll see NPE.

Question: do we really need to account for code like "list.add(null);"?

In a recent blog post [1] I argued our warning is kind-of good enough to alert about this problem in unannotated code, at list.add(null) we warn:
    Null type mismatch (type annotations): 'null' is not compatible to the free type variable 'T'

Attempts to declare a variable of type T and assign null to it, will always lead to a warning at least.

I'm ready to believe that the situation is "safe enough".


What's missing in bug 482242 and my blog post: consider type variables as type arguments in the receiving method's signature. Currently, I consider only concrete types and wildcards.


Things to consider:

1. don't let TVB.nullBoundCheck() report when we see UNCHECKED_TO_UNANNOTATED.
   -> simple but possibly incomplete

2. fully integrate TVB as type argument in the solution from bug 482242

3. avoid the difference between source and binary case (regarding annotations within parameterized superclass).

[1] https://objectteams.wordpress.com/2020/02/06/interfacing-null-safe-code-with-legacy-code/
Comment 4 Eclipse Genie CLA 2020-02-18 10:02:47 EST
New Gerrit change created: https://git.eclipse.org/r/157908
Comment 5 Stephan Herrmann CLA 2020-02-18 10:06:25 EST
(In reply to Eclipse Genie from comment #4)
> New Gerrit change created: https://git.eclipse.org/r/157908

This applies option (1) from comment 3, i.e., avoid reporting any new problem (from bug 482242) in this particular situation, thus fixing the regression.

I'm aware that today is test day, but as I'll not be able to work on this tomorrow, I prepared the simplest possible fix today, which I'm planning to release today EOD, unless someone objects.
Comment 7 Stephan Herrmann CLA 2020-02-18 16:44:48 EST
(In reply to Eclipse Genie from comment #6)
> Gerrit change https://git.eclipse.org/r/157908 was merged to [master].
> Commit:
> http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/
> ?id=4ce8fc36a787f1398903447a1816ff5fb4392149

Minimal regression fix released to master for 4.15 M3

Left-over issues have their new home in bug 560296.
Comment 8 Till Brychcy CLA 2020-02-19 02:17:45 EST
Thanks, works!