diff --git a/clang/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h b/clang/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h deleted file mode 100644 index ecd8558970f9..000000000000 --- a/clang/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h +++ /dev/null @@ -1,98 +0,0 @@ -//===---- CFGMatchSwitch.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 `CFGMatchSwitch` abstraction for building a "switch" -// statement for control flow graph elements. Each case of the switch is -// defined by an ASTMatcher which is applied on the AST node contained in the -// input `CFGElement`. -// -// Currently, the `CFGMatchSwitch` only handles `CFGElement`s of -// `Kind::Statement` and `Kind::Initializer`. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ -#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ - -#include "clang/AST/ASTContext.h" -#include "clang/AST/Stmt.h" -#include "clang/Analysis/CFG.h" -#include "clang/Analysis/FlowSensitive/MatchSwitch.h" -#include -#include - -namespace clang { -namespace dataflow { - -template -using CFGMatchSwitch = - 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 an AST node -/// contained in a CFG element. -template class CFGMatchSwitchBuilder { -public: - /// Registers an action `A` for `CFGStmt`s that will be triggered by the match - /// of the pattern `M` against the `Stmt` contained in the input `CFGStmt`. - /// - /// Requirements: - /// - /// `NodeT` should be derived from `Stmt`. - template - CFGMatchSwitchBuilder && - CaseOfCFGStmt(MatchSwitchMatcher M, - MatchSwitchAction A) && { - std::move(StmtBuilder).template CaseOf(M, A); - return std::move(*this); - } - - /// Registers an action `A` for `CFGInitializer`s that will be triggered by - /// the match of the pattern `M` against the `CXXCtorInitializer` contained in - /// the input `CFGInitializer`. - /// - /// Requirements: - /// - /// `NodeT` should be derived from `CXXCtorInitializer`. - template - CFGMatchSwitchBuilder && - CaseOfCFGInit(MatchSwitchMatcher M, - MatchSwitchAction A) && { - std::move(InitBuilder).template CaseOf(M, A); - return std::move(*this); - } - - CFGMatchSwitch Build() && { - return [StmtMS = std::move(StmtBuilder).Build(), - InitMS = std::move(InitBuilder).Build()](const CFGElement &Element, - ASTContext &Context, - State &S) -> Result { - switch (Element.getKind()) { - case CFGElement::Initializer: - return InitMS(*Element.castAs().getInitializer(), - Context, S); - case CFGElement::Statement: - case CFGElement::Constructor: - case CFGElement::CXXRecordTypedCall: - return StmtMS(*Element.castAs().getStmt(), Context, S); - default: - // FIXME: Handle other kinds of CFGElement. - return Result(); - } - }; - } - -private: - ASTMatchSwitchBuilder StmtBuilder; - ASTMatchSwitchBuilder InitBuilder; -}; - -} // namespace dataflow -} // namespace clang - -#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ diff --git a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h index 76d18c1d2446..927aec7df573 100644 --- a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h +++ b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h @@ -16,9 +16,6 @@ // library may be generalized and moved to ASTMatchers. // //===----------------------------------------------------------------------===// -// -// FIXME: Rename to ASTMatchSwitch.h and update documentation when all usages of -// `MatchSwitch` are updated to `ASTMatchSwitch` #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ @@ -31,7 +28,6 @@ #include "llvm/ADT/StringRef.h" #include #include -#include #include #include @@ -48,35 +44,23 @@ template struct TransferState { Environment &Env; }; -template -using MatchSwitchMatcher = ast_matchers::internal::Matcher; - -template -using MatchSwitchAction = std::function; - -template -using ASTMatchSwitch = - std::function; - -// FIXME: Remove this alias when all usages of `MatchSwitch` are updated to -// `ASTMatchSwitch`. +/// Matches against `Stmt` and, based on its structure, dispatches to an +/// appropriate handler. template -using MatchSwitch = ASTMatchSwitch; +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 node -/// whose type derives from `BaseT`. This structure can simplify the definition -/// of `transfer` functions that rely on pattern-matching. +/// callbacks, which together define a switch that can be applied to a +/// `Stmt`. This structure can simplify the definition of `transfer` functions +/// that rely on pattern-matching. /// /// For example, consider an analysis that handles particular function calls. It -/// can define the `ASTMatchSwitch` once, in the constructor of the analysis, -/// and then reuse it each time that `transfer` is called, with a fresh state -/// value. +/// can define the `MatchSwitch` once, in the constructor of the analysis, and +/// then reuse it each time that `transfer` is called, with a fresh state value. /// /// \code -/// ASTMatchSwitch BuildSwitch() { -/// return ASTMatchSwitchBuilder>() +/// MatchSwitch BuildSwitch() { +/// return MatchSwitchBuilder>() /// .CaseOf(callExpr(callee(functionDecl(hasName("foo")))), TransferFooCall) /// .CaseOf(callExpr(argumentCountIs(2), /// callee(functionDecl(hasName("bar")))), @@ -84,35 +68,35 @@ using MatchSwitch = ASTMatchSwitch; /// .Build(); /// } /// \endcode -template -class ASTMatchSwitchBuilder { +template class MatchSwitchBuilder { public: /// Registers an action that will be triggered by the match of a pattern /// against the input statement. /// /// Requirements: /// - /// `NodeT` should be derived from `BaseT`. - template - ASTMatchSwitchBuilder &&CaseOf(MatchSwitchMatcher M, - MatchSwitchAction A) && { - static_assert(std::is_base_of::value, - "NodeT must be derived from BaseT."); + /// `Node` should be a subclass of `Stmt`. + template + MatchSwitchBuilder && + CaseOf(ast_matchers::internal::Matcher M, + std::function + A) && { Matchers.push_back(std::move(M)); Actions.push_back( - [A = std::move(A)](const BaseT *Node, + [A = std::move(A)](const Stmt *Stmt, const ast_matchers::MatchFinder::MatchResult &R, - State &S) { return A(cast(Node), R, S); }); + State &S) { return A(cast(Stmt), R, S); }); return std::move(*this); } - ASTMatchSwitch Build() && { + MatchSwitch Build() && { return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( - const BaseT &Node, ASTContext &Context, State &S) -> Result { - auto Results = ast_matchers::matchDynamic(Matcher, Node, Context); - if (Results.empty()) { + const Stmt &Stmt, ASTContext &Context, State &S) -> Result { + auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); + if (Results.empty()) 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()) { @@ -121,7 +105,7 @@ public: if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && Index < Actions.size()) { return Actions[Index]( - &Node, + &Stmt, ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); } } @@ -153,19 +137,15 @@ private: // The matcher type on the cases ensures that `Expr` kind is compatible with // all of the matchers. return DynTypedMatcher::constructVariadic( - DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind(), + DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind(), std::move(Matchers)); } std::vector Matchers; - std::vector> Actions; + std::vector> + Actions; }; - -// FIXME: Remove this alias when all usages of `MatchSwitchBuilder` are updated -// to `ASTMatchSwitchBuilder`. -template -using MatchSwitchBuilder = ASTMatchSwitchBuilder; - } // namespace dataflow } // namespace clang #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ diff --git a/clang/unittests/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp b/clang/unittests/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp deleted file mode 100644 index 98697616dfdb..000000000000 --- a/clang/unittests/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp +++ /dev/null @@ -1,124 +0,0 @@ -//===- unittests/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp ------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/Stmt.h" -#include "clang/Analysis/CFG.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/StringRef.h" -#include "gtest/gtest.h" - -using namespace clang; -using namespace dataflow; -using namespace ast_matchers; - -namespace { -// State for tracking the number of matches on each kind of CFGElement by the -// CFGMatchSwitch. Currently only tracks CFGStmt and CFGInitializer. -struct CFGElementMatches { - unsigned StmtMatches = 0; - unsigned InitializerMatches = 0; -}; - -// Returns a match switch that counts the number of local variables -// (singly-declared) and fields initialized to the integer literal 42. -auto buildCFGMatchSwitch() { - return CFGMatchSwitchBuilder() - .CaseOfCFGStmt( - declStmt(hasSingleDecl( - varDecl(hasInitializer(integerLiteral(equals(42)))))), - [](const DeclStmt *, const MatchFinder::MatchResult &, - CFGElementMatches &Counter) { Counter.StmtMatches++; }) - .CaseOfCFGInit( - cxxCtorInitializer(withInitializer(integerLiteral(equals(42)))), - [](const CXXCtorInitializer *, const MatchFinder::MatchResult &, - CFGElementMatches &Counter) { Counter.InitializerMatches++; }) - .Build(); -} - -// Runs the match switch `MS` on the control flow graph generated from `Code`, -// tracking information in state `S`. For simplicity, this test utility is -// restricted to CFGs with a single control flow block (excluding entry and -// exit blocks) - generated by `Code` with sequential flow (i.e. no branching). -// -// Requirements: -// -// `Code` must contain a function named `f`, the body of this function will be -// used to generate the CFG. -template -void applySwitchToCode(CFGMatchSwitch &MS, State &S, - llvm::StringRef Code) { - auto Unit = tooling::buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"}); - auto &Ctx = Unit->getASTContext(); - const auto *F = selectFirst( - "f", match(functionDecl(isDefinition(), hasName("f")).bind("f"), Ctx)); - - CFG::BuildOptions BO; - BO.AddInitializers = true; - - auto CFG = CFG::buildCFG(F, F->getBody(), &Ctx, BO); - auto CFGBlock = *CFG->getEntry().succ_begin(); - for (auto &Elt : CFGBlock->Elements) { - MS(Elt, Ctx, S); - } -} - -TEST(CFGMatchSwitchTest, NoInitializationTo42) { - CFGMatchSwitch Switch = buildCFGMatchSwitch(); - CFGElementMatches Counter; - applySwitchToCode(Switch, Counter, R"( - void f() { - 42; - } - )"); - EXPECT_EQ(Counter.StmtMatches, 0); - EXPECT_EQ(Counter.InitializerMatches, 0); -} - -TEST(CFGMatchSwitchTest, SingleLocalVarInitializationTo42) { - CFGMatchSwitch Switch = buildCFGMatchSwitch(); - CFGElementMatches Counter; - applySwitchToCode(Switch, Counter, R"( - void f() { - int i = 42; - } - )"); - EXPECT_EQ(Counter.StmtMatches, 1); - EXPECT_EQ(Counter.InitializerMatches, 0); -} - -TEST(CFGMatchSwitchTest, SingleFieldInitializationTo42) { - CFGMatchSwitch Switch = buildCFGMatchSwitch(); - CFGElementMatches Counter; - applySwitchToCode(Switch, Counter, R"( - struct f { - int i; - f(): i(42) {} - }; - )"); - EXPECT_EQ(Counter.StmtMatches, 0); - EXPECT_EQ(Counter.InitializerMatches, 1); -} - -TEST(CFGMatchSwitchTest, LocalVarAndFieldInitializationTo42) { - CFGMatchSwitch Switch = buildCFGMatchSwitch(); - CFGElementMatches Counter; - applySwitchToCode(Switch, Counter, R"( - struct f { - int i; - f(): i(42) { - int j = 42; - } - }; - )"); - EXPECT_EQ(Counter.StmtMatches, 1); - EXPECT_EQ(Counter.InitializerMatches, 1); -} -} // namespace diff --git a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt index 85499ecb3001..8ce2549df36d 100644 --- a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt +++ b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt @@ -4,7 +4,6 @@ set(LLVM_LINK_COMPONENTS ) add_clang_unittest(ClangAnalysisFlowSensitiveTests - CFGMatchSwitchTest.cpp ChromiumCheckModelTest.cpp DataflowAnalysisContextTest.cpp DataflowEnvironmentTest.cpp diff --git a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp index 90cc4a19ac7f..bf8c2f5eedc9 100644 --- a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp @@ -5,6 +5,12 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +// +// This file defines a simplistic version of Constant Propagation as an example +// of a forward, monotonic dataflow analysis. The analysis tracks all +// variables in the scope, but lacks escape analysis. +// +//===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/MatchSwitch.h" #include "TestingSupport.h"