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 29namespace clang { 30namespace dataflow { 31 32template <typename State, typename Result = void> 33using 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. 39template <typename State, typename Result = void> class CFGMatchSwitchBuilder { 40public: 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 && 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 && 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 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 90private: 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