From 0474a92c9e77d56ab4e64b96f1bbef1932a7086f Mon Sep 17 00:00:00 2001 From: martinboehme Date: Mon, 11 Dec 2023 14:14:16 +0100 Subject: [PATCH] [clang][dataflow] Convert `SpecialBoolAnalysis` to synthetic fields. (#74706) We're working towards eliminating `RecordValue`; this eliminates one more blocker on that path. --- .../TypeErasedDataflowAnalysisTest.cpp | 78 +++++-------------- 1 file changed, 20 insertions(+), 58 deletions(-) diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index f92afd8c3d84a0..4c3cb322eacfb3 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -514,8 +514,17 @@ TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchReturns) { class SpecialBoolAnalysis final : public DataflowAnalysis { public: - explicit SpecialBoolAnalysis(ASTContext &Context) - : DataflowAnalysis(Context) {} + explicit SpecialBoolAnalysis(ASTContext &Context, Environment &Env) + : DataflowAnalysis(Context) { + Env.getDataflowAnalysisContext().setSyntheticFieldCallback( + [](QualType Ty) -> llvm::StringMap { + RecordDecl *RD = Ty->getAsRecordDecl(); + if (RD == nullptr || RD->getIdentifier() == nullptr || + RD->getName() != "SpecialBool") + return {}; + return {{"is_set", RD->getASTContext().BoolTy}}; + }); + } static NoopLattice initialElement() { return {}; } @@ -530,67 +539,18 @@ class SpecialBoolAnalysis final if (const auto *E = selectFirst( "call", match(cxxConstructExpr(HasSpecialBoolType).bind("call"), *S, getASTContext()))) { - cast(Env.getValue(*E)) - ->setProperty("is_set", Env.getBoolLiteralValue(false)); + Env.setValue(Env.getResultObjectLocation(*E).getSyntheticField("is_set"), + Env.getBoolLiteralValue(false)); } else if (const auto *E = selectFirst( "call", match(cxxMemberCallExpr(callee(cxxMethodDecl(ofClass( SpecialBoolRecordDecl)))) .bind("call"), *S, getASTContext()))) { - auto &ObjectLoc = - *cast(getImplicitObjectLocation(*E, Env)); - - refreshRecordValue(ObjectLoc, Env) - .setProperty("is_set", Env.getBoolLiteralValue(true)); + if (RecordStorageLocation *ObjectLoc = getImplicitObjectLocation(*E, Env)) + Env.setValue(ObjectLoc->getSyntheticField("is_set"), + Env.getBoolLiteralValue(true)); } } - - ComparisonResult compare(QualType Type, const Value &Val1, - const Environment &Env1, const Value &Val2, - const Environment &Env2) override { - const auto *Decl = Type->getAsCXXRecordDecl(); - if (Decl == nullptr || Decl->getIdentifier() == nullptr || - Decl->getName() != "SpecialBool") - return ComparisonResult::Unknown; - - auto *IsSet1 = cast_or_null(Val1.getProperty("is_set")); - auto *IsSet2 = cast_or_null(Val2.getProperty("is_set")); - if (IsSet1 == nullptr) - return IsSet2 == nullptr ? ComparisonResult::Same - : ComparisonResult::Different; - - if (IsSet2 == nullptr) - return ComparisonResult::Different; - - return Env1.proves(IsSet1->formula()) == Env2.proves(IsSet2->formula()) - ? ComparisonResult::Same - : ComparisonResult::Different; - } - - // Always returns `true` to accept the `MergedVal`. - bool merge(QualType Type, const Value &Val1, const Environment &Env1, - const Value &Val2, const Environment &Env2, Value &MergedVal, - Environment &MergedEnv) override { - const auto *Decl = Type->getAsCXXRecordDecl(); - if (Decl == nullptr || Decl->getIdentifier() == nullptr || - Decl->getName() != "SpecialBool") - return true; - - auto *IsSet1 = cast_or_null(Val1.getProperty("is_set")); - if (IsSet1 == nullptr) - return true; - - auto *IsSet2 = cast_or_null(Val2.getProperty("is_set")); - if (IsSet2 == nullptr) - return true; - - auto &IsSet = MergedEnv.makeAtomicBoolValue(); - MergedVal.setProperty("is_set", IsSet); - if (Env1.proves(IsSet1->formula()) && Env2.proves(IsSet2->formula())) - MergedEnv.assume(IsSet.formula()); - - return true; - } }; class JoinFlowConditionsTest : public Test { @@ -602,7 +562,7 @@ class JoinFlowConditionsTest : public Test { AnalysisInputs( Code, ast_matchers::hasName("target"), [](ASTContext &Context, Environment &Env) { - return SpecialBoolAnalysis(Context); + return SpecialBoolAnalysis(Context, Env); }) .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}), /*VerifyResults=*/[&Match](const llvm::StringMap< @@ -650,7 +610,9 @@ TEST_F(JoinFlowConditionsTest, JoinDistinctButProvablyEquivalentValues) { ASSERT_THAT(FooDecl, NotNull()); auto GetFoo = [FooDecl](const Environment &Env) -> const Formula & { - return cast(Env.getValue(*FooDecl)->getProperty("is_set")) + auto *Loc = + cast(Env.getStorageLocation(*FooDecl)); + return cast(Env.getValue(Loc->getSyntheticField("is_set"))) ->formula(); };