-
Notifications
You must be signed in to change notification settings - Fork 299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Properly check generic method overriding in explicitly-typed anonymous classes #808
Changes from 93 commits
362ee2f
4a690c2
ac1e7f8
241793d
7c86f30
899f615
90b0c69
74837a1
6e3f2d0
56cddbe
b9d698c
56fb488
304e567
7381c6e
2689a62
5d7e5af
570a03a
7cdb1b8
a2dbade
608f3db
39c6e7d
ac24db5
eb1ecae
3bbd1d6
ee73b04
e56cb12
05782eb
90a4530
a769e30
6630bbf
b33ff48
8500957
250fb68
0593341
68adca8
1298081
fb3f418
e2bd583
40affd0
564c8dc
662606a
3de870c
f7d8dc9
08596f0
97ec62a
8bca16e
242b2e0
631c417
9024a67
be06ff1
87d194a
b364573
bb848fa
55ac129
58dcd9f
1ad0952
7333529
09a2679
d0aa308
12e78ea
2e36bde
83b82fb
bc3b181
254c99a
fee899b
df25816
9582cff
4afd3d9
2e4a0e7
bb94132
aa2bc8c
dc1c5fa
4f6c05b
2521dac
eefe6e2
549146c
033b081
f7e0a87
f266006
9a981dc
3633f7b
d1a50bf
cfdda5f
ef854c4
ed5a7bc
b6c7081
df4d0f7
bcc16c4
2721787
73255af
778447e
af6ca1f
16eb9c2
26085c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
import com.google.errorprone.CompilationTestHelper; | ||
import java.util.Arrays; | ||
import org.junit.Ignore; | ||
import org.junit.Test; | ||
|
||
public class NullAwayJSpecifyGenericsTests extends NullAwayTestsBase { | ||
|
@@ -974,6 +975,163 @@ public void overrideParameterType() { | |
.doTest(); | ||
} | ||
|
||
@Test | ||
public void overrideExplicitlyTypedAnonymousClass() { | ||
makeHelper() | ||
.addSourceLines( | ||
"Test.java", | ||
"package com.uber;", | ||
"import org.jspecify.annotations.Nullable;", | ||
"class Test {", | ||
" interface Fn<P extends @Nullable Object, R extends @Nullable Object> {", | ||
" R apply(P p);", | ||
" }", | ||
" static abstract class FnClass<P extends @Nullable Object, R extends @Nullable Object> {", | ||
" abstract R apply(P p);", | ||
" }", | ||
" static void anonymousClasses() {", | ||
" Fn<@Nullable String, String> fn1 = new Fn<@Nullable String, String>() {", | ||
" // BUG: Diagnostic contains: parameter s is @NonNull, but parameter in superclass method", | ||
" public String apply(String s) { return s; }", | ||
" };", | ||
" FnClass<String, String> fn2 = new FnClass<String, String>() {", | ||
" // BUG: Diagnostic contains: method returns @Nullable, but superclass method", | ||
" public @Nullable String apply(String s) { return null; }", | ||
" };", | ||
" Fn<String, @Nullable String> fn3 = new Fn<String, @Nullable String>() {", | ||
" public @Nullable String apply(String s) { return null; }", | ||
" };", | ||
" FnClass<@Nullable String, String> fn4 = new FnClass<@Nullable String, String>() {", | ||
" public String apply(@Nullable String s) { return \"hello\"; }", | ||
" };", | ||
" }", | ||
" static void anonymousClassesFullName() {", | ||
" Test.Fn<@Nullable String, String> fn1 = new Test.Fn<@Nullable String, String>() {", | ||
" // BUG: Diagnostic contains: parameter s is @NonNull, but parameter in superclass method", | ||
" public String apply(String s) { return s; }", | ||
" };", | ||
" Test.FnClass<String, String> fn2 = new Test.FnClass<String, String>() {", | ||
" // BUG: Diagnostic contains: method returns @Nullable, but superclass method", | ||
" public @Nullable String apply(String s) { return null; }", | ||
" };", | ||
" Test.Fn<String, @Nullable String> fn3 = new Test.Fn<String, @Nullable String>() {", | ||
" public @Nullable String apply(String s) { return null; }", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are both true positive cases on the parameter and both true negatives on the return value? Seems like it might test more combinations to do one each? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
" };", | ||
" Test.FnClass<@Nullable String, String> fn4 = new Test.FnClass<@Nullable String, String>() {", | ||
" public String apply(@Nullable String s) { return \"hello\"; }", | ||
" };", | ||
" }", | ||
"}") | ||
.doTest(); | ||
} | ||
|
||
@Ignore("Need to add support for this case") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's create and link an issue! |
||
@Test | ||
public void overrideAnonymousNestedClass() { | ||
makeHelper() | ||
.addSourceLines( | ||
"Test.java", | ||
"package com.uber;", | ||
"import org.jspecify.annotations.Nullable;", | ||
"class Test {", | ||
" class Wrapper<P extends @Nullable Object> {", | ||
" abstract class Fn<R extends @Nullable Object> {", | ||
" abstract R apply(P p);", | ||
" }", | ||
" }", | ||
" void anonymousNestedClasses() {", | ||
" Wrapper<@Nullable String>.Fn<String> fn1 = (this.new Wrapper<@Nullable String>()).new Fn<String>() {", | ||
" // BUG: Diagnostic contains: parameter s is @NonNull, but parameter in superclass method", | ||
" public String apply(String s) { return s; }", | ||
" };", | ||
" }", | ||
"}") | ||
.doTest(); | ||
} | ||
|
||
@Test | ||
public void explicitlyTypedAnonymousClassAsReceiver() { | ||
makeHelper() | ||
.addSourceLines( | ||
"Test.java", | ||
"package com.uber;", | ||
"import org.jspecify.annotations.Nullable;", | ||
"class Test {", | ||
" interface Fn<P extends @Nullable Object, R extends @Nullable Object> {", | ||
" R apply(P p);", | ||
" }", | ||
" static abstract class FnClass<P extends @Nullable Object, R extends @Nullable Object> {", | ||
" abstract R apply(P p);", | ||
" }", | ||
" static void anonymousClasses() {", | ||
" String s1 = (new Fn<String, @Nullable String>() {", | ||
" public @Nullable String apply(String s) { return null; }", | ||
" }).apply(\"hi\");", | ||
" // BUG: Diagnostic contains: dereferenced expression s1", | ||
" s1.hashCode();", | ||
" String s2 = (new FnClass<String, @Nullable String>() {", | ||
" public @Nullable String apply(String s) { return null; }", | ||
" }).apply(\"hi\");", | ||
" // BUG: Diagnostic contains: dereferenced expression s2", | ||
" s2.hashCode();", | ||
" (new Fn<String, String>() {", | ||
" public String apply(String s) { return \"hi\"; }", | ||
" // BUG: Diagnostic contains: passing @Nullable parameter", | ||
" }).apply(null);", | ||
" (new FnClass<String, String>() {", | ||
" public String apply(String s) { return \"hi\"; }", | ||
" // BUG: Diagnostic contains: passing @Nullable parameter", | ||
" }).apply(null);", | ||
" (new Fn<@Nullable String, String>() {", | ||
" public String apply(@Nullable String s) { return \"hi\"; }", | ||
" }).apply(null);", | ||
" (new FnClass<@Nullable String, String>() {", | ||
" public String apply(@Nullable String s) { return \"hi\"; }", | ||
" }).apply(null);", | ||
" }", | ||
"}") | ||
.doTest(); | ||
} | ||
|
||
/** Diamond anonymous classes are not supported yet; tests are for future reference */ | ||
@Test | ||
public void overrideDiamondAnonymousClass() { | ||
makeHelper() | ||
.addSourceLines( | ||
"Test.java", | ||
"package com.uber;", | ||
"import org.jspecify.annotations.Nullable;", | ||
"class Test {", | ||
" interface Fn<P extends @Nullable Object, R extends @Nullable Object> {", | ||
" R apply(P p);", | ||
" }", | ||
" static abstract class FnClass<P extends @Nullable Object, R extends @Nullable Object> {", | ||
" abstract R apply(P p);", | ||
" }", | ||
" static void anonymousClasses() {", | ||
" Fn<@Nullable String, String> fn1 = new Fn<>() {", | ||
" // TODO: should report a bug here", | ||
" public String apply(String s) { return s; }", | ||
" };", | ||
" FnClass<@Nullable String, String> fn2 = new FnClass<>() {", | ||
" // TODO: should report a bug here", | ||
" public String apply(String s) { return s; }", | ||
" };", | ||
" Fn<String, @Nullable String> fn3 = new Fn<>() {", | ||
" // TODO: this is a false positive", | ||
" // BUG: Diagnostic contains: method returns @Nullable, but superclass method", | ||
" public @Nullable String apply(String s) { return null; }", | ||
" };", | ||
" FnClass<String, @Nullable String> fn4 = new FnClass<>() {", | ||
" // TODO: this is a false positive", | ||
" // BUG: Diagnostic contains: method returns @Nullable, but superclass method", | ||
" public @Nullable String apply(String s) { return null; }", | ||
" };", | ||
" }", | ||
"}") | ||
.doTest(); | ||
} | ||
|
||
@Test | ||
public void nullableGenericTypeVariableReturnType() { | ||
makeHelper() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want a check that the
NewClassTree
is for the same type assymbol
['s supertype]? Or can that be safely assumed to never break?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a test case for when the class name is given as something other than a simple name?
new Foo.Builder<@Nullable String>() { ... }
or evennew Foo<@Nullable String>.Builder() {...}
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a check in af6ca1f; can't hurt :-)
I added some tests in 16eb9c2 but one of them is failing (see
overrideAnonymousNestedClass()
) 😐 I propose I fix that issue in a follow-up; does that sound ok?