forked from OSchip/llvm-project
166 lines
5.6 KiB
C++
166 lines
5.6 KiB
C++
//===--- 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 "llvm/ADT/Optional.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;
|
|
}
|
|
|
|
llvm::Optional<Header> Header::named(llvm::StringRef Name) {
|
|
ensureInitialized();
|
|
auto It = HeaderIDs->find(Name);
|
|
if (It == HeaderIDs->end())
|
|
return llvm::None;
|
|
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; }
|
|
llvm::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 llvm::None;
|
|
}
|
|
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;
|
|
}
|
|
|
|
llvm::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 llvm::None;
|
|
|
|
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 llvm::None;
|
|
|
|
auto It = Symbols->find(Name);
|
|
if (It == Symbols->end())
|
|
return llvm::None;
|
|
return Symbol(It->second);
|
|
}
|
|
|
|
} // namespace stdlib
|
|
} // namespace tooling
|
|
} // namespace clang
|