[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