-
Notifications
You must be signed in to change notification settings - Fork 11
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
Introduce bottom store to improve dataflow analysis #167
base: master
Are you sure you want to change the base?
Conversation
framework/src/main/java/org/checkerframework/framework/flow/CFAbstractTransfer.java
Show resolved
Hide resolved
…into bottom-store
framework/src/main/java/org/checkerframework/framework/flow/CFAbstractValue.java
Outdated
Show resolved
Hide resolved
…into bottom-store
…into bottom-store
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.
Most of the changes LGTM! 👍
AnnotationMirror guardBy = ((LockAnnotatedTypeFactory) analysis.getTypeFactory()).GUARDEDBY; | ||
AnnotationMirror lockHeld = ((LockAnnotatedTypeFactory) analysis.getTypeFactory()).LOCKHELD; | ||
|
||
return analysis.createAbstractValue(new HashSet<>(Arrays.asList(lockHeld, guardBy)), type); |
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.
new HashSet<>(Arrays.asList(lockHeld, guardBy)
Can we replace it with ImmutableSet.of(...)
? Or should we store these bottom annotations instead of creating a new set each time this method is invoked?
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.
Actually there is a final field bottomAnnos
in the these store classes that represents the set of bottom annotations. That field is initialized in the constructor with AnnotatedTypeFactory.getBottomAnnotations()
.
But LockStore
is special. We can't use the real bottom annotations, so here the getBottomValue
is overriden.
isPolyNullNonNull = false; | ||
isPolyNullNull = false; | ||
this.isPolyNullNull = false; |
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.
Why adding this.
on line 49 while line 48 doesn't have this.
?
|
||
// Is it necessary to consider `x = true ? y : z` | ||
if (parentTree.getKind() == Tree.Kind.CONDITIONAL_EXPRESSION) { | ||
return ((ConditionalExpressionTree) parentTree).getCondition() == tree; |
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.
What if the condition is wrapped by parentheses? For example, (x == true) ? y : z
.
return ((ConditionalExpressionTree) parentTree).getCondition() == tree; | ||
} | ||
|
||
return parentTree.getKind() == Tree.Kind.IF |
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.
This logic may work as expected, but I think it's safer to compare with parentTree.getCondition()
so we know it indeed is a condition.
int @MinLen(10) [] res = arr; | ||
int @MinLen(4) [] res2 = arr; | ||
// :: error: (assignment.type.incompatible) |
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.
These changes make sense, but they also alter the meaning of this test. Should we write a new test case for the merging of @BottomVal
and @MinLen(4)
?
@@ -6,7 +6,6 @@ String testWhile1() { | |||
String ans = "x"; | |||
while (true) { | |||
if (true) { | |||
// :: error: (return.type.incompatible) |
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.
Same issue here: we are removing all occurences of // :: error: (return.type.incompatible)
in this file, and we need some new test cases to cover issue typetools#548.
|
||
class DeadBranch { | ||
|
||
Object foo(@Nullable Object myObj, boolean x) { |
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.
Why do we need boolean x
?
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.
Thanks for pointing out! I need to add another case using x
as the condition.
@@ -23,10 +22,8 @@ public static void Bottom(int @BottomVal [] arg, int @MinLen(4) [] arg2) { | |||
} else { | |||
arr = arg2; | |||
} | |||
// :: error: (assignment.type.incompatible) |
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.
Same issue here: I think we need to test LUB of @BottomVal
and @MinLen(4)
, and LUB of @MinLen(10)
and @MinLen(4)
.
Thank you for the comments @zcai1 |
public abstract S createBottomStore(boolean sequentialSemantics); | ||
|
||
/** | ||
* Get the singleton of the bottom store corresponding to the type. |
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.
... corresponding to the type system
@Override | ||
public S leastUpperBound(S other) { | ||
if (this.isBottom) return other; | ||
if (other != null && other.isBottom) return (S) this; |
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 need to test the nullness of other
here? The dataflow code is nullness-type-safe guaranteed by NullnessChecker, isn't it?
@@ -27,6 +27,11 @@ public KeyForStore createEmptyStore(boolean sequentialSemantics) { | |||
return new KeyForStore(this, sequentialSemantics); | |||
} | |||
|
|||
@Override | |||
public KeyForStore createBottomStore(boolean sequentialSemantics) { | |||
return new KeyForStore(this, sequentialSemantics); |
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.
Maybe just return createEmptyStore(sequentialSemantics)
?
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.
return new KeyForStore(this, sequentialSemantics, true);
"contracts.conditional.postcondition.not.satisfied" // TODO: `if` needs the | ||
// BOTH_TO_THEN treatment that ?: gets. | ||
) | ||
@SuppressWarnings("contracts.conditional.postcondition.not.satisfied") |
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.
add comment for reason for suppressWarning
add another case return true in if and return false in else
* @return ture if the given tree is a condition | ||
*/ | ||
@SuppressWarnings("interning:not.interned") | ||
boolean isCondition(ExpressionTree tree) { |
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.
private
* @param type the input {@link TypeMirror} | ||
* @return the bottom value | ||
*/ | ||
protected V getBottomValue(TypeMirror type) { |
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.
maybe createBottomValue
?
The bottom store has the following properties: