xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp (revision 0362a29905ab8d68a8eb48741840a514b66552f8)
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/OperationKinds.h"
13 #include "clang/AST/Type.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/ASTMatchers/ASTMatchers.h"
16 #include "clang/Analysis/CFG.h"
17 #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
18 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
19 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
20 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
21 #include "clang/Analysis/FlowSensitive/DebugSupport.h"
22 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
23 #include "clang/Analysis/FlowSensitive/Value.h"
24 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
25 #include "clang/Tooling/Tooling.h"
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/ADT/SmallSet.h"
28 #include "llvm/ADT/StringMap.h"
29 #include "llvm/ADT/StringRef.h"
30 #include "llvm/Support/Error.h"
31 #include "llvm/Testing/ADT/StringMapEntry.h"
32 #include "llvm/Testing/Support/Error.h"
33 #include "gmock/gmock.h"
34 #include "gtest/gtest.h"
35 #include <cassert>
36 #include <memory>
37 #include <optional>
38 #include <ostream>
39 #include <string>
40 #include <utility>
41 #include <vector>
42 
43 namespace {
44 
45 using namespace clang;
46 using namespace dataflow;
47 using namespace test;
48 using namespace ast_matchers;
49 using llvm::IsStringMapEntry;
50 using ::testing::DescribeMatcher;
51 using ::testing::IsEmpty;
52 using ::testing::NotNull;
53 using ::testing::Test;
54 using ::testing::UnorderedElementsAre;
55 
56 class DataflowAnalysisTest : public Test {
57 protected:
58   template <typename AnalysisT>
59   llvm::Expected<std::vector<
60       std::optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>>
61   runAnalysis(llvm::StringRef Code, AnalysisT (*MakeAnalysis)(ASTContext &)) {
62     AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++11"});
63 
64     auto *Func = selectFirst<FunctionDecl>(
65         "func",
66         match(functionDecl(ast_matchers::hasName("target")).bind("func"),
67               AST->getASTContext()));
68     assert(Func != nullptr);
69 
70     ACFG =
71         std::make_unique<AdornedCFG>(llvm::cantFail(AdornedCFG::build(*Func)));
72 
73     AnalysisT Analysis = MakeAnalysis(AST->getASTContext());
74     DACtx = std::make_unique<DataflowAnalysisContext>(
75         std::make_unique<WatchedLiteralsSolver>());
76     Environment Env(*DACtx, *Func);
77 
78     return runDataflowAnalysis(*ACFG, Analysis, Env);
79   }
80 
81   /// Returns the `CFGBlock` containing `S` (and asserts that it exists).
82   const CFGBlock *blockForStmt(const Stmt &S) {
83     const CFGBlock *Block = ACFG->blockForStmt(S);
84     assert(Block != nullptr);
85     return Block;
86   }
87 
88   template <typename StateT>
89   const StateT &
90   blockStateForStmt(const std::vector<std::optional<StateT>> &BlockStates,
91                     const Stmt &S) {
92     const std::optional<StateT> &MaybeState =
93         BlockStates[blockForStmt(S)->getBlockID()];
94     assert(MaybeState.has_value());
95     return *MaybeState;
96   }
97 
98   /// Returns the first node that matches `Matcher` (and asserts that the match
99   /// was successful, i.e. the returned node is not null).
100   template <typename NodeT, typename MatcherT>
101   const NodeT &matchNode(MatcherT Matcher) {
102     const auto *Node = selectFirst<NodeT>(
103         "node", match(Matcher.bind("node"), AST->getASTContext()));
104     assert(Node != nullptr);
105     return *Node;
106   }
107 
108   std::unique_ptr<ASTUnit> AST;
109   std::unique_ptr<AdornedCFG> ACFG;
110   std::unique_ptr<DataflowAnalysisContext> DACtx;
111 };
112 
113 TEST_F(DataflowAnalysisTest, NoopAnalysis) {
114   auto BlockStates = llvm::cantFail(
115       runAnalysis<NoopAnalysis>("void target() {}", [](ASTContext &C) {
116         return NoopAnalysis(C,
117                             // Don't use builtin transfer function.
118                             DataflowAnalysisOptions{std::nullopt});
119       }));
120   EXPECT_EQ(BlockStates.size(), 2u);
121   EXPECT_TRUE(BlockStates[0].has_value());
122   EXPECT_TRUE(BlockStates[1].has_value());
123 }
124 
125 // Basic test that `diagnoseFunction` calls the Diagnoser function for the
126 // number of elements expected.
127 TEST_F(DataflowAnalysisTest, DiagnoseFunctionDiagnoserCalledOnEachElement) {
128   std::string Code = R"(void target() { int x = 0; ++x; })";
129   std::unique_ptr<ASTUnit> AST =
130       tooling::buildASTFromCodeWithArgs(Code, {"-std=c++11"});
131 
132   auto *Func =
133       cast<FunctionDecl>(findValueDecl(AST->getASTContext(), "target"));
134   auto Diagnoser = [](const CFGElement &Elt, ASTContext &,
135                       const TransferStateForDiagnostics<NoopLattice> &) {
136     llvm::SmallVector<std::string> Diagnostics(1);
137     llvm::raw_string_ostream OS(Diagnostics.front());
138     Elt.dumpToStream(OS);
139     return Diagnostics;
140   };
141   auto Result = diagnoseFunction<NoopAnalysis, std::string>(
142       *Func, AST->getASTContext(), Diagnoser);
143   // `diagnoseFunction` provides no guarantees about the order in which elements
144   // are visited, so we use `UnorderedElementsAre`.
145   EXPECT_THAT_EXPECTED(Result, llvm::HasValue(UnorderedElementsAre(
146                                    "0\n", "int x = 0;\n", "x\n", "++x\n",
147                                    " (Lifetime ends)\n")));
148 }
149 
150 TEST_F(DataflowAnalysisTest, CanAnalyzeStmt) {
151   std::string Code = R"cc(
152       struct S { bool b; };
153       void foo() {
154         S AnS = S{true};
155       }
156     )cc";
157   AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++11"});
158   const auto &DeclStatement =
159       matchNode<DeclStmt>(declStmt(hasSingleDecl(varDecl(hasName("AnS")))));
160   const auto &Func = matchNode<FunctionDecl>(functionDecl(hasName("foo")));
161 
162   ACFG = std::make_unique<AdornedCFG>(llvm::cantFail(AdornedCFG::build(
163       Func, const_cast<DeclStmt &>(DeclStatement), AST->getASTContext())));
164 
165   NoopAnalysis Analysis = NoopAnalysis(AST->getASTContext());
166   DACtx = std::make_unique<DataflowAnalysisContext>(
167       std::make_unique<WatchedLiteralsSolver>());
168   Environment Env(*DACtx, const_cast<DeclStmt &>(DeclStatement));
169 
170   llvm::Expected<std::vector<std::optional<DataflowAnalysisState<NoopLattice>>>>
171       Results = runDataflowAnalysis(*ACFG, Analysis, Env);
172 
173   ASSERT_THAT_ERROR(Results.takeError(), llvm::Succeeded());
174   const Environment &ExitBlockEnv = Results->front()->Env;
175   BoolValue *BoolFieldValue = cast<BoolValue>(
176       getFieldValue(ExitBlockEnv.get<RecordStorageLocation>(
177                         *cast<VarDecl>((*DeclStatement.decl_begin()))),
178                     "b", AST->getASTContext(), ExitBlockEnv));
179   EXPECT_TRUE(Env.proves(BoolFieldValue->formula()));
180 }
181 
182 // Tests for the statement-to-block map.
183 using StmtToBlockTest = DataflowAnalysisTest;
184 
185 TEST_F(StmtToBlockTest, ConditionalOperator) {
186   std::string Code = R"(
187     void target(bool b) {
188       int i = b ? 1 : 0;
189     }
190   )";
191   ASSERT_THAT_ERROR(runAnalysis<NoopAnalysis>(
192                         Code, [](ASTContext &C) { return NoopAnalysis(C); })
193                         .takeError(),
194                     llvm::Succeeded());
195 
196   const auto &IDecl = matchNode<DeclStmt>(declStmt(has(varDecl(hasName("i")))));
197   const auto &ConditionalOp =
198       matchNode<ConditionalOperator>(conditionalOperator());
199 
200   // The conditional operator should be associated with the same block as the
201   // `DeclStmt` for `i`. (Specifically, the conditional operator should not be
202   // associated with the block for which it is the terminator.)
203   EXPECT_EQ(blockForStmt(IDecl), blockForStmt(ConditionalOp));
204 }
205 
206 TEST_F(StmtToBlockTest, LogicalAnd) {
207   std::string Code = R"(
208     void target(bool b1, bool b2) {
209       bool b = b1 && b2;
210     }
211   )";
212   ASSERT_THAT_ERROR(runAnalysis<NoopAnalysis>(
213                         Code, [](ASTContext &C) { return NoopAnalysis(C); })
214                         .takeError(),
215                     llvm::Succeeded());
216 
217   const auto &BDecl = matchNode<DeclStmt>(declStmt(has(varDecl(hasName("b")))));
218   const auto &AndOp =
219       matchNode<BinaryOperator>(binaryOperator(hasOperatorName("&&")));
220 
221   // The `&&` operator should be associated with the same block as the
222   // `DeclStmt` for `b`. (Specifically, the `&&` operator should not be
223   // associated with the block for which it is the terminator.)
224   EXPECT_EQ(blockForStmt(BDecl), blockForStmt(AndOp));
225 }
226 
227 TEST_F(StmtToBlockTest, IfStatementWithLogicalAnd) {
228   std::string Code = R"(
229     void target(bool b1, bool b2) {
230       if (b1 && b2)
231         ;
232     }
233   )";
234   ASSERT_THAT_ERROR(runAnalysis<NoopAnalysis>(
235                         Code, [](ASTContext &C) { return NoopAnalysis(C); })
236                         .takeError(),
237                     llvm::Succeeded());
238 
239   const auto &If = matchNode<IfStmt>(ifStmt());
240   const auto &B2 =
241       matchNode<DeclRefExpr>(declRefExpr(to(varDecl(hasName("b2")))));
242   const auto &AndOp =
243       matchNode<BinaryOperator>(binaryOperator(hasOperatorName("&&")));
244 
245   // The if statement is the terminator for the block that contains both `b2`
246   // and the `&&` operator (which appears only as a terminator condition, not
247   // as a regular `CFGElement`).
248   const CFGBlock *IfBlock = blockForStmt(If);
249   const CFGBlock *B2Block = blockForStmt(B2);
250   const CFGBlock *AndOpBlock = blockForStmt(AndOp);
251   EXPECT_EQ(IfBlock, B2Block);
252   EXPECT_EQ(IfBlock, AndOpBlock);
253 }
254 
255 // Tests that check we discard state for expressions correctly.
256 using DiscardExprStateTest = DataflowAnalysisTest;
257 
258 TEST_F(DiscardExprStateTest, WhileStatement) {
259   std::string Code = R"(
260     void foo(int *p);
261     void target(int *p) {
262       while (p != nullptr)
263         foo(p);
264     }
265   )";
266   auto BlockStates = llvm::cantFail(runAnalysis<NoopAnalysis>(
267       Code, [](ASTContext &C) { return NoopAnalysis(C); }));
268 
269   const auto &NotEqOp =
270       matchNode<BinaryOperator>(binaryOperator(hasOperatorName("!=")));
271   const auto &CallFoo =
272       matchNode<CallExpr>(callExpr(callee(functionDecl(hasName("foo")))));
273 
274   // In the block that evaluates the expression `p != nullptr`, this expression
275   // is associated with a value.
276   const auto &NotEqOpState = blockStateForStmt(BlockStates, NotEqOp);
277   EXPECT_NE(NotEqOpState.Env.getValue(NotEqOp), nullptr);
278 
279   // In the block that calls `foo(p)`, the value for `p != nullptr` is discarded
280   // because it is not consumed outside the block it is in.
281   const auto &CallFooState = blockStateForStmt(BlockStates, CallFoo);
282   EXPECT_EQ(CallFooState.Env.getValue(NotEqOp), nullptr);
283 }
284 
285 TEST_F(DiscardExprStateTest, BooleanOperator) {
286   std::string Code = R"(
287     void f();
288     void target(bool b1, bool b2) {
289       if (b1 && b2)
290         f();
291     }
292   )";
293   auto BlockStates = llvm::cantFail(runAnalysis<NoopAnalysis>(
294       Code, [](ASTContext &C) { return NoopAnalysis(C); }));
295 
296   const auto &AndOp =
297       matchNode<BinaryOperator>(binaryOperator(hasOperatorName("&&")));
298   const auto &CallF =
299       matchNode<CallExpr>(callExpr(callee(functionDecl(hasName("f")))));
300 
301   // In the block that evaluates the LHS of the `&&` operator, the LHS is
302   // associated with a value, while the right-hand side is not (unsurprisingly,
303   // as it hasn't been evaluated yet).
304   const auto &LHSState = blockStateForStmt(BlockStates, *AndOp.getLHS());
305   auto *LHSValue = cast<BoolValue>(LHSState.Env.getValue(*AndOp.getLHS()));
306   EXPECT_NE(LHSValue, nullptr);
307   EXPECT_EQ(LHSState.Env.getValue(*AndOp.getRHS()), nullptr);
308 
309   // In the block that evaluates the RHS, both the LHS and RHS are associated
310   // with values, as they are both subexpressions of the `&&` operator, which
311   // is evaluated in a later block.
312   const auto &RHSState = blockStateForStmt(BlockStates, *AndOp.getRHS());
313   EXPECT_EQ(RHSState.Env.getValue(*AndOp.getLHS()), LHSValue);
314   auto *RHSValue = RHSState.Env.get<BoolValue>(*AndOp.getRHS());
315   EXPECT_NE(RHSValue, nullptr);
316 
317   // In the block that evaluates `b1 && b2`, the `&&` as well as its operands
318   // are associated with values.
319   const auto &AndOpState = blockStateForStmt(BlockStates, AndOp);
320   EXPECT_EQ(AndOpState.Env.getValue(*AndOp.getLHS()), LHSValue);
321   EXPECT_EQ(AndOpState.Env.getValue(*AndOp.getRHS()), RHSValue);
322   EXPECT_EQ(AndOpState.Env.getValue(AndOp),
323             &AndOpState.Env.makeAnd(*LHSValue, *RHSValue));
324 
325   // In the block that calls `f()`, none of `b1`, `b2`, or `b1 && b2` should be
326   // associated with values.
327   const auto &CallFState = blockStateForStmt(BlockStates, CallF);
328   EXPECT_EQ(CallFState.Env.getValue(*AndOp.getLHS()), nullptr);
329   EXPECT_EQ(CallFState.Env.getValue(*AndOp.getRHS()), nullptr);
330   EXPECT_EQ(CallFState.Env.getValue(AndOp), nullptr);
331 }
332 
333 TEST_F(DiscardExprStateTest, ConditionalOperator) {
334   std::string Code = R"(
335     void f(int*, int);
336     void g();
337     bool cond();
338 
339     void target() {
340       int i = 0;
341       if (cond())
342         f(&i, cond() ? 1 : 0);
343       g();
344     }
345   )";
346   auto BlockStates = llvm::cantFail(runAnalysis<NoopAnalysis>(
347       Code, [](ASTContext &C) { return NoopAnalysis(C); }));
348 
349   const auto &AddrOfI =
350       matchNode<UnaryOperator>(unaryOperator(hasOperatorName("&")));
351   const auto &CallF =
352       matchNode<CallExpr>(callExpr(callee(functionDecl(hasName("f")))));
353   const auto &CallG =
354       matchNode<CallExpr>(callExpr(callee(functionDecl(hasName("g")))));
355 
356   // In the block that evaluates `&i`, it should obviously have a value.
357   const auto &AddrOfIState = blockStateForStmt(BlockStates, AddrOfI);
358   auto *AddrOfIVal = AddrOfIState.Env.get<PointerValue>(AddrOfI);
359   EXPECT_NE(AddrOfIVal, nullptr);
360 
361   // Because of the conditional operator, the `f(...)` call is evaluated in a
362   // different block than `&i`, but `&i` still needs to have a value here
363   // because it's a subexpression of the call.
364   const auto &CallFState = blockStateForStmt(BlockStates, CallF);
365   EXPECT_NE(&CallFState, &AddrOfIState);
366   EXPECT_EQ(CallFState.Env.get<PointerValue>(AddrOfI), AddrOfIVal);
367 
368   // In the block that calls `g()`, `&i` should no longer be associated with a
369   // value.
370   const auto &CallGState = blockStateForStmt(BlockStates, CallG);
371   EXPECT_EQ(CallGState.Env.get<PointerValue>(AddrOfI), nullptr);
372 }
373 
374 TEST_F(DiscardExprStateTest, CallWithParenExprTreatedCorrectly) {
375   // This is a regression test.
376   // In the CFG for `target()` below, the expression that evaluates the function
377   // pointer for `expect` and the actual call are separated into different
378   // baseic blocks (because of the control flow introduced by the `||`
379   // operator).
380   // The value for the `expect` function pointer was erroneously discarded
381   // from the environment between these two blocks because the code that
382   // determines whether the expression values for a block need to be preserved
383   // did not ignore the `ParenExpr` around `(i == 1)` (which is not represented
384   // in the CFG).
385   std::string Code = R"(
386     bool expect(bool, bool);
387     void target(int i) {
388       expect(false || (i == 1), false);
389     }
390   )";
391   auto BlockStates = llvm::cantFail(runAnalysis<NoopAnalysis>(
392       Code, [](ASTContext &C) { return NoopAnalysis(C); }));
393 
394   const auto &FnToPtrDecay = matchNode<ImplicitCastExpr>(
395       implicitCastExpr(hasCastKind(CK_FunctionToPointerDecay)));
396   const auto &CallExpect =
397       matchNode<CallExpr>(callExpr(callee(functionDecl(hasName("expect")))));
398 
399   // In the block that evaluates the implicit cast of `expect` to a pointer,
400   // this expression is associated with a value.
401   const auto &FnToPtrDecayState = blockStateForStmt(BlockStates, FnToPtrDecay);
402   EXPECT_NE(FnToPtrDecayState.Env.getValue(FnToPtrDecay), nullptr);
403 
404   // In the block that calls `expect()`, the implicit cast of `expect` to a
405   // pointer is still associated with a value.
406   const auto &CallExpectState = blockStateForStmt(BlockStates, CallExpect);
407   EXPECT_NE(CallExpectState.Env.getValue(FnToPtrDecay), nullptr);
408 }
409 
410 struct NonConvergingLattice {
411   int State;
412 
413   bool operator==(const NonConvergingLattice &Other) const {
414     return State == Other.State;
415   }
416 
417   LatticeJoinEffect join(const NonConvergingLattice &Other) {
418     if (Other.State == 0)
419       return LatticeJoinEffect::Unchanged;
420     State += Other.State;
421     return LatticeJoinEffect::Changed;
422   }
423 };
424 
425 class NonConvergingAnalysis
426     : public DataflowAnalysis<NonConvergingAnalysis, NonConvergingLattice> {
427 public:
428   explicit NonConvergingAnalysis(ASTContext &Context)
429       : DataflowAnalysis<NonConvergingAnalysis, NonConvergingLattice>(
430             Context,
431             // Don't apply builtin transfer function.
432             DataflowAnalysisOptions{std::nullopt}) {}
433 
434   static NonConvergingLattice initialElement() { return {0}; }
435 
436   void transfer(const CFGElement &, NonConvergingLattice &E, Environment &) {
437     ++E.State;
438   }
439 };
440 
441 TEST_F(DataflowAnalysisTest, NonConvergingAnalysis) {
442   std::string Code = R"(
443     void target() {
444       while(true) {}
445     }
446   )";
447   auto Res = runAnalysis<NonConvergingAnalysis>(
448       Code, [](ASTContext &C) { return NonConvergingAnalysis(C); });
449   EXPECT_EQ(llvm::toString(Res.takeError()),
450             "maximum number of blocks processed");
451 }
452 
453 // Regression test for joins of bool-typed lvalue expressions. The first loop
454 // results in two passes through the code that follows. Each pass results in a
455 // different `StorageLocation` for the pointee of `v`. Then, the second loop
456 // causes a join at the loop head where the two environments map expresssion
457 // `*v` to different `StorageLocation`s.
458 //
459 // An earlier version crashed for this condition (for boolean-typed lvalues), so
460 // this test only verifies that the analysis runs successfully, without
461 // examining any details of the results.
462 TEST_F(DataflowAnalysisTest, JoinBoolLValues) {
463   std::string Code = R"(
464     void target() {
465       for (int x = 1; x; x = 0)
466         (void)x;
467       bool *v;
468       if (*v)
469         for (int x = 1; x; x = 0)
470           (void)x;
471     }
472   )";
473   ASSERT_THAT_ERROR(
474       runAnalysis<NoopAnalysis>(Code,
475                                 [](ASTContext &C) {
476                                   auto EnableBuiltIns = DataflowAnalysisOptions{
477                                       DataflowAnalysisContext::Options{}};
478                                   return NoopAnalysis(C, EnableBuiltIns);
479                                 })
480           .takeError(),
481       llvm::Succeeded());
482 }
483 
484 struct FunctionCallLattice {
485   using FunctionSet = llvm::SmallSet<std::string, 8>;
486   FunctionSet CalledFunctions;
487 
488   bool operator==(const FunctionCallLattice &Other) const {
489     return CalledFunctions == Other.CalledFunctions;
490   }
491 
492   LatticeJoinEffect join(const FunctionCallLattice &Other) {
493     if (Other.CalledFunctions.empty())
494       return LatticeJoinEffect::Unchanged;
495     const size_t size_before = CalledFunctions.size();
496     CalledFunctions.insert(Other.CalledFunctions.begin(),
497                            Other.CalledFunctions.end());
498     return CalledFunctions.size() == size_before ? LatticeJoinEffect::Unchanged
499                                                  : LatticeJoinEffect::Changed;
500   }
501 };
502 
503 std::ostream &operator<<(std::ostream &OS, const FunctionCallLattice &L) {
504   std::string S;
505   llvm::raw_string_ostream ROS(S);
506   llvm::interleaveComma(L.CalledFunctions, ROS);
507   return OS << "{" << S << "}";
508 }
509 
510 class FunctionCallAnalysis
511     : public DataflowAnalysis<FunctionCallAnalysis, FunctionCallLattice> {
512 public:
513   explicit FunctionCallAnalysis(ASTContext &Context)
514       : DataflowAnalysis<FunctionCallAnalysis, FunctionCallLattice>(Context) {}
515 
516   static FunctionCallLattice initialElement() { return {}; }
517 
518   void transfer(const CFGElement &Elt, FunctionCallLattice &E, Environment &) {
519     auto CS = Elt.getAs<CFGStmt>();
520     if (!CS)
521       return;
522     const auto *S = CS->getStmt();
523     if (auto *C = dyn_cast<CallExpr>(S)) {
524       if (auto *F = dyn_cast<FunctionDecl>(C->getCalleeDecl())) {
525         E.CalledFunctions.insert(F->getNameInfo().getAsString());
526       }
527     }
528   }
529 };
530 
531 class NoreturnDestructorTest : public Test {
532 protected:
533   template <typename Matcher>
534   void runDataflow(llvm::StringRef Code, Matcher Expectations) {
535     tooling::FileContentMappings FilesContents;
536     FilesContents.push_back(std::make_pair<std::string, std::string>(
537         "noreturn_destructor_test_defs.h", R"(
538       int foo();
539 
540       class Fatal {
541        public:
542         ~Fatal() __attribute__((noreturn));
543         int bar();
544         int baz();
545       };
546 
547       class NonFatal {
548        public:
549         ~NonFatal();
550         int bar();
551       };
552     )"));
553 
554     ASSERT_THAT_ERROR(
555         test::checkDataflow<FunctionCallAnalysis>(
556             AnalysisInputs<FunctionCallAnalysis>(
557                 Code, ast_matchers::hasName("target"),
558                 [](ASTContext &C, Environment &) {
559                   return FunctionCallAnalysis(C);
560                 })
561                 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"})
562                 .withASTBuildVirtualMappedFiles(std::move(FilesContents)),
563             /*VerifyResults=*/
564             [&Expectations](
565                 const llvm::StringMap<
566                     DataflowAnalysisState<FunctionCallLattice>> &Results,
567                 const AnalysisOutputs &) {
568               EXPECT_THAT(Results, Expectations);
569             }),
570         llvm::Succeeded());
571   }
572 };
573 
574 MATCHER_P(HoldsFunctionCallLattice, m,
575           ((negation ? "doesn't hold" : "holds") +
576            llvm::StringRef(" a lattice element that ") +
577            DescribeMatcher<FunctionCallLattice>(m))
578               .str()) {
579   return ExplainMatchResult(m, arg.Lattice, result_listener);
580 }
581 
582 MATCHER_P(HasCalledFunctions, m,
583           ((negation ? "doesn't hold" : "holds") +
584            llvm::StringRef(" a set of called functions that ") +
585            DescribeMatcher<FunctionCallLattice::FunctionSet>(m))
586               .str()) {
587   return ExplainMatchResult(m, arg.CalledFunctions, result_listener);
588 }
589 
590 TEST_F(NoreturnDestructorTest, ConditionalOperatorBothBranchesReturn) {
591   std::string Code = R"(
592     #include "noreturn_destructor_test_defs.h"
593 
594     void target(bool b) {
595       int value = b ? foo() : NonFatal().bar();
596       (void)0;
597       // [[p]]
598     }
599   )";
600   runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
601                         "p", HoldsFunctionCallLattice(HasCalledFunctions(
602                                  UnorderedElementsAre("foo", "bar"))))));
603 }
604 
605 TEST_F(NoreturnDestructorTest, ConditionalOperatorLeftBranchReturns) {
606   std::string Code = R"(
607     #include "noreturn_destructor_test_defs.h"
608 
609     void target(bool b) {
610       int value = b ? foo() : Fatal().bar();
611       (void)0;
612       // [[p]]
613     }
614   )";
615   runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
616                         "p", HoldsFunctionCallLattice(HasCalledFunctions(
617                                  UnorderedElementsAre("foo"))))));
618 }
619 
620 TEST_F(NoreturnDestructorTest,
621        ConditionalOperatorConstantCondition_LeftBranchReturns) {
622   std::string Code = R"(
623     #include "noreturn_destructor_test_defs.h"
624 
625     void target() {
626       int value = true ? foo() : Fatal().bar();
627       (void)0;
628       // [[p]]
629     }
630   )";
631   runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
632                         "p", HoldsFunctionCallLattice(HasCalledFunctions(
633                                  UnorderedElementsAre("foo"))))));
634 }
635 
636 TEST_F(NoreturnDestructorTest, ConditionalOperatorRightBranchReturns) {
637   std::string Code = R"(
638     #include "noreturn_destructor_test_defs.h"
639 
640     void target(bool b) {
641       int value = b ? Fatal().bar() : foo();
642       (void)0;
643       // [[p]]
644     }
645   )";
646   runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
647                         "p", HoldsFunctionCallLattice(HasCalledFunctions(
648                                  UnorderedElementsAre("foo"))))));
649 }
650 
651 TEST_F(NoreturnDestructorTest,
652        ConditionalOperatorConstantCondition_RightBranchReturns) {
653   std::string Code = R"(
654     #include "noreturn_destructor_test_defs.h"
655 
656     void target() {
657       int value = false ? Fatal().bar() : foo();
658       (void)0;
659       // [[p]]
660     }
661   )";
662   runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
663                         "p", HoldsFunctionCallLattice(HasCalledFunctions(
664                                  UnorderedElementsAre("foo"))))));
665 }
666 
667 TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchesDoNotReturn) {
668   std::string Code = R"(
669     #include "noreturn_destructor_test_defs.h"
670 
671     void target(bool b1, bool b2) {
672       int value = b1 ? foo() : (b2 ? Fatal().bar() : Fatal().baz());
673       (void)0;
674       // [[p]]
675     }
676   )";
677   runDataflow(Code, IsEmpty());
678   // FIXME: Called functions at point `p` should contain "foo".
679 }
680 
681 TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchReturns) {
682   std::string Code = R"(
683     #include "noreturn_destructor_test_defs.h"
684 
685     void target(bool b1, bool b2) {
686       int value = b1 ? Fatal().bar() : (b2 ? Fatal().baz() : foo());
687       (void)0;
688       // [[p]]
689     }
690   )";
691   runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
692                         "p", HoldsFunctionCallLattice(HasCalledFunctions(
693                                  UnorderedElementsAre("baz", "foo"))))));
694   // FIXME: Called functions at point `p` should contain only "foo".
695 }
696 
697 // Models an analysis that uses flow conditions.
698 class SpecialBoolAnalysis final
699     : public DataflowAnalysis<SpecialBoolAnalysis, NoopLattice> {
700 public:
701   explicit SpecialBoolAnalysis(ASTContext &Context, Environment &Env)
702       : DataflowAnalysis<SpecialBoolAnalysis, NoopLattice>(Context) {
703     Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
704         [](QualType Ty) -> llvm::StringMap<QualType> {
705           RecordDecl *RD = Ty->getAsRecordDecl();
706           if (RD == nullptr || RD->getIdentifier() == nullptr ||
707               RD->getName() != "SpecialBool")
708             return {};
709           return {{"is_set", RD->getASTContext().BoolTy}};
710         });
711   }
712 
713   static NoopLattice initialElement() { return {}; }
714 
715   void transfer(const CFGElement &Elt, NoopLattice &, Environment &Env) {
716     auto CS = Elt.getAs<CFGStmt>();
717     if (!CS)
718       return;
719     const auto *S = CS->getStmt();
720     auto SpecialBoolRecordDecl = recordDecl(hasName("SpecialBool"));
721     auto HasSpecialBoolType = hasType(SpecialBoolRecordDecl);
722 
723     if (const auto *E = selectFirst<CXXConstructExpr>(
724             "call", match(cxxConstructExpr(HasSpecialBoolType).bind("call"), *S,
725                           getASTContext()))) {
726       Env.setValue(Env.getResultObjectLocation(*E).getSyntheticField("is_set"),
727                    Env.getBoolLiteralValue(false));
728     } else if (const auto *E = selectFirst<CXXMemberCallExpr>(
729                    "call", match(cxxMemberCallExpr(callee(cxxMethodDecl(ofClass(
730                                                        SpecialBoolRecordDecl))))
731                                      .bind("call"),
732                                  *S, getASTContext()))) {
733       if (RecordStorageLocation *ObjectLoc = getImplicitObjectLocation(*E, Env))
734         Env.setValue(ObjectLoc->getSyntheticField("is_set"),
735                      Env.getBoolLiteralValue(true));
736     }
737   }
738 };
739 
740 class JoinFlowConditionsTest : public Test {
741 protected:
742   template <typename Matcher>
743   void runDataflow(llvm::StringRef Code, Matcher Match) {
744     ASSERT_THAT_ERROR(
745         test::checkDataflow<SpecialBoolAnalysis>(
746             AnalysisInputs<SpecialBoolAnalysis>(
747                 Code, ast_matchers::hasName("target"),
748                 [](ASTContext &Context, Environment &Env) {
749                   return SpecialBoolAnalysis(Context, Env);
750                 })
751                 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
752             /*VerifyResults=*/[&Match](const llvm::StringMap<
753                                            DataflowAnalysisState<NoopLattice>>
754                                            &Results,
755                                        const AnalysisOutputs
756                                            &AO) { Match(Results, AO.ASTCtx); }),
757         llvm::Succeeded());
758   }
759 };
760 
761 TEST_F(JoinFlowConditionsTest, JoinDistinctButProvablyEquivalentValues) {
762   std::string Code = R"(
763     struct SpecialBool {
764       SpecialBool() = default;
765       void set();
766     };
767 
768     void target(bool Cond) {
769       SpecialBool Foo;
770       /*[[p1]]*/
771       if (Cond) {
772         Foo.set();
773         /*[[p2]]*/
774       } else {
775         Foo.set();
776         /*[[p3]]*/
777       }
778       (void)0;
779       /*[[p4]]*/
780     }
781   )";
782   runDataflow(
783       Code,
784       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
785          ASTContext &ASTCtx) {
786         ASSERT_THAT(Results.keys(),
787                     UnorderedElementsAre("p1", "p2", "p3", "p4"));
788         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
789         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
790         const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");
791         const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4");
792 
793         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
794         ASSERT_THAT(FooDecl, NotNull());
795 
796         auto GetFoo = [FooDecl](const Environment &Env) -> const Formula & {
797           auto *Loc =
798               cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
799           return cast<BoolValue>(Env.getValue(Loc->getSyntheticField("is_set")))
800               ->formula();
801         };
802 
803         EXPECT_FALSE(Env1.proves(GetFoo(Env1)));
804         EXPECT_TRUE(Env2.proves(GetFoo(Env2)));
805         EXPECT_TRUE(Env3.proves(GetFoo(Env3)));
806         EXPECT_TRUE(Env4.proves(GetFoo(Env4)));
807       });
808 }
809 
810 class NullPointerAnalysis final
811     : public DataflowAnalysis<NullPointerAnalysis, NoopLattice> {
812 public:
813   explicit NullPointerAnalysis(ASTContext &Context)
814       : DataflowAnalysis<NullPointerAnalysis, NoopLattice>(Context) {}
815 
816   static NoopLattice initialElement() { return {}; }
817 
818   void transfer(const CFGElement &Elt, NoopLattice &, Environment &Env) {
819     auto CS = Elt.getAs<CFGStmt>();
820     if (!CS)
821       return;
822     const Stmt *S = CS->getStmt();
823     const Expr *E = dyn_cast<Expr>(S);
824     if (!E)
825       return;
826 
827     if (!E->getType()->isPointerType())
828       return;
829 
830     // Make sure we have a `PointerValue` for `E`.
831     auto *PtrVal = cast_or_null<PointerValue>(Env.getValue(*E));
832     if (PtrVal == nullptr) {
833       PtrVal = cast<PointerValue>(Env.createValue(E->getType()));
834       Env.setValue(*E, *PtrVal);
835     }
836 
837     if (auto *Cast = dyn_cast<ImplicitCastExpr>(E);
838         Cast && Cast->getCastKind() == CK_NullToPointer)
839       PtrVal->setProperty("is_null", Env.getBoolLiteralValue(true));
840     else if (auto *Op = dyn_cast<UnaryOperator>(E);
841              Op && Op->getOpcode() == UO_AddrOf)
842       PtrVal->setProperty("is_null", Env.getBoolLiteralValue(false));
843   }
844 
845   ComparisonResult compare(QualType Type, const Value &Val1,
846                            const Environment &Env1, const Value &Val2,
847                            const Environment &Env2) override {
848     // Nothing to say about a value that is not a pointer.
849     if (!Type->isPointerType())
850       return ComparisonResult::Unknown;
851 
852     auto *Prop1 = Val1.getProperty("is_null");
853     auto *Prop2 = Val2.getProperty("is_null");
854     assert(Prop1 != nullptr && Prop2 != nullptr);
855     return areEquivalentValues(*Prop1, *Prop2) ? ComparisonResult::Same
856                                                : ComparisonResult::Different;
857   }
858 
859   void join(QualType Type, const Value &Val1, const Environment &Env1,
860             const Value &Val2, const Environment &Env2, Value &JoinedVal,
861             Environment &JoinedEnv) override {
862     // Nothing to say about a value that is not a pointer...
863     if (!Type->isPointerType())
864       return;
865 
866     // ... or, a pointer without the `is_null` property.
867     auto *IsNull1 = cast_or_null<BoolValue>(Val1.getProperty("is_null"));
868     auto *IsNull2 = cast_or_null<BoolValue>(Val2.getProperty("is_null"));
869     if (IsNull1 == nullptr || IsNull2 == nullptr)
870       return;
871 
872     if (IsNull1 == IsNull2)
873       JoinedVal.setProperty("is_null", *IsNull1);
874     else
875       JoinedVal.setProperty("is_null", JoinedEnv.makeTopBoolValue());
876   }
877 
878   std::optional<WidenResult> widen(QualType Type, Value &Prev,
879                                    const Environment &PrevEnv, Value &Current,
880                                    Environment &CurrentEnv) override {
881     switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
882     case ComparisonResult::Same:
883       return WidenResult{&Current, LatticeJoinEffect::Unchanged};
884     case ComparisonResult::Different: {
885       auto &CurPtr = cast<PointerValue>(Current);
886       auto &WidenedPtr =
887           CurrentEnv.create<PointerValue>(CurPtr.getPointeeLoc());
888       WidenedPtr.setProperty("is_null", CurrentEnv.makeTopBoolValue());
889       return WidenResult{&WidenedPtr, LatticeJoinEffect::Changed};
890     }
891     case ComparisonResult::Unknown:
892       return std::nullopt;
893     }
894     llvm_unreachable("all cases in switch covered");
895   }
896 };
897 
898 class WideningTest : public Test {
899 protected:
900   template <typename Matcher>
901   void runDataflow(llvm::StringRef Code, Matcher Match) {
902     ASSERT_THAT_ERROR(
903         checkDataflow<NullPointerAnalysis>(
904             AnalysisInputs<NullPointerAnalysis>(
905                 Code, ast_matchers::hasName("target"),
906                 [](ASTContext &Context, Environment &Env) {
907                   return NullPointerAnalysis(Context);
908                 })
909                 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
910             /*VerifyResults=*/[&Match](const llvm::StringMap<
911                                            DataflowAnalysisState<NoopLattice>>
912                                            &Results,
913                                        const AnalysisOutputs
914                                            &AO) { Match(Results, AO.ASTCtx); }),
915         llvm::Succeeded());
916   }
917 };
918 
919 TEST_F(WideningTest, JoinDistinctValuesWithDistinctProperties) {
920   std::string Code = R"(
921     void target(bool Cond) {
922       int *Foo = nullptr;
923       int i = 0;
924       /*[[p1]]*/
925       if (Cond) {
926         Foo = &i;
927         /*[[p2]]*/
928       }
929       (void)0;
930       /*[[p3]]*/
931     }
932   )";
933   runDataflow(
934       Code,
935       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
936          ASTContext &ASTCtx) {
937         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
938         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
939         const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");
940 
941         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
942         ASSERT_THAT(FooDecl, NotNull());
943 
944         auto GetFooValue = [FooDecl](const Environment &Env) {
945           return Env.getValue(*FooDecl);
946         };
947 
948         EXPECT_EQ(GetFooValue(Env1)->getProperty("is_null"),
949                   &Env1.getBoolLiteralValue(true));
950         EXPECT_EQ(GetFooValue(Env2)->getProperty("is_null"),
951                   &Env2.getBoolLiteralValue(false));
952         EXPECT_TRUE(
953             isa<TopBoolValue>(GetFooValue(Env3)->getProperty("is_null")));
954       });
955 }
956 
957 TEST_F(WideningTest, JoinDistinctValuesWithSameProperties) {
958   std::string Code = R"(
959     void target(bool Cond) {
960       int *Foo = nullptr;
961       int i1 = 0;
962       int i2 = 0;
963       /*[[p1]]*/
964       if (Cond) {
965         Foo = &i1;
966         /*[[p2]]*/
967       } else {
968         Foo = &i2;
969         /*[[p3]]*/
970       }
971       (void)0;
972       /*[[p4]]*/
973     }
974   )";
975   runDataflow(
976       Code,
977       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
978          ASTContext &ASTCtx) {
979         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
980         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
981         const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");
982         const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4");
983 
984         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
985         ASSERT_THAT(FooDecl, NotNull());
986 
987         auto GetFooValue = [FooDecl](const Environment &Env) {
988           return Env.getValue(*FooDecl);
989         };
990 
991         EXPECT_EQ(GetFooValue(Env1)->getProperty("is_null"),
992                   &Env1.getBoolLiteralValue(true));
993         EXPECT_EQ(GetFooValue(Env2)->getProperty("is_null"),
994                   &Env2.getBoolLiteralValue(false));
995         EXPECT_EQ(GetFooValue(Env3)->getProperty("is_null"),
996                   &Env3.getBoolLiteralValue(false));
997         EXPECT_EQ(GetFooValue(Env4)->getProperty("is_null"),
998                   &Env4.getBoolLiteralValue(false));
999       });
1000 }
1001 
1002 TEST_F(WideningTest, DistinctPointersToTheSameLocationAreEquivalent) {
1003   std::string Code = R"(
1004     void target(int Foo, bool Cond) {
1005       int *Bar = &Foo;
1006       while (Cond) {
1007         Bar = &Foo;
1008       }
1009       (void)0;
1010       // [[p]]
1011     }
1012   )";
1013   runDataflow(
1014       Code,
1015       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1016          ASTContext &ASTCtx) {
1017         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1018         const auto &FooLoc =
1019             getLocForDecl<ScalarStorageLocation>(ASTCtx, Env, "Foo");
1020         const auto &BarVal = getValueForDecl<PointerValue>(ASTCtx, Env, "Bar");
1021         EXPECT_EQ(&BarVal.getPointeeLoc(), &FooLoc);
1022       });
1023 }
1024 
1025 TEST_F(WideningTest, DistinctValuesWithSamePropertiesAreEquivalent) {
1026   std::string Code = R"(
1027     void target(bool Cond) {
1028       int *Foo;
1029       int i1 = 0;
1030       int i2 = 0;
1031       Foo = &i1;
1032       while (Cond) {
1033         Foo = &i2;
1034       }
1035       (void)0;
1036       /*[[p]]*/
1037     }
1038   )";
1039   runDataflow(
1040       Code,
1041       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1042          ASTContext &ASTCtx) {
1043         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1044         const auto &FooVal = getValueForDecl<Value>(ASTCtx, Env, "Foo");
1045         EXPECT_EQ(FooVal.getProperty("is_null"),
1046                   &Env.getBoolLiteralValue(false));
1047       });
1048 }
1049 
1050 TEST_F(WideningTest, DistinctValuesWithDifferentPropertiesWidenedToTop) {
1051   std::string Code = R"(
1052     void target(bool Cond) {
1053       int *Foo;
1054       int i = 0;
1055       Foo = nullptr;
1056       while (Cond) {
1057         Foo = &i;
1058       }
1059       (void)0;
1060       /*[[p]]*/
1061     }
1062   )";
1063   runDataflow(
1064       Code,
1065       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1066          ASTContext &ASTCtx) {
1067         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1068         const auto &FooVal = getValueForDecl<Value>(ASTCtx, Env, "Foo");
1069         ASSERT_THAT(FooVal.getProperty("is_null"), NotNull());
1070         EXPECT_TRUE(areEquivalentValues(*FooVal.getProperty("is_null"),
1071                                         Env.makeTopBoolValue()));
1072       });
1073 }
1074 
1075 class FlowConditionTest : public Test {
1076 protected:
1077   template <typename Matcher>
1078   void runDataflow(llvm::StringRef Code, Matcher Match) {
1079     ASSERT_THAT_ERROR(
1080         checkDataflow<NoopAnalysis>(
1081             AnalysisInputs<NoopAnalysis>(
1082                 Code, ast_matchers::hasName("target"),
1083                 [](ASTContext &Context, Environment &Env) {
1084                   return NoopAnalysis(Context);
1085                 })
1086                 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
1087             /*VerifyResults=*/[&Match](const llvm::StringMap<
1088                                            DataflowAnalysisState<NoopLattice>>
1089                                            &Results,
1090                                        const AnalysisOutputs
1091                                            &AO) { Match(Results, AO.ASTCtx); }),
1092         llvm::Succeeded());
1093   }
1094 };
1095 
1096 TEST_F(FlowConditionTest, IfStmtSingleVar) {
1097   std::string Code = R"(
1098     void target(bool Foo) {
1099       if (Foo) {
1100         (void)0;
1101         /*[[p1]]*/
1102       } else {
1103         (void)1;
1104         /*[[p2]]*/
1105       }
1106     }
1107   )";
1108   runDataflow(
1109       Code,
1110       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1111          ASTContext &ASTCtx) {
1112         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1113         ASSERT_THAT(FooDecl, NotNull());
1114 
1115         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1116 
1117         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1118         auto &FooVal1 = cast<BoolValue>(Env1.getValue(*FooDecl))->formula();
1119         EXPECT_TRUE(Env1.proves(FooVal1));
1120 
1121         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1122         auto &FooVal2 = cast<BoolValue>(Env2.getValue(*FooDecl))->formula();
1123         EXPECT_FALSE(Env2.proves(FooVal2));
1124       });
1125 }
1126 
1127 TEST_F(FlowConditionTest, IfStmtSingleNegatedVar) {
1128   std::string Code = R"(
1129     void target(bool Foo) {
1130       if (!Foo) {
1131         (void)0;
1132         /*[[p1]]*/
1133       } else {
1134         (void)1;
1135         /*[[p2]]*/
1136       }
1137     }
1138   )";
1139   runDataflow(
1140       Code,
1141       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1142          ASTContext &ASTCtx) {
1143         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1144         ASSERT_THAT(FooDecl, NotNull());
1145 
1146         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1147 
1148         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1149         auto &FooVal1 = cast<BoolValue>(Env1.getValue(*FooDecl))->formula();
1150         EXPECT_FALSE(Env1.proves(FooVal1));
1151 
1152         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1153         auto &FooVal2 = cast<BoolValue>(Env2.getValue(*FooDecl))->formula();
1154         EXPECT_TRUE(Env2.proves(FooVal2));
1155       });
1156 }
1157 
1158 TEST_F(FlowConditionTest, WhileStmt) {
1159   std::string Code = R"(
1160     void target(bool Foo) {
1161       while (Foo) {
1162         (void)0;
1163         /*[[p]]*/
1164       }
1165     }
1166   )";
1167   runDataflow(
1168       Code,
1169       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1170          ASTContext &ASTCtx) {
1171         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1172         ASSERT_THAT(FooDecl, NotNull());
1173 
1174         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1175         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1176 
1177         auto &FooVal = cast<BoolValue>(Env.getValue(*FooDecl))->formula();
1178         EXPECT_TRUE(Env.proves(FooVal));
1179       });
1180 }
1181 
1182 TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) {
1183   std::string Code = R"(
1184     void target(bool Foo) {
1185       // This test checks whether the analysis preserves the connection between
1186       // the value of `Foo` and the assignment expression, despite widening.
1187       // The equality operator generates a fresh boolean variable on each
1188       // interpretation, which forces use of widening.
1189       while ((Foo = (3 == 4))) {
1190         (void)0;
1191         /*[[p]]*/
1192       }
1193     }
1194   )";
1195   runDataflow(
1196       Code,
1197       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1198          ASTContext &ASTCtx) {
1199         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1200         auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Foo").formula();
1201         EXPECT_TRUE(Env.proves(FooVal));
1202       });
1203 }
1204 
1205 TEST_F(FlowConditionTest, Conjunction) {
1206   std::string Code = R"(
1207     void target(bool Foo, bool Bar) {
1208       if (Foo && Bar) {
1209         (void)0;
1210         /*[[p1]]*/
1211       } else {
1212         (void)1;
1213         /*[[p2]]*/
1214       }
1215     }
1216   )";
1217   runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
1218                            &Results,
1219                        ASTContext &ASTCtx) {
1220     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1221     ASSERT_THAT(FooDecl, NotNull());
1222 
1223     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1224     ASSERT_THAT(BarDecl, NotNull());
1225 
1226     ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1227 
1228     const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1229     auto &FooVal1 = cast<BoolValue>(Env1.getValue(*FooDecl))->formula();
1230     auto &BarVal1 = cast<BoolValue>(Env1.getValue(*BarDecl))->formula();
1231     EXPECT_TRUE(Env1.proves(FooVal1));
1232     EXPECT_TRUE(Env1.proves(BarVal1));
1233 
1234     const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1235     auto &FooVal2 = cast<BoolValue>(Env2.getValue(*FooDecl))->formula();
1236     auto &BarVal2 = cast<BoolValue>(Env2.getValue(*BarDecl))->formula();
1237     EXPECT_FALSE(Env2.proves(FooVal2));
1238     EXPECT_FALSE(Env2.proves(BarVal2));
1239   });
1240 }
1241 
1242 TEST_F(FlowConditionTest, Disjunction) {
1243   std::string Code = R"(
1244     void target(bool Foo, bool Bar) {
1245       if (Foo || Bar) {
1246         (void)0;
1247         /*[[p1]]*/
1248       } else {
1249         (void)1;
1250         /*[[p2]]*/
1251       }
1252     }
1253   )";
1254   runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
1255                            &Results,
1256                        ASTContext &ASTCtx) {
1257     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1258     ASSERT_THAT(FooDecl, NotNull());
1259 
1260     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1261     ASSERT_THAT(BarDecl, NotNull());
1262 
1263     ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1264 
1265     const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1266     auto &FooVal1 = cast<BoolValue>(Env1.getValue(*FooDecl))->formula();
1267     auto &BarVal1 = cast<BoolValue>(Env1.getValue(*BarDecl))->formula();
1268     EXPECT_FALSE(Env1.proves(FooVal1));
1269     EXPECT_FALSE(Env1.proves(BarVal1));
1270 
1271     const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1272     auto &FooVal2 = cast<BoolValue>(Env2.getValue(*FooDecl))->formula();
1273     auto &BarVal2 = cast<BoolValue>(Env2.getValue(*BarDecl))->formula();
1274     EXPECT_FALSE(Env2.proves(FooVal2));
1275     EXPECT_FALSE(Env2.proves(BarVal2));
1276   });
1277 }
1278 
1279 TEST_F(FlowConditionTest, NegatedConjunction) {
1280   std::string Code = R"(
1281     void target(bool Foo, bool Bar) {
1282       if (!(Foo && Bar)) {
1283         (void)0;
1284         /*[[p1]]*/
1285       } else {
1286         (void)1;
1287         /*[[p2]]*/
1288       }
1289     }
1290   )";
1291   runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
1292                            &Results,
1293                        ASTContext &ASTCtx) {
1294     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1295     ASSERT_THAT(FooDecl, NotNull());
1296 
1297     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1298     ASSERT_THAT(BarDecl, NotNull());
1299 
1300     ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1301 
1302     const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1303     auto &FooVal1 = cast<BoolValue>(Env1.getValue(*FooDecl))->formula();
1304     auto &BarVal1 = cast<BoolValue>(Env1.getValue(*BarDecl))->formula();
1305     EXPECT_FALSE(Env1.proves(FooVal1));
1306     EXPECT_FALSE(Env1.proves(BarVal1));
1307 
1308     const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1309     auto &FooVal2 = cast<BoolValue>(Env2.getValue(*FooDecl))->formula();
1310     auto &BarVal2 = cast<BoolValue>(Env2.getValue(*BarDecl))->formula();
1311     EXPECT_TRUE(Env2.proves(FooVal2));
1312     EXPECT_TRUE(Env2.proves(BarVal2));
1313   });
1314 }
1315 
1316 TEST_F(FlowConditionTest, DeMorgan) {
1317   std::string Code = R"(
1318     void target(bool Foo, bool Bar) {
1319       if (!(!Foo || !Bar)) {
1320         (void)0;
1321         /*[[p1]]*/
1322       } else {
1323         (void)1;
1324         /*[[p2]]*/
1325       }
1326     }
1327   )";
1328   runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
1329                            &Results,
1330                        ASTContext &ASTCtx) {
1331     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1332     ASSERT_THAT(FooDecl, NotNull());
1333 
1334     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1335     ASSERT_THAT(BarDecl, NotNull());
1336 
1337     ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1338 
1339     const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1340     auto &FooVal1 = cast<BoolValue>(Env1.getValue(*FooDecl))->formula();
1341     auto &BarVal1 = cast<BoolValue>(Env1.getValue(*BarDecl))->formula();
1342     EXPECT_TRUE(Env1.proves(FooVal1));
1343     EXPECT_TRUE(Env1.proves(BarVal1));
1344 
1345     const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1346     auto &FooVal2 = cast<BoolValue>(Env2.getValue(*FooDecl))->formula();
1347     auto &BarVal2 = cast<BoolValue>(Env2.getValue(*BarDecl))->formula();
1348     EXPECT_FALSE(Env2.proves(FooVal2));
1349     EXPECT_FALSE(Env2.proves(BarVal2));
1350   });
1351 }
1352 
1353 TEST_F(FlowConditionTest, Join) {
1354   std::string Code = R"(
1355     void target(bool Foo, bool Bar) {
1356       if (Bar) {
1357         if (!Foo)
1358           return;
1359       } else {
1360         if (!Foo)
1361           return;
1362       }
1363       (void)0;
1364       /*[[p]]*/
1365     }
1366   )";
1367   runDataflow(
1368       Code,
1369       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1370          ASTContext &ASTCtx) {
1371         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1372 
1373         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1374         ASSERT_THAT(FooDecl, NotNull());
1375 
1376         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1377         auto &FooVal = cast<BoolValue>(Env.getValue(*FooDecl))->formula();
1378         EXPECT_TRUE(Env.proves(FooVal));
1379       });
1380 }
1381 
1382 // Verifies that flow conditions are properly constructed even when the
1383 // condition is not meaningfully interpreted.
1384 //
1385 // Note: currently, arbitrary function calls are uninterpreted, so the test
1386 // exercises this case. If and when we change that, this test will not add to
1387 // coverage (although it may still test a valuable case).
1388 TEST_F(FlowConditionTest, OpaqueFlowConditionJoinsToOpaqueBool) {
1389   std::string Code = R"(
1390     bool foo();
1391 
1392     void target() {
1393       bool Bar = true;
1394       if (foo())
1395         Bar = false;
1396       (void)0;
1397       /*[[p]]*/
1398     }
1399   )";
1400   runDataflow(
1401       Code,
1402       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1403          ASTContext &ASTCtx) {
1404         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1405         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1406 
1407         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1408         ASSERT_THAT(BarDecl, NotNull());
1409 
1410         auto &BarVal = cast<BoolValue>(Env.getValue(*BarDecl))->formula();
1411 
1412         EXPECT_FALSE(Env.proves(BarVal));
1413       });
1414 }
1415 
1416 // Verifies that flow conditions are properly constructed even when the
1417 // condition is not meaningfully interpreted.
1418 //
1419 // Note: currently, fields with recursive type calls are uninterpreted (beneath
1420 // the first instance), so the test exercises this case. If and when we change
1421 // that, this test will not add to coverage (although it may still test a
1422 // valuable case).
1423 TEST_F(FlowConditionTest, OpaqueFieldFlowConditionJoinsToOpaqueBool) {
1424   std::string Code = R"(
1425     struct Rec {
1426       Rec* Next;
1427     };
1428 
1429     struct Foo {
1430       Rec* X;
1431     };
1432 
1433     void target(Foo F) {
1434       bool Bar = true;
1435       if (F.X->Next)
1436         Bar = false;
1437       (void)0;
1438       /*[[p]]*/
1439     }
1440   )";
1441   runDataflow(
1442       Code,
1443       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1444          ASTContext &ASTCtx) {
1445         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1446         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1447 
1448         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1449         ASSERT_THAT(BarDecl, NotNull());
1450 
1451         auto &BarVal = cast<BoolValue>(Env.getValue(*BarDecl))->formula();
1452 
1453         EXPECT_FALSE(Env.proves(BarVal));
1454       });
1455 }
1456 
1457 // Verifies that flow conditions are properly constructed even when the
1458 // condition is not meaningfully interpreted. Adds to above by nesting the
1459 // interestnig case inside a normal branch. This protects against degenerate
1460 // solutions which only test for empty flow conditions, for example.
1461 TEST_F(FlowConditionTest, OpaqueFlowConditionInsideBranchJoinsToOpaqueBool) {
1462   std::string Code = R"(
1463     bool foo();
1464 
1465     void target(bool Cond) {
1466       bool Bar = true;
1467       if (Cond) {
1468         if (foo())
1469           Bar = false;
1470         (void)0;
1471         /*[[p]]*/
1472       }
1473     }
1474   )";
1475   runDataflow(
1476       Code,
1477       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1478          ASTContext &ASTCtx) {
1479         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1480         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1481 
1482         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1483         ASSERT_THAT(BarDecl, NotNull());
1484 
1485         auto &BarVal = cast<BoolValue>(Env.getValue(*BarDecl))->formula();
1486 
1487         EXPECT_FALSE(Env.proves(BarVal));
1488       });
1489 }
1490 
1491 TEST_F(FlowConditionTest, PointerToBoolImplicitCast) {
1492   std::string Code = R"(
1493     void target(int *Ptr) {
1494       bool Foo = false;
1495       if (Ptr) {
1496         Foo = true;
1497         /*[[p1]]*/
1498       }
1499 
1500       (void)0;
1501       /*[[p2]]*/
1502     }
1503   )";
1504   runDataflow(
1505       Code,
1506       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1507          ASTContext &ASTCtx) {
1508         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1509 
1510         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1511         ASSERT_THAT(FooDecl, NotNull());
1512 
1513         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1514         auto &FooVal1 = cast<BoolValue>(Env1.getValue(*FooDecl))->formula();
1515         EXPECT_TRUE(Env1.proves(FooVal1));
1516 
1517         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1518         auto &FooVal2 = cast<BoolValue>(Env2.getValue(*FooDecl))->formula();
1519         EXPECT_FALSE(Env2.proves(FooVal2));
1520       });
1521 }
1522 
1523 class TopAnalysis final : public DataflowAnalysis<TopAnalysis, NoopLattice> {
1524 public:
1525   explicit TopAnalysis(ASTContext &Context)
1526       : DataflowAnalysis<TopAnalysis, NoopLattice>(Context) {}
1527 
1528   static NoopLattice initialElement() { return {}; }
1529 
1530   void transfer(const CFGElement &Elt, NoopLattice &, Environment &Env) {
1531     auto CS = Elt.getAs<CFGStmt>();
1532     if (!CS)
1533       return;
1534     const Stmt *S = CS->getStmt();
1535     SmallVector<BoundNodes, 1> Matches =
1536         match(callExpr(callee(functionDecl(hasName("makeTop")))).bind("top"),
1537               *S, getASTContext());
1538     if (const auto *E = selectFirst<CallExpr>("top", Matches)) {
1539       Env.setValue(*E, Env.makeTopBoolValue());
1540     }
1541   }
1542 
1543   ComparisonResult compare(QualType Type, const Value &Val1,
1544                            const Environment &Env1, const Value &Val2,
1545                            const Environment &Env2) override {
1546     // Changes to a sound approximation, which allows us to test whether we can
1547     // (soundly) converge for some loops.
1548     return ComparisonResult::Unknown;
1549   }
1550 };
1551 
1552 class TopTest : public Test {
1553 protected:
1554   template <typename Matcher>
1555   void runDataflow(llvm::StringRef Code, Matcher VerifyResults) {
1556     ASSERT_THAT_ERROR(
1557         checkDataflow<TopAnalysis>(
1558             AnalysisInputs<TopAnalysis>(
1559                 Code, ast_matchers::hasName("target"),
1560                 [](ASTContext &Context, Environment &Env) {
1561                   return TopAnalysis(Context);
1562                 })
1563                 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
1564             VerifyResults),
1565         llvm::Succeeded());
1566   }
1567 };
1568 
1569 // Tests that when Top is unused it remains Top.
1570 TEST_F(TopTest, UnusedTopInitializer) {
1571   std::string Code = R"(
1572     bool makeTop();
1573 
1574     void target() {
1575       bool Foo = makeTop();
1576       /*[[p1]]*/
1577       (void)0;
1578       /*[[p2]]*/
1579     }
1580   )";
1581   runDataflow(
1582       Code,
1583       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1584          const AnalysisOutputs &AO) {
1585         ASSERT_THAT(Results.keys(),
1586                     UnorderedElementsAre("p1", "p2"));
1587         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1588         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1589 
1590         const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo");
1591         ASSERT_THAT(FooDecl, NotNull());
1592 
1593         auto GetFooValue = [FooDecl](const Environment &Env) {
1594           return Env.getValue(*FooDecl);
1595         };
1596 
1597         Value *FooVal1 = GetFooValue(Env1);
1598         ASSERT_THAT(FooVal1, NotNull());
1599         EXPECT_TRUE(isa<TopBoolValue>(FooVal1))
1600             << debugString(FooVal1->getKind());
1601 
1602         Value *FooVal2 = GetFooValue(Env2);
1603         ASSERT_THAT(FooVal2, NotNull());
1604         EXPECT_TRUE(isa<TopBoolValue>(FooVal2))
1605             << debugString(FooVal2->getKind());
1606 
1607         EXPECT_EQ(FooVal1, FooVal2);
1608       });
1609 }
1610 
1611 // Tests that when Top is unused it remains Top. Like above, but uses the
1612 // assignment form rather than initialization, which uses Top as an lvalue that
1613 // is *not* in an rvalue position.
1614 TEST_F(TopTest, UnusedTopAssignment) {
1615   std::string Code = R"(
1616     bool makeTop();
1617 
1618     void target() {
1619       bool Foo;
1620       Foo = makeTop();
1621       /*[[p1]]*/
1622       (void)0;
1623       /*[[p2]]*/
1624     }
1625   )";
1626   runDataflow(
1627       Code,
1628       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1629          const AnalysisOutputs &AO) {
1630         ASSERT_THAT(Results.keys(),
1631                     UnorderedElementsAre("p1", "p2"));
1632         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1633         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1634 
1635         const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo");
1636         ASSERT_THAT(FooDecl, NotNull());
1637 
1638         auto GetFooValue = [FooDecl](const Environment &Env) {
1639           return Env.getValue(*FooDecl);
1640         };
1641 
1642         Value *FooVal1 = GetFooValue(Env1);
1643         ASSERT_THAT(FooVal1, NotNull());
1644         EXPECT_TRUE(isa<TopBoolValue>(FooVal1))
1645             << debugString(FooVal1->getKind());
1646 
1647         Value *FooVal2 = GetFooValue(Env2);
1648         ASSERT_THAT(FooVal2, NotNull());
1649         EXPECT_TRUE(isa<TopBoolValue>(FooVal2))
1650             << debugString(FooVal2->getKind());
1651 
1652         EXPECT_EQ(FooVal1, FooVal2);
1653       });
1654 }
1655 
1656 TEST_F(TopTest, UnusedTopJoinsToTop) {
1657   std::string Code = R"(
1658     bool makeTop();
1659 
1660     void target(bool Cond, bool F) {
1661       bool Foo = makeTop();
1662       // Force a new CFG block.
1663       if (F) return;
1664       (void)0;
1665       /*[[p1]]*/
1666 
1667       bool Zab1;
1668       bool Zab2;
1669       if (Cond) {
1670         Zab1 = true;
1671       } else {
1672         Zab2 = true;
1673       }
1674       (void)0;
1675       /*[[p2]]*/
1676     }
1677   )";
1678   runDataflow(
1679       Code,
1680       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1681          const AnalysisOutputs &AO) {
1682         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1683         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1684         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1685 
1686         const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo");
1687         ASSERT_THAT(FooDecl, NotNull());
1688 
1689         auto GetFooValue = [FooDecl](const Environment &Env) {
1690           return Env.getValue(*FooDecl);
1691         };
1692 
1693         Value *FooVal1 = GetFooValue(Env1);
1694         ASSERT_THAT(FooVal1, NotNull());
1695         EXPECT_TRUE(isa<TopBoolValue>(FooVal1))
1696             << debugString(FooVal1->getKind());
1697 
1698         Value *FooVal2 = GetFooValue(Env2);
1699         ASSERT_THAT(FooVal2, NotNull());
1700         EXPECT_TRUE(isa<TopBoolValue>(FooVal2))
1701             << debugString(FooVal2->getKind());
1702       });
1703 }
1704 
1705 TEST_F(TopTest, TopUsedBeforeBranchJoinsToSameAtomicBool) {
1706   std::string Code = R"(
1707     bool makeTop();
1708 
1709     void target(bool Cond, bool F) {
1710       bool Foo = makeTop();
1711       /*[[p0]]*/
1712 
1713       // Use `Top`.
1714       bool Bar = Foo;
1715       // Force a new CFG block.
1716       if (F) return;
1717       (void)0;
1718       /*[[p1]]*/
1719 
1720       bool Zab1;
1721       bool Zab2;
1722       if (Cond) {
1723         Zab1 = true;
1724       } else {
1725         Zab2 = true;
1726       }
1727       (void)0;
1728       /*[[p2]]*/
1729     }
1730   )";
1731   runDataflow(
1732       Code,
1733       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1734          const AnalysisOutputs &AO) {
1735         ASSERT_THAT(Results.keys(),
1736                     UnorderedElementsAre("p0", "p1", "p2"));
1737         const Environment &Env0 = getEnvironmentAtAnnotation(Results, "p0");
1738         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1739         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1740 
1741         const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo");
1742         ASSERT_THAT(FooDecl, NotNull());
1743 
1744         auto GetFooValue = [FooDecl](const Environment &Env) {
1745           return Env.getValue(*FooDecl);
1746         };
1747 
1748         Value *FooVal0 = GetFooValue(Env0);
1749         ASSERT_THAT(FooVal0, NotNull());
1750         EXPECT_TRUE(isa<TopBoolValue>(FooVal0))
1751             << debugString(FooVal0->getKind());
1752 
1753         Value *FooVal1 = GetFooValue(Env1);
1754         ASSERT_THAT(FooVal1, NotNull());
1755         EXPECT_TRUE(isa<AtomicBoolValue>(FooVal1))
1756             << debugString(FooVal1->getKind());
1757 
1758         Value *FooVal2 = GetFooValue(Env2);
1759         ASSERT_THAT(FooVal2, NotNull());
1760         EXPECT_TRUE(isa<AtomicBoolValue>(FooVal2))
1761             << debugString(FooVal2->getKind());
1762 
1763         EXPECT_EQ(FooVal2, FooVal1);
1764       });
1765 }
1766 
1767 TEST_F(TopTest, TopUsedInBothBranchesJoinsToAtomic) {
1768   std::string Code = R"(
1769     bool makeTop();
1770 
1771     void target(bool Cond, bool F) {
1772       bool Foo = makeTop();
1773       // Force a new CFG block.
1774       if (F) return;
1775       (void)0;
1776       /*[[p1]]*/
1777 
1778       bool Zab1;
1779       bool Zab2;
1780       if (Cond) {
1781         Zab1 = Foo;
1782       } else {
1783         Zab2 = Foo;
1784       }
1785       (void)0;
1786       /*[[p2]]*/
1787     }
1788   )";
1789   runDataflow(
1790       Code,
1791       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1792          const AnalysisOutputs &AO) {
1793         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1794         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1795         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1796 
1797         const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo");
1798         ASSERT_THAT(FooDecl, NotNull());
1799 
1800         auto GetFooValue = [FooDecl](const Environment &Env) {
1801           return Env.getValue(*FooDecl);
1802         };
1803 
1804         Value *FooVal1 = GetFooValue(Env1);
1805         ASSERT_THAT(FooVal1, NotNull());
1806         EXPECT_TRUE(isa<TopBoolValue>(FooVal1))
1807             << debugString(FooVal1->getKind());
1808 
1809         Value *FooVal2 = GetFooValue(Env2);
1810         ASSERT_THAT(FooVal2, NotNull());
1811         EXPECT_TRUE(isa<AtomicBoolValue>(FooVal2))
1812             << debugString(FooVal2->getKind());
1813       });
1814 }
1815 
1816 TEST_F(TopTest, TopUsedInBothBranchesWithoutPrecisionLoss) {
1817   std::string Code = R"(
1818     bool makeTop();
1819 
1820     void target(bool Cond, bool F) {
1821       bool Foo = makeTop();
1822       // Force a new CFG block.
1823       if (F) return;
1824       (void)0;
1825 
1826       bool Bar;
1827       if (Cond) {
1828         Bar = Foo;
1829       } else {
1830         Bar = Foo;
1831       }
1832       (void)0;
1833       /*[[p]]*/
1834     }
1835   )";
1836   runDataflow(
1837       Code,
1838       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1839          const AnalysisOutputs &AO) {
1840         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1841         const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1842 
1843         const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo");
1844         ASSERT_THAT(FooDecl, NotNull());
1845 
1846         const ValueDecl *BarDecl = findValueDecl(AO.ASTCtx, "Bar");
1847         ASSERT_THAT(BarDecl, NotNull());
1848 
1849         auto *FooVal = dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
1850         ASSERT_THAT(FooVal, NotNull());
1851 
1852         auto *BarVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
1853         ASSERT_THAT(BarVal, NotNull());
1854 
1855         EXPECT_TRUE(Env.proves(
1856             Env.arena().makeEquals(FooVal->formula(), BarVal->formula())));
1857       });
1858 }
1859 
1860 TEST_F(TopTest, TopUnusedBeforeLoopHeadJoinsToTop) {
1861   std::string Code = R"(
1862     bool makeTop();
1863 
1864     void target(bool Cond, bool F) {
1865       bool Foo = makeTop();
1866       // Force a new CFG block.
1867       if (F) return;
1868       (void)0;
1869       /*[[p1]]*/
1870 
1871       while (Cond) {
1872         // Use `Foo`.
1873         bool Zab = Foo;
1874         Zab = false;
1875         Foo = makeTop();
1876       }
1877       (void)0;
1878       /*[[p2]]*/
1879     }
1880   )";
1881   runDataflow(
1882       Code,
1883       [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1884          const AnalysisOutputs &AO) {
1885         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1886         const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
1887         const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
1888 
1889         const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo");
1890         ASSERT_THAT(FooDecl, NotNull());
1891 
1892         auto GetFooValue = [FooDecl](const Environment &Env) {
1893           return Env.getValue(*FooDecl);
1894         };
1895 
1896         Value *FooVal1 = GetFooValue(Env1);
1897         ASSERT_THAT(FooVal1, NotNull());
1898         EXPECT_TRUE(isa<TopBoolValue>(FooVal1))
1899             << debugString(FooVal1->getKind());
1900 
1901         Value *FooVal2 = GetFooValue(Env2);
1902         ASSERT_THAT(FooVal2, NotNull());
1903         EXPECT_TRUE(isa<TopBoolValue>(FooVal2))
1904             << debugString(FooVal2->getKind());
1905 
1906       });
1907 }
1908 
1909 TEST_F(TopTest, ForRangeStmtConverges) {
1910   std::string Code = R"(
1911     void target(bool Foo) {
1912       int Ints[10];
1913       bool B = false;
1914       for (int I : Ints)
1915         B = true;
1916     }
1917   )";
1918   runDataflow(Code,
1919               [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
1920                  const AnalysisOutputs &) {
1921                 // No additional expectations. We're only checking that the
1922                 // analysis converged.
1923               });
1924 }
1925 } // namespace
1926