//===---- 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 #include namespace clang { namespace dataflow { template using CFGMatchSwitch = std::function; /// 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 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 CFGMatchSwitchBuilder && CaseOfCFGStmt(MatchSwitchMatcher M, MatchSwitchAction A) && { std::move(StmtBuilder).template CaseOf(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 CFGMatchSwitchBuilder && CaseOfCFGInit(MatchSwitchMatcher M, MatchSwitchAction A) && { std::move(InitBuilder).template CaseOf(M, A); return std::move(*this); } CFGMatchSwitch 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().getInitializer(), Context, S); case CFGElement::Statement: case CFGElement::Constructor: case CFGElement::CXXRecordTypedCall: return StmtMS(*Element.castAs().getStmt(), Context, S); default: // FIXME: Handle other kinds of CFGElement. return Result(); } }; } private: ASTMatchSwitchBuilder StmtBuilder; ASTMatchSwitchBuilder InitBuilder; }; } // namespace dataflow } // namespace clang #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_