Coverage Report

Created: 2023-05-31 04:38

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- StandardLibrary.cpp ------------------------------------*- 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
#include "clang/Tooling/Inclusions/StandardLibrary.h"
10
#include "clang/AST/Decl.h"
11
#include "clang/Basic/LangOptions.h"
12
#include "llvm/ADT/ArrayRef.h"
13
#include "llvm/ADT/DenseSet.h"
14
#include "llvm/ADT/STLExtras.h"
15
#include "llvm/ADT/StringRef.h"
16
#include "llvm/Support/Casting.h"
17
#include <optional>
18
19
namespace clang {
20
namespace tooling {
21
namespace stdlib {
22
23
namespace {
24
// Symbol name -> Symbol::ID, within a namespace.
25
using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>;
26
27
// A Mapping per language.
28
struct SymbolHeaderMapping {
29
  llvm::StringRef *HeaderNames = nullptr;
30
  // Header name => Header::ID
31
  llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs;
32
33
  unsigned SymbolCount = 0;
34
  // Symbol::ID => symbol qualified_name/name/scope
35
  struct SymbolName {
36
    const char *Data;  // std::vector
37
    unsigned ScopeLen; // ~~~~~
38
    unsigned NameLen;  //      ~~~~~~
39
2
    StringRef scope() const { return StringRef(Data, ScopeLen); }
40
2
    StringRef name() const { return StringRef(Data + ScopeLen, NameLen); }
41
4.19M
    StringRef qualifiedName() const {
42
4.19M
      return StringRef(Data, ScopeLen + NameLen);
43
4.19M
    }
44
  } *SymbolNames = nullptr;
45
  // Symbol name -> Symbol::ID, within a namespace.
46
  llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols = nullptr;
47
  // Symbol::ID => Header::ID
48
  llvm::SmallVector<unsigned> *SymbolHeaderIDs = nullptr;
49
};
50
} // namespace
51
static SymbolHeaderMapping
52
    *LanguageMappings[static_cast<unsigned>(Lang::LastValue) + 1];
53
70
static const SymbolHeaderMapping *getMappingPerLang(Lang L) {
54
70
  return LanguageMappings[static_cast<unsigned>(L)];
55
70
}
56
57
8
static int countSymbols(Lang Language) {
58
8
  llvm::DenseSet<llvm::StringRef> Set;
59
20.6k
#define SYMBOL(Name, NS, Header) Set.insert(#NS #Name);
60
8
  switch (Language) {
61
4
  case Lang::C:
62
4
#include "CSymbolMap.inc"
63
4
    break;
64
4
  case Lang::CXX:
65
4
#include "StdSpecialSymbolMap.inc"
66
4
#include "StdSymbolMap.inc"
67
4
#include "StdTsSymbolMap.inc"
68
4
    break;
69
8
  }
70
8
#undef SYMBOL
71
8
  return Set.size();
72
8
}
73
74
8
static int initialize(Lang Language) {
75
8
  SymbolHeaderMapping *Mapping = new SymbolHeaderMapping();
76
8
  LanguageMappings[static_cast<unsigned>(Language)] = Mapping;
77
78
8
  unsigned SymCount = countSymbols(Language);
79
8
  Mapping->SymbolCount = SymCount;
80
8
  Mapping->SymbolNames =
81
8
      new std::remove_reference_t<decltype(*Mapping->SymbolNames)>[SymCount];
82
8
  Mapping->SymbolHeaderIDs = new std::remove_reference_t<
83
8
      decltype(*Mapping->SymbolHeaderIDs)>[SymCount];
84
8
  Mapping->NamespaceSymbols =
85
8
      new std::remove_reference_t<decltype(*Mapping->NamespaceSymbols)>;
86
8
  Mapping->HeaderIDs =
87
8
      new std::remove_reference_t<decltype(*Mapping->HeaderIDs)>;
88
20.6k
  auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & {
89
20.6k
    auto R = Mapping->NamespaceSymbols->try_emplace(NS, nullptr);
90
20.6k
    if (R.second)
91
52
      R.first->second = new NSSymbolMap();
92
20.6k
    return *R.first->second;
93
20.6k
  };
94
95
20.6k
  auto AddHeader = [&](llvm::StringRef Header) -> unsigned {
96
20.6k
    return Mapping->HeaderIDs->try_emplace(Header, Mapping->HeaderIDs->size())
97
20.6k
        .first->second;
98
20.6k
  };
99
100
8
  auto Add = [&, SymIndex(-1)](llvm::StringRef QName, unsigned NSLen,
101
20.6k
                               llvm::StringRef HeaderName) mutable {
102
    // Correct "Nonefoo" => foo.
103
    // FIXME: get rid of "None" from the generated mapping files.
104
20.6k
    if (QName.take_front(NSLen) == "None") {
105
9.95k
      QName = QName.drop_front(NSLen);
106
9.95k
      NSLen = 0;
107
9.95k
    }
108
109
20.6k
    if (SymIndex >= 0 &&
110
20.6k
        
Mapping->SymbolNames[SymIndex].qualifiedName() == QName20.6k
) {
111
      // Not a new symbol, use the same index.
112
4.22k
      assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex),
113
4.22k
                           [&QName](const SymbolHeaderMapping::SymbolName &S) {
114
4.22k
                             return S.qualifiedName() == QName;
115
4.22k
                           }) &&
116
4.22k
             "The symbol has been added before, make sure entries in the .inc "
117
4.22k
             "file are grouped by symbol name!");
118
16.3k
    } else {
119
      // First symbol or new symbol, increment next available index.
120
16.3k
      ++SymIndex;
121
16.3k
    }
122
20.6k
    Mapping->SymbolNames[SymIndex] = {
123
20.6k
        QName.data(), NSLen, static_cast<unsigned int>(QName.size() - NSLen)};
124
20.6k
    if (!HeaderName.empty())
125
20.6k
       Mapping->SymbolHeaderIDs[SymIndex].push_back(AddHeader(HeaderName));
126
127
20.6k
    NSSymbolMap &NSSymbols = AddNS(QName.take_front(NSLen));
128
20.6k
    NSSymbols.try_emplace(QName.drop_front(NSLen), SymIndex);
129
20.6k
  };
130
20.6k
#define SYMBOL(Name, NS, Header) Add(#NS #Name, strlen(#NS), #Header);
131
8
  switch (Language) {
132
4
  case Lang::C:
133
4
#include "CSymbolMap.inc"
134
4
    break;
135
4
  case Lang::CXX:
136
4
#include "StdSpecialSymbolMap.inc"
137
4
#include "StdSymbolMap.inc"
138
4
#include "StdTsSymbolMap.inc"
139
4
    break;
140
8
  }
141
8
#undef SYMBOL
142
143
8
  Mapping->HeaderNames = new llvm::StringRef[Mapping->HeaderIDs->size()];
144
8
  for (const auto &E : *Mapping->HeaderIDs)
145
596
    Mapping->HeaderNames[E.second] = E.first;
146
147
8
  return 0;
148
8
}
149
150
48
static void ensureInitialized() {
151
48
  static int Dummy = []() {
152
12
    for (unsigned L = 0; L <= static_cast<unsigned>(Lang::LastValue); 
++L8
)
153
8
      initialize(static_cast<Lang>(L));
154
4
    return 0;
155
4
  }();
156
48
  (void)Dummy;
157
48
}
158
159
1
std::vector<Header> Header::all(Lang L) {
160
1
  ensureInitialized();
161
1
  std::vector<Header> Result;
162
1
  const auto *Mapping = getMappingPerLang(L);
163
1
  Result.reserve(Mapping->HeaderIDs->size());
164
123
  for (unsigned I = 0, E = Mapping->HeaderIDs->size(); I < E; 
++I122
)
165
122
    Result.push_back(Header(I, L));
166
1
  return Result;
167
1
}
168
25
std::optional<Header> Header::named(llvm::StringRef Name, Lang L) {
169
25
  ensureInitialized();
170
25
  const auto *Mapping = getMappingPerLang(L);
171
25
  auto It = Mapping->HeaderIDs->find(Name);
172
25
  if (It == Mapping->HeaderIDs->end())
173
4
    return std::nullopt;
174
21
  return Header(It->second, L);
175
25
}
176
2
llvm::StringRef Header::name() const {
177
2
  return getMappingPerLang(Language)->HeaderNames[ID];
178
2
}
179
180
1
std::vector<Symbol> Symbol::all(Lang L) {
181
1
  ensureInitialized();
182
1
  std::vector<Symbol> Result;
183
1
  const auto *Mapping = getMappingPerLang(L);
184
1
  Result.reserve(Mapping->SymbolCount);
185
3.16k
  for (unsigned I = 0, E = Mapping->SymbolCount; I < E; 
++I3.16k
)
186
3.16k
    Result.push_back(Symbol(I, L));
187
1
  return Result;
188
1
}
189
2
llvm::StringRef Symbol::scope() const {
190
2
  return getMappingPerLang(Language)->SymbolNames[ID].scope();
191
2
}
192
2
llvm::StringRef Symbol::name() const {
193
2
  return getMappingPerLang(Language)->SymbolNames[ID].name();
194
2
}
195
3
llvm::StringRef Symbol::qualifiedName() const {
196
3
  return getMappingPerLang(Language)->SymbolNames[ID].qualifiedName();
197
3
}
198
std::optional<Symbol> Symbol::named(llvm::StringRef Scope, llvm::StringRef Name,
199
20
                                    Lang L) {
200
20
  ensureInitialized();
201
202
20
  if (NSSymbolMap *NSSymbols =
203
20
          getMappingPerLang(L)->NamespaceSymbols->lookup(Scope)) {
204
17
    auto It = NSSymbols->find(Name);
205
17
    if (It != NSSymbols->end())
206
16
      return Symbol(It->second, L);
207
17
  }
208
4
  return std::nullopt;
209
20
}
210
4
std::optional<Header> Symbol::header() const {
211
4
  const auto& Headers = getMappingPerLang(Language)->SymbolHeaderIDs[ID];
212
4
  if (Headers.empty())
213
1
    return std::nullopt;
214
3
  return Header(Headers.front(), Language);
215
4
}
216
6
llvm::SmallVector<Header> Symbol::headers() const {
217
6
  llvm::SmallVector<Header> Results;
218
6
  for (auto HeaderID : getMappingPerLang(Language)->SymbolHeaderIDs[ID])
219
15
    Results.emplace_back(Header(HeaderID, Language));
220
6
  return Results;
221
6
}
222
223
1
Recognizer::Recognizer() { ensureInitialized(); }
224
225
7
NSSymbolMap *Recognizer::namespaceSymbols(const DeclContext *DC, Lang L) {
226
7
  if (DC->isTranslationUnit()) // global scope.
227
2
    return getMappingPerLang(L)->NamespaceSymbols->lookup("");
228
229
5
  auto It = NamespaceCache.find(DC);
230
5
  if (It != NamespaceCache.end())
231
3
    return It->second;
232
2
  const NamespaceDecl *D = llvm::cast<NamespaceDecl>(DC);
233
2
  NSSymbolMap *Result = [&]() -> NSSymbolMap * {
234
2
    if (D->isAnonymousNamespace())
235
0
      return nullptr;
236
    // Print the namespace and its parents ommitting inline scopes.
237
2
    std::string Scope;
238
8
    for (const auto *ND = D; ND;
239
6
         ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent()))
240
6
      if (!ND->isInlineNamespace() && 
!ND->isAnonymousNamespace()3
)
241
3
        Scope = ND->getName().str() + "::" + Scope;
242
2
    return getMappingPerLang(L)->NamespaceSymbols->lookup(Scope);
243
2
  }();
244
2
  NamespaceCache.try_emplace(D, Result);
245
2
  return Result;
246
5
}
247
248
7
std::optional<Symbol> Recognizer::operator()(const Decl *D) {
249
7
  Lang L;
250
7
  if (D->getLangOpts().CPlusPlus) {
251
7
    L = Lang::CXX;
252
7
  } else 
if (0
D->getLangOpts().C110
) {
253
0
    L = Lang::C;
254
0
  } else {
255
0
    return std::nullopt; // not a supported language.
256
0
  }
257
258
  // If D is std::vector::iterator, `vector` is the outer symbol to look up.
259
  // We keep all the candidate DCs as some may turn out to be anon enums.
260
  // Do this resolution lazily as we may turn out not to have a std namespace.
261
7
  llvm::SmallVector<const DeclContext *> IntermediateDecl;
262
7
  const DeclContext *DC = D->getDeclContext();
263
7
  if (!DC) // The passed D is a TranslationUnitDecl!
264
0
    return std::nullopt;
265
8
  
while (7
!DC->isNamespace() &&
!DC->isTranslationUnit()3
) {
266
1
    if (NamedDecl::classofKind(DC->getDeclKind()))
267
1
      IntermediateDecl.push_back(DC);
268
1
    DC = DC->getParent();
269
1
  }
270
7
  NSSymbolMap *Symbols = namespaceSymbols(DC, L);
271
7
  if (!Symbols)
272
0
    return std::nullopt;
273
274
7
  llvm::StringRef Name = [&]() -> llvm::StringRef {
275
7
    for (const auto *SymDC : llvm::reverse(IntermediateDecl)) {
276
1
      DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName();
277
1
      if (const auto *II = N.getAsIdentifierInfo())
278
1
        return II->getName();
279
0
      if (!N.isEmpty())
280
0
        return ""; // e.g. operator<: give up
281
0
    }
282
6
    if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
283
6
      if (const auto *II = ND->getIdentifier())
284
6
        return II->getName();
285
0
    return "";
286
6
  }();
287
7
  if (Name.empty())
288
0
    return std::nullopt;
289
290
7
  auto It = Symbols->find(Name);
291
7
  if (It == Symbols->end())
292
2
    return std::nullopt;
293
5
  return Symbol(It->second, L);
294
7
}
295
296
} // namespace stdlib
297
} // namespace tooling
298
} // namespace clang