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 &&
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 
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