[clang] 58fe7f9 - [clang][dataflow] Add API to separate analysis from diagnosis
Author: Sam Estep Date: 2022-06-29T19:18:39Z New Revision: 58fe7f9683a020a880426a4d8d61b067b83a9380 URL: https://github.com/llvm/llvm-project/commit/58fe7f9683a020a880426a4d8d61b067b83a9380 DIFF: https://github.com/llvm/llvm-project/commit/58fe7f9683a020a880426a4d8d61b067b83a9380.diff LOG: [clang][dataflow] Add API to separate analysis from diagnosis This patch adds an optional `PostVisitStmt` parameter to the `runTypeErasedDataflowAnalysis` function, which does one more pass over all statements in the CFG after a fixpoint is reached. It then defines a `diagnose` method for the optional model in a new `UncheckedOptionalAccessDiagnosis` class, but only integrates that into the tests and not the actual optional check for `clang-tidy`. That will be done in a followup patch. The primary motivation is to separate the implementation of the unchecked optional access check into two parts, to allow for further refactoring of just the model part later, while leaving the checking part alone. Currently there is duplication between the `transferUnwrapCall` and `diagnoseUnwrapCall` functions, but that will be dealt with in the followup. Because diagnostics are now all gathered into one collection rather than being populated at each program point like when computing a fixpoint, this patch removes the usage of `Pair` and `UnorderedElementsAre` from the optional model tests, and instead modifies all their expectations to simply check the stringified set of diagnostics against a single string, either `"safe"` or some concatenation of `"unsafe: input.cc:y:x"`. This is not ideal as it loses any connection to the `/*[[check]]*/` annotations in the source strings, but it does still retain the source locations from the diagnostic strings themselves. Reviewed By: sgatev, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D127898 Added: Modified: clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h index 2102ed56907bb..701db6470ac2f 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h +++ b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h @@ -20,6 +20,8 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/MatchSwitch.h" #include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" +#include "clang/Basic/SourceLocation.h" +#include namespace clang { namespace dataflow { @@ -71,6 +73,19 @@ class UncheckedOptionalAccessModel MatchSwitch> TransferMatchSwitch; }; +class UncheckedOptionalAccessDiagnoser { +public: + UncheckedOptionalAccessDiagnoser( + UncheckedOptionalAccessModelOptions Options = {}); + + std::vector diagnose(ASTContext &Context, const Stmt *Stmt, + const Environment &Env); + +private: + MatchSwitch> + DiagnoseMatchSwitch; +}; + } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index 2d3a9e456370d..5e168194064f4 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -115,13 +115,17 @@ TypeErasedDataflowAnalysisState transferBlock( HandleTransferredStmt = nullptr); /// Performs dataflow analysis and returns a mapping from basic block IDs to -/// dataflow analysis states that model the respective basic blocks. Indices -/// of the returned vector correspond to basic block IDs. Returns an error if -/// the dataflow analysis cannot be performed successfully. +/// dataflow analysis states that model the respective basic blocks. Indices of +/// the returned vector correspond to basic block IDs. Returns an error if the +/// dataflow analysis cannot be performed successfully. Otherwise, calls +/// `PostVisitStmt` on each statement with the final analysis results at that +/// program point. llvm::Expected>> -runTypeErasedDataflowAnalysis(const ControlFlowContext &CFCtx, - TypeErasedDataflowAnalysis &Analysis, - const Environment &InitEnv); +runTypeErasedDataflowAnalysis( +const Contro
[clang-tools-extra] cafb8b4 - [clang][dataflow] Use diagnosis API in optional checker
Author: Sam Estep Date: 2022-06-29T19:20:09Z New Revision: cafb8b4ff2c38f81e65f97193eb1d8d16c581522 URL: https://github.com/llvm/llvm-project/commit/cafb8b4ff2c38f81e65f97193eb1d8d16c581522 DIFF: https://github.com/llvm/llvm-project/commit/cafb8b4ff2c38f81e65f97193eb1d8d16c581522.diff LOG: [clang][dataflow] Use diagnosis API in optional checker Followup to D127898. This patch updates `bugprone-unchecked-optional-access` to use the new `diagnoseCFG` function instead of just looking at the exit block. A followup to this will update the optional model itself to use a noop lattice rather than redundantly computing the diagnostics in both phases of the analysis. Reviewed By: ymandel, sgatev, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D128352 Added: Modified: clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h Removed: diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp index 07fb19ff81ac1..9766450e81654 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp @@ -23,6 +23,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/Any.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include #include @@ -32,12 +33,13 @@ namespace tidy { namespace bugprone { using ast_matchers::MatchFinder; using dataflow::SourceLocationsLattice; +using dataflow::UncheckedOptionalAccessDiagnoser; using dataflow::UncheckedOptionalAccessModel; using llvm::Optional; static constexpr llvm::StringLiteral FuncID("fun"); -static Optional +static Optional> analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) { using dataflow::ControlFlowContext; using dataflow::DataflowAnalysisState; @@ -52,23 +54,22 @@ analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) { std::make_unique()); dataflow::Environment Env(AnalysisContext, FuncDecl); UncheckedOptionalAccessModel Analysis(ASTCtx); + UncheckedOptionalAccessDiagnoser Diagnoser; + std::vector Diagnostics; Expected>>> - BlockToOutputState = - dataflow::runDataflowAnalysis(*Context, Analysis, Env); + BlockToOutputState = dataflow::runDataflowAnalysis( + *Context, Analysis, Env, + [&ASTCtx, &Diagnoser, + &Diagnostics](const Stmt *Stmt, + const DataflowAnalysisState + &State) mutable { +auto StmtDiagnostics = Diagnoser.diagnose(ASTCtx, Stmt, State.Env); +llvm::move(StmtDiagnostics, std::back_inserter(Diagnostics)); + }); if (!BlockToOutputState) return llvm::None; - assert(Context->getCFG().getExit().getBlockID() < BlockToOutputState->size()); - const Optional> - &ExitBlockState = - (*BlockToOutputState)[Context->getCFG().getExit().getBlockID()]; - // `runDataflowAnalysis` doesn't guarantee that the exit block is visited; - // for example, when it is unreachable. - // FIXME: Diagnose violations even when the exit block is unreachable. - if (!ExitBlockState) -return llvm::None; - - return std::move(ExitBlockState->Lattice); + return Diagnostics; } void UncheckedOptionalAccessCheck::registerMatchers(MatchFinder *Finder) { @@ -97,9 +98,9 @@ void UncheckedOptionalAccessCheck::check( if (FuncDecl->isTemplated()) return; - if (Optional Errors = + if (Optional> Errors = analyzeFunction(*FuncDecl, *Result.Context)) -for (const SourceLocation &Loc : Errors->getSourceLocations()) +for (const SourceLocation &Loc : *Errors) diag(Loc, "unchecked access to optional value"); } diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index f4d6a221abecc..40ac95b3abddb 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -109,14 +109,33 @@ template struct DataflowAnalysisState { /// dataflow analysis states that model the respective basic blocks. The /// returned vector, if any, will have the same size as the number of CFG /// blocks, with indices corresponding to basic block IDs. Returns an error if -/// the dataflow analysis cannot be performed successfully. +/// the dataflow analysis cannot be performed successfully. Otherwise, calls +/// `PostVisitStmt` on each statement with the final analysis results at that +/// program point. template llvm::Expected>>> -runDataflowAnalysis(const ControlFlowContext &CFCtx, AnalysisT &Analysis, -const Environm
[clang] 58fe7f9 - [clang][dataflow] Add API to separate analysis from diagnosis
Author: Sam Estep Date: 2022-06-29T19:18:39Z New Revision: 58fe7f9683a020a880426a4d8d61b067b83a9380 URL: https://github.com/llvm/llvm-project/commit/58fe7f9683a020a880426a4d8d61b067b83a9380 DIFF: https://github.com/llvm/llvm-project/commit/58fe7f9683a020a880426a4d8d61b067b83a9380.diff LOG: [clang][dataflow] Add API to separate analysis from diagnosis This patch adds an optional `PostVisitStmt` parameter to the `runTypeErasedDataflowAnalysis` function, which does one more pass over all statements in the CFG after a fixpoint is reached. It then defines a `diagnose` method for the optional model in a new `UncheckedOptionalAccessDiagnosis` class, but only integrates that into the tests and not the actual optional check for `clang-tidy`. That will be done in a followup patch. The primary motivation is to separate the implementation of the unchecked optional access check into two parts, to allow for further refactoring of just the model part later, while leaving the checking part alone. Currently there is duplication between the `transferUnwrapCall` and `diagnoseUnwrapCall` functions, but that will be dealt with in the followup. Because diagnostics are now all gathered into one collection rather than being populated at each program point like when computing a fixpoint, this patch removes the usage of `Pair` and `UnorderedElementsAre` from the optional model tests, and instead modifies all their expectations to simply check the stringified set of diagnostics against a single string, either `"safe"` or some concatenation of `"unsafe: input.cc:y:x"`. This is not ideal as it loses any connection to the `/*[[check]]*/` annotations in the source strings, but it does still retain the source locations from the diagnostic strings themselves. Reviewed By: sgatev, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D127898 Added: Modified: clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h index 2102ed56907bb..701db6470ac2f 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h +++ b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h @@ -20,6 +20,8 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/MatchSwitch.h" #include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" +#include "clang/Basic/SourceLocation.h" +#include namespace clang { namespace dataflow { @@ -71,6 +73,19 @@ class UncheckedOptionalAccessModel MatchSwitch> TransferMatchSwitch; }; +class UncheckedOptionalAccessDiagnoser { +public: + UncheckedOptionalAccessDiagnoser( + UncheckedOptionalAccessModelOptions Options = {}); + + std::vector diagnose(ASTContext &Context, const Stmt *Stmt, + const Environment &Env); + +private: + MatchSwitch> + DiagnoseMatchSwitch; +}; + } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index 2d3a9e456370d..5e168194064f4 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -115,13 +115,17 @@ TypeErasedDataflowAnalysisState transferBlock( HandleTransferredStmt = nullptr); /// Performs dataflow analysis and returns a mapping from basic block IDs to -/// dataflow analysis states that model the respective basic blocks. Indices -/// of the returned vector correspond to basic block IDs. Returns an error if -/// the dataflow analysis cannot be performed successfully. +/// dataflow analysis states that model the respective basic blocks. Indices of +/// the returned vector correspond to basic block IDs. Returns an error if the +/// dataflow analysis cannot be performed successfully. Otherwise, calls +/// `PostVisitStmt` on each statement with the final analysis results at that +/// program point. llvm::Expected>> -runTypeErasedDataflowAnalysis(const ControlFlowContext &CFCtx, - TypeErasedDataflowAnalysis &Analysis, - const Environment &InitEnv); +runTypeErasedDataflowAnalysis( +const Contro
[clang] 335c05f - [clang][dataflow] Use NoopLattice in optional model
Author: Sam Estep Date: 2022-06-29T19:20:58Z New Revision: 335c05f5d19fecd5c0972ac801e58248d772a78e URL: https://github.com/llvm/llvm-project/commit/335c05f5d19fecd5c0972ac801e58248d772a78e DIFF: https://github.com/llvm/llvm-project/commit/335c05f5d19fecd5c0972ac801e58248d772a78e.diff LOG: [clang][dataflow] Use NoopLattice in optional model Followup to D128352. This patch pulls the `NoopLattice` class out from the `NoopAnalysis.h` test file into its own `NoopLattice.h` source file, and uses it to replace usage of `SourceLocationsLattice` in `UncheckedOptionalAccessModel`. Reviewed By: ymandel, sgatev, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D128356 Added: clang/include/clang/Analysis/FlowSensitive/NoopLattice.h Modified: clang/docs/tools/clang-formatted-files.txt clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h Removed: diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index ed8b5e7e7ae7c..40d95411c3a0a 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -131,6 +131,7 @@ clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h clang/include/clang/Analysis/FlowSensitive/MapLattice.h clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h +clang/include/clang/Analysis/FlowSensitive/NoopLattice.h clang/include/clang/Analysis/FlowSensitive/Solver.h clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h diff --git a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h index 701db6470ac2f..25054deaf8afc 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h +++ b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h @@ -19,7 +19,7 @@ #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/MatchSwitch.h" -#include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" +#include "clang/Analysis/FlowSensitive/NoopLattice.h" #include "clang/Basic/SourceLocation.h" #include @@ -38,15 +38,11 @@ struct UncheckedOptionalAccessModelOptions { bool IgnoreSmartPointerDereference = false; }; -/// Dataflow analysis that discovers unsafe accesses of optional values and -/// adds the respective source locations to the lattice. +/// Dataflow analysis that models whether optionals hold values or not. /// /// Models the `std::optional`, `absl::optional`, and `base::Optional` types. -/// -/// FIXME: Consider separating the models from the unchecked access analysis. class UncheckedOptionalAccessModel -: public DataflowAnalysis { +: public DataflowAnalysis { public: UncheckedOptionalAccessModel( ASTContext &AstContext, UncheckedOptionalAccessModelOptions Options = {}); @@ -54,12 +50,9 @@ class UncheckedOptionalAccessModel /// Returns a matcher for the optional classes covered by this model. static ast_matchers::DeclarationMatcher optionalClassDecl(); - static SourceLocationsLattice initialElement() { -return SourceLocationsLattice(); - } + static NoopLattice initialElement() { return {}; } - void transfer(const Stmt *Stmt, SourceLocationsLattice &State, -Environment &Env); + void transfer(const Stmt *Stmt, NoopLattice &State, Environment &Env); bool compareEquivalent(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, @@ -70,7 +63,7 @@ class UncheckedOptionalAccessModel Environment &MergedEnv) override; private: - MatchSwitch> TransferMatchSwitch; + MatchSwitch> TransferMatchSwitch; }; class UncheckedOptionalAccessDiagnoser { diff --git a/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h b/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h new file mode 100644 index 0..0192193281119 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h @@ -0,0 +1,41 @@ +//===-- NoopLattice.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// This file defines the lattice with exactly one element. +//
[clang] 8361877 - Revert "[clang][dataflow] Use NoopLattice in optional model"
Author: Sam Estep Date: 2022-06-29T19:34:30Z New Revision: 8361877b10b8180ab12300b289da54a403ce7554 URL: https://github.com/llvm/llvm-project/commit/8361877b10b8180ab12300b289da54a403ce7554 DIFF: https://github.com/llvm/llvm-project/commit/8361877b10b8180ab12300b289da54a403ce7554.diff LOG: Revert "[clang][dataflow] Use NoopLattice in optional model" This reverts commit 335c05f5d19fecd5c0972ac801e58248d772a78e. Added: Modified: clang/docs/tools/clang-formatted-files.txt clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h Removed: clang/include/clang/Analysis/FlowSensitive/NoopLattice.h diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index 40d95411c3a0a..ed8b5e7e7ae7c 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -131,7 +131,6 @@ clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h clang/include/clang/Analysis/FlowSensitive/MapLattice.h clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h -clang/include/clang/Analysis/FlowSensitive/NoopLattice.h clang/include/clang/Analysis/FlowSensitive/Solver.h clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h diff --git a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h index 25054deaf8afc..701db6470ac2f 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h +++ b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h @@ -19,7 +19,7 @@ #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/MatchSwitch.h" -#include "clang/Analysis/FlowSensitive/NoopLattice.h" +#include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" #include "clang/Basic/SourceLocation.h" #include @@ -38,11 +38,15 @@ struct UncheckedOptionalAccessModelOptions { bool IgnoreSmartPointerDereference = false; }; -/// Dataflow analysis that models whether optionals hold values or not. +/// Dataflow analysis that discovers unsafe accesses of optional values and +/// adds the respective source locations to the lattice. /// /// Models the `std::optional`, `absl::optional`, and `base::Optional` types. +/// +/// FIXME: Consider separating the models from the unchecked access analysis. class UncheckedOptionalAccessModel -: public DataflowAnalysis { +: public DataflowAnalysis { public: UncheckedOptionalAccessModel( ASTContext &AstContext, UncheckedOptionalAccessModelOptions Options = {}); @@ -50,9 +54,12 @@ class UncheckedOptionalAccessModel /// Returns a matcher for the optional classes covered by this model. static ast_matchers::DeclarationMatcher optionalClassDecl(); - static NoopLattice initialElement() { return {}; } + static SourceLocationsLattice initialElement() { +return SourceLocationsLattice(); + } - void transfer(const Stmt *Stmt, NoopLattice &State, Environment &Env); + void transfer(const Stmt *Stmt, SourceLocationsLattice &State, +Environment &Env); bool compareEquivalent(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, @@ -63,7 +70,7 @@ class UncheckedOptionalAccessModel Environment &MergedEnv) override; private: - MatchSwitch> TransferMatchSwitch; + MatchSwitch> TransferMatchSwitch; }; class UncheckedOptionalAccessDiagnoser { diff --git a/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h b/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h deleted file mode 100644 index 0192193281119..0 --- a/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h +++ /dev/null @@ -1,41 +0,0 @@ -//===-- NoopLattice.h ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===--===// -// -// This file defines the lattice with exactly one element. -// -//===--===// - -#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOP_LATTICE_H -#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOP_LATTICE_H - -#include "clang/Analysis/FlowSensitive/DataflowLattice.h" -#include -
[clang-tools-extra] 2a33d12 - Revert "[clang][dataflow] Use diagnosis API in optional checker"
Author: Sam Estep Date: 2022-06-29T19:34:44Z New Revision: 2a33d12642d862a8aa307e4a8b8a94d2d0c5ad1d URL: https://github.com/llvm/llvm-project/commit/2a33d12642d862a8aa307e4a8b8a94d2d0c5ad1d DIFF: https://github.com/llvm/llvm-project/commit/2a33d12642d862a8aa307e4a8b8a94d2d0c5ad1d.diff LOG: Revert "[clang][dataflow] Use diagnosis API in optional checker" This reverts commit cafb8b4ff2c38f81e65f97193eb1d8d16c581522. Added: Modified: clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h Removed: diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp index 9766450e81654..07fb19ff81ac1 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp @@ -23,7 +23,6 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/Any.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include #include @@ -33,13 +32,12 @@ namespace tidy { namespace bugprone { using ast_matchers::MatchFinder; using dataflow::SourceLocationsLattice; -using dataflow::UncheckedOptionalAccessDiagnoser; using dataflow::UncheckedOptionalAccessModel; using llvm::Optional; static constexpr llvm::StringLiteral FuncID("fun"); -static Optional> +static Optional analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) { using dataflow::ControlFlowContext; using dataflow::DataflowAnalysisState; @@ -54,22 +52,23 @@ analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) { std::make_unique()); dataflow::Environment Env(AnalysisContext, FuncDecl); UncheckedOptionalAccessModel Analysis(ASTCtx); - UncheckedOptionalAccessDiagnoser Diagnoser; - std::vector Diagnostics; Expected>>> - BlockToOutputState = dataflow::runDataflowAnalysis( - *Context, Analysis, Env, - [&ASTCtx, &Diagnoser, - &Diagnostics](const Stmt *Stmt, - const DataflowAnalysisState - &State) mutable { -auto StmtDiagnostics = Diagnoser.diagnose(ASTCtx, Stmt, State.Env); -llvm::move(StmtDiagnostics, std::back_inserter(Diagnostics)); - }); + BlockToOutputState = + dataflow::runDataflowAnalysis(*Context, Analysis, Env); if (!BlockToOutputState) return llvm::None; + assert(Context->getCFG().getExit().getBlockID() < BlockToOutputState->size()); - return Diagnostics; + const Optional> + &ExitBlockState = + (*BlockToOutputState)[Context->getCFG().getExit().getBlockID()]; + // `runDataflowAnalysis` doesn't guarantee that the exit block is visited; + // for example, when it is unreachable. + // FIXME: Diagnose violations even when the exit block is unreachable. + if (!ExitBlockState) +return llvm::None; + + return std::move(ExitBlockState->Lattice); } void UncheckedOptionalAccessCheck::registerMatchers(MatchFinder *Finder) { @@ -98,9 +97,9 @@ void UncheckedOptionalAccessCheck::check( if (FuncDecl->isTemplated()) return; - if (Optional> Errors = + if (Optional Errors = analyzeFunction(*FuncDecl, *Result.Context)) -for (const SourceLocation &Loc : *Errors) +for (const SourceLocation &Loc : Errors->getSourceLocations()) diag(Loc, "unchecked access to optional value"); } diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index 40ac95b3abddb..f4d6a221abecc 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -109,33 +109,14 @@ template struct DataflowAnalysisState { /// dataflow analysis states that model the respective basic blocks. The /// returned vector, if any, will have the same size as the number of CFG /// blocks, with indices corresponding to basic block IDs. Returns an error if -/// the dataflow analysis cannot be performed successfully. Otherwise, calls -/// `PostVisitStmt` on each statement with the final analysis results at that -/// program point. +/// the dataflow analysis cannot be performed successfully. template llvm::Expected>>> -runDataflowAnalysis( -const ControlFlowContext &CFCtx, AnalysisT &Analysis, -const Environment &InitEnv, -std::function &)> -PostVisitStmt = nullptr) { - std::function - PostVisitStmtClosure = nullptr; - if (PostVisitStmt != nullptr) { -PostVisitStmtClosure = [&PostVisitStmt]( - const Stmt *Stmt, - const TypeErasedDataflowAnalysisState &State) { - auto *Lattice = -
[clang-tools-extra] 2adaca5 - [clang][dataflow] Use diagnosis API in optional checker
Author: Sam Estep Date: 2022-06-29T19:50:36Z New Revision: 2adaca532df4d3d7ae4cd3b724b2099ffefe235c URL: https://github.com/llvm/llvm-project/commit/2adaca532df4d3d7ae4cd3b724b2099ffefe235c DIFF: https://github.com/llvm/llvm-project/commit/2adaca532df4d3d7ae4cd3b724b2099ffefe235c.diff LOG: [clang][dataflow] Use diagnosis API in optional checker Followup to D127898. This patch updates `bugprone-unchecked-optional-access` to use the new `diagnoseCFG` function instead of just looking at the exit block. A followup to this will update the optional model itself to use a noop lattice rather than redundantly computing the diagnostics in both phases of the analysis. Reviewed By: ymandel, sgatev, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D128352 Added: Modified: clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h Removed: diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp index 07fb19ff81ac1..9766450e81654 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp @@ -23,6 +23,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/Any.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include #include @@ -32,12 +33,13 @@ namespace tidy { namespace bugprone { using ast_matchers::MatchFinder; using dataflow::SourceLocationsLattice; +using dataflow::UncheckedOptionalAccessDiagnoser; using dataflow::UncheckedOptionalAccessModel; using llvm::Optional; static constexpr llvm::StringLiteral FuncID("fun"); -static Optional +static Optional> analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) { using dataflow::ControlFlowContext; using dataflow::DataflowAnalysisState; @@ -52,23 +54,22 @@ analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) { std::make_unique()); dataflow::Environment Env(AnalysisContext, FuncDecl); UncheckedOptionalAccessModel Analysis(ASTCtx); + UncheckedOptionalAccessDiagnoser Diagnoser; + std::vector Diagnostics; Expected>>> - BlockToOutputState = - dataflow::runDataflowAnalysis(*Context, Analysis, Env); + BlockToOutputState = dataflow::runDataflowAnalysis( + *Context, Analysis, Env, + [&ASTCtx, &Diagnoser, + &Diagnostics](const Stmt *Stmt, + const DataflowAnalysisState + &State) mutable { +auto StmtDiagnostics = Diagnoser.diagnose(ASTCtx, Stmt, State.Env); +llvm::move(StmtDiagnostics, std::back_inserter(Diagnostics)); + }); if (!BlockToOutputState) return llvm::None; - assert(Context->getCFG().getExit().getBlockID() < BlockToOutputState->size()); - const Optional> - &ExitBlockState = - (*BlockToOutputState)[Context->getCFG().getExit().getBlockID()]; - // `runDataflowAnalysis` doesn't guarantee that the exit block is visited; - // for example, when it is unreachable. - // FIXME: Diagnose violations even when the exit block is unreachable. - if (!ExitBlockState) -return llvm::None; - - return std::move(ExitBlockState->Lattice); + return Diagnostics; } void UncheckedOptionalAccessCheck::registerMatchers(MatchFinder *Finder) { @@ -97,9 +98,9 @@ void UncheckedOptionalAccessCheck::check( if (FuncDecl->isTemplated()) return; - if (Optional Errors = + if (Optional> Errors = analyzeFunction(*FuncDecl, *Result.Context)) -for (const SourceLocation &Loc : Errors->getSourceLocations()) +for (const SourceLocation &Loc : *Errors) diag(Loc, "unchecked access to optional value"); } diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index f4d6a221abecc..40ac95b3abddb 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -109,14 +109,33 @@ template struct DataflowAnalysisState { /// dataflow analysis states that model the respective basic blocks. The /// returned vector, if any, will have the same size as the number of CFG /// blocks, with indices corresponding to basic block IDs. Returns an error if -/// the dataflow analysis cannot be performed successfully. +/// the dataflow analysis cannot be performed successfully. Otherwise, calls +/// `PostVisitStmt` on each statement with the final analysis results at that +/// program point. template llvm::Expected>>> -runDataflowAnalysis(const ControlFlowContext &CFCtx, AnalysisT &Analysis, -const Environm
[clang] cf1f978 - [clang][dataflow] Use NoopLattice in optional model
Author: Sam Estep Date: 2022-06-29T20:10:42Z New Revision: cf1f978d319b91464370d71289e1c7c30baa4243 URL: https://github.com/llvm/llvm-project/commit/cf1f978d319b91464370d71289e1c7c30baa4243 DIFF: https://github.com/llvm/llvm-project/commit/cf1f978d319b91464370d71289e1c7c30baa4243.diff LOG: [clang][dataflow] Use NoopLattice in optional model Followup to D128352. This patch pulls the `NoopLattice` class out from the `NoopAnalysis.h` test file into its own `NoopLattice.h` source file, and uses it to replace usage of `SourceLocationsLattice` in `UncheckedOptionalAccessModel`. Reviewed By: ymandel, sgatev, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D128356 Added: clang/include/clang/Analysis/FlowSensitive/NoopLattice.h Modified: clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp clang/docs/tools/clang-formatted-files.txt clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h Removed: diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp index 9766450e81654..8a945a5143067 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp @@ -18,7 +18,6 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h" -#include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/Any.h" @@ -32,7 +31,6 @@ namespace clang { namespace tidy { namespace bugprone { using ast_matchers::MatchFinder; -using dataflow::SourceLocationsLattice; using dataflow::UncheckedOptionalAccessDiagnoser; using dataflow::UncheckedOptionalAccessModel; using llvm::Optional; @@ -56,13 +54,14 @@ analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) { UncheckedOptionalAccessModel Analysis(ASTCtx); UncheckedOptionalAccessDiagnoser Diagnoser; std::vector Diagnostics; - Expected>>> + Expected>>> BlockToOutputState = dataflow::runDataflowAnalysis( *Context, Analysis, Env, - [&ASTCtx, &Diagnoser, - &Diagnostics](const Stmt *Stmt, - const DataflowAnalysisState - &State) mutable { + [&ASTCtx, &Diagnoser, &Diagnostics]( + const Stmt *Stmt, + const DataflowAnalysisState + &State) mutable { auto StmtDiagnostics = Diagnoser.diagnose(ASTCtx, Stmt, State.Env); llvm::move(StmtDiagnostics, std::back_inserter(Diagnostics)); }); diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index ed8b5e7e7ae7c..40d95411c3a0a 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -131,6 +131,7 @@ clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h clang/include/clang/Analysis/FlowSensitive/MapLattice.h clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h +clang/include/clang/Analysis/FlowSensitive/NoopLattice.h clang/include/clang/Analysis/FlowSensitive/Solver.h clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h diff --git a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h index 701db6470ac2f..25054deaf8afc 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h +++ b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h @@ -19,7 +19,7 @@ #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/MatchSwitch.h" -#include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" +#include "clang/Analysis/FlowSensitive/NoopLattice.h" #include "clang/Basic/SourceLocation.h" #include @@ -38,15 +38,11 @@ struct UncheckedOptionalAccessModelOptions { bool IgnoreSmartPointerDereference = false; }; -/// Dataflow analysis that discovers unsafe accesses of optional values and -/// adds the respective source locations to the lattice. +/// Dataflow analysis that models whether optionals hold values or not. /// /// Models the `std::optional`,
[clang] 6a97be2 - [clang][dataflow] Delete SourceLocationsLattice
Author: Sam Estep Date: 2022-06-29T20:14:07Z New Revision: 6a97be27a1de652b8f09f43178d09fc100b05990 URL: https://github.com/llvm/llvm-project/commit/6a97be27a1de652b8f09f43178d09fc100b05990 DIFF: https://github.com/llvm/llvm-project/commit/6a97be27a1de652b8f09f43178d09fc100b05990.diff LOG: [clang][dataflow] Delete SourceLocationsLattice This patch deletes the now-unused `SourceLocationsLattice` class, along with its containing files and surrounding helper functions and tests. Reviewed By: xazax.hun, ymandel, sgatev, gribozavr2 Differential Revision: https://reviews.llvm.org/D128448 Added: Modified: clang/docs/tools/clang-formatted-files.txt clang/lib/Analysis/FlowSensitive/CMakeLists.txt clang/unittests/Analysis/FlowSensitive/CMakeLists.txt llvm/utils/gn/secondary/clang/lib/Analysis/FlowSensitive/BUILD.gn llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn Removed: clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h clang/lib/Analysis/FlowSensitive/SourceLocationsLattice.cpp clang/unittests/Analysis/FlowSensitive/SourceLocationsLatticeTest.cpp diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index 40d95411c3a0a..5e1c6f130a0e4 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -133,7 +133,6 @@ clang/include/clang/Analysis/FlowSensitive/MapLattice.h clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h clang/include/clang/Analysis/FlowSensitive/NoopLattice.h clang/include/clang/Analysis/FlowSensitive/Solver.h -clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -310,7 +309,6 @@ clang/lib/Analysis/CodeInjector.cpp clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp -clang/lib/Analysis/FlowSensitive/SourceLocationsLattice.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp @@ -637,7 +635,6 @@ clang/unittests/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h clang/unittests/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp clang/unittests/Analysis/FlowSensitive/SolverTest.cpp -clang/unittests/Analysis/FlowSensitive/SourceLocationsLatticeTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp diff --git a/clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h b/clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h deleted file mode 100644 index d294f9768cdc5..0 --- a/clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h +++ /dev/null @@ -1,65 +0,0 @@ -//===-- SourceLocationsLattice.h *- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===--===// -// -// This file defines a lattice that collects source locations of interest. -// -//===--===// - -#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOURCELOCATIONS_LATTICE_H -#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOURCELOCATIONS_LATTICE_H - -#include "clang/AST/ASTContext.h" -#include "clang/Analysis/FlowSensitive/DataflowLattice.h" -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/DenseSet.h" -#include -#include - -namespace clang { -namespace dataflow { - -/// Lattice for dataflow analysis that keeps track of a set of source locations. -/// -/// Bottom is the empty set, join is set union, and equality is set equality. -/// -/// FIXME: Generalize into a (templated) PowerSetLattice. -class SourceLocationsLattice { -public: - SourceLocationsLattice() = default; - - explicit SourceLocationsLattice(llvm::DenseSet Locs) - : Locs(std::move(Locs)) {} - - bool operator==(const SourceLocationsLattice &Other) const { -return Locs == Other.Locs; - } - - bool operator!=(const SourceLocationsLattice &Other) const { -return !(*this == Other); - } - - LatticeJoinEffect join(const SourceLocationsLattice &Other); - - llvm::DenseSet &getSourceLocations() { return Locs; } - - const llvm::DenseSet &getSourceLocations()
[clang] 1d83a16 - [clang][dataflow] Replace TEST_F with TEST where possible
Author: Sam Estep Date: 2022-06-30T16:03:33Z New Revision: 1d83a16bd3faa1dfb6e8ed40c53d018dc03e2c81 URL: https://github.com/llvm/llvm-project/commit/1d83a16bd3faa1dfb6e8ed40c53d018dc03e2c81 DIFF: https://github.com/llvm/llvm-project/commit/1d83a16bd3faa1dfb6e8ed40c53d018dc03e2c81.diff LOG: [clang][dataflow] Replace TEST_F with TEST where possible Many of our tests are currently written using `TEST_F` where the test fixture class doesn't have any `SetUp` or `TearDown` methods, and just one helper method. In those cases, this patch deletes the class and pulls its method out into a standalone function, using `TEST` instead of `TEST_F`. There are still a few test files leftover in `clang/unittests/Analysis/FlowSensitive/` that use `TEST_F`: - `DataflowAnalysisContextTest.cpp` because the class contains a `Context` field which is used - `DataflowEnvironmentTest.cpp` because the class contains an `Environment` field which is used - `SolverTest.cpp` because the class contains a `Vals` field which is used - `TypeErasedDataflowAnalysisTest.cpp` because there are several different classes which all share the same method name Reviewed By: ymandel, sgatev Differential Revision: https://reviews.llvm.org/D128924 Added: Modified: clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp clang/unittests/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp clang/unittests/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp index a61d6dc682d87..2be1405465838 100644 --- a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp @@ -128,31 +128,28 @@ class ModelAdaptorAnalysis Model M; }; -class ChromiumCheckModelTest : public ::testing::TestWithParam { -protected: - template - void runDataflow(llvm::StringRef Code, Matcher Match) { -const tooling::FileContentMappings FileContents = { -{"check.h", ChromiumCheckHeader}, {"othercheck.h", OtherCheckHeader}}; - -ASSERT_THAT_ERROR( -test::checkDataflow>( -Code, "target", -[](ASTContext &C, Environment &) { - return ModelAdaptorAnalysis(C); -}, -[&Match]( -llvm::ArrayRef< -std::pair>> -Results, -ASTContext &ASTCtx) { Match(Results, ASTCtx); }, -{"-fsyntax-only", "-fno-delayed-template-parsing", "-std=c++17"}, -FileContents), -llvm::Succeeded()); - } -}; +template +void runDataflow(llvm::StringRef Code, Matcher Match) { + const tooling::FileContentMappings FileContents = { + {"check.h", ChromiumCheckHeader}, {"othercheck.h", OtherCheckHeader}}; + + ASSERT_THAT_ERROR( + test::checkDataflow>( + Code, "target", + [](ASTContext &C, Environment &) { +return ModelAdaptorAnalysis(C); + }, + [&Match]( + llvm::ArrayRef< + std::pair>> + Results, + ASTContext &ASTCtx) { Match(Results, ASTCtx); }, + {"-fsyntax-only", "-fno-delayed-template-parsing", "-std=c++17"}, + FileContents), + llvm::Succeeded()); +} -TEST_F(ChromiumCheckModelTest, CheckSuccessImpliesConditionHolds) { +TEST(ChromiumCheckModelTest, CheckSuccessImpliesConditionHolds) { auto Expectations = [](llvm::ArrayRef< std::pair>> @@ -185,7 +182,7 @@ TEST_F(ChromiumCheckModelTest, CheckSuccessImpliesConditionHolds) { runDataflow(ReplacePattern(Code, "$check", "DPCHECK"), Expectations); } -TEST_F(ChromiumCheckModelTest, UnrelatedCheckIgnored) { +TEST(ChromiumCheckModelTest, UnrelatedCheckIgnored) { auto Expectations = [](llvm::ArrayRef< std::pair>> diff --git a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp index 98319760fd206..bf8c2f5eedc95 100644 --- a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp @@ -123,25 +123,22 @@ class TestAnalysis : public DataflowAnalysis { } }; -class MatchSwitchTest : public ::testing::Test { -protected: - template - void RunDataflow(llvm::StringRef Code, Matcher Expectations) { -ASSERT_THAT_ERROR( -test::checkDataflow( -Code, "fun", -[](ASTContext &C, Environment &) { return TestAnalysis(C); }, -[&Expectations]( -llvm::ArrayR
[clang] fa2b83d - [clang][dataflow] Analyze calls to in-TU functions
Author: Sam Estep Date: 2022-07-26T17:27:19Z New Revision: fa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317 URL: https://github.com/llvm/llvm-project/commit/fa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317 DIFF: https://github.com/llvm/llvm-project/commit/fa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317.diff LOG: [clang][dataflow] Analyze calls to in-TU functions Depends On D130305 This patch adds initial support for context-sensitive analysis of simple functions whose definition is available in the translation unit, guarded by the `ContextSensitive` flag in the new `TransferOptions` struct. When this option is true, the `VisitCallExpr` case in the builtin transfer function has a fallthrough case which checks for a direct callee with a body. In that case, it constructs a CFG from that callee body, uses the new `pushCall` method on the `Environment` to make an environment to analyze the callee, and then calls `runDataflowAnalysis` with a `NoopAnalysis` (disabling context-sensitive analysis on that sub-analysis, to avoid problems with recursion). After the sub-analysis completes, the `Environment` from its exit block is simply assigned back to the environment at the callsite. The `pushCall` method (which currently only supports non-method functions with some restrictions) first calls `initGlobalVars`, then maps the `SourceLocation`s for all the parameters to the existing source locations for the corresponding arguments from the callsite. This patch adds a few tests to check that this context-sensitive analysis works on simple functions. More sophisticated functionality will be added later; the most important next step is to explicitly model context in some fields of the `DataflowAnalysisContext` class, as mentioned in a `TODO` comment in the `pushCall` implementation. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D130306 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index f17df36f6a4a..2e9c088d0e5c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -128,6 +128,21 @@ class Environment { /// with a symbolic representation of the `this` pointee. Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx); + /// Creates and returns an environment to use for an inline analysis of the + /// callee. Uses the storage location from each argument in the `Call` as the + /// storage location for the corresponding parameter in the callee. + /// + /// Requirements: + /// + /// The callee of `Call` must be a `FunctionDecl` with a body. + /// + /// The body of the callee must not reference globals. + /// + /// The arguments of `Call` must map 1:1 to the callee's parameters. + /// + /// Each argument of `Call` must already have a `StorageLocation`. + Environment pushCall(const CallExpr *Call) const; + /// Returns true if and only if the environment is equivalent to `Other`, i.e /// the two environments: /// - have the same mappings from declarations to storage locations, diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index 25afa01f307c..cbb625487c1e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -20,6 +20,12 @@ namespace clang { namespace dataflow { +struct TransferOptions { + /// Determines whether to analyze function bodies when present in the + /// translation unit. + bool ContextSensitive = false; +}; + /// Maps statements to the environments of basic blocks that contain them. class StmtToEnvMap { public: @@ -36,7 +42,8 @@ class StmtToEnvMap { /// Requirements: /// /// `S` must not be `ParenExpr` or `ExprWithCleanups`. -void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env); +void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, + TransferOptions Options); } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index b043062459e4..92700f164e7b 100644 --- a/clang/include/clang/Analysis/FlowSensitiv
[clang] cc9aa15 - Revert "[clang][dataflow] Analyze calls to in-TU functions"
Author: Sam Estep Date: 2022-07-26T17:30:09Z New Revision: cc9aa157a83a4da52f9749807429205583d815da URL: https://github.com/llvm/llvm-project/commit/cc9aa157a83a4da52f9749807429205583d815da DIFF: https://github.com/llvm/llvm-project/commit/cc9aa157a83a4da52f9749807429205583d815da.diff LOG: Revert "[clang][dataflow] Analyze calls to in-TU functions" This reverts commit fa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317. Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 2e9c088d0e5c..f17df36f6a4a 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -128,21 +128,6 @@ class Environment { /// with a symbolic representation of the `this` pointee. Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx); - /// Creates and returns an environment to use for an inline analysis of the - /// callee. Uses the storage location from each argument in the `Call` as the - /// storage location for the corresponding parameter in the callee. - /// - /// Requirements: - /// - /// The callee of `Call` must be a `FunctionDecl` with a body. - /// - /// The body of the callee must not reference globals. - /// - /// The arguments of `Call` must map 1:1 to the callee's parameters. - /// - /// Each argument of `Call` must already have a `StorageLocation`. - Environment pushCall(const CallExpr *Call) const; - /// Returns true if and only if the environment is equivalent to `Other`, i.e /// the two environments: /// - have the same mappings from declarations to storage locations, diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index cbb625487c1e..25afa01f307c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -20,12 +20,6 @@ namespace clang { namespace dataflow { -struct TransferOptions { - /// Determines whether to analyze function bodies when present in the - /// translation unit. - bool ContextSensitive = false; -}; - /// Maps statements to the environments of basic blocks that contain them. class StmtToEnvMap { public: @@ -42,8 +36,7 @@ class StmtToEnvMap { /// Requirements: /// /// `S` must not be `ParenExpr` or `ExprWithCleanups`. -void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, - TransferOptions Options); +void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env); } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index 92700f164e7b..b043062459e4 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -23,7 +23,6 @@ #include "clang/Analysis/FlowSensitive/ControlFlowContext.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" -#include "clang/Analysis/FlowSensitive/Transfer.h" #include "llvm/ADT/Any.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Error.h" @@ -37,9 +36,6 @@ struct DataflowAnalysisOptions { // (at which point the built-in transfer functions can be simply a standalone // analysis). bool ApplyBuiltinTransfer = true; - - /// Only has an effect if `ApplyBuiltinTransfer` is true. - TransferOptions BuiltinTransferOptions; }; /// Type-erased lattice element container. @@ -61,7 +57,7 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel { /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. TypeErasedDataflowAnalysis(bool ApplyBuiltinTransfer) - : Options({ApplyBuiltinTransfer, TransferOptions{}}) {} + : Options({ApplyBuiltinTransfer}) {} TypeErasedDataflowAnalysis(DataflowAnalysisOptions Options) : Options(Options) {} @@ -94,11 +90,6 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel { /// Determines whether to apply the built-in transfer functions, which model /// the heap and stack in the `Environment`. bool applyBuiltinTransfer() const
[clang] 300fbf5 - [clang][dataflow] Analyze calls to in-TU functions
Author: Sam Estep Date: 2022-07-26T17:54:27Z New Revision: 300fbf56f89aebbe2ef9ed490066bab23e5356d1 URL: https://github.com/llvm/llvm-project/commit/300fbf56f89aebbe2ef9ed490066bab23e5356d1 DIFF: https://github.com/llvm/llvm-project/commit/300fbf56f89aebbe2ef9ed490066bab23e5356d1.diff LOG: [clang][dataflow] Analyze calls to in-TU functions This patch adds initial support for context-sensitive analysis of simple functions whose definition is available in the translation unit, guarded by the `ContextSensitive` flag in the new `TransferOptions` struct. When this option is true, the `VisitCallExpr` case in the builtin transfer function has a fallthrough case which checks for a direct callee with a body. In that case, it constructs a CFG from that callee body, uses the new `pushCall` method on the `Environment` to make an environment to analyze the callee, and then calls `runDataflowAnalysis` with a `NoopAnalysis` (disabling context-sensitive analysis on that sub-analysis, to avoid problems with recursion). After the sub-analysis completes, the `Environment` from its exit block is simply assigned back to the environment at the callsite. The `pushCall` method (which currently only supports non-method functions with some restrictions) maps the `SourceLocation`s for all the parameters to the existing source locations for the corresponding arguments from the callsite. This patch adds a few tests to check that this context-sensitive analysis works on simple functions. More sophisticated functionality will be added later; the most important next step is to explicitly model context in some fields of the `DataflowAnalysisContext` class, as mentioned in a `FIXME` comment in the `pushCall` implementation. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D130306 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index f17df36f6a4a..2e9c088d0e5c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -128,6 +128,21 @@ class Environment { /// with a symbolic representation of the `this` pointee. Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx); + /// Creates and returns an environment to use for an inline analysis of the + /// callee. Uses the storage location from each argument in the `Call` as the + /// storage location for the corresponding parameter in the callee. + /// + /// Requirements: + /// + /// The callee of `Call` must be a `FunctionDecl` with a body. + /// + /// The body of the callee must not reference globals. + /// + /// The arguments of `Call` must map 1:1 to the callee's parameters. + /// + /// Each argument of `Call` must already have a `StorageLocation`. + Environment pushCall(const CallExpr *Call) const; + /// Returns true if and only if the environment is equivalent to `Other`, i.e /// the two environments: /// - have the same mappings from declarations to storage locations, diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index 25afa01f307c..cbb625487c1e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -20,6 +20,12 @@ namespace clang { namespace dataflow { +struct TransferOptions { + /// Determines whether to analyze function bodies when present in the + /// translation unit. + bool ContextSensitive = false; +}; + /// Maps statements to the environments of basic blocks that contain them. class StmtToEnvMap { public: @@ -36,7 +42,8 @@ class StmtToEnvMap { /// Requirements: /// /// `S` must not be `ParenExpr` or `ExprWithCleanups`. -void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env); +void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, + TransferOptions Options); } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index b043062459e4..92700f164e7b 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clan
[clang] a6ddc68 - [clang][dataflow] Handle multiple context-sensitive calls to the same function
Author: Sam Estep Date: 2022-07-29T19:40:19Z New Revision: a6ddc68487823d48c0ec0ddd649ace4a2732d0b0 URL: https://github.com/llvm/llvm-project/commit/a6ddc68487823d48c0ec0ddd649ace4a2732d0b0 DIFF: https://github.com/llvm/llvm-project/commit/a6ddc68487823d48c0ec0ddd649ace4a2732d0b0.diff LOG: [clang][dataflow] Handle multiple context-sensitive calls to the same function This patch enables context-sensitive analysis of multiple different calls to the same function (see the `ContextSensitiveSetBothTrueAndFalse` example in the `TransferTest` suite) by replacing the `Environment` copy-assignment with a call to the new `popCall` method, which `std::move`s some fields but specifically does not move `DeclToLoc` and `ExprToLoc` from the callee back to the caller. To enable this, the `StorageLocation` for a given parameter needs to be stable across different calls to the same function, so this patch also improves the modeling of parameter initialization, using `ReferenceValue` when necessary (for arguments passed by reference). This approach explicitly does not work for recursive calls, because we currently only plan to use this context-sensitive machinery to support specialized analysis models we write, not analysis of arbitrary callees. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D130726 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 2e9c088d0e5c3..9ba73d9224a6e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -143,6 +143,10 @@ class Environment { /// Each argument of `Call` must already have a `StorageLocation`. Environment pushCall(const CallExpr *Call) const; + /// Moves gathered information back into `this` from a `CalleeEnv` created via + /// `pushCall`. + void popCall(const Environment &CalleeEnv); + /// Returns true if and only if the environment is equivalent to `Other`, i.e /// the two environments: /// - have the same mappings from declarations to storage locations, diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index cbb625487c1eb..8babc5724d46e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -22,7 +22,10 @@ namespace dataflow { struct TransferOptions { /// Determines whether to analyze function bodies when present in the - /// translation unit. + /// translation unit. Note: this is currently only meant to be used for + /// inlining of specialized model code, not for context-sensitive analysis of + /// arbitrary subject code. In particular, some fundamentals such as recursion + /// are explicitly unsupported. bool ContextSensitive = false; }; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index f6f71e34b8927..1bb4e192ef341 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -203,14 +203,6 @@ Environment::Environment(DataflowAnalysisContext &DACtx, Environment Environment::pushCall(const CallExpr *Call) const { Environment Env(*this); - // FIXME: Currently this only works if the callee is never a method and the - // same callee is never analyzed from multiple separate callsites. To - // generalize this, we'll need to store a "context" field (probably a stack of - // `const CallExpr *`s) in the `Environment`, and then change the - // `DataflowAnalysisContext` class to hold a map from contexts to "frames", - // where each frame stores its own version of what are currently the - // `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields. - const auto *FuncDecl = Call->getDirectCallee(); assert(FuncDecl != nullptr); assert(FuncDecl->getBody() != nullptr); @@ -226,16 +218,40 @@ Environment Environment::pushCall(const CallExpr *Call) const { for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) { assert(ParamIt != FuncDecl->param_end()); -const VarDecl *Param = *ParamIt; const Expr *Arg = *ArgIt; auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); assert(ArgLoc != nullptr); -Env.setStorageLocation(*Param, *ArgLoc); + +const VarDecl *Param = *ParamIt; +auto &Loc = Env.createStorageLocation(*Param); +Env
[clang] 0eaecbb - [clang][dataflow] Handle return statements
Author: Sam Estep Date: 2022-08-04T17:42:19Z New Revision: 0eaecbbc231883b43d3ac761b276d9f505c89c27 URL: https://github.com/llvm/llvm-project/commit/0eaecbbc231883b43d3ac761b276d9f505c89c27 DIFF: https://github.com/llvm/llvm-project/commit/0eaecbbc231883b43d3ac761b276d9f505c89c27.diff LOG: [clang][dataflow] Handle return statements This patch adds a `ReturnLoc` field to the `Environment`, serving a similar to the `ThisPointeeLoc` field in the `DataflowAnalysisContext`. It then uses that (along with a new `VisitReturnStmt` method in `TransferVisitor`) to handle non-`void`-returning functions in context-sensitive analysis. Reviewed By: ymandel, sgatev Differential Revision: https://reviews.llvm.org/D130600 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index ab60d313f242c..c83d0cbbbdbb3 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -322,6 +322,7 @@ class DataflowAnalysisContext { llvm::DenseMap DeclToLoc; llvm::DenseMap ExprToLoc; + // FIXME: Move this into `Environment`. StorageLocation *ThisPointeeLoc = nullptr; // Null pointer values, keyed by the canonical pointee type. diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 1ecac86125a7b..e8a1c2db53b5c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -222,6 +222,9 @@ class Environment { /// in the environment. StorageLocation *getThisPointeeStorageLocation() const; + /// Returns the storage location of the return value or null, if unset. + StorageLocation *getReturnStorageLocation() const; + /// Returns a pointer value that represents a null pointer. Calls with /// `PointeeType` that are canonically equivalent will return the same result. PointerValue &getOrCreateNullPointerValue(QualType PointeeType); @@ -374,6 +377,11 @@ class Environment { // `DACtx` is not null and not owned by this object. DataflowAnalysisContext *DACtx; + // In a properly initialized `Environment`, `ReturnLoc` should only be null if + // its `DeclContext` could not be cast to a `FunctionDecl`. + StorageLocation *ReturnLoc = nullptr; + // FIXME: Move `ThisPointeeLoc` here from `DataflowAnalysisContext`. + // Maps from program declarations and statements to storage locations that are // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these // include only storage locations that are in scope for a particular basic diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 4e5b2adee5c99..f4dadbb79b5c9 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -154,9 +154,9 @@ Environment::Environment(DataflowAnalysisContext &DACtx) : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {} Environment::Environment(const Environment &Other) -: DACtx(Other.DACtx), DeclToLoc(Other.DeclToLoc), - ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal), - MemberLocToStruct(Other.MemberLocToStruct), +: DACtx(Other.DACtx), ReturnLoc(Other.ReturnLoc), + DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc), + LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct), FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) { } @@ -179,6 +179,9 @@ Environment::Environment(DataflowAnalysisContext &DACtx, if (Value *ParamVal = createValue(ParamDecl->getType())) setValue(ParamLoc, *ParamVal); } + +QualType ReturnType = FuncDecl->getReturnType(); +ReturnLoc = &createStorageLocation(ReturnType); } if (const auto *MethodDecl = dyn_cast(&DeclCtx)) { @@ -202,10 +205,11 @@ Environment::Environment(DataflowAnalysisContext &DACtx, Environment Environment::pushCall(const CallExpr *Call) const { Environment Env(*this); + // FIXME: Support references here. + Env.ReturnLoc = Env.getStorageLocation(*Call, SkipPast::Reference); const auto *FuncDecl = Call->getDirectCallee(); assert(FuncDecl != nullptr); - assert(FuncDecl->getBody() != nullptr); // FIXME: In order to allow the callee to re
[clang] 8611a77 - [clang][dataflow] Analyze method bodies
Author: Sam Estep Date: 2022-08-04T17:45:47Z New Revision: 8611a77ee7ee342f5925cba2fa6df023596af9d9 URL: https://github.com/llvm/llvm-project/commit/8611a77ee7ee342f5925cba2fa6df023596af9d9 DIFF: https://github.com/llvm/llvm-project/commit/8611a77ee7ee342f5925cba2fa6df023596af9d9.diff LOG: [clang][dataflow] Analyze method bodies This patch adds the ability to context-sensitively analyze method bodies, by moving `ThisPointeeLoc` from `DataflowAnalysisContext` to `Environment`, and adding code in `pushCall` to set it. Reviewed By: ymandel, sgatev, xazax.hun Differential Revision: https://reviews.llvm.org/D131170 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index c83d0cbbbdbb3..e7533794de48b 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -137,22 +137,6 @@ class DataflowAnalysisContext { return It == ExprToLoc.end() ? nullptr : It->second; } - /// Assigns `Loc` as the storage location of the `this` pointee. - /// - /// Requirements: - /// - /// The `this` pointee must not be assigned a storage location. - void setThisPointeeStorageLocation(StorageLocation &Loc) { -assert(ThisPointeeLoc == nullptr); -ThisPointeeLoc = &Loc; - } - - /// Returns the storage location assigned to the `this` pointee or null if the - /// `this` pointee has no assigned storage location. - StorageLocation *getThisPointeeStorageLocation() const { -return ThisPointeeLoc; - } - /// Returns a pointer value that represents a null pointer. Calls with /// `PointeeType` that are canonically equivalent will return the same result. /// A null `PointeeType` can be used for the pointee of `std::nullptr_t`. @@ -322,9 +306,6 @@ class DataflowAnalysisContext { llvm::DenseMap DeclToLoc; llvm::DenseMap ExprToLoc; - // FIXME: Move this into `Environment`. - StorageLocation *ThisPointeeLoc = nullptr; - // Null pointer values, keyed by the canonical pointee type. // // FIXME: The pointer values are indexed by the pointee types which are diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index e8a1c2db53b5c..fc43b6b43575f 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -380,7 +380,9 @@ class Environment { // In a properly initialized `Environment`, `ReturnLoc` should only be null if // its `DeclContext` could not be cast to a `FunctionDecl`. StorageLocation *ReturnLoc = nullptr; - // FIXME: Move `ThisPointeeLoc` here from `DataflowAnalysisContext`. + // The storage location of the `this` pointee. Should only be null if the + // function being analyzed is only a function and not a method. + StorageLocation *ThisPointeeLoc = nullptr; // Maps from program declarations and statements to storage locations that are // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index f4dadbb79b5c9..ff27a2a45179b 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -155,8 +155,9 @@ Environment::Environment(DataflowAnalysisContext &DACtx) Environment::Environment(const Environment &Other) : DACtx(Other.DACtx), ReturnLoc(Other.ReturnLoc), - DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc), - LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct), + ThisPointeeLoc(Other.ThisPointeeLoc), DeclToLoc(Other.DeclToLoc), + ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal), + MemberLocToStruct(Other.MemberLocToStruct), FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) { } @@ -194,10 +195,9 @@ Environment::Environment(DataflowAnalysisContext &DACtx, QualType ThisPointeeType = MethodDecl->getThisObjectType(); // FIXME: Add support for union types. if (!ThisPointeeType->isUnionType()) { -auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType); -DACtx.setThisPointeeStorageLocation(ThisPointeeLoc); +ThisPointeeLoc = &createStorageLocation(ThisPointeeType); if (Value *ThisPointeeVal = createValue(ThisPointeeType)) -
[clang] 000c8fe - [clang][dataflow] Analyze constructor bodies
Author: Sam Estep Date: 2022-08-10T14:01:45Z New Revision: 000c8fef86abb7f056cbea2de99f21dca4b81bf8 URL: https://github.com/llvm/llvm-project/commit/000c8fef86abb7f056cbea2de99f21dca4b81bf8 DIFF: https://github.com/llvm/llvm-project/commit/000c8fef86abb7f056cbea2de99f21dca4b81bf8.diff LOG: [clang][dataflow] Analyze constructor bodies This patch adds the ability to context-sensitively analyze constructor bodies, by changing `pushCall` to allow both `CallExpr` and `CXXConstructExpr`, and extracting the main context-sensitive logic out of `VisitCallExpr` into a new `transferInlineCall` method which is now also called at the end of `VisitCXXConstructExpr`. Reviewed By: ymandel, sgatev, xazax.hun Differential Revision: https://reviews.llvm.org/D131438 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 1b154010bf365..8c169005846ef 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -135,7 +135,7 @@ class Environment { /// /// Requirements: /// - /// The callee of `Call` must be a `FunctionDecl` with a body. + /// The callee of `Call` must be a `FunctionDecl`. /// /// The body of the callee must not reference globals. /// @@ -143,6 +143,7 @@ class Environment { /// /// Each argument of `Call` must already have a `StorageLocation`. Environment pushCall(const CallExpr *Call) const; + Environment pushCall(const CXXConstructExpr *Call) const; /// Moves gathered information back into `this` from a `CalleeEnv` created via /// `pushCall`. @@ -381,6 +382,12 @@ class Environment { StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const; const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const; + /// Shared implementation of `pushCall` overloads. Note that unlike + /// `pushCall`, this member is invoked on the environment of the callee, not + /// of the caller. + void pushCallInternal(const FunctionDecl *FuncDecl, +ArrayRef Args); + // `DACtx` is not null and not owned by this object. DataflowAnalysisContext *DACtx; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 16c83cad9d9e3..e4af68e53e14e 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -207,52 +207,68 @@ Environment::Environment(DataflowAnalysisContext &DACtx, Environment Environment::pushCall(const CallExpr *Call) const { Environment Env(*this); - // FIXME: Support references here. - Env.ReturnLoc = Env.getStorageLocation(*Call, SkipPast::Reference); - - const auto *FuncDecl = Call->getDirectCallee(); - assert(FuncDecl != nullptr); - Env.setDeclCtx(FuncDecl); - - // FIXME: In order to allow the callee to reference globals, we probably need - // to call `initGlobalVars` here in some way. + // FIXME: Support references here. + Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference); if (const auto *MethodCall = dyn_cast(Call)) { if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { - Env.ThisPointeeLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); + Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference); } } + Env.pushCallInternal(Call->getDirectCallee(), + llvm::makeArrayRef(Call->getArgs(), Call->getNumArgs())); + + return Env; +} + +Environment Environment::pushCall(const CXXConstructExpr *Call) const { + Environment Env(*this); + + // FIXME: Support references here. + Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference); + + Env.ThisPointeeLoc = Env.ReturnLoc; + + Env.pushCallInternal(Call->getConstructor(), + llvm::makeArrayRef(Call->getArgs(), Call->getNumArgs())); + + return Env; +} + +void Environment::pushCallInternal(const FunctionDecl *FuncDecl, + ArrayRef Args) { + setDeclCtx(FuncDecl); + + // FIXME: In order to allow the callee to reference globals, we probably need + // to call `initGlobalVars` here in some way. + auto ParamIt = FuncDecl->param_begin(); - auto ArgIt = Call->arg_begin(); - auto ArgEnd = Call->arg_end(); // FIXME: Parameters don't always map to arguments 1:1; examples include // overloaded operators implemented as member functions, and parameter packs. - for (; ArgIt != ArgEnd; ++ParamIt, ++ArgI
[clang] 43b298e - [clang][dataflow] Don't crash when caller args are missing storage locations
Author: Sam Estep Date: 2022-08-10T17:50:34Z New Revision: 43b298ea1282f29d448fc0f6ca971bc5fa698355 URL: https://github.com/llvm/llvm-project/commit/43b298ea1282f29d448fc0f6ca971bc5fa698355 DIFF: https://github.com/llvm/llvm-project/commit/43b298ea1282f29d448fc0f6ca971bc5fa698355.diff LOG: [clang][dataflow] Don't crash when caller args are missing storage locations This patch modifies `Environment`'s `pushCall` method to pass over arguments that are missing storage locations, instead of crashing. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D131600 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 8c169005846ef..b3bc52a79a2fc 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -140,8 +140,6 @@ class Environment { /// The body of the callee must not reference globals. /// /// The arguments of `Call` must map 1:1 to the callee's parameters. - /// - /// Each argument of `Call` must already have a `StorageLocation`. Environment pushCall(const CallExpr *Call) const; Environment pushCall(const CXXConstructExpr *Call) const; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index e4af68e53e14e..119ef337c6319 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -253,7 +253,8 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl, const Expr *Arg = Args[ArgIndex]; auto *ArgLoc = getStorageLocation(*Arg, SkipPast::Reference); -assert(ArgLoc != nullptr); +if (ArgLoc == nullptr) + continue; const VarDecl *Param = *ParamIt; auto &Loc = createStorageLocation(*Param); diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index af06021abccfd..0e33df3a38008 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4229,6 +4229,27 @@ TEST(TransferTest, ContextSensitiveReturnArg) { /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}}); } +TEST(TransferTest, ContextSensitiveReturnInt) { + std::string Code = R"( +int identity(int x) { return x; } + +void target() { + int y = identity(42); + // [[p]] +} + )"; + runDataflow(Code, + [](llvm::ArrayRef< + std::pair>> + Results, + ASTContext &ASTCtx) { +ASSERT_THAT(Results, ElementsAre(Pair("p", _))); +// This just tests that the analysis doesn't crash. + }, + {/*.ApplyBuiltinTransfer=*/true, + /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}}); +} + TEST(TransferTest, ContextSensitiveMethodLiteral) { std::string Code = R"( class MyClass { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 32dcb75 - [clang][dataflow] Move NoopAnalysis from unittests to include
Author: Sam Estep Date: 2022-07-22T14:11:32Z New Revision: 32dcb759c3005d8395b411a9aaa3d90815661d1c URL: https://github.com/llvm/llvm-project/commit/32dcb759c3005d8395b411a9aaa3d90815661d1c DIFF: https://github.com/llvm/llvm-project/commit/32dcb759c3005d8395b411a9aaa3d90815661d1c.diff LOG: [clang][dataflow] Move NoopAnalysis from unittests to include This patch moves `Analysis/FlowSensitive/NoopAnalysis.h` from `clang/unittests/` to `clang/include/clang/`, so that we can use it for doing context-sensitive analysis. Reviewed By: ymandel, gribozavr2, sgatev Differential Revision: https://reviews.llvm.org/D130304 Added: clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h Modified: clang/docs/tools/clang-formatted-files.txt clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index 107d4a7f3a02d..81d0e9522e604 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -132,6 +132,7 @@ clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h clang/include/clang/Analysis/FlowSensitive/DebugSupport.h clang/include/clang/Analysis/FlowSensitive/MapLattice.h clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h +clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h clang/include/clang/Analysis/FlowSensitive/NoopLattice.h clang/include/clang/Analysis/FlowSensitive/Solver.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h @@ -634,7 +635,6 @@ clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/MapLatticeTest.cpp clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp clang/unittests/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp -clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h clang/unittests/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp clang/unittests/Analysis/FlowSensitive/SolverTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp diff --git a/clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h similarity index 83% rename from clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h rename to clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h index 45ed414406372..15b72211fa18c 100644 --- a/clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h @@ -6,13 +6,12 @@ // //===--===// // -// This file defines a NoopAnalysis class that is used by dataflow analysis -// tests. +// This file defines a NoopAnalysis class that just uses the builtin transfer. // //===--===// -#ifndef LLVM_CLANG_UNITTESTS_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H -#define LLVM_CLANG_UNITTESTS_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" @@ -41,4 +40,4 @@ class NoopAnalysis : public DataflowAnalysis { } // namespace dataflow } // namespace clang -#endif // LLVM_CLANG_UNITTESTS_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H diff --git a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp index 2be1405465838..103e424755e3c 100644 --- a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp @@ -8,10 +8,10 @@ // FIXME: Move this to clang/unittests/Analysis/FlowSensitive/Models. #include "clang/Analysis/FlowSensitive/Models/ChromiumCheckModel.h" -#include "NoopAnalysis.h" #include "TestingSupport.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Analysis/FlowSensitive/NoopAnalysis.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 434bc6b8042ee..ae70131a60a57 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensiti
[clang] aed1ab8 - [clang][dataflow] Refactor ApplyBuiltinTransfer field out into DataflowAnalysisOptions struct
Author: Sam Estep Date: 2022-07-22T15:16:29Z New Revision: aed1ab8cabac64b59338f5ebadd12a371cb2ee5d URL: https://github.com/llvm/llvm-project/commit/aed1ab8cabac64b59338f5ebadd12a371cb2ee5d DIFF: https://github.com/llvm/llvm-project/commit/aed1ab8cabac64b59338f5ebadd12a371cb2ee5d.diff LOG: [clang][dataflow] Refactor ApplyBuiltinTransfer field out into DataflowAnalysisOptions struct Depends On D130304 This patch pulls the `ApplyBuiltinTransfer` from the `TypeErasedDataflowAnalysis` class into a new `DataflowAnalysisOptions` struct, to allow us to add additional options later without breaking existing code. Reviewed By: gribozavr2, sgatev Differential Revision: https://reviews.llvm.org/D130305 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index 40ac95b3abddb..ef8f7a51496c9 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -63,9 +63,15 @@ class DataflowAnalysis : public TypeErasedDataflowAnalysis { using Lattice = LatticeT; explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {} + + /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) : TypeErasedDataflowAnalysis(ApplyBuiltinTransfer), Context(Context) {} + explicit DataflowAnalysis(ASTContext &Context, +DataflowAnalysisOptions Options) + : TypeErasedDataflowAnalysis(Options), Context(Context) {} + ASTContext &getASTContext() final { return Context; } TypeErasedLattice typeErasedInitialElement() final { diff --git a/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h index 15b72211fa18c..4f05f5f4554bb 100644 --- a/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h @@ -24,13 +24,17 @@ namespace dataflow { class NoopAnalysis : public DataflowAnalysis { public: + /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. + NoopAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) + : DataflowAnalysis(Context, +ApplyBuiltinTransfer) {} + /// `ApplyBuiltinTransfer` controls whether to run the built-in transfer /// functions that model memory during the analysis. Their results are not /// used by `NoopAnalysis`, but tests that need to inspect the environment /// should enable them. - NoopAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) - : DataflowAnalysis(Context, -ApplyBuiltinTransfer) {} + NoopAnalysis(ASTContext &Context, DataflowAnalysisOptions Options) + : DataflowAnalysis(Context, Options) {} static NoopLattice initialElement() { return {}; } diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index 5e168194064f4..b043062459e4e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -30,6 +30,14 @@ namespace clang { namespace dataflow { +struct DataflowAnalysisOptions { + /// Determines whether to apply the built-in transfer functions. + // FIXME: Remove this option once the framework supports composing analyses + // (at which point the built-in transfer functions can be simply a standalone + // analysis). + bool ApplyBuiltinTransfer = true; +}; + /// Type-erased lattice element container. /// /// Requirements: @@ -42,16 +50,17 @@ struct TypeErasedLattice { /// Type-erased base class for dataflow analyses built on a single lattice type. class TypeErasedDataflowAnalysis : public Environment::ValueModel { - /// Determines whether to apply the built-in transfer functions. - // FIXME: Remove this option once the framework supports composing analyses - // (at which point the built-in transfer functions can be simply a standalone - // analysis). - bool ApplyBuiltinTransfer; + DataflowAnalysisOptions Options; public: - TypeErasedDataflowAnalysis() : ApplyBuiltinTransfer(true) {} + TypeErasedDataflowAnalysis() : Options({}) {} + + /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. TypeErasedDataflowAnalysis(bool ApplyBuiltinTransfer) - : ApplyBuiltinTransfer(ApplyBuiltinTransfer) {} + : Options({App
[clang] b3f1a6b - [clang][dataflow] Encode options using llvm::Optional
Author: Sam Estep Date: 2022-08-12T16:29:41Z New Revision: b3f1a6bf1080fb67cb1760a924a56d38d51211aa URL: https://github.com/llvm/llvm-project/commit/b3f1a6bf1080fb67cb1760a924a56d38d51211aa DIFF: https://github.com/llvm/llvm-project/commit/b3f1a6bf1080fb67cb1760a924a56d38d51211aa.diff LOG: [clang][dataflow] Encode options using llvm::Optional This patch restructures `DataflowAnalysisOptions` and `TransferOptions` to use `llvm::Optional`, in preparation for adding more sub-options to the `ContextSensitiveOptions` struct introduced here. Reviewed By: sgatev, xazax.hun Differential Revision: https://reviews.llvm.org/D131779 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index 99e16f8255446..4c785b21526da 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -65,8 +65,9 @@ class DataflowAnalysis : public TypeErasedDataflowAnalysis { /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) - : DataflowAnalysis(Context, DataflowAnalysisOptions{ApplyBuiltinTransfer, - TransferOptions{}}) {} + : DataflowAnalysis(Context, {ApplyBuiltinTransfer + ? TransferOptions{} + : llvm::Optional()}) {} explicit DataflowAnalysis(ASTContext &Context, DataflowAnalysisOptions Options) diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index 8babc5724d46e..93afcc284e1af 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -16,17 +16,19 @@ #include "clang/AST/Stmt.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "llvm/ADT/Optional.h" namespace clang { namespace dataflow { +struct ContextSensitiveOptions {}; + struct TransferOptions { - /// Determines whether to analyze function bodies when present in the - /// translation unit. Note: this is currently only meant to be used for - /// inlining of specialized model code, not for context-sensitive analysis of - /// arbitrary subject code. In particular, some fundamentals such as recursion - /// are explicitly unsupported. - bool ContextSensitive = false; + /// Options for analyzing function bodies when present in the translation + /// unit, or empty to disable context-sensitive analysis. Note that this is + /// fundamentally limited: some constructs, such as recursion, are explicitly + /// unsupported. + llvm::Optional ContextSensitiveOpts; }; /// Maps statements to the environments of basic blocks that contain them. diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index 3bd1c8e12e9b2..58acda7e6389d 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -32,14 +32,11 @@ namespace clang { namespace dataflow { struct DataflowAnalysisOptions { - /// Determines whether to apply the built-in transfer functions. + /// Options for the built-in transfer functions, or empty to not apply them. // FIXME: Remove this option once the framework supports composing analyses // (at which point the built-in transfer functions can be simply a standalone // analysis). - bool ApplyBuiltinTransfer = true; - - /// Only has an effect if `ApplyBuiltinTransfer` is true. - TransferOptions BuiltinTransferOptions; + llvm::Optional BuiltinTransferOpts = TransferOptions{}; }; /// Type-erased lattice element container. @@ -87,13 +84,11 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel { virtual void transferTypeErased(const Stmt *, TypeErasedLattice &, Environment &) = 0; - /// Determines whether to apply the built-in transfer functions, which model - /// the heap and stack in the `Environment`. - bool applyBuiltinTransfer() const { return Options.ApplyBuiltinTransfer; } - - /// Returns the options to be passed to the built-in transfer functions. - Transfe
[clang] 2efc8f8 - [clang][dataflow] Add an option for context-sensitive depth
Author: Sam Estep Date: 2022-08-15T19:58:40Z New Revision: 2efc8f8d6561421c3f47de2f27a365ddfb734425 URL: https://github.com/llvm/llvm-project/commit/2efc8f8d6561421c3f47de2f27a365ddfb734425 DIFF: https://github.com/llvm/llvm-project/commit/2efc8f8d6561421c3f47de2f27a365ddfb734425.diff LOG: [clang][dataflow] Add an option for context-sensitive depth This patch adds a `Depth` field (default value 2) to `ContextSensitiveOptions`, allowing context-sensitive analysis of functions that call other functions. This also requires replacing the `DeclCtx` field on `Environment` with a `CallString` field that contains a vector of decl contexts, to ensure that the analysis doesn't try to analyze recursive or mutually recursive calls (which would result in a crash, due to the way we handle `StorageLocation`s). Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D131809 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 5b29915e368ed..6955bcf2fb4ca 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -348,10 +348,12 @@ class Environment { /// Returns the `DeclContext` of the block being analysed, if any. Otherwise, /// returns null. - const DeclContext *getDeclCtx() { return DeclCtx; } + const DeclContext *getDeclCtx() { return CallStack.back(); } - /// Sets the `DeclContext` of the block being analysed. - void setDeclCtx(const DeclContext *Ctx) { DeclCtx = Ctx; } + /// Returns whether this `Environment` can be extended to analyze the given + /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a + /// given `MaxDepth`. + bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const; /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise, /// returns null. @@ -390,7 +392,7 @@ class Environment { DataflowAnalysisContext *DACtx; // `DeclContext` of the block being analysed if provided. - const DeclContext *DeclCtx = nullptr; + std::vector CallStack; // In a properly initialized `Environment`, `ReturnLoc` should only be null if // its `DeclContext` could not be cast to a `FunctionDecl`. diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index 93afcc284e1af..fa05013bb7208 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -21,7 +21,11 @@ namespace clang { namespace dataflow { -struct ContextSensitiveOptions {}; +struct ContextSensitiveOptions { + /// The maximum depth to analyze. A value of zero is equivalent to disabling + /// context-sensitive analysis entirely. + unsigned Depth = 2; +}; struct TransferOptions { /// Options for analyzing function bodies when present in the translation diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 119ef337c6319..f64ade34bcb82 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -154,10 +154,10 @@ Environment::Environment(DataflowAnalysisContext &DACtx) : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {} Environment::Environment(const Environment &Other) -: DACtx(Other.DACtx), DeclCtx(Other.DeclCtx), ReturnLoc(Other.ReturnLoc), - ThisPointeeLoc(Other.ThisPointeeLoc), DeclToLoc(Other.DeclToLoc), - ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal), - MemberLocToStruct(Other.MemberLocToStruct), +: DACtx(Other.DACtx), CallStack(Other.CallStack), + ReturnLoc(Other.ReturnLoc), ThisPointeeLoc(Other.ThisPointeeLoc), + DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc), + LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct), FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) { } @@ -168,11 +168,11 @@ Environment &Environment::operator=(const Environment &Other) { } Environment::Environment(DataflowAnalysisContext &DACtx, - const DeclContext &DeclCtxArg) + const DeclContext &DeclCtx) : Environment(DACtx) { - setDeclCtx(&DeclCtxArg); + CallStack.push_back(&DeclCtx); - if (const auto *FuncDecl = dyn_cast(DeclCtx)) { + if (const auto *FuncDecl = dyn_
[clang] 4eecd19 - [clang][dataflow] Allow MatchSwitch to return a value
Author: Sam Estep Date: 2022-06-24T13:32:47Z New Revision: 4eecd194b073492a309b87c8f60da6614bba9153 URL: https://github.com/llvm/llvm-project/commit/4eecd194b073492a309b87c8f60da6614bba9153 DIFF: https://github.com/llvm/llvm-project/commit/4eecd194b073492a309b87c8f60da6614bba9153.diff LOG: [clang][dataflow] Allow MatchSwitch to return a value This patch adds another `typename` parameter to `MatchSwitch` class: `Result` (defaults to `void`), corresponding to the return type of the function. This necessitates a couple minor changes to the `MatchSwitchBuilder` class, and is tested via a new `ReturnNonVoid` test in `clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp`. Reviewed By: gribozavr2, sgatev, xazax.hun Differential Revision: https://reviews.llvm.org/D128467 Added: Modified: clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h index 2aaaf78f9cd0e..77271bda188d5 100644 --- a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h +++ b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h @@ -46,8 +46,8 @@ template struct TransferState { /// Matches against `Stmt` and, based on its structure, dispatches to an /// appropriate handler. -template -using MatchSwitch = std::function; +template +using MatchSwitch = std::function; /// Collects cases of a "match switch": a collection of matchers paired with /// callbacks, which together define a switch that can be applied to a @@ -68,7 +68,7 @@ using MatchSwitch = std::function; /// .Build(); /// } /// \endcode -template class MatchSwitchBuilder { +template class MatchSwitchBuilder { public: /// Registers an action that will be triggered by the match of a pattern /// against the input statement. @@ -79,24 +79,24 @@ template class MatchSwitchBuilder { template MatchSwitchBuilder && CaseOf(ast_matchers::internal::Matcher M, - std::function + std::function A) && { Matchers.push_back(std::move(M)); Actions.push_back( [A = std::move(A)](const Stmt *Stmt, const ast_matchers::MatchFinder::MatchResult &R, - State &S) { A(cast(Stmt), R, S); }); + State &S) { return A(cast(Stmt), R, S); }); return std::move(*this); } - MatchSwitch Build() && { + MatchSwitch Build() && { return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( - const Stmt &Stmt, ASTContext &Context, State &S) { + const Stmt &Stmt, ASTContext &Context, State &S) -> Result { auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); if (Results.empty()) -return; +return {}; // Look through the map for the first binding of the form "TagN..." use // that to select the action. for (const auto &Element : Results[0].getMap()) { @@ -104,12 +104,12 @@ template class MatchSwitchBuilder { size_t Index = 0; if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && Index < Actions.size()) { - Actions[Index]( + return Actions[Index]( &Stmt, ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); - return; } } + return {}; }; } @@ -142,7 +142,7 @@ template class MatchSwitchBuilder { } std::vector Matchers; - std::vector> Actions; }; diff --git a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp index bd2ae0e96c01e..98319760fd206 100644 --- a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp @@ -204,3 +204,29 @@ TEST_F(MatchSwitchTest, Neither) { RunDataflow(Code, UnorderedElementsAre(Pair("p", Holds(BooleanLattice(false); } + +TEST_F(MatchSwitchTest, ReturnNonVoid) { + using namespace ast_matchers; + + auto Unit = + tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc", +std::make_shared()); + auto &Context = Unit->getASTContext(); + const auto *S = + selectFirst( + "f", + match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context)) + ->getBody(); + + MatchSwitch> Switch = + MatchSwitchBuilder>() + .CaseOf(stmt(), +[](const Stmt *, const MatchFinder::MatchResult &, + const int &State) -> std::vector { + return {1, State, 3}; +}) + .Build(); + std::vector Actual = Switch(*S, Context, 7); +
[clang] 7b326b9 - Revert "[clang][dataflow] Allow MatchSwitch to return a value"
Author: Sam Estep Date: 2022-06-24T13:52:11Z New Revision: 7b326b946a38f58c9b3fdfeee09678bc4bf91292 URL: https://github.com/llvm/llvm-project/commit/7b326b946a38f58c9b3fdfeee09678bc4bf91292 DIFF: https://github.com/llvm/llvm-project/commit/7b326b946a38f58c9b3fdfeee09678bc4bf91292.diff LOG: Revert "[clang][dataflow] Allow MatchSwitch to return a value" This reverts commit 4eecd194b073492a309b87c8f60da6614bba9153. Added: Modified: clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h index 77271bda188d5..2aaaf78f9cd0e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h +++ b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h @@ -46,8 +46,8 @@ template struct TransferState { /// Matches against `Stmt` and, based on its structure, dispatches to an /// appropriate handler. -template -using MatchSwitch = std::function; +template +using MatchSwitch = std::function; /// Collects cases of a "match switch": a collection of matchers paired with /// callbacks, which together define a switch that can be applied to a @@ -68,7 +68,7 @@ using MatchSwitch = std::function; /// .Build(); /// } /// \endcode -template class MatchSwitchBuilder { +template class MatchSwitchBuilder { public: /// Registers an action that will be triggered by the match of a pattern /// against the input statement. @@ -79,24 +79,24 @@ template class MatchSwitchBuilder { template MatchSwitchBuilder && CaseOf(ast_matchers::internal::Matcher M, - std::function + std::function A) && { Matchers.push_back(std::move(M)); Actions.push_back( [A = std::move(A)](const Stmt *Stmt, const ast_matchers::MatchFinder::MatchResult &R, - State &S) { return A(cast(Stmt), R, S); }); + State &S) { A(cast(Stmt), R, S); }); return std::move(*this); } - MatchSwitch Build() && { + MatchSwitch Build() && { return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( - const Stmt &Stmt, ASTContext &Context, State &S) -> Result { + const Stmt &Stmt, ASTContext &Context, State &S) { auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); if (Results.empty()) -return {}; +return; // Look through the map for the first binding of the form "TagN..." use // that to select the action. for (const auto &Element : Results[0].getMap()) { @@ -104,12 +104,12 @@ template class MatchSwitchBuilder { size_t Index = 0; if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && Index < Actions.size()) { - return Actions[Index]( + Actions[Index]( &Stmt, ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); + return; } } - return {}; }; } @@ -142,7 +142,7 @@ template class MatchSwitchBuilder { } std::vector Matchers; - std::vector> Actions; }; diff --git a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp index 98319760fd206..bd2ae0e96c01e 100644 --- a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp @@ -204,29 +204,3 @@ TEST_F(MatchSwitchTest, Neither) { RunDataflow(Code, UnorderedElementsAre(Pair("p", Holds(BooleanLattice(false); } - -TEST_F(MatchSwitchTest, ReturnNonVoid) { - using namespace ast_matchers; - - auto Unit = - tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc", -std::make_shared()); - auto &Context = Unit->getASTContext(); - const auto *S = - selectFirst( - "f", - match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context)) - ->getBody(); - - MatchSwitch> Switch = - MatchSwitchBuilder>() - .CaseOf(stmt(), -[](const Stmt *, const MatchFinder::MatchResult &, - const int &State) -> std::vector { - return {1, State, 3}; -}) - .Build(); - std::vector Actual = Switch(*S, Context, 7); - std::vector Expected{1, 7, 3}; - EXPECT_EQ(Actual, Expected); -} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 8c278a2 - [clang][dataflow] Allow MatchSwitch to return a value
Author: Sam Estep Date: 2022-06-24T14:38:00Z New Revision: 8c278a27811ccf9d7a32c0a460b08069c4b3b7b5 URL: https://github.com/llvm/llvm-project/commit/8c278a27811ccf9d7a32c0a460b08069c4b3b7b5 DIFF: https://github.com/llvm/llvm-project/commit/8c278a27811ccf9d7a32c0a460b08069c4b3b7b5.diff LOG: [clang][dataflow] Allow MatchSwitch to return a value Reland of D128467. This version replaces `return {};` with `return Result();`, since the former failed on GCC with `Result = void`. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D128533 Added: Modified: clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h index 2aaaf78f9cd0e..927aec7df5731 100644 --- a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h +++ b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h @@ -46,8 +46,8 @@ template struct TransferState { /// Matches against `Stmt` and, based on its structure, dispatches to an /// appropriate handler. -template -using MatchSwitch = std::function; +template +using MatchSwitch = std::function; /// Collects cases of a "match switch": a collection of matchers paired with /// callbacks, which together define a switch that can be applied to a @@ -68,7 +68,7 @@ using MatchSwitch = std::function; /// .Build(); /// } /// \endcode -template class MatchSwitchBuilder { +template class MatchSwitchBuilder { public: /// Registers an action that will be triggered by the match of a pattern /// against the input statement. @@ -79,24 +79,24 @@ template class MatchSwitchBuilder { template MatchSwitchBuilder && CaseOf(ast_matchers::internal::Matcher M, - std::function + std::function A) && { Matchers.push_back(std::move(M)); Actions.push_back( [A = std::move(A)](const Stmt *Stmt, const ast_matchers::MatchFinder::MatchResult &R, - State &S) { A(cast(Stmt), R, S); }); + State &S) { return A(cast(Stmt), R, S); }); return std::move(*this); } - MatchSwitch Build() && { + MatchSwitch Build() && { return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( - const Stmt &Stmt, ASTContext &Context, State &S) { + const Stmt &Stmt, ASTContext &Context, State &S) -> Result { auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); if (Results.empty()) -return; +return Result(); // Look through the map for the first binding of the form "TagN..." use // that to select the action. for (const auto &Element : Results[0].getMap()) { @@ -104,12 +104,12 @@ template class MatchSwitchBuilder { size_t Index = 0; if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && Index < Actions.size()) { - Actions[Index]( + return Actions[Index]( &Stmt, ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); - return; } } + return Result(); }; } @@ -142,7 +142,7 @@ template class MatchSwitchBuilder { } std::vector Matchers; - std::vector> Actions; }; diff --git a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp index bd2ae0e96c01e..98319760fd206 100644 --- a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp @@ -204,3 +204,29 @@ TEST_F(MatchSwitchTest, Neither) { RunDataflow(Code, UnorderedElementsAre(Pair("p", Holds(BooleanLattice(false); } + +TEST_F(MatchSwitchTest, ReturnNonVoid) { + using namespace ast_matchers; + + auto Unit = + tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc", +std::make_shared()); + auto &Context = Unit->getASTContext(); + const auto *S = + selectFirst( + "f", + match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context)) + ->getBody(); + + MatchSwitch> Switch = + MatchSwitchBuilder>() + .CaseOf(stmt(), +[](const Stmt *, const MatchFinder::MatchResult &, + const int &State) -> std::vector { + return {1, State, 3}; +}) + .Build(); + std::vector Actual = Switch(*S, Context, 7); + std::vector Expected{1, 7, 3}; + EXPECT_EQ(Actual, Expected); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailma