1 //===- unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp ===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "TestingSupport.h"
10 #include "clang/AST/Decl.h"
11 #include "clang/AST/ExprCXX.h"
12 #include "clang/AST/Type.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/ASTMatchers/ASTMatchers.h"
15 #include "clang/Analysis/CFG.h"
16 #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
17 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
18 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
19 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
20 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
21 #include "clang/Analysis/FlowSensitive/Value.h"
22 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
23 #include "clang/Tooling/Tooling.h"
24 #include "llvm/ADT/Optional.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/SmallSet.h"
27 #include "llvm/ADT/StringRef.h"
28 #include "llvm/Support/Error.h"
29 #include "llvm/Testing/Support/Error.h"
30 #include "gmock/gmock.h"
31 #include "gtest/gtest.h"
32 #include <cassert>
33 #include <memory>
34 #include <ostream>
35 #include <string>
36 #include <utility>
37 #include <vector>
38 
39 namespace {
40 
41 using namespace clang;
42 using namespace dataflow;
43 using namespace test;
44 using namespace ast_matchers;
45 using ::testing::_;
46 using ::testing::ElementsAre;
47 using ::testing::IsEmpty;
48 using ::testing::IsNull;
49 using ::testing::NotNull;
50 using ::testing::Pair;
51 using ::testing::Test;
52 using ::testing::UnorderedElementsAre;
53 
54 template <typename AnalysisT>
55 llvm::Expected<std::vector<
56     llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>>
runAnalysis(llvm::StringRef Code,AnalysisT (* MakeAnalysis)(ASTContext &))57 runAnalysis(llvm::StringRef Code, AnalysisT (*MakeAnalysis)(ASTContext &)) {
58   std::unique_ptr<ASTUnit> AST =
59       tooling::buildASTFromCodeWithArgs(Code, {"-std=c++11"});
60 
61   auto *Func = selectFirst<FunctionDecl>(
62       "func", match(functionDecl(ast_matchers::hasName("target")).bind("func"),
63                     AST->getASTContext()));
64   assert(Func != nullptr);
65 
66   Stmt *Body = Func->getBody();
67   assert(Body != nullptr);
68 
69   auto CFCtx = llvm::cantFail(
70       ControlFlowContext::build(nullptr, Body, &AST->getASTContext()));
71 
72   AnalysisT Analysis = MakeAnalysis(AST->getASTContext());
73   DataflowAnalysisContext DACtx(std::make_unique<WatchedLiteralsSolver>());
74   Environment Env(DACtx);
75 
76   return runDataflowAnalysis(CFCtx, Analysis, Env);
77 }
78 
TEST(DataflowAnalysisTest,NoopAnalysis)79 TEST(DataflowAnalysisTest, NoopAnalysis) {
80   auto BlockStates = llvm::cantFail(
81       runAnalysis<NoopAnalysis>("void target() {}", [](ASTContext &C) {
82         return NoopAnalysis(C, false);
83       }));
84   EXPECT_EQ(BlockStates.size(), 2u);
85   EXPECT_TRUE(BlockStates[0].has_value());
86   EXPECT_TRUE(BlockStates[1].has_value());
87 }
88 
89 struct NonConvergingLattice {
90   int State;
91 
operator ==__anon5856d3660111::NonConvergingLattice92   bool operator==(const NonConvergingLattice &Other) const {
93     return State == Other.State;
94   }
95 
join__anon5856d3660111::NonConvergingLattice96   LatticeJoinEffect join(const NonConvergingLattice &Other) {
97     if (Other.State == 0)
98       return LatticeJoinEffect::Unchanged;
99     State += Other.State;
100     return LatticeJoinEffect::Changed;
101   }
102 };
103 
104 class NonConvergingAnalysis
105     : public DataflowAnalysis<NonConvergingAnalysis, NonConvergingLattice> {
106 public:
NonConvergingAnalysis(ASTContext & Context)107   explicit NonConvergingAnalysis(ASTContext &Context)
108       : DataflowAnalysis<NonConvergingAnalysis, NonConvergingLattice>(
109             Context,
110             /*ApplyBuiltinTransfer=*/false) {}
111 
initialElement()112   static NonConvergingLattice initialElement() { return {0}; }
113 
transfer(const Stmt * S,NonConvergingLattice & E,Environment & Env)114   void transfer(const Stmt *S, NonConvergingLattice &E, Environment &Env) {
115     ++E.State;
116   }
117 };
118 
TEST(DataflowAnalysisTest,NonConvergingAnalysis)119 TEST(DataflowAnalysisTest, NonConvergingAnalysis) {
120   std::string Code = R"(
121     void target() {
122       while(true) {}
123     }
124   )";
125   auto Res = runAnalysis<NonConvergingAnalysis>(
126       Code, [](ASTContext &C) { return NonConvergingAnalysis(C); });
127   EXPECT_EQ(llvm::toString(Res.takeError()),
128             "maximum number of iterations reached");
129 }
130 
131 struct FunctionCallLattice {
132   llvm::SmallSet<std::string, 8> CalledFunctions;
133 
operator ==__anon5856d3660111::FunctionCallLattice134   bool operator==(const FunctionCallLattice &Other) const {
135     return CalledFunctions == Other.CalledFunctions;
136   }
137 
join__anon5856d3660111::FunctionCallLattice138   LatticeJoinEffect join(const FunctionCallLattice &Other) {
139     if (Other.CalledFunctions.empty())
140       return LatticeJoinEffect::Unchanged;
141     const size_t size_before = CalledFunctions.size();
142     CalledFunctions.insert(Other.CalledFunctions.begin(),
143                            Other.CalledFunctions.end());
144     return CalledFunctions.size() == size_before ? LatticeJoinEffect::Unchanged
145                                                  : LatticeJoinEffect::Changed;
146   }
147 };
148 
operator <<(std::ostream & OS,const FunctionCallLattice & L)149 std::ostream &operator<<(std::ostream &OS, const FunctionCallLattice &L) {
150   std::string S;
151   llvm::raw_string_ostream ROS(S);
152   llvm::interleaveComma(L.CalledFunctions, ROS);
153   return OS << "{" << S << "}";
154 }
155 
156 class FunctionCallAnalysis
157     : public DataflowAnalysis<FunctionCallAnalysis, FunctionCallLattice> {
158 public:
FunctionCallAnalysis(ASTContext & Context)159   explicit FunctionCallAnalysis(ASTContext &Context)
160       : DataflowAnalysis<FunctionCallAnalysis, FunctionCallLattice>(Context) {}
161 
initialElement()162   static FunctionCallLattice initialElement() { return {}; }
163 
transfer(const Stmt * S,FunctionCallLattice & E,Environment & Env)164   void transfer(const Stmt *S, FunctionCallLattice &E, Environment &Env) {
165     if (auto *C = dyn_cast<CallExpr>(S)) {
166       if (auto *F = dyn_cast<FunctionDecl>(C->getCalleeDecl())) {
167         E.CalledFunctions.insert(F->getNameInfo().getAsString());
168       }
169     }
170   }
171 };
172 
173 class NoreturnDestructorTest : public Test {
174 protected:
175   template <typename Matcher>
runDataflow(llvm::StringRef Code,Matcher Expectations)176   void runDataflow(llvm::StringRef Code, Matcher Expectations) {
177     tooling::FileContentMappings FilesContents;
178     FilesContents.push_back(std::make_pair<std::string, std::string>(
179         "noreturn_destructor_test_defs.h", R"(
180       int foo();
181 
182       class Fatal {
183        public:
184         ~Fatal() __attribute__((noreturn));
185         int bar();
186         int baz();
187       };
188 
189       class NonFatal {
190        public:
191         ~NonFatal();
192         int bar();
193       };
194     )"));
195 
196     ASSERT_THAT_ERROR(
197         test::checkDataflow<FunctionCallAnalysis>(
198             Code, "target",
199             [](ASTContext &C, Environment &) {
200               return FunctionCallAnalysis(C);
201             },
202             [&Expectations](
203                 llvm::ArrayRef<std::pair<
204                     std::string, DataflowAnalysisState<FunctionCallLattice>>>
205                     Results,
206                 ASTContext &) { EXPECT_THAT(Results, Expectations); },
207             {"-fsyntax-only", "-std=c++17"}, FilesContents),
208         llvm::Succeeded());
209   }
210 };
211 
212 MATCHER_P(HoldsFunctionCallLattice, m,
213           ((negation ? "doesn't hold" : "holds") +
214            llvm::StringRef(" a lattice element that ") +
215            ::testing::DescribeMatcher<FunctionCallLattice>(m, negation))
216               .str()) {
217   return ExplainMatchResult(m, arg.Lattice, result_listener);
218 }
219 
220 MATCHER_P(HasCalledFunctions, m, "") {
221   return ExplainMatchResult(m, arg.CalledFunctions, result_listener);
222 }
223 
TEST_F(NoreturnDestructorTest,ConditionalOperatorBothBranchesReturn)224 TEST_F(NoreturnDestructorTest, ConditionalOperatorBothBranchesReturn) {
225   std::string Code = R"(
226     #include "noreturn_destructor_test_defs.h"
227 
228     void target(bool b) {
229       int value = b ? foo() : NonFatal().bar();
230       (void)0;
231       // [[p]]
232     }
233   )";
234   runDataflow(Code, UnorderedElementsAre(
235                         Pair("p", HoldsFunctionCallLattice(HasCalledFunctions(
236                                       UnorderedElementsAre("foo", "bar"))))));
237 }
238 
TEST_F(NoreturnDestructorTest,ConditionalOperatorLeftBranchReturns)239 TEST_F(NoreturnDestructorTest, ConditionalOperatorLeftBranchReturns) {
240   std::string Code = R"(
241     #include "noreturn_destructor_test_defs.h"
242 
243     void target(bool b) {
244       int value = b ? foo() : Fatal().bar();
245       (void)0;
246       // [[p]]
247     }
248   )";
249   runDataflow(Code, UnorderedElementsAre(
250                         Pair("p", HoldsFunctionCallLattice(HasCalledFunctions(
251                                       UnorderedElementsAre("foo"))))));
252 }
253 
TEST_F(NoreturnDestructorTest,ConditionalOperatorRightBranchReturns)254 TEST_F(NoreturnDestructorTest, ConditionalOperatorRightBranchReturns) {
255   std::string Code = R"(
256     #include "noreturn_destructor_test_defs.h"
257 
258     void target(bool b) {
259       int value = b ? Fatal().bar() : foo();
260       (void)0;
261       // [[p]]
262     }
263   )";
264   runDataflow(Code, UnorderedElementsAre(
265                         Pair("p", HoldsFunctionCallLattice(HasCalledFunctions(
266                                       UnorderedElementsAre("foo"))))));
267 }
268 
TEST_F(NoreturnDestructorTest,ConditionalOperatorNestedBranchesDoNotReturn)269 TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchesDoNotReturn) {
270   std::string Code = R"(
271     #include "noreturn_destructor_test_defs.h"
272 
273     void target(bool b1, bool b2) {
274       int value = b1 ? foo() : (b2 ? Fatal().bar() : Fatal().baz());
275       (void)0;
276       // [[p]]
277     }
278   )";
279   runDataflow(Code, IsEmpty());
280   // FIXME: Called functions at point `p` should contain "foo".
281 }
282 
TEST_F(NoreturnDestructorTest,ConditionalOperatorNestedBranchReturns)283 TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchReturns) {
284   std::string Code = R"(
285     #include "noreturn_destructor_test_defs.h"
286 
287     void target(bool b1, bool b2) {
288       int value = b1 ? Fatal().bar() : (b2 ? Fatal().baz() : foo());
289       (void)0;
290       // [[p]]
291     }
292   )";
293   runDataflow(Code, UnorderedElementsAre(
294                         Pair("p", HoldsFunctionCallLattice(HasCalledFunctions(
295                                       UnorderedElementsAre("baz", "foo"))))));
296   // FIXME: Called functions at point `p` should contain only "foo".
297 }
298 
299 // Models an analysis that uses flow conditions.
300 class SpecialBoolAnalysis
301     : public DataflowAnalysis<SpecialBoolAnalysis, NoopLattice> {
302 public:
SpecialBoolAnalysis(ASTContext & Context)303   explicit SpecialBoolAnalysis(ASTContext &Context)
304       : DataflowAnalysis<SpecialBoolAnalysis, NoopLattice>(Context) {}
305 
initialElement()306   static NoopLattice initialElement() { return {}; }
307 
transfer(const Stmt * S,NoopLattice &,Environment & Env)308   void transfer(const Stmt *S, NoopLattice &, Environment &Env) {
309     auto SpecialBoolRecordDecl = recordDecl(hasName("SpecialBool"));
310     auto HasSpecialBoolType = hasType(SpecialBoolRecordDecl);
311 
312     if (const auto *E = selectFirst<CXXConstructExpr>(
313             "call", match(cxxConstructExpr(HasSpecialBoolType).bind("call"), *S,
314                           getASTContext()))) {
315       auto &ConstructorVal = *Env.createValue(E->getType());
316       ConstructorVal.setProperty("is_set", Env.getBoolLiteralValue(false));
317       Env.setValue(*Env.getStorageLocation(*E, SkipPast::None), ConstructorVal);
318     } else if (const auto *E = selectFirst<CXXMemberCallExpr>(
319                    "call", match(cxxMemberCallExpr(callee(cxxMethodDecl(ofClass(
320                                                        SpecialBoolRecordDecl))))
321                                      .bind("call"),
322                                  *S, getASTContext()))) {
323       auto *Object = E->getImplicitObjectArgument();
324       assert(Object != nullptr);
325 
326       auto *ObjectLoc =
327           Env.getStorageLocation(*Object, SkipPast::ReferenceThenPointer);
328       assert(ObjectLoc != nullptr);
329 
330       auto &ConstructorVal = *Env.createValue(Object->getType());
331       ConstructorVal.setProperty("is_set", Env.getBoolLiteralValue(true));
332       Env.setValue(*ObjectLoc, ConstructorVal);
333     }
334   }
335 
compareEquivalent(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2)336   bool compareEquivalent(QualType Type, const Value &Val1,
337                          const Environment &Env1, const Value &Val2,
338                          const Environment &Env2) final {
339     const auto *Decl = Type->getAsCXXRecordDecl();
340     if (Decl == nullptr || Decl->getIdentifier() == nullptr ||
341         Decl->getName() != "SpecialBool")
342       return false;
343 
344     auto *IsSet1 = cast_or_null<BoolValue>(Val1.getProperty("is_set"));
345     if (IsSet1 == nullptr)
346       return true;
347 
348     auto *IsSet2 = cast_or_null<BoolValue>(Val2.getProperty("is_set"));
349     if (IsSet2 == nullptr)
350       return false;
351 
352     return Env1.flowConditionImplies(*IsSet1) ==
353            Env2.flowConditionImplies(*IsSet2);
354   }
355 
356   // Always returns `true` to accept the `MergedVal`.
merge(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2,Value & MergedVal,Environment & MergedEnv)357   bool merge(QualType Type, const Value &Val1, const Environment &Env1,
358              const Value &Val2, const Environment &Env2, Value &MergedVal,
359              Environment &MergedEnv) final {
360     const auto *Decl = Type->getAsCXXRecordDecl();
361     if (Decl == nullptr || Decl->getIdentifier() == nullptr ||
362         Decl->getName() != "SpecialBool")
363       return true;
364 
365     auto *IsSet1 = cast_or_null<BoolValue>(Val1.getProperty("is_set"));
366     if (IsSet1 == nullptr)
367       return true;
368 
369     auto *IsSet2 = cast_or_null<BoolValue>(Val2.getProperty("is_set"));
370     if (IsSet2 == nullptr)
371       return true;
372 
373     auto &IsSet = MergedEnv.makeAtomicBoolValue();
374     MergedVal.setProperty("is_set", IsSet);
375     if (Env1.flowConditionImplies(*IsSet1) &&
376         Env2.flowConditionImplies(*IsSet2))
377       MergedEnv.addToFlowCondition(IsSet);
378 
379     return true;
380   }
381 };
382 
383 class JoinFlowConditionsTest : public Test {
384 protected:
385   template <typename Matcher>
runDataflow(llvm::StringRef Code,Matcher Match)386   void runDataflow(llvm::StringRef Code, Matcher Match) {
387     ASSERT_THAT_ERROR(
388         test::checkDataflow<SpecialBoolAnalysis>(
389             Code, "target",
390             [](ASTContext &Context, Environment &Env) {
391               return SpecialBoolAnalysis(Context);
392             },
393             [&Match](
394                 llvm::ArrayRef<
395                     std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
396                     Results,
397                 ASTContext &ASTCtx) { Match(Results, ASTCtx); },
398             {"-fsyntax-only", "-std=c++17"}),
399         llvm::Succeeded());
400   }
401 };
402 
TEST_F(JoinFlowConditionsTest,JoinDistinctButProvablyEquivalentValues)403 TEST_F(JoinFlowConditionsTest, JoinDistinctButProvablyEquivalentValues) {
404   std::string Code = R"(
405     struct SpecialBool {
406       SpecialBool() = default;
407       void set();
408     };
409 
410     void target(bool Cond) {
411       SpecialBool Foo;
412       /*[[p1]]*/
413       if (Cond) {
414         Foo.set();
415         /*[[p2]]*/
416       } else {
417         Foo.set();
418         /*[[p3]]*/
419       }
420       (void)0;
421       /*[[p4]]*/
422     }
423   )";
424   runDataflow(
425       Code, [](llvm::ArrayRef<
426                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
427                    Results,
428                ASTContext &ASTCtx) {
429         ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _),
430                                          Pair("p2", _), Pair("p1", _)));
431         const Environment &Env1 = Results[3].second.Env;
432         const Environment &Env2 = Results[2].second.Env;
433         const Environment &Env3 = Results[1].second.Env;
434         const Environment &Env4 = Results[0].second.Env;
435 
436         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
437         ASSERT_THAT(FooDecl, NotNull());
438 
439         auto GetFooValue = [FooDecl](const Environment &Env) {
440           return cast<BoolValue>(
441               Env.getValue(*FooDecl, SkipPast::None)->getProperty("is_set"));
442         };
443 
444         EXPECT_FALSE(Env1.flowConditionImplies(*GetFooValue(Env1)));
445         EXPECT_TRUE(Env2.flowConditionImplies(*GetFooValue(Env2)));
446         EXPECT_TRUE(Env3.flowConditionImplies(*GetFooValue(Env3)));
447         EXPECT_TRUE(Env4.flowConditionImplies(*GetFooValue(Env3)));
448       });
449 }
450 
451 class OptionalIntAnalysis
452     : public DataflowAnalysis<OptionalIntAnalysis, NoopLattice> {
453 public:
OptionalIntAnalysis(ASTContext & Context,BoolValue & HasValueTop)454   explicit OptionalIntAnalysis(ASTContext &Context, BoolValue &HasValueTop)
455       : DataflowAnalysis<OptionalIntAnalysis, NoopLattice>(Context),
456         HasValueTop(HasValueTop) {}
457 
initialElement()458   static NoopLattice initialElement() { return {}; }
459 
transfer(const Stmt * S,NoopLattice &,Environment & Env)460   void transfer(const Stmt *S, NoopLattice &, Environment &Env) {
461     auto OptionalIntRecordDecl = recordDecl(hasName("OptionalInt"));
462     auto HasOptionalIntType = hasType(OptionalIntRecordDecl);
463 
464     if (const auto *E = selectFirst<CXXConstructExpr>(
465             "call", match(cxxConstructExpr(HasOptionalIntType).bind("call"), *S,
466                           getASTContext()))) {
467       auto &ConstructorVal = *Env.createValue(E->getType());
468       ConstructorVal.setProperty("has_value", Env.getBoolLiteralValue(false));
469       Env.setValue(*Env.getStorageLocation(*E, SkipPast::None), ConstructorVal);
470     } else if (const auto *E = selectFirst<CXXOperatorCallExpr>(
471                    "call",
472                    match(cxxOperatorCallExpr(callee(cxxMethodDecl(ofClass(
473                                                  OptionalIntRecordDecl))))
474                              .bind("call"),
475                          *S, getASTContext()))) {
476       assert(E->getNumArgs() > 0);
477       auto *Object = E->getArg(0);
478       assert(Object != nullptr);
479 
480       auto *ObjectLoc =
481           Env.getStorageLocation(*Object, SkipPast::ReferenceThenPointer);
482       assert(ObjectLoc != nullptr);
483 
484       auto &ConstructorVal = *Env.createValue(Object->getType());
485       ConstructorVal.setProperty("has_value", Env.getBoolLiteralValue(true));
486       Env.setValue(*ObjectLoc, ConstructorVal);
487     }
488   }
489 
compareEquivalent(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2)490   bool compareEquivalent(QualType Type, const Value &Val1,
491                          const Environment &Env1, const Value &Val2,
492                          const Environment &Env2) final {
493     // Nothing to say about a value that does not model an `OptionalInt`.
494     if (!Type->isRecordType() ||
495         Type->getAsCXXRecordDecl()->getQualifiedNameAsString() != "OptionalInt")
496       return false;
497 
498     return Val1.getProperty("has_value") == Val2.getProperty("has_value");
499   }
500 
merge(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2,Value & MergedVal,Environment & MergedEnv)501   bool merge(QualType Type, const Value &Val1, const Environment &Env1,
502              const Value &Val2, const Environment &Env2, Value &MergedVal,
503              Environment &MergedEnv) final {
504     // Nothing to say about a value that does not model an `OptionalInt`.
505     if (!Type->isRecordType() ||
506         Type->getAsCXXRecordDecl()->getQualifiedNameAsString() != "OptionalInt")
507       return false;
508 
509     auto *HasValue1 = cast_or_null<BoolValue>(Val1.getProperty("has_value"));
510     if (HasValue1 == nullptr)
511       return false;
512 
513     auto *HasValue2 = cast_or_null<BoolValue>(Val2.getProperty("has_value"));
514     if (HasValue2 == nullptr)
515       return false;
516 
517     if (HasValue1 == HasValue2)
518       MergedVal.setProperty("has_value", *HasValue1);
519     else
520       MergedVal.setProperty("has_value", HasValueTop);
521     return true;
522   }
523 
524   BoolValue &HasValueTop;
525 };
526 
527 class WideningTest : public Test {
528 protected:
529   template <typename Matcher>
runDataflow(llvm::StringRef Code,Matcher Match)530   void runDataflow(llvm::StringRef Code, Matcher Match) {
531     tooling::FileContentMappings FilesContents;
532     FilesContents.push_back(
533         std::make_pair<std::string, std::string>("widening_test_defs.h", R"(
534       struct OptionalInt {
535         OptionalInt() = default;
536         OptionalInt& operator=(int);
537       };
538     )"));
539     ASSERT_THAT_ERROR(
540         test::checkDataflow<OptionalIntAnalysis>(
541             Code, "target",
542             [this](ASTContext &Context, Environment &Env) {
543               assert(HasValueTop == nullptr);
544               HasValueTop =
545                   &Env.takeOwnership(std::make_unique<AtomicBoolValue>());
546               return OptionalIntAnalysis(Context, *HasValueTop);
547             },
548             [&Match](
549                 llvm::ArrayRef<
550                     std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
551                     Results,
552                 ASTContext &ASTCtx) { Match(Results, ASTCtx); },
553             {"-fsyntax-only", "-std=c++17"}, FilesContents),
554         llvm::Succeeded());
555   }
556 
557   BoolValue *HasValueTop = nullptr;
558 };
559 
TEST_F(WideningTest,JoinDistinctValuesWithDistinctProperties)560 TEST_F(WideningTest, JoinDistinctValuesWithDistinctProperties) {
561   std::string Code = R"(
562     #include "widening_test_defs.h"
563 
564     void target(bool Cond) {
565       OptionalInt Foo;
566       /*[[p1]]*/
567       if (Cond) {
568         Foo = 1;
569         /*[[p2]]*/
570       }
571       (void)0;
572       /*[[p3]]*/
573     }
574   )";
575   runDataflow(
576       Code,
577       [this](llvm::ArrayRef<
578                  std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
579                  Results,
580              ASTContext &ASTCtx) {
581         ASSERT_THAT(Results,
582                     ElementsAre(Pair("p3", _), Pair("p2", _), Pair("p1", _)));
583         const Environment &Env1 = Results[2].second.Env;
584         const Environment &Env2 = Results[1].second.Env;
585         const Environment &Env3 = Results[0].second.Env;
586 
587         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
588         ASSERT_THAT(FooDecl, NotNull());
589 
590         auto GetFooValue = [FooDecl](const Environment &Env) {
591           return Env.getValue(*FooDecl, SkipPast::None);
592         };
593 
594         EXPECT_EQ(GetFooValue(Env1)->getProperty("has_value"),
595                   &Env1.getBoolLiteralValue(false));
596         EXPECT_EQ(GetFooValue(Env2)->getProperty("has_value"),
597                   &Env2.getBoolLiteralValue(true));
598         EXPECT_EQ(GetFooValue(Env3)->getProperty("has_value"), HasValueTop);
599       });
600 }
601 
TEST_F(WideningTest,JoinDistinctValuesWithSameProperties)602 TEST_F(WideningTest, JoinDistinctValuesWithSameProperties) {
603   std::string Code = R"(
604     #include "widening_test_defs.h"
605 
606     void target(bool Cond) {
607       OptionalInt Foo;
608       /*[[p1]]*/
609       if (Cond) {
610         Foo = 1;
611         /*[[p2]]*/
612       } else {
613         Foo = 2;
614         /*[[p3]]*/
615       }
616       (void)0;
617       /*[[p4]]*/
618     }
619   )";
620   runDataflow(Code,
621               [](llvm::ArrayRef<
622                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
623                      Results,
624                  ASTContext &ASTCtx) {
625                 ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _),
626                                                  Pair("p2", _), Pair("p1", _)));
627                 const Environment &Env1 = Results[3].second.Env;
628                 const Environment &Env2 = Results[2].second.Env;
629                 const Environment &Env3 = Results[1].second.Env;
630                 const Environment &Env4 = Results[0].second.Env;
631 
632                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
633                 ASSERT_THAT(FooDecl, NotNull());
634 
635                 auto GetFooValue = [FooDecl](const Environment &Env) {
636                   return Env.getValue(*FooDecl, SkipPast::None);
637                 };
638 
639                 EXPECT_EQ(GetFooValue(Env1)->getProperty("has_value"),
640                           &Env1.getBoolLiteralValue(false));
641                 EXPECT_EQ(GetFooValue(Env2)->getProperty("has_value"),
642                           &Env2.getBoolLiteralValue(true));
643                 EXPECT_EQ(GetFooValue(Env3)->getProperty("has_value"),
644                           &Env3.getBoolLiteralValue(true));
645                 EXPECT_EQ(GetFooValue(Env4)->getProperty("has_value"),
646                           &Env4.getBoolLiteralValue(true));
647               });
648 }
649 
TEST_F(WideningTest,DistinctPointersToTheSameLocationAreEquivalent)650 TEST_F(WideningTest, DistinctPointersToTheSameLocationAreEquivalent) {
651   std::string Code = R"(
652     void target(int Foo, bool Cond) {
653       int *Bar = &Foo;
654       while (Cond) {
655         Bar = &Foo;
656       }
657       (void)0;
658       // [[p]]
659     }
660   )";
661   runDataflow(Code,
662               [](llvm::ArrayRef<
663                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
664                      Results,
665                  ASTContext &ASTCtx) {
666                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
667                 const Environment &Env = Results[0].second.Env;
668 
669                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
670                 ASSERT_THAT(FooDecl, NotNull());
671 
672                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
673                 ASSERT_THAT(BarDecl, NotNull());
674 
675                 const auto *FooLoc = cast<ScalarStorageLocation>(
676                     Env.getStorageLocation(*FooDecl, SkipPast::None));
677                 const auto *BarVal =
678                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
679                 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
680               });
681 }
682 
TEST_F(WideningTest,DistinctValuesWithSamePropertiesAreEquivalent)683 TEST_F(WideningTest, DistinctValuesWithSamePropertiesAreEquivalent) {
684   std::string Code = R"(
685     #include "widening_test_defs.h"
686 
687     void target(bool Cond) {
688       OptionalInt Foo;
689       Foo = 1;
690       while (Cond) {
691         Foo = 2;
692       }
693       (void)0;
694       /*[[p]]*/
695     }
696   )";
697   runDataflow(Code,
698               [](llvm::ArrayRef<
699                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
700                      Results,
701                  ASTContext &ASTCtx) {
702                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
703                 const Environment &Env = Results[0].second.Env;
704 
705                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
706                 ASSERT_THAT(FooDecl, NotNull());
707 
708                 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
709                 EXPECT_EQ(FooVal->getProperty("has_value"),
710                           &Env.getBoolLiteralValue(true));
711               });
712 }
713 
714 class FlowConditionTest : public Test {
715 protected:
716   template <typename Matcher>
runDataflow(llvm::StringRef Code,Matcher Match)717   void runDataflow(llvm::StringRef Code, Matcher Match) {
718     ASSERT_THAT_ERROR(
719         test::checkDataflow<NoopAnalysis>(
720             Code, "target",
721             [](ASTContext &Context, Environment &Env) {
722               return NoopAnalysis(Context, true);
723             },
724             [&Match](
725                 llvm::ArrayRef<
726                     std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
727                     Results,
728                 ASTContext &ASTCtx) { Match(Results, ASTCtx); },
729             {"-fsyntax-only", "-std=c++17"}),
730         llvm::Succeeded());
731   }
732 };
733 
TEST_F(FlowConditionTest,IfStmtSingleVar)734 TEST_F(FlowConditionTest, IfStmtSingleVar) {
735   std::string Code = R"(
736     void target(bool Foo) {
737       if (Foo) {
738         (void)0;
739         /*[[p1]]*/
740       } else {
741         (void)1;
742         /*[[p2]]*/
743       }
744     }
745   )";
746   runDataflow(Code,
747               [](llvm::ArrayRef<
748                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
749                      Results,
750                  ASTContext &ASTCtx) {
751                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
752                 ASSERT_THAT(FooDecl, NotNull());
753 
754                 ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _)));
755 
756                 const Environment &Env1 = Results[1].second.Env;
757                 auto *FooVal1 =
758                     cast<BoolValue>(Env1.getValue(*FooDecl, SkipPast::None));
759                 EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1));
760 
761                 const Environment &Env2 = Results[0].second.Env;
762                 auto *FooVal2 =
763                     cast<BoolValue>(Env2.getValue(*FooDecl, SkipPast::None));
764                 EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2));
765               });
766 }
767 
TEST_F(FlowConditionTest,IfStmtSingleNegatedVar)768 TEST_F(FlowConditionTest, IfStmtSingleNegatedVar) {
769   std::string Code = R"(
770     void target(bool Foo) {
771       if (!Foo) {
772         (void)0;
773         /*[[p1]]*/
774       } else {
775         (void)1;
776         /*[[p2]]*/
777       }
778     }
779   )";
780   runDataflow(Code,
781               [](llvm::ArrayRef<
782                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
783                      Results,
784                  ASTContext &ASTCtx) {
785                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
786                 ASSERT_THAT(FooDecl, NotNull());
787 
788                 ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _)));
789 
790                 const Environment &Env1 = Results[1].second.Env;
791                 auto *FooVal1 =
792                     cast<BoolValue>(Env1.getValue(*FooDecl, SkipPast::None));
793                 EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1));
794 
795                 const Environment &Env2 = Results[0].second.Env;
796                 auto *FooVal2 =
797                     cast<BoolValue>(Env2.getValue(*FooDecl, SkipPast::None));
798                 EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2));
799               });
800 }
801 
TEST_F(FlowConditionTest,WhileStmt)802 TEST_F(FlowConditionTest, WhileStmt) {
803   std::string Code = R"(
804     void target(bool Foo) {
805       while (Foo) {
806         (void)0;
807         /*[[p]]*/
808       }
809     }
810   )";
811   runDataflow(
812       Code, [](llvm::ArrayRef<
813                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
814                    Results,
815                ASTContext &ASTCtx) {
816         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
817         ASSERT_THAT(FooDecl, NotNull());
818 
819         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
820         const Environment &Env = Results[0].second.Env;
821 
822         auto *FooVal = cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
823         EXPECT_TRUE(Env.flowConditionImplies(*FooVal));
824       });
825 }
826 
TEST_F(FlowConditionTest,Conjunction)827 TEST_F(FlowConditionTest, Conjunction) {
828   std::string Code = R"(
829     void target(bool Foo, bool Bar) {
830       if (Foo && Bar) {
831         (void)0;
832         /*[[p1]]*/
833       } else {
834         (void)1;
835         /*[[p2]]*/
836       }
837     }
838   )";
839   runDataflow(Code,
840               [](llvm::ArrayRef<
841                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
842                      Results,
843                  ASTContext &ASTCtx) {
844                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
845                 ASSERT_THAT(FooDecl, NotNull());
846 
847                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
848                 ASSERT_THAT(BarDecl, NotNull());
849 
850                 ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _)));
851 
852                 const Environment &Env1 = Results[1].second.Env;
853                 auto *FooVal1 =
854                     cast<BoolValue>(Env1.getValue(*FooDecl, SkipPast::None));
855                 auto *BarVal1 =
856                     cast<BoolValue>(Env1.getValue(*BarDecl, SkipPast::None));
857                 EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1));
858                 EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1));
859 
860                 const Environment &Env2 = Results[0].second.Env;
861                 auto *FooVal2 =
862                     cast<BoolValue>(Env2.getValue(*FooDecl, SkipPast::None));
863                 auto *BarVal2 =
864                     cast<BoolValue>(Env2.getValue(*BarDecl, SkipPast::None));
865                 EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2));
866                 EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2));
867               });
868 }
869 
TEST_F(FlowConditionTest,Disjunction)870 TEST_F(FlowConditionTest, Disjunction) {
871   std::string Code = R"(
872     void target(bool Foo, bool Bar) {
873       if (Foo || Bar) {
874         (void)0;
875         /*[[p1]]*/
876       } else {
877         (void)1;
878         /*[[p2]]*/
879       }
880     }
881   )";
882   runDataflow(Code,
883               [](llvm::ArrayRef<
884                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
885                      Results,
886                  ASTContext &ASTCtx) {
887                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
888                 ASSERT_THAT(FooDecl, NotNull());
889 
890                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
891                 ASSERT_THAT(BarDecl, NotNull());
892 
893                 ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _)));
894 
895                 const Environment &Env1 = Results[1].second.Env;
896                 auto *FooVal1 =
897                     cast<BoolValue>(Env1.getValue(*FooDecl, SkipPast::None));
898                 auto *BarVal1 =
899                     cast<BoolValue>(Env1.getValue(*BarDecl, SkipPast::None));
900                 EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1));
901                 EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1));
902 
903                 const Environment &Env2 = Results[0].second.Env;
904                 auto *FooVal2 =
905                     cast<BoolValue>(Env2.getValue(*FooDecl, SkipPast::None));
906                 auto *BarVal2 =
907                     cast<BoolValue>(Env2.getValue(*BarDecl, SkipPast::None));
908                 EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2));
909                 EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2));
910               });
911 }
912 
TEST_F(FlowConditionTest,NegatedConjunction)913 TEST_F(FlowConditionTest, NegatedConjunction) {
914   std::string Code = R"(
915     void target(bool Foo, bool Bar) {
916       if (!(Foo && Bar)) {
917         (void)0;
918         /*[[p1]]*/
919       } else {
920         (void)1;
921         /*[[p2]]*/
922       }
923     }
924   )";
925   runDataflow(Code,
926               [](llvm::ArrayRef<
927                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
928                      Results,
929                  ASTContext &ASTCtx) {
930                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
931                 ASSERT_THAT(FooDecl, NotNull());
932 
933                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
934                 ASSERT_THAT(BarDecl, NotNull());
935 
936                 ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _)));
937 
938                 const Environment &Env1 = Results[1].second.Env;
939                 auto *FooVal1 =
940                     cast<BoolValue>(Env1.getValue(*FooDecl, SkipPast::None));
941                 auto *BarVal1 =
942                     cast<BoolValue>(Env1.getValue(*BarDecl, SkipPast::None));
943                 EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1));
944                 EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1));
945 
946                 const Environment &Env2 = Results[0].second.Env;
947                 auto *FooVal2 =
948                     cast<BoolValue>(Env2.getValue(*FooDecl, SkipPast::None));
949                 auto *BarVal2 =
950                     cast<BoolValue>(Env2.getValue(*BarDecl, SkipPast::None));
951                 EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2));
952                 EXPECT_TRUE(Env2.flowConditionImplies(*BarVal2));
953               });
954 }
955 
TEST_F(FlowConditionTest,DeMorgan)956 TEST_F(FlowConditionTest, DeMorgan) {
957   std::string Code = R"(
958     void target(bool Foo, bool Bar) {
959       if (!(!Foo || !Bar)) {
960         (void)0;
961         /*[[p1]]*/
962       } else {
963         (void)1;
964         /*[[p2]]*/
965       }
966     }
967   )";
968   runDataflow(Code,
969               [](llvm::ArrayRef<
970                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
971                      Results,
972                  ASTContext &ASTCtx) {
973                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
974                 ASSERT_THAT(FooDecl, NotNull());
975 
976                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
977                 ASSERT_THAT(BarDecl, NotNull());
978 
979                 ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _)));
980 
981                 const Environment &Env1 = Results[1].second.Env;
982                 auto *FooVal1 =
983                     cast<BoolValue>(Env1.getValue(*FooDecl, SkipPast::None));
984                 auto *BarVal1 =
985                     cast<BoolValue>(Env1.getValue(*BarDecl, SkipPast::None));
986                 EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1));
987                 EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1));
988 
989                 const Environment &Env2 = Results[0].second.Env;
990                 auto *FooVal2 =
991                     cast<BoolValue>(Env2.getValue(*FooDecl, SkipPast::None));
992                 auto *BarVal2 =
993                     cast<BoolValue>(Env2.getValue(*BarDecl, SkipPast::None));
994                 EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2));
995                 EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2));
996               });
997 }
998 
TEST_F(FlowConditionTest,Join)999 TEST_F(FlowConditionTest, Join) {
1000   std::string Code = R"(
1001     void target(bool Foo, bool Bar) {
1002       if (Bar) {
1003         if (!Foo)
1004           return;
1005       } else {
1006         if (!Foo)
1007           return;
1008       }
1009       (void)0;
1010       /*[[p]]*/
1011     }
1012   )";
1013   runDataflow(
1014       Code, [](llvm::ArrayRef<
1015                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1016                    Results,
1017                ASTContext &ASTCtx) {
1018         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1019 
1020         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1021         ASSERT_THAT(FooDecl, NotNull());
1022 
1023         const Environment &Env = Results[0].second.Env;
1024         auto *FooVal = cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
1025         EXPECT_TRUE(Env.flowConditionImplies(*FooVal));
1026       });
1027 }
1028 
1029 // Verifies that flow conditions are properly constructed even when the
1030 // condition is not meaningfully interpreted.
1031 //
1032 // Note: currently, arbitrary function calls are uninterpreted, so the test
1033 // exercises this case. If and when we change that, this test will not add to
1034 // coverage (although it may still test a valuable case).
TEST_F(FlowConditionTest,OpaqueFlowConditionMergesToOpaqueBool)1035 TEST_F(FlowConditionTest, OpaqueFlowConditionMergesToOpaqueBool) {
1036   std::string Code = R"(
1037     bool foo();
1038 
1039     void target() {
1040       bool Bar = true;
1041       if (foo())
1042         Bar = false;
1043       (void)0;
1044       /*[[p]]*/
1045     }
1046   )";
1047   runDataflow(
1048       Code, [](llvm::ArrayRef<
1049                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1050                    Results,
1051                ASTContext &ASTCtx) {
1052         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1053         const Environment &Env = Results[0].second.Env;
1054 
1055         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1056         ASSERT_THAT(BarDecl, NotNull());
1057 
1058         auto &BarVal =
1059             *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::Reference));
1060 
1061         EXPECT_FALSE(Env.flowConditionImplies(BarVal));
1062       });
1063 }
1064 
1065 // Verifies that flow conditions are properly constructed even when the
1066 // condition is not meaningfully interpreted.
1067 //
1068 // Note: currently, fields with recursive type calls are uninterpreted (beneath
1069 // the first instance), so the test exercises this case. If and when we change
1070 // that, this test will not add to coverage (although it may still test a
1071 // valuable case).
TEST_F(FlowConditionTest,OpaqueFieldFlowConditionMergesToOpaqueBool)1072 TEST_F(FlowConditionTest, OpaqueFieldFlowConditionMergesToOpaqueBool) {
1073   std::string Code = R"(
1074     struct Rec {
1075       Rec* Next;
1076     };
1077 
1078     struct Foo {
1079       Rec* X;
1080     };
1081 
1082     void target(Foo F) {
1083       bool Bar = true;
1084       if (F.X->Next)
1085         Bar = false;
1086       (void)0;
1087       /*[[p]]*/
1088     }
1089   )";
1090   runDataflow(
1091       Code, [](llvm::ArrayRef<
1092                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1093                    Results,
1094                ASTContext &ASTCtx) {
1095         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1096         const Environment &Env = Results[0].second.Env;
1097 
1098         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1099         ASSERT_THAT(BarDecl, NotNull());
1100 
1101         auto &BarVal =
1102             *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::Reference));
1103 
1104         EXPECT_FALSE(Env.flowConditionImplies(BarVal));
1105       });
1106 }
1107 
1108 // Verifies that flow conditions are properly constructed even when the
1109 // condition is not meaningfully interpreted. Adds to above by nesting the
1110 // interestnig case inside a normal branch. This protects against degenerate
1111 // solutions which only test for empty flow conditions, for example.
TEST_F(FlowConditionTest,OpaqueFlowConditionInsideBranchMergesToOpaqueBool)1112 TEST_F(FlowConditionTest, OpaqueFlowConditionInsideBranchMergesToOpaqueBool) {
1113   std::string Code = R"(
1114     bool foo();
1115 
1116     void target(bool Cond) {
1117       bool Bar = true;
1118       if (Cond) {
1119         if (foo())
1120           Bar = false;
1121         (void)0;
1122         /*[[p]]*/
1123       }
1124     }
1125   )";
1126   runDataflow(
1127       Code, [](llvm::ArrayRef<
1128                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1129                    Results,
1130                ASTContext &ASTCtx) {
1131         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1132         const Environment &Env = Results[0].second.Env;
1133 
1134         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1135         ASSERT_THAT(BarDecl, NotNull());
1136 
1137         auto &BarVal =
1138             *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::Reference));
1139 
1140         EXPECT_FALSE(Env.flowConditionImplies(BarVal));
1141       });
1142 }
1143 
TEST_F(FlowConditionTest,PointerToBoolImplicitCast)1144 TEST_F(FlowConditionTest, PointerToBoolImplicitCast) {
1145   std::string Code = R"(
1146     void target(int *Ptr) {
1147       bool Foo = false;
1148       if (Ptr) {
1149         Foo = true;
1150         /*[[p1]]*/
1151       }
1152 
1153       (void)0;
1154       /*[[p2]]*/
1155     }
1156   )";
1157   runDataflow(
1158       Code, [](llvm::ArrayRef<
1159                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1160                    Results,
1161                ASTContext &ASTCtx) {
1162         ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _)));
1163         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1164         ASSERT_THAT(FooDecl, NotNull());
1165 
1166         const Environment &Env1 = Results[1].second.Env;
1167         auto &FooVal1 =
1168             *cast<BoolValue>(Env1.getValue(*FooDecl, SkipPast::Reference));
1169         EXPECT_TRUE(Env1.flowConditionImplies(FooVal1));
1170 
1171         const Environment &Env2 = Results[0].second.Env;
1172         auto &FooVal2 =
1173             *cast<BoolValue>(Env2.getValue(*FooDecl, SkipPast::Reference));
1174         EXPECT_FALSE(Env2.flowConditionImplies(FooVal2));
1175       });
1176 }
1177 
1178 } // namespace
1179