Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- CallDescription.cpp - function/method call matching     --*- 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
/// \file This file defines a generic mechanism for matching for function and
10
/// method calls of C, C++, and Objective-C languages. Instances of these
11
/// classes are frequently used together with the CallEvent classes.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
16
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18
#include "llvm/ADT/ArrayRef.h"
19
#include "llvm/ADT/Optional.h"
20
#include <iterator>
21
22
using namespace llvm;
23
using namespace clang;
24
25
using MaybeCount = Optional<unsigned>;
26
27
// A constructor helper.
28
static MaybeCount readRequiredParams(MaybeCount RequiredArgs,
29
871k
                                     MaybeCount RequiredParams) {
30
871k
  if (RequiredParams)
31
53.1k
    return RequiredParams;
32
818k
  if (RequiredArgs)
33
816k
    return RequiredArgs;
34
2.14k
  return None;
35
818k
}
36
37
ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
38
                                       ArrayRef<const char *> QualifiedName,
39
                                       MaybeCount RequiredArgs /*= None*/,
40
                                       MaybeCount RequiredParams /*= None*/)
41
    : RequiredArgs(RequiredArgs),
42
      RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
43
871k
      Flags(Flags) {
44
871k
  assert(!QualifiedName.empty());
45
0
  this->QualifiedName.reserve(QualifiedName.size());
46
871k
  llvm::copy(QualifiedName, std::back_inserter(this->QualifiedName));
47
871k
}
48
49
/// Construct a CallDescription with default flags.
50
ento::CallDescription::CallDescription(ArrayRef<const char *> QualifiedName,
51
                                       MaybeCount RequiredArgs /*= None*/,
52
                                       MaybeCount RequiredParams /*= None*/)
53
864k
    : CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
Unexecuted instantiation: clang::ento::CallDescription::CallDescription(llvm::ArrayRef<char const*>, llvm::Optional<unsigned int>, llvm::Optional<unsigned int>)
clang::ento::CallDescription::CallDescription(llvm::ArrayRef<char const*>, llvm::Optional<unsigned int>, llvm::Optional<unsigned int>)
Line
Count
Source
53
864k
    : CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
54
55
2.13M
bool ento::CallDescription::matches(const CallEvent &Call) const {
56
  // FIXME: Add ObjC Message support.
57
2.13M
  if (Call.getKind() == CE_ObjCMessage)
58
3.12k
    return false;
59
60
2.13M
  const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
61
2.13M
  if (!FD)
62
403
    return false;
63
64
2.13M
  if (Flags & CDF_MaybeBuiltin) {
65
573k
    return CheckerContext::isCLibraryFunction(FD, getFunctionName()) &&
66
573k
           
(2.19k
!RequiredArgs2.19k
||
*RequiredArgs <= Call.getNumArgs()2.19k
) &&
67
573k
           
(2.18k
!RequiredParams2.18k
||
*RequiredParams <= Call.parameters().size()2.18k
);
68
573k
  }
69
70
1.55M
  if (!II.hasValue()) {
71
10.0k
    II = &Call.getState()->getStateManager().getContext().Idents.get(
72
10.0k
        getFunctionName());
73
10.0k
  }
74
75
1.55M
  const auto MatchNameOnly = [](const CallDescription &CD,
76
1.55M
                                const NamedDecl *ND) -> bool {
77
718k
    DeclarationName Name = ND->getDeclName();
78
718k
    if (const auto *II = Name.getAsIdentifierInfo())
79
560k
      return II == CD.II.getValue(); // Fast case.
80
81
    // Fallback to the slow stringification and comparison for:
82
    // C++ overloaded operators, constructors, destructors, etc.
83
    // FIXME This comparison is way SLOWER than comparing pointers.
84
    // At some point in the future, we should compare FunctionDecl pointers.
85
157k
    return Name.getAsString() == CD.getFunctionName();
86
718k
  };
87
88
1.55M
  const auto ExactMatchArgAndParamCounts =
89
1.55M
      [](const CallEvent &Call, const CallDescription &CD) -> bool {
90
1.55M
    const bool ArgsMatch =
91
1.55M
        !CD.RequiredArgs || 
*CD.RequiredArgs == Call.getNumArgs()1.36M
;
92
1.55M
    const bool ParamsMatch =
93
1.55M
        !CD.RequiredParams || 
*CD.RequiredParams == Call.parameters().size()1.36M
;
94
1.55M
    return ArgsMatch && 
ParamsMatch720k
;
95
1.55M
  };
96
97
1.55M
  const auto MatchQualifiedNameParts = [](const CallDescription &CD,
98
1.55M
                                          const Decl *D) -> bool {
99
2.45k
    const auto FindNextNamespaceOrRecord =
100
5.35k
        [](const DeclContext *Ctx) -> const DeclContext * {
101
7.79k
      while (Ctx && 
!isa<NamespaceDecl, RecordDecl>(Ctx)5.35k
)
102
2.44k
        Ctx = Ctx->getParent();
103
5.35k
      return Ctx;
104
5.35k
    };
105
106
2.45k
    auto QualifierPartsIt = CD.begin_qualified_name_parts();
107
2.45k
    const auto QualifierPartsEndIt = CD.end_qualified_name_parts();
108
109
    // Match namespace and record names. Skip unrelated names if they don't
110
    // match.
111
2.45k
    const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext());
112
5.35k
    for (; Ctx && 
QualifierPartsIt != QualifierPartsEndIt2.90k
;
113
2.89k
         Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) {
114
      // If not matched just continue and try matching for the next one.
115
2.89k
      if (cast<NamedDecl>(Ctx)->getName() != *QualifierPartsIt)
116
734
        continue;
117
2.16k
      ++QualifierPartsIt;
118
2.16k
    }
119
120
    // We matched if we consumed all expected qualifier segments.
121
2.45k
    return QualifierPartsIt == QualifierPartsEndIt;
122
2.45k
  };
123
124
  // Let's start matching...
125
1.55M
  if (!ExactMatchArgAndParamCounts(Call, *this))
126
839k
    return false;
127
128
718k
  if (!MatchNameOnly(*this, FD))
129
707k
    return false;
130
131
11.1k
  if (!hasQualifiedNameParts())
132
8.69k
    return true;
133
134
2.45k
  return MatchQualifiedNameParts(*this, FD);
135
11.1k
}
136
137
ento::CallDescriptionSet::CallDescriptionSet(
138
57
    std::initializer_list<CallDescription> &&List) {
139
57
  Impl.LinearMap.reserve(List.size());
140
57
  for (const CallDescription &CD : List)
141
228
    Impl.LinearMap.push_back({CD, /*unused*/ true});
142
57
}
143
144
1.12k
bool ento::CallDescriptionSet::contains(const CallEvent &Call) const {
145
1.12k
  return static_cast<bool>(Impl.lookup(Call));
146
1.12k
}