clang 17.0.0git
MatchSwitch.h
Go to the documentation of this file.
1//===---- MatchSwitch.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 `MatchSwitch` abstraction for building a "switch"
10// statement, where each case of the switch is defined by an AST matcher. The
11// cases are considered in order, like pattern matching in functional
12// languages.
13//
14// Currently, the design is catered towards simplifying the implementation of
15// `DataflowAnalysis` transfer functions. Based on experience here, this
16// library may be generalized and moved to ASTMatchers.
17//
18//===----------------------------------------------------------------------===//
19//
20// FIXME: Rename to ASTMatchSwitch.h and update documentation when all usages of
21// `MatchSwitch` are updated to `ASTMatchSwitch<Stmt>`
22
23#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
24#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
25
27#include "clang/AST/Stmt.h"
31#include "llvm/ADT/StringRef.h"
32#include <functional>
33#include <string>
34#include <type_traits>
35#include <utility>
36#include <vector>
37
38namespace clang {
39namespace dataflow {
40
41/// A common form of state shared between the cases of a transfer function.
42template <typename LatticeT> struct TransferState {
44 : Lattice(Lattice), Env(Env) {}
45
46 /// Current lattice element.
47 LatticeT &Lattice;
49};
50
51/// A read-only version of TransferState.
52template <typename LatticeT> struct TransferStateForDiagnostics {
54 : Lattice(Lattice), Env(Env) {}
55
56 /// Current lattice element.
57 const LatticeT &Lattice;
59};
60
61template <typename T>
62using MatchSwitchMatcher = ast_matchers::internal::Matcher<T>;
63
64template <typename T, typename State, typename Result = void>
65using MatchSwitchAction = std::function<Result(
66 const T *, const ast_matchers::MatchFinder::MatchResult &, State &)>;
67
68template <typename BaseT, typename State, typename Result = void>
70 std::function<Result(const BaseT &, ASTContext &, State &)>;
71
72// FIXME: Remove this alias when all usages of `MatchSwitch` are updated to
73// `ASTMatchSwitch<Stmt>`.
74template <typename State, typename Result = void>
76
77/// Collects cases of a "match switch": a collection of matchers paired with
78/// callbacks, which together define a switch that can be applied to a node
79/// whose type derives from `BaseT`. This structure can simplify the definition
80/// of `transfer` functions that rely on pattern-matching.
81///
82/// For example, consider an analysis that handles particular function calls. It
83/// can define the `ASTMatchSwitch` once, in the constructor of the analysis,
84/// and then reuse it each time that `transfer` is called, with a fresh state
85/// value.
86///
87/// \code
88/// ASTMatchSwitch<Stmt, TransferState<MyLattice> BuildSwitch() {
89/// return ASTMatchSwitchBuilder<TransferState<MyLattice>>()
90/// .CaseOf(callExpr(callee(functionDecl(hasName("foo")))), TransferFooCall)
91/// .CaseOf(callExpr(argumentCountIs(2),
92/// callee(functionDecl(hasName("bar")))),
93/// TransferBarCall)
94/// .Build();
95/// }
96/// \endcode
97template <typename BaseT, typename State, typename Result = void>
99public:
100 /// Registers an action that will be triggered by the match of a pattern
101 /// against the input statement.
102 ///
103 /// Requirements:
104 ///
105 /// `NodeT` should be derived from `BaseT`.
106 template <typename NodeT>
109 static_assert(std::is_base_of<BaseT, NodeT>::value,
110 "NodeT must be derived from BaseT.");
111 Matchers.push_back(std::move(M));
112 Actions.push_back(
113 [A = std::move(A)](const BaseT *Node,
115 State &S) { return A(cast<NodeT>(Node), R, S); });
116 return std::move(*this);
117 }
118
120 return [Matcher = BuildMatcher(), Actions = std::move(Actions)](
121 const BaseT &Node, ASTContext &Context, State &S) -> Result {
122 auto Results = ast_matchers::matchDynamic(Matcher, Node, Context);
123 if (Results.empty()) {
124 return Result();
125 }
126 // Look through the map for the first binding of the form "TagN..." use
127 // that to select the action.
128 for (const auto &Element : Results[0].getMap()) {
129 llvm::StringRef ID(Element.first);
130 size_t Index = 0;
131 if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) &&
132 Index < Actions.size()) {
133 return Actions[Index](
134 &Node,
135 ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S);
136 }
137 }
138 return Result();
139 };
140 }
141
142private:
143 ast_matchers::internal::DynTypedMatcher BuildMatcher() {
145 using ast_matchers::stmt;
147 using ast_matchers::internal::DynTypedMatcher;
148 if (Matchers.empty())
149 return stmt(unless(anything()));
150 for (int I = 0, N = Matchers.size(); I < N; ++I) {
151 std::string Tag = ("Tag" + llvm::Twine(I)).str();
152 // Many matchers are not bindable, so ensure that tryBind will work.
153 Matchers[I].setAllowBind(true);
154 auto M = *Matchers[I].tryBind(Tag);
155 // Each anyOf explicitly controls the traversal kind. The anyOf itself is
156 // set to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to
157 // the kind of the branches. Then, each branch is either left as is, if
158 // the kind is already set, or explicitly set to `TK_AsIs`. We choose this
159 // setting because it is the default interpretation of matchers.
160 Matchers[I] =
161 !M.getTraversalKind() ? M.withTraversalKind(TK_AsIs) : std::move(M);
162 }
163 // The matcher type on the cases ensures that `Expr` kind is compatible with
164 // all of the matchers.
165 return DynTypedMatcher::constructVariadic(
166 DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind<BaseT>(),
167 std::move(Matchers));
168 }
169
170 std::vector<ast_matchers::internal::DynTypedMatcher> Matchers;
171 std::vector<MatchSwitchAction<BaseT, State, Result>> Actions;
172};
173
174// FIXME: Remove this alias when all usages of `MatchSwitchBuilder` are updated
175// to `ASTMatchSwitchBuilder<Stmt>`.
176template <typename State, typename Result = void>
178
179} // namespace dataflow
180} // namespace clang
181#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
Defines the clang::ASTContext interface.
DynTypedNode Node
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
Collects cases of a "match switch": a collection of matchers paired with callbacks,...
Definition: MatchSwitch.h:98
ASTMatchSwitchBuilder && CaseOf(MatchSwitchMatcher< BaseT > M, MatchSwitchAction< NodeT, State, Result > A) &&
Registers an action that will be triggered by the match of a pattern against the input statement.
Definition: MatchSwitch.h:107
ASTMatchSwitch< BaseT, State, Result > Build() &&
Definition: MatchSwitch.h:119
Holds the state of the program (store and heap) at a given program point.
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
internal::TrueMatcher anything()
Matches any node.
Definition: ASTMatchers.h:170
SmallVector< BoundNodes, 1 > matchDynamic(internal::DynTypedMatcher Matcher, const DynTypedNode &Node, ASTContext &Context)
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
ASTMatchSwitch< Stmt, State, Result > MatchSwitch
Definition: MatchSwitch.h:75
std::function< Result(const T *, const ast_matchers::MatchFinder::MatchResult &, State &)> MatchSwitchAction
Definition: MatchSwitch.h:66
std::function< Result(const BaseT &, ASTContext &, State &)> ASTMatchSwitch
Definition: MatchSwitch.h:70
ast_matchers::internal::Matcher< T > MatchSwitchMatcher
Definition: MatchSwitch.h:62
@ TK_AsIs
Will traverse all child nodes.
Definition: ASTTypeTraits.h:40
@ Result
The result type of a method or function.
Contains all information for a given match.
A read-only version of TransferState.
Definition: MatchSwitch.h:52
const LatticeT & Lattice
Current lattice element.
Definition: MatchSwitch.h:57
TransferStateForDiagnostics(const LatticeT &Lattice, const Environment &Env)
Definition: MatchSwitch.h:53
A common form of state shared between the cases of a transfer function.
Definition: MatchSwitch.h:42
TransferState(LatticeT &Lattice, Environment &Env)
Definition: MatchSwitch.h:43
LatticeT & Lattice
Current lattice element.
Definition: MatchSwitch.h:47