Path: blob/main/contrib/llvm-project/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp
35293 views
//===--- StandardLibrary.cpp ------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Tooling/Inclusions/StandardLibrary.h"9#include "clang/AST/Decl.h"10#include "clang/Basic/LangOptions.h"11#include "llvm/ADT/ArrayRef.h"12#include "llvm/ADT/DenseSet.h"13#include "llvm/ADT/STLExtras.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/Support/Casting.h"16#include <optional>1718namespace clang {19namespace tooling {20namespace stdlib {2122namespace {23// Symbol name -> Symbol::ID, within a namespace.24using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>;2526// A Mapping per language.27struct SymbolHeaderMapping {28llvm::StringRef *HeaderNames = nullptr;29// Header name => Header::ID30llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs;3132unsigned SymbolCount = 0;33// Symbol::ID => symbol qualified_name/name/scope34struct SymbolName {35const char *Data; // std::vector36unsigned ScopeLen; // ~~~~~37unsigned NameLen; // ~~~~~~38StringRef scope() const { return StringRef(Data, ScopeLen); }39StringRef name() const { return StringRef(Data + ScopeLen, NameLen); }40StringRef qualifiedName() const {41return StringRef(Data, ScopeLen + NameLen);42}43} *SymbolNames = nullptr;44// Symbol name -> Symbol::ID, within a namespace.45llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols = nullptr;46// Symbol::ID => Header::ID47llvm::SmallVector<unsigned> *SymbolHeaderIDs = nullptr;48};49} // namespace50static SymbolHeaderMapping51*LanguageMappings[static_cast<unsigned>(Lang::LastValue) + 1];52static const SymbolHeaderMapping *getMappingPerLang(Lang L) {53return LanguageMappings[static_cast<unsigned>(L)];54}5556static int countSymbols(Lang Language) {57ArrayRef<const char *> Symbols;58#define SYMBOL(Name, NS, Header) #NS #Name,59switch (Language) {60case Lang::C: {61static constexpr const char *CSymbols[] = {62#include "CSpecialSymbolMap.inc"63#include "CSymbolMap.inc"64};65Symbols = CSymbols;66break;67}68case Lang::CXX: {69static constexpr const char *CXXSymbols[] = {70#include "StdSpecialSymbolMap.inc"71#include "StdSymbolMap.inc"72#include "StdTsSymbolMap.inc"73};74Symbols = CXXSymbols;75break;76}77}78#undef SYMBOL79return llvm::DenseSet<StringRef>(Symbols.begin(), Symbols.end()).size();80}8182static int initialize(Lang Language) {83SymbolHeaderMapping *Mapping = new SymbolHeaderMapping();84LanguageMappings[static_cast<unsigned>(Language)] = Mapping;8586unsigned SymCount = countSymbols(Language);87Mapping->SymbolCount = SymCount;88Mapping->SymbolNames =89new std::remove_reference_t<decltype(*Mapping->SymbolNames)>[SymCount];90Mapping->SymbolHeaderIDs = new std::remove_reference_t<91decltype(*Mapping->SymbolHeaderIDs)>[SymCount];92Mapping->NamespaceSymbols =93new std::remove_reference_t<decltype(*Mapping->NamespaceSymbols)>;94Mapping->HeaderIDs =95new std::remove_reference_t<decltype(*Mapping->HeaderIDs)>;96auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & {97auto R = Mapping->NamespaceSymbols->try_emplace(NS, nullptr);98if (R.second)99R.first->second = new NSSymbolMap();100return *R.first->second;101};102103auto AddHeader = [&](llvm::StringRef Header) -> unsigned {104return Mapping->HeaderIDs->try_emplace(Header, Mapping->HeaderIDs->size())105.first->second;106};107108auto Add = [&, SymIndex(-1)](llvm::StringRef QName, unsigned NSLen,109llvm::StringRef HeaderName) mutable {110// Correct "Nonefoo" => foo.111// FIXME: get rid of "None" from the generated mapping files.112if (QName.take_front(NSLen) == "None") {113QName = QName.drop_front(NSLen);114NSLen = 0;115}116117if (SymIndex >= 0 &&118Mapping->SymbolNames[SymIndex].qualifiedName() == QName) {119// Not a new symbol, use the same index.120assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex),121[&QName](const SymbolHeaderMapping::SymbolName &S) {122return S.qualifiedName() == QName;123}) &&124"The symbol has been added before, make sure entries in the .inc "125"file are grouped by symbol name!");126} else {127// First symbol or new symbol, increment next available index.128++SymIndex;129}130Mapping->SymbolNames[SymIndex] = {131QName.data(), NSLen, static_cast<unsigned int>(QName.size() - NSLen)};132if (!HeaderName.empty())133Mapping->SymbolHeaderIDs[SymIndex].push_back(AddHeader(HeaderName));134135NSSymbolMap &NSSymbols = AddNS(QName.take_front(NSLen));136NSSymbols.try_emplace(QName.drop_front(NSLen), SymIndex);137};138139struct Symbol {140const char *QName;141unsigned NSLen;142const char *HeaderName;143};144#define SYMBOL(Name, NS, Header) \145{#NS #Name, static_cast<decltype(Symbol::NSLen)>(StringRef(#NS).size()), \146#Header},147switch (Language) {148case Lang::C: {149static constexpr Symbol CSymbols[] = {150#include "CSpecialSymbolMap.inc"151#include "CSymbolMap.inc"152};153for (const Symbol &S : CSymbols)154Add(S.QName, S.NSLen, S.HeaderName);155break;156}157case Lang::CXX: {158static constexpr Symbol CXXSymbols[] = {159#include "StdSpecialSymbolMap.inc"160#include "StdSymbolMap.inc"161#include "StdTsSymbolMap.inc"162};163for (const Symbol &S : CXXSymbols)164Add(S.QName, S.NSLen, S.HeaderName);165break;166}167}168#undef SYMBOL169170Mapping->HeaderNames = new llvm::StringRef[Mapping->HeaderIDs->size()];171for (const auto &E : *Mapping->HeaderIDs)172Mapping->HeaderNames[E.second] = E.first;173174return 0;175}176177static void ensureInitialized() {178static int Dummy = []() {179for (unsigned L = 0; L <= static_cast<unsigned>(Lang::LastValue); ++L)180initialize(static_cast<Lang>(L));181return 0;182}();183(void)Dummy;184}185186std::vector<Header> Header::all(Lang L) {187ensureInitialized();188std::vector<Header> Result;189const auto *Mapping = getMappingPerLang(L);190Result.reserve(Mapping->HeaderIDs->size());191for (unsigned I = 0, E = Mapping->HeaderIDs->size(); I < E; ++I)192Result.push_back(Header(I, L));193return Result;194}195std::optional<Header> Header::named(llvm::StringRef Name, Lang L) {196ensureInitialized();197const auto *Mapping = getMappingPerLang(L);198auto It = Mapping->HeaderIDs->find(Name);199if (It == Mapping->HeaderIDs->end())200return std::nullopt;201return Header(It->second, L);202}203llvm::StringRef Header::name() const {204return getMappingPerLang(Language)->HeaderNames[ID];205}206207std::vector<Symbol> Symbol::all(Lang L) {208ensureInitialized();209std::vector<Symbol> Result;210const auto *Mapping = getMappingPerLang(L);211Result.reserve(Mapping->SymbolCount);212for (unsigned I = 0, E = Mapping->SymbolCount; I < E; ++I)213Result.push_back(Symbol(I, L));214return Result;215}216llvm::StringRef Symbol::scope() const {217return getMappingPerLang(Language)->SymbolNames[ID].scope();218}219llvm::StringRef Symbol::name() const {220return getMappingPerLang(Language)->SymbolNames[ID].name();221}222llvm::StringRef Symbol::qualifiedName() const {223return getMappingPerLang(Language)->SymbolNames[ID].qualifiedName();224}225std::optional<Symbol> Symbol::named(llvm::StringRef Scope, llvm::StringRef Name,226Lang L) {227ensureInitialized();228229if (NSSymbolMap *NSSymbols =230getMappingPerLang(L)->NamespaceSymbols->lookup(Scope)) {231auto It = NSSymbols->find(Name);232if (It != NSSymbols->end())233return Symbol(It->second, L);234}235return std::nullopt;236}237std::optional<Header> Symbol::header() const {238const auto& Headers = getMappingPerLang(Language)->SymbolHeaderIDs[ID];239if (Headers.empty())240return std::nullopt;241return Header(Headers.front(), Language);242}243llvm::SmallVector<Header> Symbol::headers() const {244llvm::SmallVector<Header> Results;245for (auto HeaderID : getMappingPerLang(Language)->SymbolHeaderIDs[ID])246Results.emplace_back(Header(HeaderID, Language));247return Results;248}249250Recognizer::Recognizer() { ensureInitialized(); }251252NSSymbolMap *Recognizer::namespaceSymbols(const DeclContext *DC, Lang L) {253if (DC->isTranslationUnit()) // global scope.254return getMappingPerLang(L)->NamespaceSymbols->lookup("");255256auto It = NamespaceCache.find(DC);257if (It != NamespaceCache.end())258return It->second;259const NamespaceDecl *D = llvm::cast<NamespaceDecl>(DC);260NSSymbolMap *Result = [&]() -> NSSymbolMap * {261if (D->isAnonymousNamespace())262return nullptr;263// Print the namespace and its parents ommitting inline scopes.264std::string Scope;265for (const auto *ND = D; ND;266ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent()))267if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace())268Scope = ND->getName().str() + "::" + Scope;269return getMappingPerLang(L)->NamespaceSymbols->lookup(Scope);270}();271NamespaceCache.try_emplace(D, Result);272return Result;273}274275std::optional<Symbol> Recognizer::operator()(const Decl *D) {276Lang L;277if (D->getLangOpts().CPlusPlus)278L = Lang::CXX;279else if (D->getLangOpts().C99)280L = Lang::C;281else282return std::nullopt; // not a supported language.283284// If D is std::vector::iterator, `vector` is the outer symbol to look up.285// We keep all the candidate DCs as some may turn out to be anon enums.286// Do this resolution lazily as we may turn out not to have a std namespace.287llvm::SmallVector<const DeclContext *> IntermediateDecl;288const DeclContext *DC = D->getDeclContext();289if (!DC) // The passed D is a TranslationUnitDecl!290return std::nullopt;291while (!DC->isNamespace() && !DC->isTranslationUnit()) {292if (NamedDecl::classofKind(DC->getDeclKind()))293IntermediateDecl.push_back(DC);294DC = DC->getParent();295}296NSSymbolMap *Symbols = namespaceSymbols(DC, L);297if (!Symbols)298return std::nullopt;299300llvm::StringRef Name = [&]() -> llvm::StringRef {301for (const auto *SymDC : llvm::reverse(IntermediateDecl)) {302DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName();303if (const auto *II = N.getAsIdentifierInfo())304return II->getName();305if (!N.isEmpty())306return ""; // e.g. operator<: give up307}308if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))309if (const auto *II = ND->getIdentifier())310return II->getName();311return "";312}();313if (Name.empty())314return std::nullopt;315316auto It = Symbols->find(Name);317if (It == Symbols->end())318return std::nullopt;319return Symbol(It->second, L);320}321322} // namespace stdlib323} // namespace tooling324} // namespace clang325326327