//===---- 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_