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