-
Notifications
You must be signed in to change notification settings - Fork 353
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
Second Phase of RLC inference #6278
Changes from 172 commits
695416d
ab26997
ad74e0b
1f16be4
833231f
22af6f6
2d23295
155ded6
ef2ac88
6a28bfc
617a7c7
8f27be1
e455aa1
3a483f5
2e87329
aae7e30
c48227b
d83eb35
98279da
37cd3e2
9e2cc1a
a958009
f795b0e
7e678fb
d32645e
ee90781
3bd8772
74cfa33
6b9f194
6b787ca
7d85c7f
3b7d062
421cdbc
bd1372e
4993d96
1849e13
7dd793a
6e518fb
e5da11a
6b00ac4
111c0aa
15097e2
c968553
f53afbc
5216a62
885d952
4e9a811
8af4608
da6f840
6f0ad6e
16e9687
51cfa50
3be91db
e32a557
6005941
ae36399
dc24008
29e941e
996cce1
e0cb22b
998c87a
447e1ed
f4eb105
a1eb2c1
39c9961
d4157d0
4911657
1ab7ff1
612ef9d
1299f7a
372cac3
48f5a01
09fb026
2c70b8d
a6e8546
12ee23a
3761941
d7ed3dd
c6a94f1
17b7853
bc0b737
8354a14
36ddd8e
c1c3d7b
f70a11e
94bb05f
a64af88
9ffc0a1
7110866
206643d
f6e82cc
4cda0ed
0bc4ed8
5a57c79
145bb3e
4caab8a
8b6896f
79e2911
041fc0a
2f6d925
bbcc548
d21d164
fa72f43
1793e3f
ca50189
61283f1
cdcb572
a18c47f
5a4c853
39bc3aa
0155950
3f116a1
271d455
beac03b
a4ffad6
a8128d2
233d349
79a6d92
b473dbc
6c254aa
6be4874
06900ac
518a598
74bf6d2
ffc2472
217e105
3ee6e82
3c7d78a
13e16da
8ab8a64
3acf330
80323c3
f3d465c
75f2e84
f089e3c
3a7cfda
2b2cca2
eb9f86f
c03056b
2e3c073
8bfa69c
dd2e68d
8f3debe
8068f05
d2d896b
b33b705
d4128a6
3b39cbb
f80dcde
bf851fc
a0670c1
53e6f05
3011552
67f7b52
1e5499f
29cfb1f
4b64bf4
2ed4210
124f3d0
09d1d4e
7fa1eea
1274c9b
4f46157
fe2554c
e679bfe
4cba487
69d8a42
f650990
9b46a6d
6f38468
5c86c43
8b41fec
db0ed91
7a735cd
d107269
ea65dc4
6f4819d
d8681c0
b4e1b2a
2ba55f1
324e9f6
acc5d3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// This test ensures that the @NotOwning annotation is inferred for the return type of a method if | ||
// it returns a field. | ||
|
||
import org.checkerframework.checker.calledmethods.qual.*; | ||
import org.checkerframework.checker.mustcall.qual.*; | ||
|
||
class AddNotOwning { | ||
|
||
@InheritableMustCall("a") | ||
static class Foo { | ||
void a() {} | ||
} | ||
|
||
static class NonEmptyMustCallFinalField { | ||
final Foo f; // expect owning annotation for this field | ||
|
||
NonEmptyMustCallFinalField() { | ||
// :: warning: (required.method.not.called) | ||
f = new Foo(); | ||
} | ||
|
||
Foo getField() { | ||
return f; | ||
} | ||
|
||
Foo getFieldOnSomePath() { | ||
if (true) { | ||
return null; | ||
} else { | ||
return f; | ||
} | ||
} | ||
|
||
void testNotOwningOnFinal() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = getField(); | ||
} | ||
|
||
void testNotOwningOnGetFieldOnSomePath() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = getFieldOnSomePath(); | ||
} | ||
|
||
@EnsuresCalledMethods( | ||
value = {"this.f"}, | ||
methods = {"a"}) | ||
void dispose() { | ||
f.a(); | ||
} | ||
} | ||
|
||
@InheritableMustCall("dispose") | ||
static class NonEmptyMustCallNonFinalField { | ||
Foo f; // expect owning annotation for this field | ||
|
||
@SuppressWarnings("missing.creates.mustcall.for") | ||
void initialyzeFoo() { | ||
f.a(); | ||
// :: warning: (required.method.not.called) | ||
f = new Foo(); | ||
} | ||
|
||
Foo getField() { | ||
return f; | ||
} | ||
|
||
Foo getFieldOnSomePath() { | ||
if (true) { | ||
return null; | ||
} else { | ||
return f; | ||
} | ||
} | ||
|
||
void testNotOwningOnNonFinal() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = getField(); | ||
} | ||
|
||
void testNotOwningOnGetFieldOnSomePath() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = getFieldOnSomePath(); | ||
} | ||
|
||
@EnsuresCalledMethods( | ||
value = {"this.f"}, | ||
methods = {"a"}) | ||
void dispose() { | ||
f.a(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// This test ensures that the @MustCallAlias annotation is not inferred when the enclosing class has | ||
// more than one owning field. | ||
|
||
import org.checkerframework.checker.calledmethods.qual.*; | ||
import org.checkerframework.checker.mustcall.qual.*; | ||
|
||
class ClassWithTwoOwningFieldsTest { | ||
@InheritableMustCall("a") | ||
static class Foo { | ||
void a() {} | ||
} | ||
|
||
@InheritableMustCall("close") | ||
private class ClassWithTwoOwningFields { | ||
// :: warning: (required.method.not.called) | ||
final @Owning Foo foo1; | ||
// :: warning: (required.method.not.called) | ||
final @Owning Foo foo2; | ||
|
||
public ClassWithTwoOwningFields(Foo f1, Foo f2) { | ||
foo1 = f1; | ||
foo2 = f2; | ||
} | ||
|
||
void close() { | ||
foo1.a(); | ||
foo2.a(); | ||
} | ||
} | ||
|
||
void testTwoOwning() { | ||
// :: warning: (required.method.not.called) | ||
Foo f1 = new Foo(); | ||
// :: warning: (required.method.not.called) | ||
Foo f2 = new Foo(); | ||
|
||
ClassWithTwoOwningFields ff = new ClassWithTwoOwningFields(f1, f2); | ||
ff.close(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// @skip-test until we have support for adding annotation on the receiver parameter. | ||
|
||
import java.io.*; | ||
import org.checkerframework.checker.calledmethods.qual.*; | ||
import org.checkerframework.checker.mustcall.qual.*; | ||
|
||
@InheritableMustCall("close") | ||
public class MustCallAliasOnReceiver { | ||
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 is this test called 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. Right now we don't have support adding |
||
|
||
final @Owning InputStream is; | ||
|
||
@MustCallAlias MustCallAliasOnReceiver(@MustCallAlias InputStream p, boolean b) { | ||
this.is = p; | ||
} | ||
|
||
MustCallAliasOnReceiver returnReceiver(MustCallAliasOnReceiver this) { | ||
return this; | ||
} | ||
|
||
// :: warning: (required.method.not.called) | ||
void testReceiverMCAAnnotation(@Owning InputStream inputStream) throws IOException { | ||
MustCallAliasOnReceiver mcar = new MustCallAliasOnReceiver(is, false); | ||
mcar.returnReceiver().close(); | ||
} | ||
|
||
@EnsuresCalledMethods(value = "this.is", methods = "close") | ||
public void close() throws IOException { | ||
this.is.close(); | ||
} | ||
|
||
public static MustCallAliasOnReceiver mcaneFactory(InputStream is) { | ||
return new MustCallAliasOnReceiver(is, false); | ||
} | ||
|
||
// :: warning: (required.method.not.called) | ||
public static void testUse(@Owning InputStream inputStream) throws Exception { | ||
MustCallAliasOnReceiver mcane = mcaneFactory(inputStream); | ||
mcane.close(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// This test ensures that the all-paths condition for inferring the @MustCallAlias annotation is | ||
// restricted to the examination of 'Regular' paths. | ||
|
||
import java.io.IOException; | ||
import org.checkerframework.checker.calledmethods.qual.*; | ||
import org.checkerframework.checker.mustcall.qual.*; | ||
|
||
class MustCallAliasOnRegularExits { | ||
|
||
@InheritableMustCall("a") | ||
static class Foo { | ||
void a() {} | ||
|
||
int b() throws IOException { | ||
return 0; | ||
} | ||
} | ||
|
||
private class MCAConstructor extends Foo { | ||
|
||
protected final @Owning Foo f; | ||
protected long s = 0L; | ||
|
||
// The Must Call Checker for assigning @MustCallAlias parameters to @Owning fields reports a | ||
// false positive. | ||
@SuppressWarnings("assignment") | ||
protected MCAConstructor(Foo foo) throws IOException { | ||
if (foo == null) { | ||
this.s = foo.b(); | ||
} | ||
this.f = foo; | ||
} | ||
|
||
@EnsuresCalledMethods( | ||
value = {"this.f"}, | ||
methods = {"a"}) | ||
public void a() { | ||
f.a(); | ||
} | ||
} | ||
|
||
void testMCAOnMCAConstructor() { | ||
Foo f = new Foo(); | ||
try { | ||
// :: warning: (required.method.not.called) | ||
MCAConstructor mcaf = new MCAConstructor(f); | ||
} catch (IOException e) { | ||
} finally { | ||
f.a(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// This test examines all scenarios for inferring the @MustCallAlias annotation. | ||
|
||
import org.checkerframework.checker.calledmethods.qual.*; | ||
import org.checkerframework.checker.mustcall.qual.*; | ||
|
||
class MustCallAliasParams { | ||
|
||
@InheritableMustCall("a") | ||
static class Foo { | ||
void a() {} | ||
} | ||
|
||
@InheritableMustCall("a") | ||
private class MCAConstructor { | ||
|
||
final @Owning Foo f; | ||
|
||
// The Must Call Checker for assigning @MustCallAlias parameters to @Owning fields reports a | ||
// false positive. | ||
@SuppressWarnings("assignment") | ||
MCAConstructor(Foo foo) { | ||
f = foo; | ||
} | ||
|
||
@EnsuresCalledMethods( | ||
value = {"this.f"}, | ||
methods = {"a"}) | ||
public void a() { | ||
f.a(); | ||
} | ||
} | ||
|
||
void testMCAConstructor() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = new Foo(); | ||
MCAConstructor mcac = new MCAConstructor(f); | ||
mcac.a(); | ||
} | ||
|
||
@InheritableMustCall("a") | ||
private class MCASuperClass { | ||
int i; | ||
final @Owning Foo f; | ||
|
||
// The Must Call Checker for assigning @MustCallAlias parameters to @Owning fields reports a | ||
// false positive. | ||
@SuppressWarnings("assignment") | ||
@MustCallAlias MCASuperClass(@MustCallAlias Foo foo, int i) { | ||
f = foo; | ||
i = i; | ||
} | ||
|
||
@EnsuresCalledMethods( | ||
value = {"this.f"}, | ||
methods = {"a"}) | ||
public void a() { | ||
f.a(); | ||
} | ||
} | ||
|
||
private class MCASuperCall extends MCASuperClass { | ||
MCASuperCall(Foo foo) { | ||
super(foo, 1); | ||
} | ||
} | ||
|
||
void mCASuperCallTest() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = new Foo(); | ||
MCASuperCall mcaSuperCall = new MCASuperCall(f); | ||
mcaSuperCall.a(); | ||
} | ||
|
||
private class MCAThisCall extends MCASuperClass { | ||
@MustCallAlias MCAThisCall(@MustCallAlias Foo foo) { | ||
super(foo, 1); | ||
} | ||
|
||
MCAThisCall(Foo foo, boolean b) { | ||
this(foo); | ||
} | ||
} | ||
|
||
void mCAThisCallTest() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = new Foo(); | ||
MCAThisCall mcaThisCall = new MCAThisCall(f, true); | ||
mcaThisCall.a(); | ||
} | ||
|
||
private class MCAMethod { | ||
Foo returnFoo(Foo foo) { | ||
return foo; | ||
} | ||
|
||
void returnFooTest() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = new Foo(); | ||
Foo foo = returnFoo(f); | ||
foo.a(); | ||
} | ||
|
||
Foo returnAliasFoo(Foo foo) { | ||
Foo f = foo; | ||
return f; | ||
} | ||
|
||
MCASuperClass returnAliasFoo2(Foo foo, int i) { | ||
MCASuperClass f = new MCASuperClass(foo, i); | ||
return f; | ||
} | ||
|
||
void testReturnAliasFoo2() { | ||
// :: warning: (required.method.not.called) | ||
Foo foo = new Foo(); | ||
MCASuperClass f = returnAliasFoo2(foo, 0); | ||
f.a(); | ||
} | ||
|
||
void returnAliasFooTest() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = new Foo(); | ||
Foo foo = returnAliasFoo(f); | ||
foo.a(); | ||
} | ||
|
||
Foo returnFooAllPaths(Foo foo) { | ||
if (true) { | ||
Foo f = foo; | ||
return f; | ||
} else { | ||
return foo; | ||
} | ||
} | ||
|
||
void returnFooAllPathsTest() { | ||
// :: warning: (required.method.not.called) | ||
Foo f = new Foo(); | ||
Foo foo = returnFooAllPaths(f); | ||
foo.a(); | ||
} | ||
|
||
Foo returnFooSomePath(Foo foo) { | ||
if (true) { | ||
Foo f = new Foo(); | ||
return f; | ||
} else { | ||
return foo; | ||
} | ||
} | ||
|
||
void returnFooSomePathTest() { | ||
Foo f = new Foo(); | ||
Foo foo = returnFooSomePath(f); | ||
f.a(); | ||
foo.a(); | ||
} | ||
} | ||
} |
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.
For all these tests in the
non-annotated
folder it's unclear to me what is being tested. Can you explain how these tests work, or is it documented somewhere?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.
It's documented here: https://github.com/typetools/checker-framework/blob/master/checker/tests/ainfer-README
That document describes the "TestChecker", but for these tests the same process is used with the RLC instead. This README is also symlinked from the ainfer-resourceleak/ directory.