1bdd1243dSDimitry Andric //===--- StandardLibrary.cpp ------------------------------------*- C++ -*-===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric 9bdd1243dSDimitry Andric #include "clang/Tooling/Inclusions/StandardLibrary.h" 10bdd1243dSDimitry Andric #include "clang/AST/Decl.h" 1106c3fb27SDimitry Andric #include "clang/Basic/LangOptions.h" 1206c3fb27SDimitry Andric #include "llvm/ADT/ArrayRef.h" 1306c3fb27SDimitry Andric #include "llvm/ADT/DenseSet.h" 1406c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h" 15bdd1243dSDimitry Andric #include "llvm/ADT/StringRef.h" 16bdd1243dSDimitry Andric #include "llvm/Support/Casting.h" 1706c3fb27SDimitry Andric #include <optional> 18bdd1243dSDimitry Andric 19bdd1243dSDimitry Andric namespace clang { 20bdd1243dSDimitry Andric namespace tooling { 21bdd1243dSDimitry Andric namespace stdlib { 22bdd1243dSDimitry Andric 2306c3fb27SDimitry Andric namespace { 2406c3fb27SDimitry Andric // Symbol name -> Symbol::ID, within a namespace. 25bdd1243dSDimitry Andric using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>; 26bdd1243dSDimitry Andric 2706c3fb27SDimitry Andric // A Mapping per language. 2806c3fb27SDimitry Andric struct SymbolHeaderMapping { 2906c3fb27SDimitry Andric llvm::StringRef *HeaderNames = nullptr; 3006c3fb27SDimitry Andric // Header name => Header::ID 3106c3fb27SDimitry Andric llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs; 3206c3fb27SDimitry Andric 3306c3fb27SDimitry Andric unsigned SymbolCount = 0; 3406c3fb27SDimitry Andric // Symbol::ID => symbol qualified_name/name/scope 3506c3fb27SDimitry Andric struct SymbolName { 3606c3fb27SDimitry Andric const char *Data; // std::vector 3706c3fb27SDimitry Andric unsigned ScopeLen; // ~~~~~ 3806c3fb27SDimitry Andric unsigned NameLen; // ~~~~~~ 3906c3fb27SDimitry Andric StringRef scope() const { return StringRef(Data, ScopeLen); } 4006c3fb27SDimitry Andric StringRef name() const { return StringRef(Data + ScopeLen, NameLen); } 4106c3fb27SDimitry Andric StringRef qualifiedName() const { 4206c3fb27SDimitry Andric return StringRef(Data, ScopeLen + NameLen); 4306c3fb27SDimitry Andric } 4406c3fb27SDimitry Andric } *SymbolNames = nullptr; 4506c3fb27SDimitry Andric // Symbol name -> Symbol::ID, within a namespace. 4606c3fb27SDimitry Andric llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols = nullptr; 4706c3fb27SDimitry Andric // Symbol::ID => Header::ID 4806c3fb27SDimitry Andric llvm::SmallVector<unsigned> *SymbolHeaderIDs = nullptr; 4906c3fb27SDimitry Andric }; 5006c3fb27SDimitry Andric } // namespace 5106c3fb27SDimitry Andric static SymbolHeaderMapping 5206c3fb27SDimitry Andric *LanguageMappings[static_cast<unsigned>(Lang::LastValue) + 1]; 5306c3fb27SDimitry Andric static const SymbolHeaderMapping *getMappingPerLang(Lang L) { 5406c3fb27SDimitry Andric return LanguageMappings[static_cast<unsigned>(L)]; 5506c3fb27SDimitry Andric } 5606c3fb27SDimitry Andric 5706c3fb27SDimitry Andric static int countSymbols(Lang Language) { 585f757f3fSDimitry Andric ArrayRef<const char *> Symbols; 595f757f3fSDimitry Andric #define SYMBOL(Name, NS, Header) #NS #Name, 6006c3fb27SDimitry Andric switch (Language) { 615f757f3fSDimitry Andric case Lang::C: { 625f757f3fSDimitry Andric static constexpr const char *CSymbols[] = { 63*0fca6ea1SDimitry Andric #include "CSpecialSymbolMap.inc" 6406c3fb27SDimitry Andric #include "CSymbolMap.inc" 655f757f3fSDimitry Andric }; 665f757f3fSDimitry Andric Symbols = CSymbols; 6706c3fb27SDimitry Andric break; 685f757f3fSDimitry Andric } 695f757f3fSDimitry Andric case Lang::CXX: { 705f757f3fSDimitry Andric static constexpr const char *CXXSymbols[] = { 7106c3fb27SDimitry Andric #include "StdSpecialSymbolMap.inc" 7206c3fb27SDimitry Andric #include "StdSymbolMap.inc" 7306c3fb27SDimitry Andric #include "StdTsSymbolMap.inc" 745f757f3fSDimitry Andric }; 755f757f3fSDimitry Andric Symbols = CXXSymbols; 7606c3fb27SDimitry Andric break; 7706c3fb27SDimitry Andric } 785f757f3fSDimitry Andric } 79bdd1243dSDimitry Andric #undef SYMBOL 805f757f3fSDimitry Andric return llvm::DenseSet<StringRef>(Symbols.begin(), Symbols.end()).size(); 8106c3fb27SDimitry Andric } 82bdd1243dSDimitry Andric 8306c3fb27SDimitry Andric static int initialize(Lang Language) { 8406c3fb27SDimitry Andric SymbolHeaderMapping *Mapping = new SymbolHeaderMapping(); 8506c3fb27SDimitry Andric LanguageMappings[static_cast<unsigned>(Language)] = Mapping; 8606c3fb27SDimitry Andric 8706c3fb27SDimitry Andric unsigned SymCount = countSymbols(Language); 8806c3fb27SDimitry Andric Mapping->SymbolCount = SymCount; 8906c3fb27SDimitry Andric Mapping->SymbolNames = 9006c3fb27SDimitry Andric new std::remove_reference_t<decltype(*Mapping->SymbolNames)>[SymCount]; 9106c3fb27SDimitry Andric Mapping->SymbolHeaderIDs = new std::remove_reference_t< 9206c3fb27SDimitry Andric decltype(*Mapping->SymbolHeaderIDs)>[SymCount]; 9306c3fb27SDimitry Andric Mapping->NamespaceSymbols = 9406c3fb27SDimitry Andric new std::remove_reference_t<decltype(*Mapping->NamespaceSymbols)>; 9506c3fb27SDimitry Andric Mapping->HeaderIDs = 9606c3fb27SDimitry Andric new std::remove_reference_t<decltype(*Mapping->HeaderIDs)>; 97bdd1243dSDimitry Andric auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & { 9806c3fb27SDimitry Andric auto R = Mapping->NamespaceSymbols->try_emplace(NS, nullptr); 99bdd1243dSDimitry Andric if (R.second) 100bdd1243dSDimitry Andric R.first->second = new NSSymbolMap(); 101bdd1243dSDimitry Andric return *R.first->second; 102bdd1243dSDimitry Andric }; 103bdd1243dSDimitry Andric 104bdd1243dSDimitry Andric auto AddHeader = [&](llvm::StringRef Header) -> unsigned { 10506c3fb27SDimitry Andric return Mapping->HeaderIDs->try_emplace(Header, Mapping->HeaderIDs->size()) 10606c3fb27SDimitry Andric .first->second; 107bdd1243dSDimitry Andric }; 108bdd1243dSDimitry Andric 10906c3fb27SDimitry Andric auto Add = [&, SymIndex(-1)](llvm::StringRef QName, unsigned NSLen, 110bdd1243dSDimitry Andric llvm::StringRef HeaderName) mutable { 11106c3fb27SDimitry Andric // Correct "Nonefoo" => foo. 11206c3fb27SDimitry Andric // FIXME: get rid of "None" from the generated mapping files. 11306c3fb27SDimitry Andric if (QName.take_front(NSLen) == "None") { 11406c3fb27SDimitry Andric QName = QName.drop_front(NSLen); 11506c3fb27SDimitry Andric NSLen = 0; 11606c3fb27SDimitry Andric } 117bdd1243dSDimitry Andric 11806c3fb27SDimitry Andric if (SymIndex >= 0 && 11906c3fb27SDimitry Andric Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { 12006c3fb27SDimitry Andric // Not a new symbol, use the same index. 12106c3fb27SDimitry Andric assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), 12206c3fb27SDimitry Andric [&QName](const SymbolHeaderMapping::SymbolName &S) { 12306c3fb27SDimitry Andric return S.qualifiedName() == QName; 12406c3fb27SDimitry Andric }) && 12506c3fb27SDimitry Andric "The symbol has been added before, make sure entries in the .inc " 12606c3fb27SDimitry Andric "file are grouped by symbol name!"); 12706c3fb27SDimitry Andric } else { 12806c3fb27SDimitry Andric // First symbol or new symbol, increment next available index. 129bdd1243dSDimitry Andric ++SymIndex; 13006c3fb27SDimitry Andric } 13106c3fb27SDimitry Andric Mapping->SymbolNames[SymIndex] = { 13206c3fb27SDimitry Andric QName.data(), NSLen, static_cast<unsigned int>(QName.size() - NSLen)}; 13306c3fb27SDimitry Andric if (!HeaderName.empty()) 13406c3fb27SDimitry Andric Mapping->SymbolHeaderIDs[SymIndex].push_back(AddHeader(HeaderName)); 13506c3fb27SDimitry Andric 13606c3fb27SDimitry Andric NSSymbolMap &NSSymbols = AddNS(QName.take_front(NSLen)); 13706c3fb27SDimitry Andric NSSymbols.try_emplace(QName.drop_front(NSLen), SymIndex); 138bdd1243dSDimitry Andric }; 1395f757f3fSDimitry Andric 1405f757f3fSDimitry Andric struct Symbol { 1415f757f3fSDimitry Andric const char *QName; 1425f757f3fSDimitry Andric unsigned NSLen; 1435f757f3fSDimitry Andric const char *HeaderName; 1445f757f3fSDimitry Andric }; 1455f757f3fSDimitry Andric #define SYMBOL(Name, NS, Header) \ 1465f757f3fSDimitry Andric {#NS #Name, static_cast<decltype(Symbol::NSLen)>(StringRef(#NS).size()), \ 1475f757f3fSDimitry Andric #Header}, 14806c3fb27SDimitry Andric switch (Language) { 1495f757f3fSDimitry Andric case Lang::C: { 1505f757f3fSDimitry Andric static constexpr Symbol CSymbols[] = { 151*0fca6ea1SDimitry Andric #include "CSpecialSymbolMap.inc" 15206c3fb27SDimitry Andric #include "CSymbolMap.inc" 1535f757f3fSDimitry Andric }; 1545f757f3fSDimitry Andric for (const Symbol &S : CSymbols) 1555f757f3fSDimitry Andric Add(S.QName, S.NSLen, S.HeaderName); 15606c3fb27SDimitry Andric break; 1575f757f3fSDimitry Andric } 1585f757f3fSDimitry Andric case Lang::CXX: { 1595f757f3fSDimitry Andric static constexpr Symbol CXXSymbols[] = { 16006c3fb27SDimitry Andric #include "StdSpecialSymbolMap.inc" 16106c3fb27SDimitry Andric #include "StdSymbolMap.inc" 16206c3fb27SDimitry Andric #include "StdTsSymbolMap.inc" 1635f757f3fSDimitry Andric }; 1645f757f3fSDimitry Andric for (const Symbol &S : CXXSymbols) 1655f757f3fSDimitry Andric Add(S.QName, S.NSLen, S.HeaderName); 16606c3fb27SDimitry Andric break; 16706c3fb27SDimitry Andric } 1685f757f3fSDimitry Andric } 169bdd1243dSDimitry Andric #undef SYMBOL 170bdd1243dSDimitry Andric 17106c3fb27SDimitry Andric Mapping->HeaderNames = new llvm::StringRef[Mapping->HeaderIDs->size()]; 17206c3fb27SDimitry Andric for (const auto &E : *Mapping->HeaderIDs) 17306c3fb27SDimitry Andric Mapping->HeaderNames[E.second] = E.first; 174bdd1243dSDimitry Andric 175bdd1243dSDimitry Andric return 0; 176bdd1243dSDimitry Andric } 177bdd1243dSDimitry Andric 178bdd1243dSDimitry Andric static void ensureInitialized() { 17906c3fb27SDimitry Andric static int Dummy = []() { 18006c3fb27SDimitry Andric for (unsigned L = 0; L <= static_cast<unsigned>(Lang::LastValue); ++L) 18106c3fb27SDimitry Andric initialize(static_cast<Lang>(L)); 18206c3fb27SDimitry Andric return 0; 18306c3fb27SDimitry Andric }(); 184bdd1243dSDimitry Andric (void)Dummy; 185bdd1243dSDimitry Andric } 186bdd1243dSDimitry Andric 18706c3fb27SDimitry Andric std::vector<Header> Header::all(Lang L) { 188bdd1243dSDimitry Andric ensureInitialized(); 18906c3fb27SDimitry Andric std::vector<Header> Result; 19006c3fb27SDimitry Andric const auto *Mapping = getMappingPerLang(L); 19106c3fb27SDimitry Andric Result.reserve(Mapping->HeaderIDs->size()); 19206c3fb27SDimitry Andric for (unsigned I = 0, E = Mapping->HeaderIDs->size(); I < E; ++I) 19306c3fb27SDimitry Andric Result.push_back(Header(I, L)); 19406c3fb27SDimitry Andric return Result; 195bdd1243dSDimitry Andric } 19606c3fb27SDimitry Andric std::optional<Header> Header::named(llvm::StringRef Name, Lang L) { 197bdd1243dSDimitry Andric ensureInitialized(); 19806c3fb27SDimitry Andric const auto *Mapping = getMappingPerLang(L); 19906c3fb27SDimitry Andric auto It = Mapping->HeaderIDs->find(Name); 20006c3fb27SDimitry Andric if (It == Mapping->HeaderIDs->end()) 20106c3fb27SDimitry Andric return std::nullopt; 20206c3fb27SDimitry Andric return Header(It->second, L); 20306c3fb27SDimitry Andric } 20406c3fb27SDimitry Andric llvm::StringRef Header::name() const { 20506c3fb27SDimitry Andric return getMappingPerLang(Language)->HeaderNames[ID]; 20606c3fb27SDimitry Andric } 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric std::vector<Symbol> Symbol::all(Lang L) { 20906c3fb27SDimitry Andric ensureInitialized(); 21006c3fb27SDimitry Andric std::vector<Symbol> Result; 21106c3fb27SDimitry Andric const auto *Mapping = getMappingPerLang(L); 21206c3fb27SDimitry Andric Result.reserve(Mapping->SymbolCount); 21306c3fb27SDimitry Andric for (unsigned I = 0, E = Mapping->SymbolCount; I < E; ++I) 21406c3fb27SDimitry Andric Result.push_back(Symbol(I, L)); 21506c3fb27SDimitry Andric return Result; 21606c3fb27SDimitry Andric } 21706c3fb27SDimitry Andric llvm::StringRef Symbol::scope() const { 21806c3fb27SDimitry Andric return getMappingPerLang(Language)->SymbolNames[ID].scope(); 21906c3fb27SDimitry Andric } 22006c3fb27SDimitry Andric llvm::StringRef Symbol::name() const { 22106c3fb27SDimitry Andric return getMappingPerLang(Language)->SymbolNames[ID].name(); 22206c3fb27SDimitry Andric } 22306c3fb27SDimitry Andric llvm::StringRef Symbol::qualifiedName() const { 22406c3fb27SDimitry Andric return getMappingPerLang(Language)->SymbolNames[ID].qualifiedName(); 22506c3fb27SDimitry Andric } 22606c3fb27SDimitry Andric std::optional<Symbol> Symbol::named(llvm::StringRef Scope, llvm::StringRef Name, 22706c3fb27SDimitry Andric Lang L) { 22806c3fb27SDimitry Andric ensureInitialized(); 22906c3fb27SDimitry Andric 23006c3fb27SDimitry Andric if (NSSymbolMap *NSSymbols = 23106c3fb27SDimitry Andric getMappingPerLang(L)->NamespaceSymbols->lookup(Scope)) { 232bdd1243dSDimitry Andric auto It = NSSymbols->find(Name); 233bdd1243dSDimitry Andric if (It != NSSymbols->end()) 23406c3fb27SDimitry Andric return Symbol(It->second, L); 235bdd1243dSDimitry Andric } 236bdd1243dSDimitry Andric return std::nullopt; 237bdd1243dSDimitry Andric } 23806c3fb27SDimitry Andric std::optional<Header> Symbol::header() const { 23906c3fb27SDimitry Andric const auto& Headers = getMappingPerLang(Language)->SymbolHeaderIDs[ID]; 24006c3fb27SDimitry Andric if (Headers.empty()) 24106c3fb27SDimitry Andric return std::nullopt; 24206c3fb27SDimitry Andric return Header(Headers.front(), Language); 24306c3fb27SDimitry Andric } 244bdd1243dSDimitry Andric llvm::SmallVector<Header> Symbol::headers() const { 24506c3fb27SDimitry Andric llvm::SmallVector<Header> Results; 24606c3fb27SDimitry Andric for (auto HeaderID : getMappingPerLang(Language)->SymbolHeaderIDs[ID]) 24706c3fb27SDimitry Andric Results.emplace_back(Header(HeaderID, Language)); 24806c3fb27SDimitry Andric return Results; 249bdd1243dSDimitry Andric } 250bdd1243dSDimitry Andric 251bdd1243dSDimitry Andric Recognizer::Recognizer() { ensureInitialized(); } 252bdd1243dSDimitry Andric 25306c3fb27SDimitry Andric NSSymbolMap *Recognizer::namespaceSymbols(const DeclContext *DC, Lang L) { 25406c3fb27SDimitry Andric if (DC->isTranslationUnit()) // global scope. 25506c3fb27SDimitry Andric return getMappingPerLang(L)->NamespaceSymbols->lookup(""); 25606c3fb27SDimitry Andric 25706c3fb27SDimitry Andric auto It = NamespaceCache.find(DC); 258bdd1243dSDimitry Andric if (It != NamespaceCache.end()) 259bdd1243dSDimitry Andric return It->second; 26006c3fb27SDimitry Andric const NamespaceDecl *D = llvm::cast<NamespaceDecl>(DC); 261bdd1243dSDimitry Andric NSSymbolMap *Result = [&]() -> NSSymbolMap * { 26206c3fb27SDimitry Andric if (D->isAnonymousNamespace()) 263bdd1243dSDimitry Andric return nullptr; 264bdd1243dSDimitry Andric // Print the namespace and its parents ommitting inline scopes. 265bdd1243dSDimitry Andric std::string Scope; 266bdd1243dSDimitry Andric for (const auto *ND = D; ND; 267bdd1243dSDimitry Andric ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent())) 268bdd1243dSDimitry Andric if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace()) 269bdd1243dSDimitry Andric Scope = ND->getName().str() + "::" + Scope; 27006c3fb27SDimitry Andric return getMappingPerLang(L)->NamespaceSymbols->lookup(Scope); 271bdd1243dSDimitry Andric }(); 272bdd1243dSDimitry Andric NamespaceCache.try_emplace(D, Result); 273bdd1243dSDimitry Andric return Result; 274bdd1243dSDimitry Andric } 275bdd1243dSDimitry Andric 276bdd1243dSDimitry Andric std::optional<Symbol> Recognizer::operator()(const Decl *D) { 27706c3fb27SDimitry Andric Lang L; 2785f757f3fSDimitry Andric if (D->getLangOpts().CPlusPlus) 27906c3fb27SDimitry Andric L = Lang::CXX; 2805f757f3fSDimitry Andric else if (D->getLangOpts().C99) 28106c3fb27SDimitry Andric L = Lang::C; 2825f757f3fSDimitry Andric else 28306c3fb27SDimitry Andric return std::nullopt; // not a supported language. 28406c3fb27SDimitry Andric 285bdd1243dSDimitry Andric // If D is std::vector::iterator, `vector` is the outer symbol to look up. 286bdd1243dSDimitry Andric // We keep all the candidate DCs as some may turn out to be anon enums. 287bdd1243dSDimitry Andric // Do this resolution lazily as we may turn out not to have a std namespace. 288bdd1243dSDimitry Andric llvm::SmallVector<const DeclContext *> IntermediateDecl; 289bdd1243dSDimitry Andric const DeclContext *DC = D->getDeclContext(); 29006c3fb27SDimitry Andric if (!DC) // The passed D is a TranslationUnitDecl! 29106c3fb27SDimitry Andric return std::nullopt; 29206c3fb27SDimitry Andric while (!DC->isNamespace() && !DC->isTranslationUnit()) { 293bdd1243dSDimitry Andric if (NamedDecl::classofKind(DC->getDeclKind())) 294bdd1243dSDimitry Andric IntermediateDecl.push_back(DC); 295bdd1243dSDimitry Andric DC = DC->getParent(); 296bdd1243dSDimitry Andric } 29706c3fb27SDimitry Andric NSSymbolMap *Symbols = namespaceSymbols(DC, L); 298bdd1243dSDimitry Andric if (!Symbols) 299bdd1243dSDimitry Andric return std::nullopt; 300bdd1243dSDimitry Andric 301bdd1243dSDimitry Andric llvm::StringRef Name = [&]() -> llvm::StringRef { 302bdd1243dSDimitry Andric for (const auto *SymDC : llvm::reverse(IntermediateDecl)) { 303bdd1243dSDimitry Andric DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName(); 304bdd1243dSDimitry Andric if (const auto *II = N.getAsIdentifierInfo()) 305bdd1243dSDimitry Andric return II->getName(); 306bdd1243dSDimitry Andric if (!N.isEmpty()) 307bdd1243dSDimitry Andric return ""; // e.g. operator<: give up 308bdd1243dSDimitry Andric } 309bdd1243dSDimitry Andric if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) 310bdd1243dSDimitry Andric if (const auto *II = ND->getIdentifier()) 311bdd1243dSDimitry Andric return II->getName(); 312bdd1243dSDimitry Andric return ""; 313bdd1243dSDimitry Andric }(); 314bdd1243dSDimitry Andric if (Name.empty()) 315bdd1243dSDimitry Andric return std::nullopt; 316bdd1243dSDimitry Andric 317bdd1243dSDimitry Andric auto It = Symbols->find(Name); 318bdd1243dSDimitry Andric if (It == Symbols->end()) 319bdd1243dSDimitry Andric return std::nullopt; 32006c3fb27SDimitry Andric return Symbol(It->second, L); 321bdd1243dSDimitry Andric } 322bdd1243dSDimitry Andric 323bdd1243dSDimitry Andric } // namespace stdlib 324bdd1243dSDimitry Andric } // namespace tooling 325bdd1243dSDimitry Andric } // namespace clang 326