/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h
Line | Count | Source (jump to first uncovered line) |
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 | | |
29 | | namespace clang { |
30 | | namespace dataflow { |
31 | | |
32 | | template <typename State, typename Result = void> |
33 | | using 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. |
39 | | template <typename State, typename Result = void> class CFGMatchSwitchBuilder { |
40 | | public: |
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 | 9.13k | MatchSwitchAction<NodeT, State, Result> A) && { |
51 | 9.13k | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); |
52 | 9.13k | return std::move(*this); |
53 | 9.13k | } clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOfCFGStmt<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 | 50 | 1.06k | MatchSwitchAction<NodeT, State, Result> A) && { | 51 | 1.06k | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | 52 | 1.06k | return std::move(*this); | 53 | 1.06k | } |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOfCFGStmt<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 | 50 | 2.10k | MatchSwitchAction<NodeT, State, Result> A) && { | 51 | 2.10k | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | 52 | 2.10k | return std::move(*this); | 53 | 2.10k | } |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOfCFGStmt<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 | 50 | 1.40k | MatchSwitchAction<NodeT, State, Result> A) && { | 51 | 1.40k | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | 52 | 1.40k | return std::move(*this); | 53 | 1.40k | } |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOfCFGStmt<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 | 50 | 1.75k | MatchSwitchAction<NodeT, State, Result> A) && { | 51 | 1.75k | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | 52 | 1.75k | return std::move(*this); | 53 | 1.75k | } |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>&& clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::CaseOfCFGStmt<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 | 50 | 2.10k | MatchSwitchAction<NodeT, State, Result> A) && { | 51 | 2.10k | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | 52 | 2.10k | return std::move(*this); | 53 | 2.10k | } |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >&& clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::CaseOfCFGStmt<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 | 50 | 351 | MatchSwitchAction<NodeT, State, Result> A) && { | 51 | 351 | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | 52 | 351 | return std::move(*this); | 53 | 351 | } |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >&& clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::CaseOfCFGStmt<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 | 50 | 351 | MatchSwitchAction<NodeT, State, Result> A) && { | 51 | 351 | std::move(StmtBuilder).template CaseOf<NodeT>(M, A); | 52 | 351 | return std::move(*this); | 53 | 351 | } |
|
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 | 714 | CFGMatchSwitch<State, Result> Build() && { |
71 | 714 | return [StmtMS = std::move(StmtBuilder).Build(), |
72 | 714 | InitMS = std::move(InitBuilder).Build()](const CFGElement &Element, |
73 | 714 | ASTContext &Context, |
74 | 18.0k | State &S) -> Result { |
75 | 18.0k | switch (Element.getKind()) { |
76 | 18 | case CFGElement::Initializer: |
77 | 18 | return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), |
78 | 18 | Context, S); |
79 | 17.9k | case CFGElement::Statement: |
80 | 17.9k | case CFGElement::Constructor: |
81 | 17.9k | case CFGElement::CXXRecordTypedCall: |
82 | 17.9k | return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); |
83 | 18 | default: |
84 | | // FIXME: Handle other kinds of CFGElement. |
85 | 18 | return Result(); |
86 | 18.0k | } |
87 | 18.0k | }; clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::Build() &&::'lambda'(clang::CFGElement const&, clang::ASTContext&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&)::operator()(clang::CFGElement const&, clang::ASTContext&, clang::dataflow::TransferState<clang::dataflow::NoopLattice>&) const Line | Count | Source | 74 | 12.3k | State &S) -> Result { | 75 | 12.3k | switch (Element.getKind()) { | 76 | 12 | case CFGElement::Initializer: | 77 | 12 | return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), | 78 | 12 | Context, S); | 79 | 12.3k | case CFGElement::Statement: | 80 | 12.3k | case CFGElement::Constructor: | 81 | 12.3k | case CFGElement::CXXRecordTypedCall: | 82 | 12.3k | return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); | 83 | 12 | default: | 84 | | // FIXME: Handle other kinds of CFGElement. | 85 | 12 | return Result(); | 86 | 12.3k | } | 87 | 12.3k | }; |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::Build() &&::'lambda'(clang::CFGElement const&, clang::ASTContext&, clang::dataflow::Environment const&)::operator()(clang::CFGElement const&, clang::ASTContext&, clang::dataflow::Environment const&) const Line | Count | Source | 74 | 5.67k | State &S) -> Result { | 75 | 5.67k | switch (Element.getKind()) { | 76 | 6 | case CFGElement::Initializer: | 77 | 6 | return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), | 78 | 6 | Context, S); | 79 | 5.66k | case CFGElement::Statement: | 80 | 5.66k | case CFGElement::Constructor: | 81 | 5.66k | case CFGElement::CXXRecordTypedCall: | 82 | 5.66k | return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); | 83 | 6 | default: | 84 | | // FIXME: Handle other kinds of CFGElement. | 85 | 6 | return Result(); | 86 | 5.67k | } | 87 | 5.67k | }; |
|
88 | 714 | } clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::TransferState<clang::dataflow::NoopLattice>, void>::Build() && Line | Count | Source | 70 | 363 | CFGMatchSwitch<State, Result> Build() && { | 71 | 363 | return [StmtMS = std::move(StmtBuilder).Build(), | 72 | 363 | InitMS = std::move(InitBuilder).Build()](const CFGElement &Element, | 73 | 363 | ASTContext &Context, | 74 | 363 | State &S) -> Result { | 75 | 363 | switch (Element.getKind()) { | 76 | 363 | case CFGElement::Initializer: | 77 | 363 | return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), | 78 | 363 | Context, S); | 79 | 363 | case CFGElement::Statement: | 80 | 363 | case CFGElement::Constructor: | 81 | 363 | case CFGElement::CXXRecordTypedCall: | 82 | 363 | return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); | 83 | 363 | default: | 84 | | // FIXME: Handle other kinds of CFGElement. | 85 | 363 | return Result(); | 86 | 363 | } | 87 | 363 | }; | 88 | 363 | } |
clang::dataflow::CFGMatchSwitchBuilder<clang::dataflow::Environment const, std::__1::vector<clang::SourceLocation, std::__1::allocator<clang::SourceLocation> > >::Build() && Line | Count | Source | 70 | 351 | CFGMatchSwitch<State, Result> Build() && { | 71 | 351 | return [StmtMS = std::move(StmtBuilder).Build(), | 72 | 351 | InitMS = std::move(InitBuilder).Build()](const CFGElement &Element, | 73 | 351 | ASTContext &Context, | 74 | 351 | State &S) -> Result { | 75 | 351 | switch (Element.getKind()) { | 76 | 351 | case CFGElement::Initializer: | 77 | 351 | return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), | 78 | 351 | Context, S); | 79 | 351 | case CFGElement::Statement: | 80 | 351 | case CFGElement::Constructor: | 81 | 351 | case CFGElement::CXXRecordTypedCall: | 82 | 351 | return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); | 83 | 351 | default: | 84 | | // FIXME: Handle other kinds of CFGElement. | 85 | 351 | return Result(); | 86 | 351 | } | 87 | 351 | }; | 88 | 351 | } |
|
89 | | |
90 | | private: |
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_ |