[clang] 5a4aece - [clang][dataflow] Add `SetupTest` parameter for `AnalysisInputs`.

Wei Yi Tee via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 1 06:49:27 PDT 2022


Author: Wei Yi Tee
Date: 2022-09-01T13:48:29Z
New Revision: 5a4aece76de7c73b9adf29b0c3f4e8641575cee1

URL: https://github.com/llvm/llvm-project/commit/5a4aece76de7c73b9adf29b0c3f4e8641575cee1
DIFF: https://github.com/llvm/llvm-project/commit/5a4aece76de7c73b9adf29b0c3f4e8641575cee1.diff

LOG: [clang][dataflow] Add `SetupTest` parameter for `AnalysisInputs`.

Moves the work required for retrieving annotation states into the `SetupTest` and `PostVisitCFG` callback to avoid having to run a separate pass over the CFG after analysis has completed.

Reviewed By: gribozavr2, sgatev, ymandel

Differential Revision: https://reviews.llvm.org/D132377

Added: 
    

Modified: 
    clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
    clang/unittests/Analysis/FlowSensitive/TestingSupport.h

Removed: 
    


################################################################################
diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
index 56df21617e5a..c0c05b0efdbb 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
@@ -53,11 +53,11 @@ isAnnotationDirectlyAfterStatement(const Stmt *Stmt, unsigned AnnotationBegin,
 }
 
 llvm::DenseMap<unsigned, std::string>
-test::getAnnotationLinesAndContent(const AnalysisOutputs &AO) {
+test::buildLineToAnnotationMapping(SourceManager &SM,
+                                   llvm::Annotations AnnotatedCode) {
   llvm::DenseMap<unsigned, std::string> LineNumberToContent;
-  auto Code = AO.Code.code();
-  auto Annotations = AO.Code.ranges();
-  auto &SM = AO.ASTCtx.getSourceManager();
+  auto Code = AnnotatedCode.code();
+  auto Annotations = AnnotatedCode.ranges();
   for (auto &AnnotationRange : Annotations) {
     auto LineNumber =
         SM.getPresumedLineNumber(SM.getLocForStartOfFile(SM.getMainFileID())

diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
index a23b0ec0709a..285c0c991d23 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
@@ -96,6 +96,11 @@ template <typename AnalysisT> struct AnalysisInputs {
 
   /// Optional fields can be set with methods of the form `withFieldName(...)`.
   AnalysisInputs<AnalysisT> &&
+  withSetupTest(std::function<llvm::Error(AnalysisOutputs &)> Arg) && {
+    SetupTest = std::move(Arg);
+    return std::move(*this);
+  }
+  AnalysisInputs<AnalysisT> &&
   withPostVisitCFG(std::function<void(ASTContext &, const CFGElement &,
                                       const TypeErasedDataflowAnalysisState &)>
                        Arg) && {
@@ -120,6 +125,11 @@ template <typename AnalysisT> struct AnalysisInputs {
   /// takes as argument the AST generated from the code being analyzed and the
   /// initial state from which the analysis starts with.
   std::function<AnalysisT(ASTContext &, Environment &)> MakeAnalysis;
+  /// Optional. If provided, this function is executed immediately before
+  /// running the dataflow analysis to allow for additional setup. All fields in
+  /// the `AnalysisOutputs` argument will be initialized except for the
+  /// `BlockStates` field which is only computed later during the analysis.
+  std::function<llvm::Error(AnalysisOutputs &)> SetupTest = nullptr;
   /// Optional. If provided, this function is applied on each CFG element after
   /// the analysis has been run.
   std::function<void(ASTContext &, const CFGElement &,
@@ -138,54 +148,10 @@ llvm::Expected<llvm::DenseMap<const Stmt *, std::string>>
 buildStatementToAnnotationMapping(const FunctionDecl *Func,
                                   llvm::Annotations AnnotatedCode);
 
-/// Returns line numbers and content of the annotations in `AO.Code`.
+/// Returns line numbers and content of the annotations in `AnnotatedCode`.
 llvm::DenseMap<unsigned, std::string>
-getAnnotationLinesAndContent(const AnalysisOutputs &AO);
-
-// FIXME: Return a string map instead of a vector of pairs.
-//
-/// Returns the analysis states at each annotated statement in `AO.Code`.
-template <typename AnalysisT>
-llvm::Expected<std::vector<
-    std::pair<std::string, DataflowAnalysisState<typename AnalysisT::Lattice>>>>
-getAnnotationStates(const AnalysisOutputs &AO) {
-  using StateT = DataflowAnalysisState<typename AnalysisT::Lattice>;
-  // FIXME: Extend to annotations on non-statement constructs.
-  // Get annotated statements.
-  llvm::Expected<llvm::DenseMap<const Stmt *, std::string>>
-      MaybeStmtToAnnotations =
-          buildStatementToAnnotationMapping(AO.Target, AO.Code);
-  if (!MaybeStmtToAnnotations)
-    return MaybeStmtToAnnotations.takeError();
-  auto &StmtToAnnotations = *MaybeStmtToAnnotations;
-
-  // Compute a map from statement annotations to the state computed
-  // for the program point immediately after the annotated statement.
-  std::vector<std::pair<std::string, StateT>> Results;
-  for (const CFGBlock *Block : AO.CFCtx.getCFG()) {
-    // Skip blocks that were not evaluated.
-    if (!AO.BlockStates[Block->getBlockID()])
-      continue;
-
-    transferBlock(
-        AO.CFCtx, AO.BlockStates, *Block, AO.InitEnv, AO.Analysis,
-        [&Results,
-         &StmtToAnnotations](const clang::CFGElement &Element,
-                             const TypeErasedDataflowAnalysisState &State) {
-          auto Stmt = Element.getAs<CFGStmt>();
-          if (!Stmt)
-            return;
-          auto It = StmtToAnnotations.find(Stmt->getStmt());
-          if (It == StmtToAnnotations.end())
-            return;
-          auto *Lattice =
-              llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value);
-          Results.emplace_back(It->second, StateT{*Lattice, State.Env});
-        });
-  }
-
-  return Results;
-}
+buildLineToAnnotationMapping(SourceManager &SM,
+                             llvm::Annotations AnnotatedCode);
 
 /// Runs dataflow specified from `AI.MakeAnalysis` and `AI.PostVisitCFG` on the
 /// body of the function that matches `AI.TargetFuncMatcher` in `AI.Code`.
@@ -200,9 +166,9 @@ getAnnotationStates(const AnalysisOutputs &AO) {
 ///
 ///   `VerifyResults` must be provided.
 template <typename AnalysisT>
-llvm::Error checkDataflow(
-    AnalysisInputs<AnalysisT> AI,
-    std::function<llvm::Error(const AnalysisOutputs &)> VerifyResults) {
+llvm::Error
+checkDataflow(AnalysisInputs<AnalysisT> AI,
+              std::function<void(const AnalysisOutputs &)> VerifyResults) {
   // Build AST context from code.
   llvm::Annotations AnnotatedCode(AI.Code);
   auto Unit = tooling::buildASTFromCodeWithArgs(
@@ -236,7 +202,7 @@ llvm::Error checkDataflow(
     return MaybeCFCtx.takeError();
   auto &CFCtx = *MaybeCFCtx;
 
-  // Initialize states and run dataflow analysis.
+  // Initialize states for running dataflow analysis.
   DataflowAnalysisContext DACtx(std::make_unique<WatchedLiteralsSolver>());
   Environment InitEnv(DACtx, *Target);
   auto Analysis = AI.MakeAnalysis(Context, InitEnv);
@@ -251,19 +217,26 @@ llvm::Error checkDataflow(
         };
   }
 
-  // If successful, the run returns a mapping from block IDs to the
-  // post-analysis states for the CFG blocks that have been evaluated.
+  // Additional test setup.
+  AnalysisOutputs AO{AnnotatedCode, Context, Target, CFCtx,
+                     Analysis,      InitEnv, {}};
+  if (AI.SetupTest) {
+    if (auto Error = AI.SetupTest(AO))
+      return Error;
+  }
+
+  // If successful, the dataflow analysis returns a mapping from block IDs to
+  // the post-analysis states for the CFG blocks that have been evaluated.
   llvm::Expected<std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>>>
       MaybeBlockStates = runTypeErasedDataflowAnalysis(CFCtx, Analysis, InitEnv,
                                                        PostVisitCFGClosure);
   if (!MaybeBlockStates)
     return MaybeBlockStates.takeError();
-  auto &BlockStates = *MaybeBlockStates;
+  AO.BlockStates = *MaybeBlockStates;
 
   // Verify dataflow analysis outputs.
-  AnalysisOutputs AO{AnnotatedCode, Context, Target,     CFCtx,
-                     Analysis,      InitEnv, BlockStates};
-  return VerifyResults(AO);
+  VerifyResults(AO);
+  return llvm::Error::success();
 }
 
 /// Runs dataflow specified from `AI.MakeAnalysis` and `AI.PostVisitCFG` on the
@@ -285,11 +258,10 @@ checkDataflow(AnalysisInputs<AnalysisT> AI,
                                  const AnalysisOutputs &)>
                   VerifyResults) {
   return checkDataflow<AnalysisT>(
-      std::move(AI),
-      [&VerifyResults](const AnalysisOutputs &AO) -> llvm::Error {
-        auto AnnotationLinesAndContent = getAnnotationLinesAndContent(AO);
+      std::move(AI), [&VerifyResults](const AnalysisOutputs &AO) {
+        auto AnnotationLinesAndContent =
+            buildLineToAnnotationMapping(AO.ASTCtx.getSourceManager(), AO.Code);
         VerifyResults(AnnotationLinesAndContent, AO);
-        return llvm::Error::success();
       });
 }
 
@@ -319,16 +291,52 @@ llvm::Error checkDataflow(
             std::string, DataflowAnalysisState<typename AnalysisT::Lattice>>>,
         const AnalysisOutputs &)>
         VerifyResults) {
+  // Compute mapping from nodes of annotated statements to the content in the
+  // annotation.
+  llvm::DenseMap<const Stmt *, std::string> StmtToAnnotations;
+  auto SetupTest = [&StmtToAnnotations,
+                    PrevSetupTest = std::move(AI.SetupTest)](
+                       AnalysisOutputs &AO) -> llvm::Error {
+    auto MaybeStmtToAnnotations = buildStatementToAnnotationMapping(
+        cast<FunctionDecl>(AO.InitEnv.getDeclCtx()), AO.Code);
+    if (!MaybeStmtToAnnotations) {
+      return MaybeStmtToAnnotations.takeError();
+    }
+    StmtToAnnotations = std::move(*MaybeStmtToAnnotations);
+    return PrevSetupTest ? PrevSetupTest(AO) : llvm::Error::success();
+  };
+
+  using StateT = DataflowAnalysisState<typename AnalysisT::Lattice>;
+
+  // FIXME: Use a string map instead of a vector of pairs.
+  //
+  // Save the states computed for program points immediately following annotated
+  // statements. The saved states are keyed by the content of the annotation.
+  std::vector<std::pair<std::string, StateT>> AnnotationStates;
+  auto PostVisitCFG = [&StmtToAnnotations, &AnnotationStates,
+                       PrevPostVisitCFG = std::move(AI.PostVisitCFG)](
+                          ASTContext &Ctx, const CFGElement &Elt,
+                          const TypeErasedDataflowAnalysisState &State) {
+    if (PrevPostVisitCFG) {
+      PrevPostVisitCFG(Ctx, Elt, State);
+    }
+    // FIXME: Extend retrieval of state for non statement constructs.
+    auto Stmt = Elt.getAs<CFGStmt>();
+    if (!Stmt)
+      return;
+    auto It = StmtToAnnotations.find(Stmt->getStmt());
+    if (It == StmtToAnnotations.end())
+      return;
+    auto *Lattice =
+        llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value);
+    AnnotationStates.emplace_back(It->second, StateT{*Lattice, State.Env});
+  };
   return checkDataflow<AnalysisT>(
-      std::move(AI),
-      [&VerifyResults](const AnalysisOutputs &AO) -> llvm::Error {
-        auto MaybeAnnotationStates = getAnnotationStates<AnalysisT>(AO);
-        if (!MaybeAnnotationStates) {
-          return MaybeAnnotationStates.takeError();
-        }
-        auto &AnnotationStates = *MaybeAnnotationStates;
+      std::move(AI)
+          .withSetupTest(std::move(SetupTest))
+          .withPostVisitCFG(std::move(PostVisitCFG)),
+      [&VerifyResults, &AnnotationStates](const AnalysisOutputs &AO) {
         VerifyResults(AnnotationStates, AO);
-        return llvm::Error::success();
       });
 }
 


        


More information about the cfe-commits mailing list