Set the null state of a PointerValue at a control flow join based on the nullability information from each incoming path.
PiperOrigin-RevId: 466890031
diff --git a/nullability_verification/pointer_nullability_analysis.cc b/nullability_verification/pointer_nullability_analysis.cc
index 12ae2e1..68bb02e 100644
--- a/nullability_verification/pointer_nullability_analysis.cc
+++ b/nullability_verification/pointer_nullability_analysis.cc
@@ -31,6 +31,7 @@
using dataflow::Environment;
using dataflow::MatchSwitchBuilder;
using dataflow::NoopLattice;
+using dataflow::PointerValue;
using dataflow::SkipPast;
using dataflow::TransferState;
using dataflow::Value;
@@ -163,13 +164,58 @@
Transferer(*Stmt, getASTContext(), State);
}
+BoolValue& mergeBoolValues(BoolValue& Bool1, const Environment& Env1,
+ BoolValue& Bool2, const Environment& Env2,
+ Environment& MergedEnv) {
+ if (&Bool1 == &Bool2) {
+ return Bool1;
+ }
+
+ auto& MergedBool = MergedEnv.makeAtomicBoolValue();
+
+ // If `Bool1` and `Bool2` is constrained to the same true / false value,
+ // `MergedBool` can be constrained similarly without needing to consider the
+ // path taken - this simplifies the flow condition tracked in `MergedEnv`.
+ // Otherwise, information about which path was taken is used to associate
+ // `MergedBool` with `Bool1` and `Bool2`.
+ if (Env1.flowConditionImplies(Bool1) && Env2.flowConditionImplies(Bool2)) {
+ MergedEnv.addToFlowCondition(MergedBool);
+ } else if (Env1.flowConditionImplies(Env1.makeNot(Bool1)) &&
+ Env2.flowConditionImplies(Env2.makeNot(Bool2))) {
+ MergedEnv.addToFlowCondition(MergedEnv.makeNot(MergedBool));
+ } else {
+ // TODO(b/233582219): Flow conditions are not necessarily mutually
+ // exclusive, a fix is in order: https://reviews.llvm.org/D130270, update
+ // this section when the patch is commited
+ auto& FC1 = Env1.getFlowConditionToken();
+ auto& FC2 = Env2.getFlowConditionToken();
+ MergedEnv.addToFlowCondition(MergedEnv.makeOr(
+ MergedEnv.makeAnd(FC1, MergedEnv.makeIff(MergedBool, Bool1)),
+ MergedEnv.makeAnd(FC2, MergedEnv.makeIff(MergedBool, Bool2))));
+ }
+ return MergedBool;
+}
+
bool PointerNullabilityAnalysis::merge(QualType Type, const Value& Val1,
const Environment& Env1,
const Value& Val2,
const Environment& Env2,
Value& MergedVal,
Environment& MergedEnv) {
- return false;
+ if (!Type->isAnyPointerType()) {
+ return false;
+ }
+
+ auto [Known1, NotNull1] = getPointerNullState(cast<PointerValue>(Val1), Env1);
+ auto [Known2, NotNull2] = getPointerNullState(cast<PointerValue>(Val2), Env2);
+
+ auto& Known = mergeBoolValues(Known1, Env1, Known2, Env2, MergedEnv);
+ auto& NotNull = mergeBoolValues(NotNull1, Env1, NotNull2, Env2, MergedEnv);
+
+ initPointerNullState(cast<PointerValue>(MergedVal), MergedEnv, &Known,
+ &NotNull);
+
+ return true;
}
} // namespace nullability
} // namespace tidy