xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/TestingSupport.h (revision cfd202141069809c3c65b8b49d3896f44ff10a6a)
1 //===--- TestingSupport.h - Testing utils for dataflow analyses -*- C++ -*-===//
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 // This file defines utilities to simplify testing of dataflow analyses.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_ANALYSIS_FLOW_SENSITIVE_TESTING_SUPPORT_H_
14 #define LLVM_CLANG_ANALYSIS_FLOW_SENSITIVE_TESTING_SUPPORT_H_
15 
16 #include <functional>
17 #include <memory>
18 #include <optional>
19 #include <ostream>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "clang/AST/ASTContext.h"
25 #include "clang/AST/Decl.h"
26 #include "clang/AST/Stmt.h"
27 #include "clang/ASTMatchers/ASTMatchFinder.h"
28 #include "clang/ASTMatchers/ASTMatchers.h"
29 #include "clang/ASTMatchers/ASTMatchersInternal.h"
30 #include "clang/Analysis/CFG.h"
31 #include "clang/Analysis/FlowSensitive/AdornedCFG.h"
32 #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
33 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
34 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
35 #include "clang/Analysis/FlowSensitive/MatchSwitch.h"
36 #include "clang/Analysis/FlowSensitive/NoopLattice.h"
37 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
38 #include "clang/Basic/LLVM.h"
39 #include "clang/Serialization/PCHContainerOperations.h"
40 #include "clang/Tooling/ArgumentsAdjusters.h"
41 #include "clang/Tooling/Tooling.h"
42 #include "llvm/ADT/ArrayRef.h"
43 #include "llvm/ADT/DenseMap.h"
44 #include "llvm/ADT/StringMap.h"
45 #include "llvm/ADT/StringRef.h"
46 #include "llvm/Support/Allocator.h"
47 #include "llvm/Support/Errc.h"
48 #include "llvm/Support/Error.h"
49 #include "llvm/Testing/Annotations/Annotations.h"
50 
51 namespace clang {
52 namespace dataflow {
53 
54 // Requires a `<<` operator for the `Lattice` type.
55 // FIXME: move to a non-test utility library.
56 template <typename Lattice>
57 std::ostream &operator<<(std::ostream &OS,
58                          const DataflowAnalysisState<Lattice> &S) {
59   // FIXME: add printing support for the environment.
60   return OS << "{lattice=" << S.Lattice << ", environment=...}";
61 }
62 
63 namespace test {
64 
65 // Caps the number of block visits in any individual analysis. Given that test
66 // code is typically quite small, we set a low number to help catch any problems
67 // early. But, the choice is arbitrary.
68 constexpr std::int32_t MaxBlockVisitsInAnalysis = 2'000;
69 
70 /// Returns the environment at the program point marked with `Annotation` from
71 /// the mapping of annotated program points to analysis state.
72 ///
73 /// Requirements:
74 ///
75 ///   `Annotation` must be present as a key in `AnnotationStates`.
76 template <typename LatticeT>
getEnvironmentAtAnnotation(const llvm::StringMap<DataflowAnalysisState<LatticeT>> & AnnotationStates,llvm::StringRef Annotation)77 const Environment &getEnvironmentAtAnnotation(
78     const llvm::StringMap<DataflowAnalysisState<LatticeT>> &AnnotationStates,
79     llvm::StringRef Annotation) {
80   auto It = AnnotationStates.find(Annotation);
81   assert(It != AnnotationStates.end());
82   return It->getValue().Env;
83 }
84 
85 /// Contains data structures required and produced by a dataflow analysis run.
86 struct AnalysisOutputs {
87   /// Input code that is analyzed. Points within the code may be marked with
88   /// annotations to facilitate testing.
89   ///
90   /// Example:
91   /// void target(int *x) {
92   ///   *x; // [[p]]
93   /// }
94   /// From the annotation `p`, the line number and analysis state immediately
95   /// after the statement `*x` can be retrieved and verified.
96   llvm::Annotations Code;
97   /// AST context generated from `Code`.
98   ASTContext &ASTCtx;
99   /// The function whose body is analyzed.
100   const FunctionDecl *Target;
101   /// Contains the control flow graph built from the body of the `Target`
102   /// function and is analyzed.
103   const AdornedCFG &ACFG;
104   /// The analysis to be run.
105   TypeErasedDataflowAnalysis &Analysis;
106   /// Initial state to start the analysis.
107   const Environment &InitEnv;
108   // Stores the state of a CFG block if it has been evaluated by the analysis.
109   // The indices correspond to the block IDs.
110   llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockStates;
111 };
112 
113 /// A callback to be called with the state before or after visiting a CFG
114 /// element.
115 /// This differs from `DiagnosisCallback` in that the return type is void.
116 template <typename AnalysisT>
117 using DiagnosisCallbackForTesting = std::function<void(
118     ASTContext &, const CFGElement &,
119     const TransferStateForDiagnostics<typename AnalysisT::Lattice> &)>;
120 
121 /// A pair of callbacks to be called with the state before and after visiting a
122 /// CFG element.
123 /// Either or both of the callbacks may be null.
124 template <typename AnalysisT> struct DiagnosisCallbacksForTesting {
125   DiagnosisCallbackForTesting<AnalysisT> Before;
126   DiagnosisCallbackForTesting<AnalysisT> After;
127 };
128 
129 /// Arguments for building the dataflow analysis.
130 template <typename AnalysisT> struct AnalysisInputs {
131   /// Required fields are set in constructor.
132   AnalysisInputs(
133       llvm::StringRef CodeArg,
134       ast_matchers::internal::Matcher<FunctionDecl> TargetFuncMatcherArg,
135       std::function<AnalysisT(ASTContext &, Environment &)> MakeAnalysisArg)
136       : Code(CodeArg), TargetFuncMatcher(std::move(TargetFuncMatcherArg)),
137         MakeAnalysis(std::move(MakeAnalysisArg)) {}
138 
139   /// Optional fields can be set with methods of the form `withFieldName(...)`.
140   AnalysisInputs<AnalysisT> &&
141   withSetupTest(std::function<llvm::Error(AnalysisOutputs &)> Arg) && {
142     SetupTest = std::move(Arg);
143     return std::move(*this);
144   }
145   AnalysisInputs<AnalysisT> &&
146   withDiagnosisCallbacks(DiagnosisCallbacksForTesting<AnalysisT> Arg) && {
147     Callbacks = std::move(Arg);
148     return std::move(*this);
149   }
150   /// Provided for backwards compatibility. New callers should use
151   /// `withDiagnosisCallbacks()`.
152   AnalysisInputs<AnalysisT> &&
153   withPostVisitCFG(DiagnosisCallbackForTesting<AnalysisT> Arg) && {
154     Callbacks.After = std::move(Arg);
155     return std::move(*this);
156   }
157   AnalysisInputs<AnalysisT> &&withASTBuildArgs(ArrayRef<std::string> Arg) && {
158     ASTBuildArgs = std::move(Arg);
159     return std::move(*this);
160   }
161   AnalysisInputs<AnalysisT> &&
162   withASTBuildVirtualMappedFiles(tooling::FileContentMappings Arg) && {
163     ASTBuildVirtualMappedFiles = std::move(Arg);
164     return std::move(*this);
165   }
166   AnalysisInputs<AnalysisT> &&
167   withBuiltinOptions(DataflowAnalysisContext::Options Options) && {
168     BuiltinOptions = std::move(Options);
169     return std::move(*this);
170   }
171   AnalysisInputs<AnalysisT> &&
172   withSolverFactory(std::function<std::unique_ptr<Solver>()> Factory) && {
173     assert(Factory);
174     SolverFactory = std::move(Factory);
175     return std::move(*this);
176   }
177 
178   /// Required. Input code that is analyzed.
179   llvm::StringRef Code;
180   /// Required. All functions that match this matcher are analyzed.
181   ast_matchers::internal::Matcher<FunctionDecl> TargetFuncMatcher;
182   /// Required. The analysis to be run is constructed with this function that
183   /// takes as argument the AST generated from the code being analyzed and the
184   /// initial state from which the analysis starts with.
185   std::function<AnalysisT(ASTContext &, Environment &)> MakeAnalysis;
186   /// Optional. If provided, this function is executed immediately before
187   /// running the dataflow analysis to allow for additional setup. All fields in
188   /// the `AnalysisOutputs` argument will be initialized except for the
189   /// `BlockStates` field which is only computed later during the analysis.
190   std::function<llvm::Error(AnalysisOutputs &)> SetupTest = nullptr;
191   /// Callbacks to run on each CFG element after the analysis has been run.
192   DiagnosisCallbacksForTesting<AnalysisT> Callbacks;
193 
194   /// Optional. Options for building the AST context.
195   ArrayRef<std::string> ASTBuildArgs = {};
196   /// Optional. Options for building the AST context.
197   tooling::FileContentMappings ASTBuildVirtualMappedFiles = {};
198   /// Configuration options for the built-in model.
199   DataflowAnalysisContext::Options BuiltinOptions;
200   /// SAT solver factory.
201   std::function<std::unique_ptr<Solver>()> SolverFactory = [] {
202     return std::make_unique<WatchedLiteralsSolver>();
203   };
204 };
205 
206 /// Returns assertions based on annotations that are present after statements in
207 /// `AnnotatedCode`.
208 llvm::Expected<llvm::DenseMap<const Stmt *, std::string>>
209 buildStatementToAnnotationMapping(const FunctionDecl *Func,
210                                   llvm::Annotations AnnotatedCode);
211 
212 /// Returns line numbers and content of the annotations in `AnnotatedCode`
213 /// within the token range `BoundingRange`.
214 llvm::DenseMap<unsigned, std::string> buildLineToAnnotationMapping(
215     const SourceManager &SM, const LangOptions &LangOpts,
216     SourceRange BoundingRange, llvm::Annotations AnnotatedCode);
217 
218 /// Runs dataflow specified from `AI.MakeAnalysis` and `AI.Callbacks` on all
219 /// functions that match `AI.TargetFuncMatcher` in `AI.Code`.  Given the
220 /// analysis outputs, `VerifyResults` checks that the results from the analysis
221 /// are correct.
222 ///
223 /// Requirements:
224 ///
225 ///   `AnalysisT` contains a type `Lattice`.
226 ///
227 ///   `Code`, `TargetFuncMatcher` and `MakeAnalysis` must be provided in `AI`.
228 ///
229 ///   `VerifyResults` must be provided.
230 template <typename AnalysisT>
231 llvm::Error
232 checkDataflow(AnalysisInputs<AnalysisT> AI,
233               std::function<void(const AnalysisOutputs &)> VerifyResults) {
234   // Build AST context from code.
235   llvm::Annotations AnnotatedCode(AI.Code);
236   auto Unit = tooling::buildASTFromCodeWithArgs(
237       AnnotatedCode.code(), AI.ASTBuildArgs, "input.cc", "clang-dataflow-test",
238       std::make_shared<PCHContainerOperations>(),
239       tooling::getClangStripDependencyFileAdjuster(),
240       AI.ASTBuildVirtualMappedFiles);
241   auto &Context = Unit->getASTContext();
242 
243   if (Context.getDiagnostics().getClient()->getNumErrors() != 0) {
244     return llvm::make_error<llvm::StringError>(
245         llvm::errc::invalid_argument, "Source file has syntax or type errors, "
246                                       "they were printed to the test log");
247   }
248 
249   CFGEltCallbacksTypeErased PostAnalysisCallbacks;
250   if (AI.Callbacks.Before) {
251     PostAnalysisCallbacks.Before =
252         [&AI, &Context](const CFGElement &Element,
253                         const TypeErasedDataflowAnalysisState &State) {
254           AI.Callbacks.Before(
255               Context, Element,
256               TransferStateForDiagnostics<typename AnalysisT::Lattice>(
257                   llvm::any_cast<const typename AnalysisT::Lattice &>(
258                       State.Lattice.Value),
259                   State.Env));
260         };
261   }
262   if (AI.Callbacks.After) {
263     PostAnalysisCallbacks.After =
264         [&AI, &Context](const CFGElement &Element,
265                         const TypeErasedDataflowAnalysisState &State) {
266           AI.Callbacks.After(
267               Context, Element,
268               TransferStateForDiagnostics<typename AnalysisT::Lattice>(
269                   llvm::any_cast<const typename AnalysisT::Lattice &>(
270                       State.Lattice.Value),
271                   State.Env));
272         };
273   }
274 
275   SmallVector<ast_matchers::BoundNodes, 1> MatchResult = ast_matchers::match(
276       ast_matchers::functionDecl(ast_matchers::hasBody(ast_matchers::stmt()),
277                                  AI.TargetFuncMatcher)
278           .bind("target"),
279       Context);
280   if (MatchResult.empty())
281     return llvm::createStringError(llvm::inconvertibleErrorCode(),
282                                    "didn't find any matching target functions");
283   for (const ast_matchers::BoundNodes &BN : MatchResult) {
284     // Get the AST node of the target function.
285     const FunctionDecl *Target = BN.getNodeAs<FunctionDecl>("target");
286     if (Target == nullptr)
287       return llvm::make_error<llvm::StringError>(
288           llvm::errc::invalid_argument, "Could not find the target function.");
289 
290     // Build the control flow graph for the target function.
291     auto MaybeACFG = AdornedCFG::build(*Target);
292     if (!MaybeACFG)
293       return MaybeACFG.takeError();
294     auto &ACFG = *MaybeACFG;
295 
296     // Initialize states for running dataflow analysis.
297     DataflowAnalysisContext DACtx(AI.SolverFactory(),
298                                   {/*Opts=*/AI.BuiltinOptions});
299     Environment InitEnv(DACtx, *Target);
300     auto Analysis = AI.MakeAnalysis(Context, InitEnv);
301 
302     AnalysisOutputs AO{AnnotatedCode, Context, Target, ACFG,
303                        Analysis,      InitEnv, {}};
304 
305     // Additional test setup.
306     if (AI.SetupTest) {
307       if (auto Error = AI.SetupTest(AO)) return Error;
308     }
309 
310     // If successful, the dataflow analysis returns a mapping from block IDs to
311     // the post-analysis states for the CFG blocks that have been evaluated.
312     llvm::Expected<std::vector<std::optional<TypeErasedDataflowAnalysisState>>>
313         MaybeBlockStates =
314             runTypeErasedDataflowAnalysis(ACFG, Analysis, InitEnv,
315                                           PostAnalysisCallbacks,
316                                           MaxBlockVisitsInAnalysis);
317     if (!MaybeBlockStates) return MaybeBlockStates.takeError();
318     AO.BlockStates = *MaybeBlockStates;
319 
320     // Verify dataflow analysis outputs.
321     VerifyResults(AO);
322   }
323 
324   return llvm::Error::success();
325 }
326 
327 /// Runs dataflow specified from `AI.MakeAnalysis` and `AI.PostVisitCFG` on all
328 /// functions that match `AI.TargetFuncMatcher` in `AI.Code`. Given the
329 /// annotation line numbers and analysis outputs, `VerifyResults` checks that
330 /// the results from the analysis are correct.
331 ///
332 /// Requirements:
333 ///
334 ///   `AnalysisT` contains a type `Lattice`.
335 ///
336 ///   `Code`, `TargetFuncMatcher` and `MakeAnalysis` must be provided in `AI`.
337 ///
338 ///   `VerifyResults` must be provided.
339 template <typename AnalysisT>
340 llvm::Error
341 checkDataflow(AnalysisInputs<AnalysisT> AI,
342               std::function<void(const llvm::DenseMap<unsigned, std::string> &,
343                                  const AnalysisOutputs &)>
344                   VerifyResults) {
345   return checkDataflow<AnalysisT>(
346       std::move(AI), [&VerifyResults](const AnalysisOutputs &AO) {
347         auto AnnotationLinesAndContent = buildLineToAnnotationMapping(
348             AO.ASTCtx.getSourceManager(), AO.ASTCtx.getLangOpts(),
349             AO.Target->getSourceRange(), AO.Code);
350         VerifyResults(AnnotationLinesAndContent, AO);
351       });
352 }
353 
354 /// Runs dataflow specified from `AI.MakeAnalysis` and `AI.PostVisitCFG` on all
355 /// functions that match `AI.TargetFuncMatcher` in `AI.Code`. Given the state
356 /// computed at each annotated statement and analysis outputs, `VerifyResults`
357 /// checks that the results from the analysis are correct.
358 ///
359 /// Requirements:
360 ///
361 ///   `AnalysisT` contains a type `Lattice`.
362 ///
363 ///   `Code`, `TargetFuncMatcher` and `MakeAnalysis` must be provided in `AI`.
364 ///
365 ///   `VerifyResults` must be provided.
366 ///
367 ///   Any annotations appearing in `Code` must come after a statement.
368 ///
369 ///   There can be at most one annotation attached per statement.
370 ///
371 ///   Annotations must not be repeated.
372 template <typename AnalysisT>
373 llvm::Error
374 checkDataflow(AnalysisInputs<AnalysisT> AI,
375               std::function<void(const llvm::StringMap<DataflowAnalysisState<
376                                      typename AnalysisT::Lattice>> &,
377                                  const AnalysisOutputs &)>
378                   VerifyResults) {
379   // Compute mapping from nodes of annotated statements to the content in the
380   // annotation.
381   llvm::DenseMap<const Stmt *, std::string> StmtToAnnotations;
382   auto SetupTest = [&StmtToAnnotations,
383                     PrevSetupTest = std::move(AI.SetupTest)](
384                        AnalysisOutputs &AO) -> llvm::Error {
385     auto MaybeStmtToAnnotations =
386         buildStatementToAnnotationMapping(AO.InitEnv.getCurrentFunc(), AO.Code);
387     if (!MaybeStmtToAnnotations) {
388       return MaybeStmtToAnnotations.takeError();
389     }
390     StmtToAnnotations = std::move(*MaybeStmtToAnnotations);
391     return PrevSetupTest ? PrevSetupTest(AO) : llvm::Error::success();
392   };
393 
394   using StateT = DataflowAnalysisState<typename AnalysisT::Lattice>;
395 
396   // Save the states computed for program points immediately following annotated
397   // statements. The saved states are keyed by the content of the annotation.
398   llvm::StringMap<StateT> AnnotationStates;
399   DiagnosisCallbacksForTesting<AnalysisT> Callbacks;
400   Callbacks.Before = std::move(AI.Callbacks.Before);
401   Callbacks.After =
402       [&StmtToAnnotations, &AnnotationStates,
403        PrevCallbackAfter = std::move(AI.Callbacks.After)](
404           ASTContext &Ctx, const CFGElement &Elt,
405           const TransferStateForDiagnostics<typename AnalysisT::Lattice>
406               &State) {
407         if (PrevCallbackAfter) {
408           PrevCallbackAfter(Ctx, Elt, State);
409         }
410         // FIXME: Extend retrieval of state for non statement constructs.
411         auto Stmt = Elt.getAs<CFGStmt>();
412         if (!Stmt)
413           return;
414         auto It = StmtToAnnotations.find(Stmt->getStmt());
415         if (It == StmtToAnnotations.end())
416           return;
417         auto [_, InsertSuccess] = AnnotationStates.insert(
418             {It->second, StateT{State.Lattice, State.Env.fork()}});
419         (void)_;
420         (void)InsertSuccess;
421         assert(InsertSuccess);
422       };
423   return checkDataflow<AnalysisT>(
424       std::move(AI)
425           .withSetupTest(std::move(SetupTest))
426           .withDiagnosisCallbacks(std::move(Callbacks)),
427       [&VerifyResults, &AnnotationStates](const AnalysisOutputs &AO) {
428         VerifyResults(AnnotationStates, AO);
429 
430         // `checkDataflow()` can analyze more than one function.  Reset the
431         // variables to prepare for analyzing the next function.
432         AnnotationStates.clear();
433       });
434 }
435 
436 using BuiltinOptions = DataflowAnalysisContext::Options;
437 
438 /// Runs dataflow on function named `TargetFun` in `Code` with a `NoopAnalysis`
439 /// and calls `VerifyResults` to verify the results.
440 llvm::Error checkDataflowWithNoopAnalysis(
441     llvm::StringRef Code,
442     std::function<
443         void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
444              ASTContext &)>
445         VerifyResults = [](const auto &, auto &) {},
446     DataflowAnalysisOptions Options = {BuiltinOptions()},
447     LangStandard::Kind Std = LangStandard::lang_cxx17,
448     llvm::StringRef TargetFun = "target");
449 
450 /// Runs dataflow on function matched by `TargetFuncMatcher` in `Code` with a
451 /// `NoopAnalysis` and calls `VerifyResults` to verify the results.
452 llvm::Error checkDataflowWithNoopAnalysis(
453     llvm::StringRef Code,
454     ast_matchers::internal::Matcher<FunctionDecl> TargetFuncMatcher,
455     std::function<
456         void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
457              ASTContext &)>
458         VerifyResults = [](const auto &, auto &) {},
459     DataflowAnalysisOptions Options = {BuiltinOptions()},
460     LangStandard::Kind Std = LangStandard::lang_cxx17,
461     std::function<llvm::StringMap<QualType>(QualType)> SyntheticFieldCallback =
462         {});
463 
464 /// Returns the `ValueDecl` for the given identifier.
465 /// The returned pointer is guaranteed to be non-null; the function asserts if
466 /// no `ValueDecl` with the given name is found.
467 ///
468 /// Requirements:
469 ///
470 ///   `Name` must be unique in `ASTCtx`.
471 const ValueDecl *findValueDecl(ASTContext &ASTCtx, llvm::StringRef Name);
472 
473 /// Returns the `IndirectFieldDecl` for the given identifier.
474 ///
475 /// Requirements:
476 ///
477 ///   `Name` must be unique in `ASTCtx`.
478 const IndirectFieldDecl *findIndirectFieldDecl(ASTContext &ASTCtx,
479                                                llvm::StringRef Name);
480 
481 /// Returns the storage location (of type `LocT`) for the given identifier.
482 /// `LocT` must be a subclass of `StorageLocation` and must be of the
483 /// appropriate type.
484 ///
485 /// Requirements:
486 ///
487 ///   `Name` must be unique in `ASTCtx`.
488 template <class LocT = StorageLocation>
489 LocT &getLocForDecl(ASTContext &ASTCtx, const Environment &Env,
490                     llvm::StringRef Name) {
491   const ValueDecl *VD = findValueDecl(ASTCtx, Name);
492   assert(VD != nullptr);
493   return *cast<LocT>(Env.getStorageLocation(*VD));
494 }
495 
496 /// Returns the value (of type `ValueT`) for the given identifier.
497 /// `ValueT` must be a subclass of `Value` and must be of the appropriate type.
498 ///
499 /// Requirements:
500 ///
501 ///   `Name` must be unique in `ASTCtx`.
502 template <class ValueT = Value>
503 ValueT &getValueForDecl(ASTContext &ASTCtx, const Environment &Env,
504                         llvm::StringRef Name) {
505   const ValueDecl *VD = findValueDecl(ASTCtx, Name);
506   assert(VD != nullptr);
507   return *cast<ValueT>(Env.getValue(*VD));
508 }
509 
510 /// Returns the storage location for the field called `Name` of `Loc`.
511 /// Optionally casts the field storage location to `T`.
512 template <typename T = StorageLocation>
513 std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T &>
514 getFieldLoc(const RecordStorageLocation &Loc, llvm::StringRef Name,
515             ASTContext &ASTCtx) {
516   return *cast<T>(Loc.getChild(*findValueDecl(ASTCtx, Name)));
517 }
518 
519 /// Returns the value of a `Field` on the record referenced by `Loc.`
520 /// Returns null if `Loc` is null.
521 inline Value *getFieldValue(const RecordStorageLocation *Loc,
522                             const ValueDecl &Field, const Environment &Env) {
523   if (Loc == nullptr)
524     return nullptr;
525   StorageLocation *FieldLoc = Loc->getChild(Field);
526   if (FieldLoc == nullptr)
527     return nullptr;
528   return Env.getValue(*FieldLoc);
529 }
530 
531 /// Returns the value of a `Field` on the record referenced by `Loc.`
532 /// Returns null if `Loc` is null.
533 inline Value *getFieldValue(const RecordStorageLocation *Loc,
534                             llvm::StringRef Name, ASTContext &ASTCtx,
535                             const Environment &Env) {
536   return getFieldValue(Loc, *findValueDecl(ASTCtx, Name), Env);
537 }
538 
539 /// Creates and owns constraints which are boolean values.
540 class ConstraintContext {
541   unsigned NextAtom = 0;
542   llvm::BumpPtrAllocator A;
543 
544   const Formula *make(Formula::Kind K,
545                       llvm::ArrayRef<const Formula *> Operands) {
546     return &Formula::create(A, K, Operands);
547   }
548 
549 public:
550   // Returns a reference to a fresh atomic variable.
551   const Formula *atom() {
552     return &Formula::create(A, Formula::AtomRef, {}, NextAtom++);
553   }
554 
555   // Returns a reference to a literal boolean value.
556   const Formula *literal(bool B) {
557     return &Formula::create(A, Formula::Literal, {}, B);
558   }
559 
560   // Creates a boolean conjunction.
561   const Formula *conj(const Formula *LHS, const Formula *RHS) {
562     return make(Formula::And, {LHS, RHS});
563   }
564 
565   // Creates a boolean disjunction.
566   const Formula *disj(const Formula *LHS, const Formula *RHS) {
567     return make(Formula::Or, {LHS, RHS});
568   }
569 
570   // Creates a boolean negation.
571   const Formula *neg(const Formula *Operand) {
572     return make(Formula::Not, {Operand});
573   }
574 
575   // Creates a boolean implication.
576   const Formula *impl(const Formula *LHS, const Formula *RHS) {
577     return make(Formula::Implies, {LHS, RHS});
578   }
579 
580   // Creates a boolean biconditional.
581   const Formula *iff(const Formula *LHS, const Formula *RHS) {
582     return make(Formula::Equal, {LHS, RHS});
583   }
584 };
585 
586 /// Parses a list of formulas, separated by newlines, and returns them.
587 /// On parse errors, calls `ADD_FAILURE()` to fail the current test.
588 std::vector<const Formula *> parseFormulas(Arena &A, StringRef Lines);
589 
590 } // namespace test
591 } // namespace dataflow
592 } // namespace clang
593 
594 #endif // LLVM_CLANG_ANALYSIS_FLOW_SENSITIVE_TESTING_SUPPORT_H_
595