| //===---- 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 <functional> |
| #include <utility> |
| |
| namespace clang { |
| namespace dataflow { |
| |
| template <typename State, typename Result = void> |
| using CFGMatchSwitch = |
| std::function<Result(const CFGElement &, ASTContext &, State &)>; |
| |
| /// 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 <typename State, typename Result = void> 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 <typename NodeT> |
| CFGMatchSwitchBuilder && |
| CaseOfCFGStmt(MatchSwitchMatcher<Stmt> M, |
| MatchSwitchAction<NodeT, State, Result> A) && { |
| std::move(StmtBuilder).template CaseOf<NodeT>(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 <typename NodeT> |
| CFGMatchSwitchBuilder && |
| CaseOfCFGInit(MatchSwitchMatcher<CXXCtorInitializer> M, |
| MatchSwitchAction<NodeT, State, Result> A) && { |
| std::move(InitBuilder).template CaseOf<NodeT>(M, A); |
| return std::move(*this); |
| } |
| |
| CFGMatchSwitch<State, Result> 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<CFGInitializer>().getInitializer(), |
| Context, S); |
| case CFGElement::Statement: |
| case CFGElement::Constructor: |
| case CFGElement::CXXRecordTypedCall: |
| return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); |
| default: |
| // FIXME: Handle other kinds of CFGElement. |
| return Result(); |
| } |
| }; |
| } |
| |
| private: |
| ASTMatchSwitchBuilder<Stmt, State, Result> StmtBuilder; |
| ASTMatchSwitchBuilder<CXXCtorInitializer, State, Result> InitBuilder; |
| }; |
| |
| } // namespace dataflow |
| } // namespace clang |
| |
| #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ |