Coverage Report

Created: 2022-07-16 07:03

/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/AST/Decl.h"
17
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19
#include "llvm/ADT/ArrayRef.h"
20
#include "llvm/ADT/Optional.h"
21
#include <iterator>
22
23
using namespace llvm;
24
using namespace clang;
25
26
using MaybeCount = Optional<unsigned>;
27
28
// A constructor helper.
29
static MaybeCount readRequiredParams(MaybeCount RequiredArgs,
30
918k
                                     MaybeCount RequiredParams) {
31
918k
  if (RequiredParams)
32
56.0k
    return RequiredParams;
33
862k
  if (RequiredArgs)
34
856k
    return RequiredArgs;
35
5.67k
  return None;
36
862k
}
37
38
ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
39
                                       ArrayRef<const char *> QualifiedName,
40
                                       MaybeCount RequiredArgs /*= None*/,
41
                                       MaybeCount RequiredParams /*= None*/)
42
    : RequiredArgs(RequiredArgs),
43
      RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
44
918k
      Flags(Flags) {
45
918k
  assert(!QualifiedName.empty());
46
0
  this->QualifiedName.reserve(QualifiedName.size());
47
918k
  llvm::copy(QualifiedName, std::back_inserter(this->QualifiedName));
48
918k
}
49
50
/// Construct a CallDescription with default flags.
51
ento::CallDescription::CallDescription(ArrayRef<const char *> QualifiedName,
52
                                       MaybeCount RequiredArgs /*= None*/,
53
                                       MaybeCount RequiredParams /*= None*/)
54
910k
    : 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
54
910k
    : CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
55
56
2.37M
bool ento::CallDescription::matches(const CallEvent &Call) const {
57
  // FIXME: Add ObjC Message support.
58
2.37M
  if (Call.getKind() == CE_ObjCMessage)
59
3.12k
    return false;
60
61
2.37M
  const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
62
2.37M
  if (!FD)
63
520
    return false;
64
65
2.37M
  return matchesImpl(FD, Call.getNumArgs(), Call.parameters().size());
66
2.37M
}
67
68
379
bool ento::CallDescription::matchesAsWritten(const CallExpr &CE) const {
69
379
  const auto *FD = dyn_cast_or_null<FunctionDecl>(CE.getCalleeDecl());
70
379
  if (!FD)
71
11
    return false;
72
73
368
  return matchesImpl(FD, CE.getNumArgs(), FD->param_size());
74
379
}
75
76
bool ento::CallDescription::matchesImpl(const FunctionDecl *Callee,
77
                                        size_t ArgCount,
78
2.37M
                                        size_t ParamCount) const {
79
2.37M
  const auto *FD = Callee;
80
2.37M
  if (!FD)
81
0
    return false;
82
83
2.37M
  if (Flags & CDF_MaybeBuiltin) {
84
603k
    return CheckerContext::isCLibraryFunction(FD, getFunctionName()) &&
85
603k
           
(2.54k
!RequiredArgs2.54k
||
*RequiredArgs <= ArgCount2.20k
) &&
86
603k
           
(2.53k
!RequiredParams2.53k
||
*RequiredParams <= ParamCount2.19k
);
87
603k
  }
88
89
1.77M
  if (!II) {
90
12.9k
    II = &FD->getASTContext().Idents.get(getFunctionName());
91
12.9k
  }
92
93
1.77M
  const auto MatchNameOnly = [](const CallDescription &CD,
94
1.77M
                                const NamedDecl *ND) -> bool {
95
931k
    DeclarationName Name = ND->getDeclName();
96
931k
    if (const auto *II = Name.getAsIdentifierInfo())
97
773k
      return II == *CD.II; // Fast case.
98
99
    // Fallback to the slow stringification and comparison for:
100
    // C++ overloaded operators, constructors, destructors, etc.
101
    // FIXME This comparison is way SLOWER than comparing pointers.
102
    // At some point in the future, we should compare FunctionDecl pointers.
103
158k
    return Name.getAsString() == CD.getFunctionName();
104
931k
  };
105
106
1.77M
  const auto ExactMatchArgAndParamCounts =
107
1.77M
      [](size_t ArgCount, size_t ParamCount,
108
1.77M
         const CallDescription &CD) -> bool {
109
1.77M
    const bool ArgsMatch = !CD.RequiredArgs || 
*CD.RequiredArgs == ArgCount1.37M
;
110
1.77M
    const bool ParamsMatch =
111
1.77M
        !CD.RequiredParams || 
*CD.RequiredParams == ParamCount1.37M
;
112
1.77M
    return ArgsMatch && 
ParamsMatch932k
;
113
1.77M
  };
114
115
1.77M
  const auto MatchQualifiedNameParts = [](const CallDescription &CD,
116
1.77M
                                          const Decl *D) -> bool {
117
2.74k
    const auto FindNextNamespaceOrRecord =
118
5.95k
        [](const DeclContext *Ctx) -> const DeclContext * {
119
8.69k
      while (Ctx && 
!isa<NamespaceDecl, RecordDecl>(Ctx)5.95k
)
120
2.73k
        Ctx = Ctx->getParent();
121
5.95k
      return Ctx;
122
5.95k
    };
123
124
2.74k
    auto QualifierPartsIt = CD.begin_qualified_name_parts();
125
2.74k
    const auto QualifierPartsEndIt = CD.end_qualified_name_parts();
126
127
    // Match namespace and record names. Skip unrelated names if they don't
128
    // match.
129
2.74k
    const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext());
130
5.95k
    for (; Ctx && 
QualifierPartsIt != QualifierPartsEndIt3.22k
;
131
3.21k
         Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) {
132
      // If not matched just continue and try matching for the next one.
133
3.21k
      if (cast<NamedDecl>(Ctx)->getName() != *QualifierPartsIt)
134
779
        continue;
135
2.43k
      ++QualifierPartsIt;
136
2.43k
    }
137
138
    // We matched if we consumed all expected qualifier segments.
139
2.74k
    return QualifierPartsIt == QualifierPartsEndIt;
140
2.74k
  };
141
142
  // Let's start matching...
143
1.77M
  if (!ExactMatchArgAndParamCounts(ArgCount, ParamCount, *this))
144
842k
    return false;
145
146
931k
  if (!MatchNameOnly(*this, FD))
147
918k
    return false;
148
149
12.8k
  if (!hasQualifiedNameParts())
150
10.1k
    return true;
151
152
2.74k
  return MatchQualifiedNameParts(*this, FD);
153
12.8k
}
154
155
ento::CallDescriptionSet::CallDescriptionSet(
156
112
    std::initializer_list<CallDescription> &&List) {
157
112
  Impl.LinearMap.reserve(List.size());
158
112
  for (const CallDescription &CD : List)
159
495
    Impl.LinearMap.push_back({CD, /*unused*/ true});
160
112
}
161
162
1.63k
bool ento::CallDescriptionSet::contains(const CallEvent &Call) const {
163
1.63k
  return static_cast<bool>(Impl.lookup(Call));
164
1.63k
}
165
166
2
bool ento::CallDescriptionSet::containsAsWritten(const CallExpr &CE) const {
167
2
  return static_cast<bool>(Impl.lookupAsWritten(CE));
168
2
}