Coverage Report

Created: 2022-07-16 07:03

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