xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp (revision be092bcde96bdcfde9013d60e442cca023bfbd1b)
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 "clang/AST/Decl.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  static int initialize() {
27    unsigned SymCount = 0;
28  #define SYMBOL(Name, NS, Header) ++SymCount;
29  #include "clang/Tooling/Inclusions/CSymbolMap.inc"
30  #include "clang/Tooling/Inclusions/StdSymbolMap.inc"
31  #undef SYMBOL
32    SymbolNames = new std::remove_reference_t<decltype(*SymbolNames)>[SymCount];
33    SymbolHeaderIDs =
34        new std::remove_reference_t<decltype(*SymbolHeaderIDs)>[SymCount];
35    NamespaceSymbols = new std::remove_reference_t<decltype(*NamespaceSymbols)>;
36    HeaderIDs = new std::remove_reference_t<decltype(*HeaderIDs)>;
37  
38    auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & {
39      auto R = NamespaceSymbols->try_emplace(NS, nullptr);
40      if (R.second)
41        R.first->second = new NSSymbolMap();
42      return *R.first->second;
43    };
44  
45    auto AddHeader = [&](llvm::StringRef Header) -> unsigned {
46      return HeaderIDs->try_emplace(Header, HeaderIDs->size()).first->second;
47    };
48  
49    auto Add = [&, SymIndex(0)](llvm::StringRef Name, llvm::StringRef NS,
50                                llvm::StringRef HeaderName) mutable {
51      if (NS == "None")
52        NS = "";
53  
54      SymbolNames[SymIndex] = {NS, Name};
55      SymbolHeaderIDs[SymIndex] = AddHeader(HeaderName);
56  
57      NSSymbolMap &NSSymbols = AddNS(NS);
58      NSSymbols.try_emplace(Name, SymIndex);
59  
60      ++SymIndex;
61    };
62  #define SYMBOL(Name, NS, Header) Add(#Name, #NS, #Header);
63  #include "clang/Tooling/Inclusions/CSymbolMap.inc"
64  #include "clang/Tooling/Inclusions/StdSymbolMap.inc"
65  #undef SYMBOL
66  
67    HeaderNames = new llvm::StringRef[HeaderIDs->size()];
68    for (const auto &E : *HeaderIDs)
69      HeaderNames[E.second] = E.first;
70  
71    return 0;
72  }
73  
74  static void ensureInitialized() {
75    static int Dummy = initialize();
76    (void)Dummy;
77  }
78  
79  std::optional<Header> Header::named(llvm::StringRef Name) {
80    ensureInitialized();
81    auto It = HeaderIDs->find(Name);
82    if (It == HeaderIDs->end())
83      return std::nullopt;
84    return Header(It->second);
85  }
86  llvm::StringRef Header::name() const { return HeaderNames[ID]; }
87  llvm::StringRef Symbol::scope() const { return SymbolNames[ID].first; }
88  llvm::StringRef Symbol::name() const { return SymbolNames[ID].second; }
89  std::optional<Symbol> Symbol::named(llvm::StringRef Scope,
90                                       llvm::StringRef Name) {
91    ensureInitialized();
92    if (NSSymbolMap *NSSymbols = NamespaceSymbols->lookup(Scope)) {
93      auto It = NSSymbols->find(Name);
94      if (It != NSSymbols->end())
95        return Symbol(It->second);
96    }
97    return std::nullopt;
98  }
99  Header Symbol::header() const { return Header(SymbolHeaderIDs[ID]); }
100  llvm::SmallVector<Header> Symbol::headers() const {
101    return {header()}; // FIXME: multiple in case of ambiguity
102  }
103  
104  Recognizer::Recognizer() { ensureInitialized(); }
105  
106  NSSymbolMap *Recognizer::namespaceSymbols(const NamespaceDecl *D) {
107    auto It = NamespaceCache.find(D);
108    if (It != NamespaceCache.end())
109      return It->second;
110  
111    NSSymbolMap *Result = [&]() -> NSSymbolMap * {
112      if (D && D->isAnonymousNamespace())
113        return nullptr;
114      // Print the namespace and its parents ommitting inline scopes.
115      std::string Scope;
116      for (const auto *ND = D; ND;
117           ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent()))
118        if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace())
119          Scope = ND->getName().str() + "::" + Scope;
120      return NamespaceSymbols->lookup(Scope);
121    }();
122    NamespaceCache.try_emplace(D, Result);
123    return Result;
124  }
125  
126  std::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    llvm::SmallVector<const DeclContext *> IntermediateDecl;
131    const DeclContext *DC = D->getDeclContext();
132    while (DC && !DC->isNamespace()) {
133      if (NamedDecl::classofKind(DC->getDeclKind()))
134        IntermediateDecl.push_back(DC);
135      DC = DC->getParent();
136    }
137    NSSymbolMap *Symbols = namespaceSymbols(cast_or_null<NamespaceDecl>(DC));
138    if (!Symbols)
139      return std::nullopt;
140  
141    llvm::StringRef Name = [&]() -> llvm::StringRef {
142      for (const auto *SymDC : llvm::reverse(IntermediateDecl)) {
143        DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName();
144        if (const auto *II = N.getAsIdentifierInfo())
145          return II->getName();
146        if (!N.isEmpty())
147          return ""; // e.g. operator<: give up
148      }
149      if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
150        if (const auto *II = ND->getIdentifier())
151          return II->getName();
152      return "";
153    }();
154    if (Name.empty())
155      return std::nullopt;
156  
157    auto It = Symbols->find(Name);
158    if (It == Symbols->end())
159      return std::nullopt;
160    return Symbol(It->second);
161  }
162  
163  } // namespace stdlib
164  } // namespace tooling
165  } // namespace clang
166