/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Inclusions/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 "llvm/ADT/Optional.h" |
11 | | #include "llvm/ADT/StringRef.h" |
12 | | #include "llvm/Support/Casting.h" |
13 | | |
14 | | namespace clang { |
15 | | namespace tooling { |
16 | | namespace stdlib { |
17 | | |
18 | | static llvm::StringRef *HeaderNames; |
19 | | static std::pair<llvm::StringRef, llvm::StringRef> *SymbolNames; |
20 | | static unsigned *SymbolHeaderIDs; |
21 | | static llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs; |
22 | | // Maps symbol name -> Symbol::ID, within a namespace. |
23 | | using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>; |
24 | | static llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols; |
25 | | |
26 | 2 | static int initialize() { |
27 | 2 | unsigned SymCount = 0; |
28 | 4.92k | #define SYMBOL(Name, NS, Header) ++SymCount; |
29 | 2 | #include "clang/Tooling/Inclusions/CSymbolMap.inc" |
30 | 2 | #include "clang/Tooling/Inclusions/StdSymbolMap.inc" |
31 | 2 | #undef SYMBOL |
32 | 2 | SymbolNames = new std::remove_reference_t<decltype(*SymbolNames)>[SymCount]; |
33 | 2 | SymbolHeaderIDs = |
34 | 2 | new std::remove_reference_t<decltype(*SymbolHeaderIDs)>[SymCount]; |
35 | 2 | NamespaceSymbols = new std::remove_reference_t<decltype(*NamespaceSymbols)>; |
36 | 2 | HeaderIDs = new std::remove_reference_t<decltype(*HeaderIDs)>; |
37 | | |
38 | 4.92k | auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & { |
39 | 4.92k | auto R = NamespaceSymbols->try_emplace(NS, nullptr); |
40 | 4.92k | if (R.second) |
41 | 14 | R.first->second = new NSSymbolMap(); |
42 | 4.92k | return *R.first->second; |
43 | 4.92k | }; |
44 | | |
45 | 4.92k | auto AddHeader = [&](llvm::StringRef Header) -> unsigned { |
46 | 4.92k | return HeaderIDs->try_emplace(Header, HeaderIDs->size()).first->second; |
47 | 4.92k | }; |
48 | | |
49 | 2 | auto Add = [&, SymIndex(0)](llvm::StringRef Name, llvm::StringRef NS, |
50 | 4.92k | llvm::StringRef HeaderName) mutable { |
51 | 4.92k | if (NS == "None") |
52 | 1.86k | NS = ""; |
53 | | |
54 | 4.92k | SymbolNames[SymIndex] = {NS, Name}; |
55 | 4.92k | SymbolHeaderIDs[SymIndex] = AddHeader(HeaderName); |
56 | | |
57 | 4.92k | NSSymbolMap &NSSymbols = AddNS(NS); |
58 | 4.92k | NSSymbols.try_emplace(Name, SymIndex); |
59 | | |
60 | 4.92k | ++SymIndex; |
61 | 4.92k | }; |
62 | 4.92k | #define SYMBOL(Name, NS, Header) Add(#Name, #NS, #Header); |
63 | 2 | #include "clang/Tooling/Inclusions/CSymbolMap.inc" |
64 | 2 | #include "clang/Tooling/Inclusions/StdSymbolMap.inc" |
65 | 2 | #undef SYMBOL |
66 | | |
67 | 2 | HeaderNames = new llvm::StringRef[HeaderIDs->size()]; |
68 | 2 | for (const auto &E : *HeaderIDs) |
69 | 220 | HeaderNames[E.second] = E.first; |
70 | | |
71 | 2 | return 0; |
72 | 2 | } |
73 | | |
74 | 10 | static void ensureInitialized() { |
75 | 10 | static int Dummy = initialize(); |
76 | 10 | (void)Dummy; |
77 | 10 | } |
78 | | |
79 | 2 | llvm::Optional<Header> Header::named(llvm::StringRef Name) { |
80 | 2 | ensureInitialized(); |
81 | 2 | auto It = HeaderIDs->find(Name); |
82 | 2 | if (It == HeaderIDs->end()) |
83 | 1 | return llvm::None; |
84 | 1 | return Header(It->second); |
85 | 2 | } |
86 | 1 | llvm::StringRef Header::name() const { return HeaderNames[ID]; } |
87 | 1 | llvm::StringRef Symbol::scope() const { return SymbolNames[ID].first; } |
88 | 1 | llvm::StringRef Symbol::name() const { return SymbolNames[ID].second; } |
89 | | llvm::Optional<Symbol> Symbol::named(llvm::StringRef Scope, |
90 | 7 | llvm::StringRef Name) { |
91 | 7 | ensureInitialized(); |
92 | 7 | if (NSSymbolMap *NSSymbols = NamespaceSymbols->lookup(Scope)) { |
93 | 6 | auto It = NSSymbols->find(Name); |
94 | 6 | if (It != NSSymbols->end()) |
95 | 4 | return Symbol(It->second); |
96 | 6 | } |
97 | 3 | return llvm::None; |
98 | 7 | } |
99 | 2 | Header Symbol::header() const { return Header(SymbolHeaderIDs[ID]); } |
100 | 1 | llvm::SmallVector<Header> Symbol::headers() const { |
101 | 1 | return {header()}; // FIXME: multiple in case of ambiguity |
102 | 1 | } |
103 | | |
104 | 1 | Recognizer::Recognizer() { ensureInitialized(); } |
105 | | |
106 | 6 | NSSymbolMap *Recognizer::namespaceSymbols(const NamespaceDecl *D) { |
107 | 6 | auto It = NamespaceCache.find(D); |
108 | 6 | if (It != NamespaceCache.end()) |
109 | 3 | return It->second; |
110 | | |
111 | 3 | NSSymbolMap *Result = [&]() -> NSSymbolMap * { |
112 | 3 | if (D && D->isAnonymousNamespace()2 ) |
113 | 0 | return nullptr; |
114 | | // Print the namespace and its parents ommitting inline scopes. |
115 | 3 | std::string Scope; |
116 | 9 | for (const auto *ND = D; ND; |
117 | 6 | ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent())) |
118 | 6 | if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace()3 ) |
119 | 3 | Scope = ND->getName().str() + "::" + Scope; |
120 | 3 | return NamespaceSymbols->lookup(Scope); |
121 | 3 | }(); |
122 | 3 | NamespaceCache.try_emplace(D, Result); |
123 | 3 | return Result; |
124 | 6 | } |
125 | | |
126 | 6 | llvm::Optional<Symbol> Recognizer::operator()(const Decl *D) { |
127 | | // If D is std::vector::iterator, `vector` is the outer symbol to look up. |
128 | | // We keep all the candidate DCs as some may turn out to be anon enums. |
129 | | // Do this resolution lazily as we may turn out not to have a std namespace. |
130 | 6 | llvm::SmallVector<const DeclContext *> IntermediateDecl; |
131 | 6 | const DeclContext *DC = D->getDeclContext(); |
132 | 9 | while (DC && !DC->isNamespace()7 ) { |
133 | 3 | if (NamedDecl::classofKind(DC->getDeclKind())) |
134 | 1 | IntermediateDecl.push_back(DC); |
135 | 3 | DC = DC->getParent(); |
136 | 3 | } |
137 | 6 | NSSymbolMap *Symbols = namespaceSymbols(cast_or_null<NamespaceDecl>(DC)); |
138 | 6 | if (!Symbols) |
139 | 0 | return llvm::None; |
140 | | |
141 | 6 | llvm::StringRef Name = [&]() -> llvm::StringRef { |
142 | 6 | for (const auto *SymDC : llvm::reverse(IntermediateDecl)) { |
143 | 1 | DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName(); |
144 | 1 | if (const auto *II = N.getAsIdentifierInfo()) |
145 | 1 | return II->getName(); |
146 | 0 | if (!N.isEmpty()) |
147 | 0 | return ""; // e.g. operator<: give up |
148 | 0 | } |
149 | 5 | if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) |
150 | 5 | if (const auto *II = ND->getIdentifier()) |
151 | 5 | return II->getName(); |
152 | 0 | return ""; |
153 | 5 | }(); |
154 | 6 | if (Name.empty()) |
155 | 0 | return llvm::None; |
156 | | |
157 | 6 | auto It = Symbols->find(Name); |
158 | 6 | if (It == Symbols->end()) |
159 | 3 | return llvm::None; |
160 | 3 | return Symbol(It->second); |
161 | 6 | } |
162 | | |
163 | | } // namespace stdlib |
164 | | } // namespace tooling |
165 | | } // namespace clang |