22
22
#include " clang/Analysis/CFG.h"
23
23
#include " clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
24
24
#include " clang/Analysis/FlowSensitive/DataflowEnvironment.h"
25
+ #include " clang/Analysis/FlowSensitive/Formula.h"
25
26
#include " clang/Analysis/FlowSensitive/NoopLattice.h"
26
27
#include " clang/Analysis/FlowSensitive/StorageLocation.h"
27
28
#include " clang/Analysis/FlowSensitive/Value.h"
@@ -234,17 +235,17 @@ auto isComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) {
234
235
hasArgument (1 , rhs_arg_matcher));
235
236
}
236
237
237
- // / Ensures that `Expr` is mapped to a `BoolValue` and returns it .
238
- BoolValue &forceBoolValue (Environment &Env, const Expr &Expr) {
238
+ // / Ensures that `Expr` is mapped to a `BoolValue` and returns its formula .
239
+ const Formula &forceBoolValue (Environment &Env, const Expr &Expr) {
239
240
auto *Value = cast_or_null<BoolValue>(Env.getValue (Expr, SkipPast::None));
240
241
if (Value != nullptr )
241
- return * Value;
242
+ return Value-> formula () ;
242
243
243
244
auto &Loc = Env.createStorageLocation (Expr);
244
245
Value = &Env.makeAtomicBoolValue ();
245
246
Env.setValue (Loc, *Value);
246
247
Env.setStorageLocation (Expr, Loc);
247
- return * Value;
248
+ return Value-> formula () ;
248
249
}
249
250
250
251
// / Sets `HasValueVal` as the symbolic value that represents the "has_value"
@@ -421,15 +422,16 @@ bool isEmptyOptional(const Value &OptionalVal, const Environment &Env) {
421
422
auto *HasValueVal =
422
423
cast_or_null<BoolValue>(OptionalVal.getProperty (" has_value" ));
423
424
return HasValueVal != nullptr &&
424
- Env.flowConditionImplies (Env.makeNot (* HasValueVal));
425
+ Env.flowConditionImplies (Env.arena (). makeNot (HasValueVal-> formula () ));
425
426
}
426
427
427
428
// / Returns true if and only if `OptionalVal` is initialized and known to be
428
429
// / non-empty in `Env`.
429
430
bool isNonEmptyOptional (const Value &OptionalVal, const Environment &Env) {
430
431
auto *HasValueVal =
431
432
cast_or_null<BoolValue>(OptionalVal.getProperty (" has_value" ));
432
- return HasValueVal != nullptr && Env.flowConditionImplies (*HasValueVal);
433
+ return HasValueVal != nullptr &&
434
+ Env.flowConditionImplies (HasValueVal->formula ());
433
435
}
434
436
435
437
Value *getValueBehindPossiblePointer (const Expr &E, const Environment &Env) {
@@ -485,12 +487,11 @@ void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr,
485
487
486
488
// / `ModelPred` builds a logical formula relating the predicate in
487
489
// / `ValueOrPredExpr` to the optional's `has_value` property.
488
- void transferValueOrImpl (const clang::Expr *ValueOrPredExpr,
489
- const MatchFinder::MatchResult &Result,
490
- LatticeTransferState &State,
491
- BoolValue &(*ModelPred)(Environment &Env,
492
- BoolValue &ExprVal,
493
- BoolValue &HasValueVal)) {
490
+ void transferValueOrImpl (
491
+ const clang::Expr *ValueOrPredExpr, const MatchFinder::MatchResult &Result,
492
+ LatticeTransferState &State,
493
+ const Formula &(*ModelPred)(Environment &Env, const Formula &ExprVal,
494
+ const Formula &HasValueVal)) {
494
495
auto &Env = State.Env ;
495
496
496
497
const auto *ObjectArgumentExpr =
@@ -502,37 +503,39 @@ void transferValueOrImpl(const clang::Expr *ValueOrPredExpr,
502
503
if (HasValueVal == nullptr )
503
504
return ;
504
505
505
- Env.addToFlowCondition (
506
- ModelPred (Env, forceBoolValue (Env, *ValueOrPredExpr), * HasValueVal));
506
+ Env.addToFlowCondition (ModelPred (Env, forceBoolValue (Env, *ValueOrPredExpr),
507
+ HasValueVal-> formula () ));
507
508
}
508
509
509
510
void transferValueOrStringEmptyCall (const clang::Expr *ComparisonExpr,
510
511
const MatchFinder::MatchResult &Result,
511
512
LatticeTransferState &State) {
512
513
return transferValueOrImpl (ComparisonExpr, Result, State,
513
- [](Environment &Env, BoolValue &ExprVal,
514
- BoolValue &HasValueVal) -> BoolValue & {
514
+ [](Environment &Env, const Formula &ExprVal,
515
+ const Formula &HasValueVal) -> const Formula & {
516
+ auto &A = Env.arena ();
515
517
// If the result is *not* empty, then we know the
516
518
// optional must have been holding a value. If
517
519
// `ExprVal` is true, though, we don't learn
518
520
// anything definite about `has_value`, so we
519
521
// don't add any corresponding implications to
520
522
// the flow condition.
521
- return Env. makeImplication (Env .makeNot (ExprVal),
522
- HasValueVal);
523
+ return A. makeImplies (A .makeNot (ExprVal),
524
+ HasValueVal);
523
525
});
524
526
}
525
527
526
528
void transferValueOrNotEqX (const Expr *ComparisonExpr,
527
529
const MatchFinder::MatchResult &Result,
528
530
LatticeTransferState &State) {
529
531
transferValueOrImpl (ComparisonExpr, Result, State,
530
- [](Environment &Env, BoolValue &ExprVal,
531
- BoolValue &HasValueVal) -> BoolValue & {
532
+ [](Environment &Env, const Formula &ExprVal,
533
+ const Formula &HasValueVal) -> const Formula & {
534
+ auto &A = Env.arena ();
532
535
// We know that if `(opt.value_or(X) != X)` then
533
536
// `opt.hasValue()`, even without knowing further
534
537
// details about the contents of `opt`.
535
- return Env. makeImplication (ExprVal, HasValueVal);
538
+ return A. makeImplies (ExprVal, HasValueVal);
536
539
});
537
540
}
538
541
@@ -701,8 +704,8 @@ void transferStdForwardCall(const CallExpr *E, const MatchFinder::MatchResult &,
701
704
State.Env .setValue (*LocRet, *ValArg);
702
705
}
703
706
704
- BoolValue &evaluateEquality (Environment &Env, BoolValue &EqVal, BoolValue &LHS ,
705
- BoolValue &RHS) {
707
+ const Formula &evaluateEquality (Arena &A, const Formula &EqVal ,
708
+ const Formula &LHS, const Formula &RHS) {
706
709
// Logically, an optional<T> object is composed of two values - a `has_value`
707
710
// bit and a value of type T. Equality of optional objects compares both
708
711
// values. Therefore, merely comparing the `has_value` bits isn't sufficient:
@@ -717,37 +720,38 @@ BoolValue &evaluateEquality(Environment &Env, BoolValue &EqVal, BoolValue &LHS,
717
720
// b) (!LHS & !RHS) => EqVal
718
721
// If neither is set, then they are equal.
719
722
// We rewrite b) as !EqVal => (LHS v RHS), for a more compact formula.
720
- return Env.makeAnd (
721
- Env.makeImplication (
722
- EqVal, Env.makeOr (Env.makeAnd (LHS, RHS),
723
- Env.makeAnd (Env.makeNot (LHS), Env.makeNot (RHS)))),
724
- Env.makeImplication (Env.makeNot (EqVal), Env.makeOr (LHS, RHS)));
723
+ return A.makeAnd (
724
+ A.makeImplies (EqVal, A.makeOr (A.makeAnd (LHS, RHS),
725
+ A.makeAnd (A.makeNot (LHS), A.makeNot (RHS)))),
726
+ A.makeImplies (A.makeNot (EqVal), A.makeOr (LHS, RHS)));
725
727
}
726
728
727
729
void transferOptionalAndOptionalCmp (const clang::CXXOperatorCallExpr *CmpExpr,
728
730
const MatchFinder::MatchResult &,
729
731
LatticeTransferState &State) {
730
732
Environment &Env = State.Env ;
733
+ auto &A = Env.arena ();
731
734
auto *CmpValue = &forceBoolValue (Env, *CmpExpr);
732
735
if (auto *LHasVal = getHasValue (
733
736
Env, Env.getValue (*CmpExpr->getArg (0 ), SkipPast::Reference)))
734
737
if (auto *RHasVal = getHasValue (
735
738
Env, Env.getValue (*CmpExpr->getArg (1 ), SkipPast::Reference))) {
736
739
if (CmpExpr->getOperator () == clang::OO_ExclaimEqual)
737
- CmpValue = &State. Env .makeNot (*CmpValue);
738
- Env.addToFlowCondition (
739
- evaluateEquality (Env, *CmpValue, *LHasVal, * RHasVal));
740
+ CmpValue = &A .makeNot (*CmpValue);
741
+ Env.addToFlowCondition (evaluateEquality (A, *CmpValue, LHasVal-> formula (),
742
+ RHasVal-> formula () ));
740
743
}
741
744
}
742
745
743
746
void transferOptionalAndValueCmp (const clang::CXXOperatorCallExpr *CmpExpr,
744
747
const clang::Expr *E, Environment &Env) {
748
+ auto &A = Env.arena ();
745
749
auto *CmpValue = &forceBoolValue (Env, *CmpExpr);
746
750
if (auto *HasVal = getHasValue (Env, Env.getValue (*E, SkipPast::Reference))) {
747
751
if (CmpExpr->getOperator () == clang::OO_ExclaimEqual)
748
- CmpValue = &Env .makeNot (*CmpValue);
749
- Env.addToFlowCondition (evaluateEquality (Env, *CmpValue, *HasVal,
750
- Env. getBoolLiteralValue (true )));
752
+ CmpValue = &A .makeNot (*CmpValue);
753
+ Env.addToFlowCondition (
754
+ evaluateEquality (A, *CmpValue, HasVal-> formula (), A. makeLiteral (true )));
751
755
}
752
756
}
753
757
@@ -929,7 +933,7 @@ std::vector<SourceLocation> diagnoseUnwrapCall(const Expr *ObjectExpr,
929
933
if (auto *OptionalVal = getValueBehindPossiblePointer (*ObjectExpr, Env)) {
930
934
auto *Prop = OptionalVal->getProperty (" has_value" );
931
935
if (auto *HasValueVal = cast_or_null<BoolValue>(Prop)) {
932
- if (Env.flowConditionImplies (* HasValueVal))
936
+ if (Env.flowConditionImplies (HasValueVal-> formula () ))
933
937
return {};
934
938
}
935
939
}
@@ -1015,13 +1019,14 @@ bool UncheckedOptionalAccessModel::merge(QualType Type, const Value &Val1,
1015
1019
bool MustNonEmpty1 = isNonEmptyOptional (Val1, Env1);
1016
1020
bool MustNonEmpty2 = isNonEmptyOptional (Val2, Env2);
1017
1021
if (MustNonEmpty1 && MustNonEmpty2)
1018
- MergedEnv.addToFlowCondition (HasValueVal);
1022
+ MergedEnv.addToFlowCondition (HasValueVal. formula () );
1019
1023
else if (
1020
1024
// Only make the costly calls to `isEmptyOptional` if we got "unknown"
1021
1025
// (false) for both calls to `isNonEmptyOptional`.
1022
1026
!MustNonEmpty1 && !MustNonEmpty2 && isEmptyOptional (Val1, Env1) &&
1023
1027
isEmptyOptional (Val2, Env2))
1024
- MergedEnv.addToFlowCondition (MergedEnv.makeNot (HasValueVal));
1028
+ MergedEnv.addToFlowCondition (
1029
+ MergedEnv.arena ().makeNot (HasValueVal.formula ()));
1025
1030
setHasValue (MergedVal, HasValueVal);
1026
1031
return true ;
1027
1032
}
0 commit comments