/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ |
21 | | #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ |
22 | | |
23 | | #include "clang/AST/ASTContext.h" |
24 | | #include "clang/AST/Stmt.h" |
25 | | #include "clang/ASTMatchers/ASTMatchFinder.h" |
26 | | #include "clang/ASTMatchers/ASTMatchers.h" |
27 | | #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" |
28 | | #include "llvm/ADT/StringRef.h" |
29 | | #include <functional> |
30 | | #include <string> |
31 | | #include <utility> |
32 | | #include <vector> |
33 | | |
34 | | namespace clang { |
35 | | namespace dataflow { |
36 | | |
37 | | /// A common form of state shared between the cases of a transfer function. |
38 | | template <typename LatticeT> struct TransferState { |
39 | | TransferState(LatticeT &Lattice, Environment &Env) |
40 | 6.91k | : Lattice(Lattice), Env(Env) {} |
41 | | |
42 | | /// Current lattice element. |
43 | | LatticeT &Lattice; |
44 | | Environment &Env; |
45 | | }; |
46 | | |
47 | | /// Matches against `Stmt` and, based on its structure, dispatches to an |
48 | | /// appropriate handler. |
49 | | template <typename State, typename Result = void> |
50 | | using MatchSwitch = std::function<Result(const Stmt &, ASTContext &, State &)>; |
51 | | |
52 | | /// Collects cases of a "match switch": a collection of matchers paired with |
53 | | /// callbacks, which together define a switch that can be applied to a |
54 | | /// `Stmt`. This structure can simplify the definition of `transfer` functions |
55 | | /// that rely on pattern-matching. |
56 | | /// |
57 | | /// For example, consider an analysis that handles particular function calls. It |
58 | | /// can define the `MatchSwitch` once, in the constructor of the analysis, and |
59 | | /// then reuse it each time that `transfer` is called, with a fresh state value. |
60 | | /// |
61 | | /// \code |
62 | | /// MatchSwitch<TransferState<MyLattice> BuildSwitch() { |
63 | | /// return MatchSwitchBuilder<TransferState<MyLattice>>() |
64 | | /// .CaseOf(callExpr(callee(functionDecl(hasName("foo")))), TransferFooCall) |
65 | | /// .CaseOf(callExpr(argumentCountIs(2), |
66 | | /// callee(functionDecl(hasName("bar")))), |
67 | | /// TransferBarCall) |
68 | | /// .Build(); |
69 | | /// } |
70 | | /// \endcode |
71 | | template <typename State, typename Result = void> class MatchSwitchBuilder { |
72 | | public: |
73 | | /// Registers an action that will be triggered by the match of a pattern |
74 | | /// against the input statement. |
75 | | /// |
76 | | /// Requirements: |
77 | | /// |
78 | | /// `Node` should be a subclass of `Stmt`. |
79 | | template <typename Node> |
80 | | MatchSwitchBuilder && |
81 | | CaseOf(ast_matchers::internal::Matcher<Stmt> M, |
82 | | std::function<Result(const Node *, |
83 | | const ast_matchers::MatchFinder::MatchResult &, |
84 | | State &)> |
85 | 4.86k | A) && { |
86 | 4.86k | Matchers.push_back(std::move(M)); |
87 | 4.86k | Actions.push_back( |
88 | 4.86k | [A = std::move(A)](const Stmt *Stmt, |
89 | 4.86k | const ast_matchers::MatchFinder::MatchResult &R, |
90 | 4.86k | State &S) { return A(cast<Node>(Stmt), R, S); }2.77k ); clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::Expr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::Expr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) &&::'lambda'(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)::operator()(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&) const Line | Count | Source | 90 | 1.02k | State &S) { return A(cast<Node>(Stmt), R, S); }); |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) &&::'lambda'(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)::operator()(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&) const Line | Count | Source | 90 | 396 | State &S) { return A(cast<Node>(Stmt), R, S); }); |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CXXConstructExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CXXConstructExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) &&::'lambda'(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)::operator()(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&) const Line | Count | Source | 90 | 264 | State &S) { return A(cast<Node>(Stmt), R, S); }); |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CXXOperatorCallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CXXOperatorCallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) &&::'lambda'(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)::operator()(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&) const Line | Count | Source | 90 | 66 | State &S) { return A(cast<Node>(Stmt), R, S); }); |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CXXMemberCallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CXXMemberCallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) &&::'lambda'(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)::operator()(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&) const Line | Count | Source | 90 | 723 | State &S) { return A(cast<Node>(Stmt), R, S); }); |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::CaseOf<clang::CXXMemberCallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > (clang::CXXMemberCallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&)>) &&::'lambda'(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&)::operator()(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&) const Line | Count | Source | 90 | 258 | State &S) { return A(cast<Node>(Stmt), R, S); }); |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::CaseOf<clang::CallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > (clang::CallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&)>) &&::'lambda'(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&)::operator()(clang::Stmt const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&) const Line | Count | Source | 90 | 48 | State &S) { return A(cast<Node>(Stmt), R, S); }); |
|
91 | 4.86k | return std::move(*this); |
92 | 4.86k | } clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::Expr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::Expr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) && Line | Count | Source | 85 | 729 | A) && { | 86 | 729 | Matchers.push_back(std::move(M)); | 87 | 729 | Actions.push_back( | 88 | 729 | [A = std::move(A)](const Stmt *Stmt, | 89 | 729 | const ast_matchers::MatchFinder::MatchResult &R, | 90 | 729 | State &S) { return A(cast<Node>(Stmt), R, S); }); | 91 | 729 | return std::move(*this); | 92 | 729 | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) && Line | Count | Source | 85 | 972 | A) && { | 86 | 972 | Matchers.push_back(std::move(M)); | 87 | 972 | Actions.push_back( | 88 | 972 | [A = std::move(A)](const Stmt *Stmt, | 89 | 972 | const ast_matchers::MatchFinder::MatchResult &R, | 90 | 972 | State &S) { return A(cast<Node>(Stmt), R, S); }); | 91 | 972 | return std::move(*this); | 92 | 972 | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CXXConstructExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CXXConstructExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) && Line | Count | Source | 85 | 729 | A) && { | 86 | 729 | Matchers.push_back(std::move(M)); | 87 | 729 | Actions.push_back( | 88 | 729 | [A = std::move(A)](const Stmt *Stmt, | 89 | 729 | const ast_matchers::MatchFinder::MatchResult &R, | 90 | 729 | State &S) { return A(cast<Node>(Stmt), R, S); }); | 91 | 729 | return std::move(*this); | 92 | 729 | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CXXOperatorCallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CXXOperatorCallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) && Line | Count | Source | 85 | 486 | A) && { | 86 | 486 | Matchers.push_back(std::move(M)); | 87 | 486 | Actions.push_back( | 88 | 486 | [A = std::move(A)](const Stmt *Stmt, | 89 | 486 | const ast_matchers::MatchFinder::MatchResult &R, | 90 | 486 | State &S) { return A(cast<Node>(Stmt), R, S); }); | 91 | 486 | return std::move(*this); | 92 | 486 | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOf<clang::CXXMemberCallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<void (clang::CXXMemberCallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)>) && Line | Count | Source | 85 | 1.45k | A) && { | 86 | 1.45k | Matchers.push_back(std::move(M)); | 87 | 1.45k | Actions.push_back( | 88 | 1.45k | [A = std::move(A)](const Stmt *Stmt, | 89 | 1.45k | const ast_matchers::MatchFinder::MatchResult &R, | 90 | 1.45k | State &S) { return A(cast<Node>(Stmt), R, S); }); | 91 | 1.45k | return std::move(*this); | 92 | 1.45k | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::CaseOf<clang::CXXMemberCallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > (clang::CXXMemberCallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&)>) && Line | Count | Source | 85 | 243 | A) && { | 86 | 243 | Matchers.push_back(std::move(M)); | 87 | 243 | Actions.push_back( | 88 | 243 | [A = std::move(A)](const Stmt *Stmt, | 89 | 243 | const ast_matchers::MatchFinder::MatchResult &R, | 90 | 243 | State &S) { return A(cast<Node>(Stmt), R, S); }); | 91 | 243 | return std::move(*this); | 92 | 243 | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >&& clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::CaseOf<clang::CallExpr>(clang::ast_matchers::internal::Matcher<clang::Stmt>, std::__1::function<std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > (clang::CallExpr const*, clang::ast_matchers::MatchFinder::MatchResult const&, clang::dataflow::Environment const&)>) && Line | Count | Source | 85 | 243 | A) && { | 86 | 243 | Matchers.push_back(std::move(M)); | 87 | 243 | Actions.push_back( | 88 | 243 | [A = std::move(A)](const Stmt *Stmt, | 89 | 243 | const ast_matchers::MatchFinder::MatchResult &R, | 90 | 243 | State &S) { return A(cast<Node>(Stmt), R, S); }); | 91 | 243 | return std::move(*this); | 92 | 243 | } |
|
93 | | |
94 | 486 | MatchSwitch<State, Result> Build() && { |
95 | 486 | return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( |
96 | 10.3k | const Stmt &Stmt, ASTContext &Context, State &S) -> Result { |
97 | 10.3k | auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); |
98 | 10.3k | if (Results.empty()) |
99 | 7.52k | return Result(); |
100 | | // Look through the map for the first binding of the form "TagN..." use |
101 | | // that to select the action. |
102 | 5.55k | for (const auto &Element : Results[0].getMap())2.77k { |
103 | 5.55k | llvm::StringRef ID(Element.first); |
104 | 5.55k | size_t Index = 0; |
105 | 5.55k | if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index)2.77k && |
106 | 5.55k | Index < Actions.size()2.77k ) { |
107 | 2.77k | return Actions[Index]( |
108 | 2.77k | &Stmt, |
109 | 2.77k | ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); |
110 | 2.77k | } |
111 | 5.55k | } |
112 | 0 | return Result(); |
113 | 2.77k | }; clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::Build() &&::'lambda'(clang::Stmt const&, clang::ASTContext&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)::operator()(clang::Stmt const&, clang::ASTContext&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&) const Line | Count | Source | 96 | 6.91k | const Stmt &Stmt, ASTContext &Context, State &S) -> Result { | 97 | 6.91k | auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); | 98 | 6.91k | if (Results.empty()) | 99 | 4.44k | return Result(); | 100 | | // Look through the map for the first binding of the form "TagN..." use | 101 | | // that to select the action. | 102 | 4.94k | for (const auto &Element : Results[0].getMap())2.47k { | 103 | 4.94k | llvm::StringRef ID(Element.first); | 104 | 4.94k | size_t Index = 0; | 105 | 4.94k | if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index)2.47k && | 106 | 4.94k | Index < Actions.size()2.47k ) { | 107 | 2.47k | return Actions[Index]( | 108 | 2.47k | &Stmt, | 109 | 2.47k | ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); | 110 | 2.47k | } | 111 | 4.94k | } | 112 | 0 | return Result(); | 113 | 2.47k | }; |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::Build() &&::'lambda'(clang::Stmt const&, clang::ASTContext&, clang::dataflow::Environment const&)::operator()(clang::Stmt const&, clang::ASTContext&, clang::dataflow::Environment const&) const Line | Count | Source | 96 | 3.39k | const Stmt &Stmt, ASTContext &Context, State &S) -> Result { | 97 | 3.39k | auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); | 98 | 3.39k | if (Results.empty()) | 99 | 3.08k | return Result(); | 100 | | // Look through the map for the first binding of the form "TagN..." use | 101 | | // that to select the action. | 102 | 612 | for (const auto &Element : Results[0].getMap())306 { | 103 | 612 | llvm::StringRef ID(Element.first); | 104 | 612 | size_t Index = 0; | 105 | 612 | if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index)306 && | 106 | 612 | Index < Actions.size()306 ) { | 107 | 306 | return Actions[Index]( | 108 | 306 | &Stmt, | 109 | 306 | ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); | 110 | 306 | } | 111 | 612 | } | 112 | 0 | return Result(); | 113 | 306 | }; |
|
114 | 486 | } clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::Build() && Line | Count | Source | 94 | 243 | MatchSwitch<State, Result> Build() && { | 95 | 243 | return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( | 96 | 243 | const Stmt &Stmt, ASTContext &Context, State &S) -> Result { | 97 | 243 | auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); | 98 | 243 | if (Results.empty()) | 99 | 243 | return Result(); | 100 | | // Look through the map for the first binding of the form "TagN..." use | 101 | | // that to select the action. | 102 | 243 | for (const auto &Element : Results[0].getMap()) { | 103 | 243 | llvm::StringRef ID(Element.first); | 104 | 243 | size_t Index = 0; | 105 | 243 | if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && | 106 | 243 | Index < Actions.size()) { | 107 | 243 | return Actions[Index]( | 108 | 243 | &Stmt, | 109 | 243 | ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); | 110 | 243 | } | 111 | 243 | } | 112 | 243 | return Result(); | 113 | 243 | }; | 114 | 243 | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::Build() && Line | Count | Source | 94 | 243 | MatchSwitch<State, Result> Build() && { | 95 | 243 | return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( | 96 | 243 | const Stmt &Stmt, ASTContext &Context, State &S) -> Result { | 97 | 243 | auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context); | 98 | 243 | if (Results.empty()) | 99 | 243 | return Result(); | 100 | | // Look through the map for the first binding of the form "TagN..." use | 101 | | // that to select the action. | 102 | 243 | for (const auto &Element : Results[0].getMap()) { | 103 | 243 | llvm::StringRef ID(Element.first); | 104 | 243 | size_t Index = 0; | 105 | 243 | if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && | 106 | 243 | Index < Actions.size()) { | 107 | 243 | return Actions[Index]( | 108 | 243 | &Stmt, | 109 | 243 | ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); | 110 | 243 | } | 111 | 243 | } | 112 | 243 | return Result(); | 113 | 243 | }; | 114 | 243 | } |
|
115 | | |
116 | | private: |
117 | 486 | ast_matchers::internal::DynTypedMatcher BuildMatcher() { |
118 | 486 | using ast_matchers::anything; |
119 | 486 | using ast_matchers::stmt; |
120 | 486 | using ast_matchers::unless; |
121 | 486 | using ast_matchers::internal::DynTypedMatcher; |
122 | 486 | if (Matchers.empty()) |
123 | 0 | return stmt(unless(anything())); |
124 | 5.34k | for (int I = 0, N = Matchers.size(); 486 I < N; ++I4.86k ) { |
125 | 4.86k | std::string Tag = ("Tag" + llvm::Twine(I)).str(); |
126 | | // Many matchers are not bindable, so ensure that tryBind will work. |
127 | 4.86k | Matchers[I].setAllowBind(true); |
128 | 4.86k | auto M = *Matchers[I].tryBind(Tag); |
129 | | // Each anyOf explicitly controls the traversal kind. The anyOf itself is |
130 | | // set to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to |
131 | | // the kind of the branches. Then, each branch is either left as is, if |
132 | | // the kind is already set, or explicitly set to `TK_AsIs`. We choose this |
133 | | // setting because it is the default interpretation of matchers. |
134 | 4.86k | Matchers[I] = |
135 | 4.86k | !M.getTraversalKind() ? M.withTraversalKind(TK_AsIs) : std::move(M)0 ; |
136 | 4.86k | } |
137 | | // The matcher type on the cases ensures that `Expr` kind is compatible with |
138 | | // all of the matchers. |
139 | 486 | return DynTypedMatcher::constructVariadic( |
140 | 486 | DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind<Stmt>(), |
141 | 486 | std::move(Matchers)); |
142 | 486 | } clang::dataflow::MatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::BuildMatcher() Line | Count | Source | 117 | 243 | ast_matchers::internal::DynTypedMatcher BuildMatcher() { | 118 | 243 | using ast_matchers::anything; | 119 | 243 | using ast_matchers::stmt; | 120 | 243 | using ast_matchers::unless; | 121 | 243 | using ast_matchers::internal::DynTypedMatcher; | 122 | 243 | if (Matchers.empty()) | 123 | 0 | return stmt(unless(anything())); | 124 | 4.61k | for (int I = 0, N = Matchers.size(); 243 I < N; ++I4.37k ) { | 125 | 4.37k | std::string Tag = ("Tag" + llvm::Twine(I)).str(); | 126 | | // Many matchers are not bindable, so ensure that tryBind will work. | 127 | 4.37k | Matchers[I].setAllowBind(true); | 128 | 4.37k | auto M = *Matchers[I].tryBind(Tag); | 129 | | // Each anyOf explicitly controls the traversal kind. The anyOf itself is | 130 | | // set to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to | 131 | | // the kind of the branches. Then, each branch is either left as is, if | 132 | | // the kind is already set, or explicitly set to `TK_AsIs`. We choose this | 133 | | // setting because it is the default interpretation of matchers. | 134 | 4.37k | Matchers[I] = | 135 | 4.37k | !M.getTraversalKind() ? M.withTraversalKind(TK_AsIs) : std::move(M)0 ; | 136 | 4.37k | } | 137 | | // The matcher type on the cases ensures that `Expr` kind is compatible with | 138 | | // all of the matchers. | 139 | 243 | return DynTypedMatcher::constructVariadic( | 140 | 243 | DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind<Stmt>(), | 141 | 243 | std::move(Matchers)); | 142 | 243 | } |
clang::dataflow::MatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::BuildMatcher() Line | Count | Source | 117 | 243 | ast_matchers::internal::DynTypedMatcher BuildMatcher() { | 118 | 243 | using ast_matchers::anything; | 119 | 243 | using ast_matchers::stmt; | 120 | 243 | using ast_matchers::unless; | 121 | 243 | using ast_matchers::internal::DynTypedMatcher; | 122 | 243 | if (Matchers.empty()) | 123 | 0 | return stmt(unless(anything())); | 124 | 729 | for (int I = 0, N = Matchers.size(); 243 I < N; ++I486 ) { | 125 | 486 | std::string Tag = ("Tag" + llvm::Twine(I)).str(); | 126 | | // Many matchers are not bindable, so ensure that tryBind will work. | 127 | 486 | Matchers[I].setAllowBind(true); | 128 | 486 | auto M = *Matchers[I].tryBind(Tag); | 129 | | // Each anyOf explicitly controls the traversal kind. The anyOf itself is | 130 | | // set to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to | 131 | | // the kind of the branches. Then, each branch is either left as is, if | 132 | | // the kind is already set, or explicitly set to `TK_AsIs`. We choose this | 133 | | // setting because it is the default interpretation of matchers. | 134 | 486 | Matchers[I] = | 135 | 486 | !M.getTraversalKind() ? M.withTraversalKind(TK_AsIs) : std::move(M)0 ; | 136 | 486 | } | 137 | | // The matcher type on the cases ensures that `Expr` kind is compatible with | 138 | | // all of the matchers. | 139 | 243 | return DynTypedMatcher::constructVariadic( | 140 | 243 | DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind<Stmt>(), | 141 | 243 | std::move(Matchers)); | 142 | 243 | } |
|
143 | | |
144 | | std::vector<ast_matchers::internal::DynTypedMatcher> Matchers; |
145 | | std::vector<std::function<Result( |
146 | | const Stmt *, const ast_matchers::MatchFinder::MatchResult &, State &)>> |
147 | | Actions; |
148 | | }; |
149 | | } // namespace dataflow |
150 | | } // namespace clang |
151 | | #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ |