-
Notifications
You must be signed in to change notification settings - Fork 13
Support refinement for conditions of comparisons #389
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
2b01a93
58d9302
5ebcb2a
eee0b78
61a9c0e
23f12b4
1d59b43
dc90cb8
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 | ||
|---|---|---|---|---|
| @@ -1,14 +1,18 @@ | ||||
| package checkers.inference.dataflow; | ||||
|
|
||||
| import org.checkerframework.dataflow.analysis.ConditionalTransferResult; | ||||
| import org.checkerframework.dataflow.analysis.RegularTransferResult; | ||||
| import org.checkerframework.dataflow.analysis.TransferInput; | ||||
| import org.checkerframework.dataflow.analysis.TransferResult; | ||||
| import org.checkerframework.dataflow.cfg.node.AssignmentNode; | ||||
| import org.checkerframework.dataflow.cfg.node.EqualToNode; | ||||
| import org.checkerframework.dataflow.cfg.node.FieldAccessNode; | ||||
| import org.checkerframework.dataflow.cfg.node.LocalVariableNode; | ||||
| import org.checkerframework.dataflow.cfg.node.Node; | ||||
| import org.checkerframework.dataflow.cfg.node.NotEqualNode; | ||||
| import org.checkerframework.dataflow.cfg.node.StringConcatenateAssignmentNode; | ||||
| import org.checkerframework.dataflow.cfg.node.TernaryExpressionNode; | ||||
| import org.checkerframework.dataflow.expression.JavaExpression; | ||||
| import org.checkerframework.framework.flow.CFStore; | ||||
| import org.checkerframework.framework.flow.CFTransfer; | ||||
| import org.checkerframework.framework.flow.CFValue; | ||||
|
|
@@ -21,6 +25,7 @@ | |||
| import java.util.Map; | ||||
| import java.util.logging.Logger; | ||||
|
|
||||
| import javax.lang.model.element.AnnotationMirror; | ||||
| import javax.lang.model.type.TypeKind; | ||||
|
|
||||
| import com.sun.source.tree.Tree; | ||||
|
|
@@ -31,6 +36,8 @@ | |||
| import checkers.inference.SlotManager; | ||||
| import checkers.inference.VariableAnnotator; | ||||
| import checkers.inference.model.AnnotationLocation; | ||||
| import checkers.inference.model.ComparisonVariableSlot; | ||||
| import checkers.inference.model.ConstraintManager; | ||||
| import checkers.inference.model.ExistentialVariableSlot; | ||||
| import checkers.inference.model.RefinementVariableSlot; | ||||
| import checkers.inference.model.Slot; | ||||
|
|
@@ -401,4 +408,94 @@ private TransferResult<CFValue, CFStore> storeDeclaration(Node lhs, | |||
| private boolean isDeclarationWithInitializer(AssignmentNode assignmentNode) { | ||||
| return (assignmentNode.getTree().getKind() == Tree.Kind.VARIABLE); | ||||
| } | ||||
|
|
||||
| private void createComparisonVariableSlot(Node node, CFStore thenStore, CFStore elseStore) { | ||||
| // Only create refinement comparison slot for variables | ||||
| // TODO: deal with comparison between more complex expressions | ||||
| Node var = node; | ||||
|
d367wang marked this conversation as resolved.
Outdated
|
||||
| if (node instanceof AssignmentNode) { | ||||
| AssignmentNode a = (AssignmentNode) node; | ||||
| var = a.getTarget(); | ||||
| } | ||||
| if (!(var instanceof LocalVariableNode) && !(var instanceof FieldAccessNode)) { | ||||
| return; | ||||
| } | ||||
| Tree tree = var.getTree(); | ||||
| ConstraintManager constraintManager = InferenceMain.getInstance().getConstraintManager(); | ||||
|
Member
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. I think these are the first constraints that are created by
Author
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. I think it works in either ways. I guess putting constraint creation here is just for convenience. I can move it to
Member
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. Did you get a chance to try whether this is nicer in
Author
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. Not all the constraints are created in
For refinement variables we add the subtype constraints in InferenceVisitor may be because we want to reuse the super method So it makes sense to put the type rule-based constraints in
Author
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. Besides, regarding the comparison variable slot, I think the subtype constraints (compareSlot <: declareType) are not precise. It's more precise to create compareSlot <: typeBeforeComparison, i.e. line 443-446 can be removed. |
||||
| SlotManager slotManager = getInferenceAnalysis().getSlotManager(); | ||||
|
|
||||
| AnnotatedTypeMirror atm = typeFactory.getAnnotatedType(tree); | ||||
|
Member
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. Shouldn't this use
Author
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. We have a problem in getting the declared type using The effect is, A common workaround for this issue in CFI is to use checker-framework-inference/src/checkers/inference/dataflow/InferenceTransfer.java Line 222 in 8a29a0e
Member
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. Thanks for the explanation! Let's try to clean this up with or after #362! |
||||
| Slot slotToRefine = slotManager.getSlot(atm); | ||||
|
|
||||
| // TODO: Understand why there are null slots | ||||
| if (InferenceMain.isHackMode(slotToRefine == null)) { | ||||
| logger.fine("HackMode: slotToRefine is null !"); | ||||
| return; | ||||
| } | ||||
|
|
||||
| if (slotToRefine instanceof RefinementVariableSlot) { | ||||
| slotToRefine = ((RefinementVariableSlot) slotToRefine).getRefined(); | ||||
| assert !(slotToRefine instanceof RefinementVariableSlot); | ||||
| } | ||||
|
|
||||
| AnnotationLocation location = | ||||
| VariableAnnotator.treeToLocation(analysis.getTypeFactory(), tree); | ||||
| // TODO: find out why there are missing location | ||||
| if (InferenceMain.isHackMode(location == AnnotationLocation.MISSING_LOCATION)) { | ||||
| logger.fine("HackMode: create ComparisonVariableSlot on MISSING_LOCATION !"); | ||||
| return; | ||||
| } | ||||
| ComparisonVariableSlot thenSlot = slotManager.createComparisonVariableSlot(location, slotToRefine, true); | ||||
| constraintManager.addSubtypeConstraint(thenSlot, slotToRefine); | ||||
| ComparisonVariableSlot elseSlot = slotManager.createComparisonVariableSlot(location, slotToRefine, false); | ||||
| constraintManager.addSubtypeConstraint(elseSlot, slotToRefine); | ||||
|
|
||||
| if (slotToRefine instanceof VariableSlot) { | ||||
| // ComparisonVariableSlots stores the refined value after comparison, so add it to the "refinedTo" list | ||||
| ((VariableSlot) slotToRefine).getRefinedToSlots().add(thenSlot); | ||||
| ((VariableSlot) slotToRefine).getRefinedToSlots().add(elseSlot); | ||||
| } | ||||
|
|
||||
| AnnotationMirror thenAm = slotManager.getAnnotation(thenSlot); | ||||
| AnnotationMirror elseAm = slotManager.getAnnotation(elseSlot); | ||||
|
|
||||
| // If node is assignment, iterate over lhs; otherwise, just node. | ||||
| JavaExpression rec; | ||||
|
d367wang marked this conversation as resolved.
Outdated
|
||||
| rec = JavaExpression.fromNode(var); | ||||
| thenStore.clearValue(rec); | ||||
| thenStore.insertValue(rec, thenAm); | ||||
| elseStore.clearValue(rec); | ||||
| elseStore.insertValue(rec, elseAm); | ||||
| } | ||||
|
|
||||
| @Override | ||||
| public TransferResult<CFValue, CFStore> visitEqualTo( | ||||
|
Member
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. These only handle equal and not-equal. Shouldn't other comparisons also be handled?
Author
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. Comparison slots are created only when type refinement can be performed. For non-numeric types (general case in CFI), type refinement is only possible when the comparison is Other kinds of comparisons are only applicable for numeric types and can be defined in specific type system, like |
||||
| EqualToNode n, TransferInput<CFValue, CFStore> in) { | ||||
| TransferResult<CFValue, CFStore> result = super.visitEqualTo(n, in); | ||||
| CFStore thenStore = result.getThenStore(); | ||||
| CFStore elseStore = result.getElseStore(); | ||||
|
|
||||
| createComparisonVariableSlot(n.getLeftOperand(), thenStore, elseStore); | ||||
| createComparisonVariableSlot(n.getRightOperand(), thenStore, elseStore); | ||||
|
|
||||
| CFValue newResultValue = | ||||
| getInferenceAnalysis() | ||||
| .createAbstractValue(typeFactory.getAnnotatedType(n.getTree())); | ||||
| return new ConditionalTransferResult<>(newResultValue, thenStore, elseStore); | ||||
| } | ||||
|
|
||||
| @Override | ||||
| public TransferResult<CFValue, CFStore> visitNotEqual( | ||||
| NotEqualNode n, TransferInput<CFValue, CFStore> in) { | ||||
| TransferResult<CFValue, CFStore> result = super.visitNotEqual(n, in); | ||||
| CFStore thenStore = result.getThenStore(); | ||||
| CFStore elseStore = result.getElseStore(); | ||||
|
|
||||
| createComparisonVariableSlot(n.getLeftOperand(), thenStore, elseStore); | ||||
| createComparisonVariableSlot(n.getRightOperand(), thenStore, elseStore); | ||||
|
|
||||
| CFValue newResultValue = | ||||
| analysis.createAbstractValue(typeFactory.getAnnotatedType(n.getTree())); | ||||
| return new ConditionalTransferResult<>(newResultValue, thenStore, elseStore); | ||||
| } | ||||
| } | ||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,7 +31,7 @@ public abstract class VariableSlot extends Slot { | |
| private AnnotationLocation location; | ||
|
|
||
| /** Refinement variables that refine this slot. */ | ||
|
Member
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. What is the motivation for this change? Can you update the javadoc to explain what kinds of VariableSlots to expect?
Member
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. Should the name of the method and field be updated to reflect this change?
Author
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. The comment for this field has been updated. I think the current name |
||
| private final Set<RefinementVariableSlot> refinedToSlots = new HashSet<>(); | ||
| private final Set<VariableSlot> refinedToSlots = new HashSet<>(); | ||
|
|
||
| /** | ||
| * Create a Slot with the given annotation location. | ||
|
|
@@ -53,7 +53,7 @@ public void setLocation(AnnotationLocation location) { | |
| this.location = location; | ||
| } | ||
|
|
||
| public Set<RefinementVariableSlot> getRefinedToSlots() { | ||
| public Set<VariableSlot> getRefinedToSlots() { | ||
| return refinedToSlots; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import ostrusted.qual.OsTrusted; | ||
| import ostrusted.qual.OsUntrusted; | ||
|
|
||
| public class Comparison { | ||
|
|
||
| void foo(@OsUntrusted Object o) { | ||
| if (o == null) { | ||
| bar(o); | ||
|
d367wang marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| @OsTrusted | ||
| Object bar(Object o) { | ||
| // :: fixable-error: (return.type.incompatible) | ||
| return o; | ||
| } | ||
|
|
||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.