1 //===---- CFGMatchSwitch.h --------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the `CFGMatchSwitch` abstraction for building a "switch" 10 // statement for control flow graph elements. Each case of the switch is 11 // defined by an ASTMatcher which is applied on the AST node contained in the 12 // input `CFGElement`. 13 // 14 // Currently, the `CFGMatchSwitch` only handles `CFGElement`s of 15 // `Kind::Statement` and `Kind::Initializer`. 16 // 17 //===----------------------------------------------------------------------===// 18 19 #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ 20 #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ 21 22 #include "clang/AST/ASTContext.h" 23 #include "clang/AST/Stmt.h" 24 #include "clang/Analysis/CFG.h" 25 #include "clang/Analysis/FlowSensitive/MatchSwitch.h" 26 #include <functional> 27 #include <utility> 28 29 namespace clang { 30 namespace dataflow { 31 32 template <typename State, typename Result = void> 33 using CFGMatchSwitch = 34 std::function<Result(const CFGElement &, ASTContext &, State &)>; 35 36 /// Collects cases of a "match switch": a collection of matchers paired with 37 /// callbacks, which together define a switch that can be applied to an AST node 38 /// contained in a CFG element. 39 template <typename State, typename Result = void> class CFGMatchSwitchBuilder { 40 public: 41 /// Registers an action `A` for `CFGStmt`s that will be triggered by the match 42 /// of the pattern `M` against the `Stmt` contained in the input `CFGStmt`. 43 /// 44 /// Requirements: 45 /// 46 /// `NodeT` should be derived from `Stmt`. 47 template <typename NodeT> 48 CFGMatchSwitchBuilder && CaseOfCFGStmt(MatchSwitchMatcher<Stmt> M,MatchSwitchAction<NodeT,State,Result> A)49 CaseOfCFGStmt(MatchSwitchMatcher<Stmt> M, 50 MatchSwitchAction<NodeT, State, Result> A) && { 51 std::move(StmtBuilder).template CaseOf<NodeT>(M, A); 52 return std::move(*this); 53 } 54 55 /// Registers an action `A` for `CFGInitializer`s that will be triggered by 56 /// the match of the pattern `M` against the `CXXCtorInitializer` contained in 57 /// the input `CFGInitializer`. 58 /// 59 /// Requirements: 60 /// 61 /// `NodeT` should be derived from `CXXCtorInitializer`. 62 template <typename NodeT> 63 CFGMatchSwitchBuilder && CaseOfCFGInit(MatchSwitchMatcher<CXXCtorInitializer> M,MatchSwitchAction<NodeT,State,Result> A)64 CaseOfCFGInit(MatchSwitchMatcher<CXXCtorInitializer> M, 65 MatchSwitchAction<NodeT, State, Result> A) && { 66 std::move(InitBuilder).template CaseOf<NodeT>(M, A); 67 return std::move(*this); 68 } 69 Build()70 CFGMatchSwitch<State, Result> Build() && { 71 return [StmtMS = std::move(StmtBuilder).Build(), 72 InitMS = std::move(InitBuilder).Build()](const CFGElement &Element, 73 ASTContext &Context, 74 State &S) -> Result { 75 switch (Element.getKind()) { 76 case CFGElement::Initializer: 77 return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), 78 Context, S); 79 case CFGElement::Statement: 80 case CFGElement::Constructor: 81 case CFGElement::CXXRecordTypedCall: 82 return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); 83 default: 84 // FIXME: Handle other kinds of CFGElement. 85 return Result(); 86 } 87 }; 88 } 89 90 private: 91 ASTMatchSwitchBuilder<Stmt, State, Result> StmtBuilder; 92 ASTMatchSwitchBuilder<CXXCtorInitializer, State, Result> InitBuilder; 93 }; 94 95 } // namespace dataflow 96 } // namespace clang 97 98 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ 99