diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -57,6 +57,21 @@ namespace test { +/// Returns the environment at the program point marked with `Annotation` from +/// the mapping of annotated program points to analysis state. +/// +/// Requirements: +/// +/// `Annotation` must be present as a key in `AnnotationStates`. +template +const Environment &getEnvironmentAtAnnotation( + const llvm::StringMap> &AnnotationStates, + llvm::StringRef Annotation) { + auto It = AnnotationStates.find(Annotation); + assert(It != AnnotationStates.end()); + return It->getValue().Env; +} + /// Contains data structures required and produced by a dataflow analysis run. struct AnalysisOutputs { /// Input code that is analyzed. Points within the code may be marked with diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -24,8 +24,10 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include "llvm/Testing/ADT/StringMapEntry.h" #include "llvm/Testing/Support/Error.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -42,12 +44,10 @@ using namespace dataflow; using namespace test; using namespace ast_matchers; -using ::testing::_; -using ::testing::ElementsAre; +using llvm::IsStringMapEntry; +using ::testing::DescribeMatcher; using ::testing::IsEmpty; -using ::testing::IsNull; using ::testing::NotNull; -using ::testing::Pair; using ::testing::Test; using ::testing::UnorderedElementsAre; @@ -130,7 +130,8 @@ } struct FunctionCallLattice { - llvm::SmallSet CalledFunctions; + using FunctionSet = llvm::SmallSet; + FunctionSet CalledFunctions; bool operator==(const FunctionCallLattice &Other) const { return CalledFunctions == Other.CalledFunctions; @@ -197,16 +198,24 @@ ASSERT_THAT_ERROR( test::checkDataflow( - Code, "target", - [](ASTContext &C, Environment &) { - return FunctionCallAnalysis(C); + /*AI:AnalysisInputs=*/ + { + .Code = Code, + .TargetFuncMatcher = ast_matchers::hasName("target"), + .MakeAnalysis = + [](ASTContext &C, Environment &) { + return FunctionCallAnalysis(C); + }, + .ASTBuildArgs = {"-fsyntax-only", "-std=c++17"}, + .ASTBuildVirtualMappedFiles = FilesContents, }, + /*VerifyResults=*/ [&Expectations]( - llvm::ArrayRef>> - Results, - ASTContext &) { EXPECT_THAT(Results, Expectations); }, - {"-fsyntax-only", "-std=c++17"}, FilesContents), + const llvm::StringMap< + DataflowAnalysisState> &Results, + const AnalysisOutputs &) { + EXPECT_THAT(Results, Expectations); + }), llvm::Succeeded()); } }; @@ -214,12 +223,16 @@ MATCHER_P(HoldsFunctionCallLattice, m, ((negation ? "doesn't hold" : "holds") + llvm::StringRef(" a lattice element that ") + - ::testing::DescribeMatcher(m, negation)) + DescribeMatcher(m)) .str()) { return ExplainMatchResult(m, arg.Lattice, result_listener); } -MATCHER_P(HasCalledFunctions, m, "") { +MATCHER_P(HasCalledFunctions, m, + ((negation ? "doesn't hold" : "holds") + + llvm::StringRef(" a set of called functions that ") + + DescribeMatcher(m)) + .str()) { return ExplainMatchResult(m, arg.CalledFunctions, result_listener); } @@ -233,9 +246,9 @@ // [[p]] } )"; - runDataflow(Code, UnorderedElementsAre( - Pair("p", HoldsFunctionCallLattice(HasCalledFunctions( - UnorderedElementsAre("foo", "bar")))))); + runDataflow(Code, UnorderedElementsAre(IsStringMapEntry( + "p", HoldsFunctionCallLattice(HasCalledFunctions( + UnorderedElementsAre("foo", "bar")))))); } TEST_F(NoreturnDestructorTest, ConditionalOperatorLeftBranchReturns) { @@ -248,9 +261,9 @@ // [[p]] } )"; - runDataflow(Code, UnorderedElementsAre( - Pair("p", HoldsFunctionCallLattice(HasCalledFunctions( - UnorderedElementsAre("foo")))))); + runDataflow(Code, UnorderedElementsAre(IsStringMapEntry( + "p", HoldsFunctionCallLattice(HasCalledFunctions( + UnorderedElementsAre("foo")))))); } TEST_F(NoreturnDestructorTest, ConditionalOperatorRightBranchReturns) { @@ -263,9 +276,9 @@ // [[p]] } )"; - runDataflow(Code, UnorderedElementsAre( - Pair("p", HoldsFunctionCallLattice(HasCalledFunctions( - UnorderedElementsAre("foo")))))); + runDataflow(Code, UnorderedElementsAre(IsStringMapEntry( + "p", HoldsFunctionCallLattice(HasCalledFunctions( + UnorderedElementsAre("foo")))))); } TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchesDoNotReturn) { @@ -292,9 +305,9 @@ // [[p]] } )"; - runDataflow(Code, UnorderedElementsAre( - Pair("p", HoldsFunctionCallLattice(HasCalledFunctions( - UnorderedElementsAre("baz", "foo")))))); + runDataflow(Code, UnorderedElementsAre(IsStringMapEntry( + "p", HoldsFunctionCallLattice(HasCalledFunctions( + UnorderedElementsAre("baz", "foo")))))); // FIXME: Called functions at point `p` should contain only "foo". } @@ -388,16 +401,21 @@ void runDataflow(llvm::StringRef Code, Matcher Match) { ASSERT_THAT_ERROR( test::checkDataflow( - Code, "target", - [](ASTContext &Context, Environment &Env) { - return SpecialBoolAnalysis(Context); + /*AI:AnalysisInputs=*/ + { + .Code = Code, + .TargetFuncMatcher = ast_matchers::hasName("target"), + .MakeAnalysis = + [](ASTContext &Context, Environment &Env) { + return SpecialBoolAnalysis(Context); + }, + .ASTBuildArgs = {"-fsyntax-only", "-std=c++17"}, }, - [&Match]( - llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { Match(Results, ASTCtx); }, - {"-fsyntax-only", "-std=c++17"}), + /*VerifyResults=*/[&Match](const llvm::StringMap< + DataflowAnalysisState> + &Results, + const AnalysisOutputs + &AO) { Match(Results, AO.ASTCtx); }), llvm::Succeeded()); } }; @@ -424,16 +442,15 @@ } )"; runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _), - Pair("p3", _), Pair("p4", _))); - const Environment &Env1 = Results[0].second.Env; - const Environment &Env2 = Results[1].second.Env; - const Environment &Env3 = Results[2].second.Env; - const Environment &Env4 = Results[3].second.Env; + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), + UnorderedElementsAre("p1", "p2", "p3", "p4")); + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); + const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4"); const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); @@ -539,20 +556,26 @@ }; )")); ASSERT_THAT_ERROR( - test::checkDataflow( - Code, "target", - [this](ASTContext &Context, Environment &Env) { - assert(HasValueTop == nullptr); - HasValueTop = - &Env.takeOwnership(std::make_unique()); - return OptionalIntAnalysis(Context, *HasValueTop); + checkDataflow( + /*AI:AnalysisInputs=*/ + { + .Code = Code, + .TargetFuncMatcher = ast_matchers::hasName("target"), + .MakeAnalysis = + [this](ASTContext &Context, Environment &Env) { + assert(HasValueTop == nullptr); + HasValueTop = &Env.takeOwnership( + std::make_unique()); + return OptionalIntAnalysis(Context, *HasValueTop); + }, + .ASTBuildArgs = {"-fsyntax-only", "-std=c++17"}, + .ASTBuildVirtualMappedFiles = FilesContents, }, - [&Match]( - llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { Match(Results, ASTCtx); }, - {"-fsyntax-only", "-std=c++17"}, FilesContents), + /*VerifyResults=*/[&Match](const llvm::StringMap< + DataflowAnalysisState> + &Results, + const AnalysisOutputs + &AO) { Match(Results, AO.ASTCtx); }), llvm::Succeeded()); } @@ -576,15 +599,12 @@ )"; runDataflow( Code, - [this](llvm::ArrayRef< - std::pair>> - Results, + [this](const llvm::StringMap> &Results, ASTContext &ASTCtx) { - ASSERT_THAT(Results, - ElementsAre(Pair("p1", _), Pair("p2", _), Pair("p3", _))); - const Environment &Env1 = Results[0].second.Env; - const Environment &Env2 = Results[1].second.Env; - const Environment &Env3 = Results[2].second.Env; + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2", "p3")); + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); @@ -619,34 +639,33 @@ /*[[p4]]*/ } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _), - Pair("p3", _), Pair("p4", _))); - const Environment &Env1 = Results[0].second.Env; - const Environment &Env2 = Results[1].second.Env; - const Environment &Env3 = Results[2].second.Env; - const Environment &Env4 = Results[3].second.Env; - - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); - }; - - EXPECT_EQ(GetFooValue(Env1)->getProperty("has_value"), - &Env1.getBoolLiteralValue(false)); - EXPECT_EQ(GetFooValue(Env2)->getProperty("has_value"), - &Env2.getBoolLiteralValue(true)); - EXPECT_EQ(GetFooValue(Env3)->getProperty("has_value"), - &Env3.getBoolLiteralValue(true)); - EXPECT_EQ(GetFooValue(Env4)->getProperty("has_value"), - &Env4.getBoolLiteralValue(true)); - }); + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), + UnorderedElementsAre("p1", "p2", "p3", "p4")); + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); + const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4"); + + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + auto GetFooValue = [FooDecl](const Environment &Env) { + return Env.getValue(*FooDecl, SkipPast::None); + }; + + EXPECT_EQ(GetFooValue(Env1)->getProperty("has_value"), + &Env1.getBoolLiteralValue(false)); + EXPECT_EQ(GetFooValue(Env2)->getProperty("has_value"), + &Env2.getBoolLiteralValue(true)); + EXPECT_EQ(GetFooValue(Env3)->getProperty("has_value"), + &Env3.getBoolLiteralValue(true)); + EXPECT_EQ(GetFooValue(Env4)->getProperty("has_value"), + &Env4.getBoolLiteralValue(true)); + }); } TEST_F(WideningTest, DistinctPointersToTheSameLocationAreEquivalent) { @@ -660,26 +679,25 @@ // [[p]] } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; - - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); - ASSERT_THAT(BarDecl, NotNull()); - - const auto *FooLoc = cast( - Env.getStorageLocation(*FooDecl, SkipPast::None)); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); - EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); - }); + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + const auto *FooLoc = cast( + Env.getStorageLocation(*FooDecl, SkipPast::None)); + const auto *BarVal = + cast(Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); + }); } TEST_F(WideningTest, DistinctValuesWithSamePropertiesAreEquivalent) { @@ -696,21 +714,20 @@ /*[[p]]*/ } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; - - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); - EXPECT_EQ(FooVal->getProperty("has_value"), - &Env.getBoolLiteralValue(true)); - }); + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); + EXPECT_EQ(FooVal->getProperty("has_value"), + &Env.getBoolLiteralValue(true)); + }); } class FlowConditionTest : public Test { @@ -718,17 +735,22 @@ template void runDataflow(llvm::StringRef Code, Matcher Match) { ASSERT_THAT_ERROR( - test::checkDataflow( - Code, "target", - [](ASTContext &Context, Environment &Env) { - return NoopAnalysis(Context, true); + checkDataflow( + /*AI:AnalysisInputs=*/ + { + .Code = Code, + .TargetFuncMatcher = ast_matchers::hasName("target"), + .MakeAnalysis = + [](ASTContext &Context, Environment &Env) { + return NoopAnalysis(Context, true); + }, + .ASTBuildArgs = {"-fsyntax-only", "-std=c++17"}, }, - [&Match]( - llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { Match(Results, ASTCtx); }, - {"-fsyntax-only", "-std=c++17"}), + /*VerifyResults=*/[&Match](const llvm::StringMap< + DataflowAnalysisState> + &Results, + const AnalysisOutputs + &AO) { Match(Results, AO.ASTCtx); }), llvm::Succeeded()); } }; @@ -745,26 +767,25 @@ } } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); - - const Environment &Env1 = Results[0].second.Env; - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); - EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); - - const Environment &Env2 = Results[1].second.Env; - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); - EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); - }); + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); + + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + auto *FooVal1 = + cast(Env1.getValue(*FooDecl, SkipPast::None)); + EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); + + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + auto *FooVal2 = + cast(Env2.getValue(*FooDecl, SkipPast::None)); + EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); + }); } TEST_F(FlowConditionTest, IfStmtSingleNegatedVar) { @@ -779,26 +800,25 @@ } } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); - - const Environment &Env1 = Results[0].second.Env; - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); - EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); - - const Environment &Env2 = Results[1].second.Env; - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); - EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2)); - }); + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); + + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + auto *FooVal1 = + cast(Env1.getValue(*FooDecl, SkipPast::None)); + EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); + + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + auto *FooVal2 = + cast(Env2.getValue(*FooDecl, SkipPast::None)); + EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2)); + }); } TEST_F(FlowConditionTest, WhileStmt) { @@ -811,15 +831,14 @@ } )"; runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); EXPECT_TRUE(Env.flowConditionImplies(*FooVal)); @@ -838,35 +857,29 @@ } } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); - ASSERT_THAT(BarDecl, NotNull()); - - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); - - const Environment &Env1 = Results[0].second.Env; - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = - cast(Env1.getValue(*BarDecl, SkipPast::None)); - EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); - EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1)); - - const Environment &Env2 = Results[1].second.Env; - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = - cast(Env2.getValue(*BarDecl, SkipPast::None)); - EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); - EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); - }); + runDataflow(Code, [](const llvm::StringMap> + &Results, + ASTContext &ASTCtx) { + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); + + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); + EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1)); + + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); + EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); + }); } TEST_F(FlowConditionTest, Disjunction) { @@ -881,35 +894,29 @@ } } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); - ASSERT_THAT(BarDecl, NotNull()); - - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); - - const Environment &Env1 = Results[0].second.Env; - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = - cast(Env1.getValue(*BarDecl, SkipPast::None)); - EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); - EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1)); - - const Environment &Env2 = Results[1].second.Env; - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = - cast(Env2.getValue(*BarDecl, SkipPast::None)); - EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); - EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); - }); + runDataflow(Code, [](const llvm::StringMap> + &Results, + ASTContext &ASTCtx) { + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); + + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); + EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1)); + + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); + EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); + }); } TEST_F(FlowConditionTest, NegatedConjunction) { @@ -924,35 +931,29 @@ } } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); - ASSERT_THAT(BarDecl, NotNull()); - - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); - - const Environment &Env1 = Results[0].second.Env; - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = - cast(Env1.getValue(*BarDecl, SkipPast::None)); - EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); - EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1)); - - const Environment &Env2 = Results[1].second.Env; - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = - cast(Env2.getValue(*BarDecl, SkipPast::None)); - EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2)); - EXPECT_TRUE(Env2.flowConditionImplies(*BarVal2)); - }); + runDataflow(Code, [](const llvm::StringMap> + &Results, + ASTContext &ASTCtx) { + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); + + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); + EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1)); + + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2)); + EXPECT_TRUE(Env2.flowConditionImplies(*BarVal2)); + }); } TEST_F(FlowConditionTest, DeMorgan) { @@ -967,35 +968,29 @@ } } )"; - runDataflow(Code, - [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); - ASSERT_THAT(BarDecl, NotNull()); - - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); - - const Environment &Env1 = Results[0].second.Env; - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = - cast(Env1.getValue(*BarDecl, SkipPast::None)); - EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); - EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1)); - - const Environment &Env2 = Results[1].second.Env; - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = - cast(Env2.getValue(*BarDecl, SkipPast::None)); - EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); - EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); - }); + runDataflow(Code, [](const llvm::StringMap> + &Results, + ASTContext &ASTCtx) { + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); + + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); + auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); + EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1)); + + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); + auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); + EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); + }); } TEST_F(FlowConditionTest, Join) { @@ -1013,16 +1008,15 @@ } )"; runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const Environment &Env = Results[0].second.Env; + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); EXPECT_TRUE(Env.flowConditionImplies(*FooVal)); }); @@ -1047,12 +1041,11 @@ } )"; runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); @@ -1090,12 +1083,11 @@ } )"; runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); @@ -1126,12 +1118,11 @@ } )"; runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); @@ -1157,20 +1148,20 @@ } )"; runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const Environment &Env1 = Results[0].second.Env; + const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); auto &FooVal1 = *cast(Env1.getValue(*FooDecl, SkipPast::Reference)); EXPECT_TRUE(Env1.flowConditionImplies(FooVal1)); - const Environment &Env2 = Results[1].second.Env; + const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); auto &FooVal2 = *cast(Env2.getValue(*FooDecl, SkipPast::Reference)); EXPECT_FALSE(Env2.flowConditionImplies(FooVal2));