Coverage Report

Created: 2023-05-31 04:38

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