aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp')
-rw-r--r--clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp
new file mode 100644
index 000000000000..9e5e421fdebc
--- /dev/null
+++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp
@@ -0,0 +1,165 @@
+//===--- StandardLibrary.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+
+namespace clang {
+namespace tooling {
+namespace stdlib {
+
+static llvm::StringRef *HeaderNames;
+static std::pair<llvm::StringRef, llvm::StringRef> *SymbolNames;
+static unsigned *SymbolHeaderIDs;
+static llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs;
+// Maps symbol name -> Symbol::ID, within a namespace.
+using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>;
+static llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols;
+
+static int initialize() {
+ unsigned SymCount = 0;
+#define SYMBOL(Name, NS, Header) ++SymCount;
+#include "clang/Tooling/Inclusions/CSymbolMap.inc"
+#include "clang/Tooling/Inclusions/StdSymbolMap.inc"
+#undef SYMBOL
+ SymbolNames = new std::remove_reference_t<decltype(*SymbolNames)>[SymCount];
+ SymbolHeaderIDs =
+ new std::remove_reference_t<decltype(*SymbolHeaderIDs)>[SymCount];
+ NamespaceSymbols = new std::remove_reference_t<decltype(*NamespaceSymbols)>;
+ HeaderIDs = new std::remove_reference_t<decltype(*HeaderIDs)>;
+
+ auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & {
+ auto R = NamespaceSymbols->try_emplace(NS, nullptr);
+ if (R.second)
+ R.first->second = new NSSymbolMap();
+ return *R.first->second;
+ };
+
+ auto AddHeader = [&](llvm::StringRef Header) -> unsigned {
+ return HeaderIDs->try_emplace(Header, HeaderIDs->size()).first->second;
+ };
+
+ auto Add = [&, SymIndex(0)](llvm::StringRef Name, llvm::StringRef NS,
+ llvm::StringRef HeaderName) mutable {
+ if (NS == "None")
+ NS = "";
+
+ SymbolNames[SymIndex] = {NS, Name};
+ SymbolHeaderIDs[SymIndex] = AddHeader(HeaderName);
+
+ NSSymbolMap &NSSymbols = AddNS(NS);
+ NSSymbols.try_emplace(Name, SymIndex);
+
+ ++SymIndex;
+ };
+#define SYMBOL(Name, NS, Header) Add(#Name, #NS, #Header);
+#include "clang/Tooling/Inclusions/CSymbolMap.inc"
+#include "clang/Tooling/Inclusions/StdSymbolMap.inc"
+#undef SYMBOL
+
+ HeaderNames = new llvm::StringRef[HeaderIDs->size()];
+ for (const auto &E : *HeaderIDs)
+ HeaderNames[E.second] = E.first;
+
+ return 0;
+}
+
+static void ensureInitialized() {
+ static int Dummy = initialize();
+ (void)Dummy;
+}
+
+std::optional<Header> Header::named(llvm::StringRef Name) {
+ ensureInitialized();
+ auto It = HeaderIDs->find(Name);
+ if (It == HeaderIDs->end())
+ return std::nullopt;
+ return Header(It->second);
+}
+llvm::StringRef Header::name() const { return HeaderNames[ID]; }
+llvm::StringRef Symbol::scope() const { return SymbolNames[ID].first; }
+llvm::StringRef Symbol::name() const { return SymbolNames[ID].second; }
+std::optional<Symbol> Symbol::named(llvm::StringRef Scope,
+ llvm::StringRef Name) {
+ ensureInitialized();
+ if (NSSymbolMap *NSSymbols = NamespaceSymbols->lookup(Scope)) {
+ auto It = NSSymbols->find(Name);
+ if (It != NSSymbols->end())
+ return Symbol(It->second);
+ }
+ return std::nullopt;
+}
+Header Symbol::header() const { return Header(SymbolHeaderIDs[ID]); }
+llvm::SmallVector<Header> Symbol::headers() const {
+ return {header()}; // FIXME: multiple in case of ambiguity
+}
+
+Recognizer::Recognizer() { ensureInitialized(); }
+
+NSSymbolMap *Recognizer::namespaceSymbols(const NamespaceDecl *D) {
+ auto It = NamespaceCache.find(D);
+ if (It != NamespaceCache.end())
+ return It->second;
+
+ NSSymbolMap *Result = [&]() -> NSSymbolMap * {
+ if (D && D->isAnonymousNamespace())
+ return nullptr;
+ // Print the namespace and its parents ommitting inline scopes.
+ std::string Scope;
+ for (const auto *ND = D; ND;
+ ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent()))
+ if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace())
+ Scope = ND->getName().str() + "::" + Scope;
+ return NamespaceSymbols->lookup(Scope);
+ }();
+ NamespaceCache.try_emplace(D, Result);
+ return Result;
+}
+
+std::optional<Symbol> Recognizer::operator()(const Decl *D) {
+ // If D is std::vector::iterator, `vector` is the outer symbol to look up.
+ // We keep all the candidate DCs as some may turn out to be anon enums.
+ // Do this resolution lazily as we may turn out not to have a std namespace.
+ llvm::SmallVector<const DeclContext *> IntermediateDecl;
+ const DeclContext *DC = D->getDeclContext();
+ while (DC && !DC->isNamespace()) {
+ if (NamedDecl::classofKind(DC->getDeclKind()))
+ IntermediateDecl.push_back(DC);
+ DC = DC->getParent();
+ }
+ NSSymbolMap *Symbols = namespaceSymbols(cast_or_null<NamespaceDecl>(DC));
+ if (!Symbols)
+ return std::nullopt;
+
+ llvm::StringRef Name = [&]() -> llvm::StringRef {
+ for (const auto *SymDC : llvm::reverse(IntermediateDecl)) {
+ DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName();
+ if (const auto *II = N.getAsIdentifierInfo())
+ return II->getName();
+ if (!N.isEmpty())
+ return ""; // e.g. operator<: give up
+ }
+ if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
+ if (const auto *II = ND->getIdentifier())
+ return II->getName();
+ return "";
+ }();
+ if (Name.empty())
+ return std::nullopt;
+
+ auto It = Symbols->find(Name);
+ if (It == Symbols->end())
+ return std::nullopt;
+ return Symbol(It->second);
+}
+
+} // namespace stdlib
+} // namespace tooling
+} // namespace clang