1 //===--- StandardLibrary.h --------------------------------------*- 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 /// \file 10 /// Provides an interface for querying information about C and C++ Standard 11 /// Library headers and symbols. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_TOOLING_INCLUSIONS_STANDARDLIBRARY_H 16 #define LLVM_CLANG_TOOLING_INCLUSIONS_STANDARDLIBRARY_H 17 18 #include "llvm/ADT/DenseMap.h" 19 #include "llvm/ADT/Hashing.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <optional> 23 #include <string> 24 #include <vector> 25 26 namespace clang { 27 class Decl; 28 class NamespaceDecl; 29 class DeclContext; 30 namespace tooling { 31 namespace stdlib { 32 33 class Symbol; 34 enum class Lang { C = 0, CXX, LastValue = CXX }; 35 36 // A standard library header, such as <iostream> 37 // Lightweight class, in fact just an index into a table. 38 // C++ and C Library compatibility headers are considered different: e.g. 39 // "<cstdio>" and "<stdio.h>" (and their symbols) are treated differently. 40 class Header { 41 public: 42 static std::vector<Header> all(Lang L = Lang::CXX); 43 // Name should contain the angle brackets, e.g. "<vector>". 44 static std::optional<Header> named(llvm::StringRef Name, 45 Lang Language = Lang::CXX); 46 47 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Header &H) { 48 return OS << H.name(); 49 } 50 llvm::StringRef name() const; 51 52 private: 53 Header(unsigned ID, Lang Language) : ID(ID), Language(Language) {} 54 unsigned ID; 55 Lang Language; 56 57 friend Symbol; 58 friend llvm::DenseMapInfo<Header>; 59 friend bool operator==(const Header &L, const Header &R) { 60 return L.ID == R.ID; 61 } 62 }; 63 64 // A top-level standard library symbol, such as std::vector 65 // Lightweight class, in fact just an index into a table. 66 // C++ and C Standard Library symbols are considered distinct: e.g. std::printf 67 // and ::printf are not treated as the same symbol. 68 // The symbols do not contain macros right now, we don't have a reliable index 69 // for them. 70 class Symbol { 71 public: 72 static std::vector<Symbol> all(Lang L = Lang::CXX); 73 /// \p Scope should have the trailing "::", for example: 74 /// named("std::chrono::", "system_clock") 75 static std::optional<Symbol> 76 named(llvm::StringRef Scope, llvm::StringRef Name, Lang Language = Lang::CXX); 77 78 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) { 79 return OS << S.qualifiedName(); 80 } 81 llvm::StringRef scope() const; 82 llvm::StringRef name() const; 83 llvm::StringRef qualifiedName() const; 84 // The preferred header for this symbol (e.g. the suggested insertion). 85 std::optional<Header> header() const; 86 // Some symbols may be provided by multiple headers. 87 llvm::SmallVector<Header> headers() const; 88 89 private: 90 Symbol(unsigned ID, Lang Language) : ID(ID), Language(Language) {} 91 unsigned ID; 92 Lang Language; 93 94 friend class Recognizer; 95 friend llvm::DenseMapInfo<Symbol>; 96 friend bool operator==(const Symbol &L, const Symbol &R) { 97 return L.ID == R.ID; 98 } 99 }; 100 101 // A functor to find the stdlib::Symbol associated with a decl. 102 // 103 // For non-top-level decls (std::vector<int>::iterator), returns the top-level 104 // symbol (std::vector). 105 class Recognizer { 106 public: 107 Recognizer(); 108 std::optional<Symbol> operator()(const Decl *D); 109 110 private: 111 using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>; 112 NSSymbolMap *namespaceSymbols(const DeclContext *DC, Lang L); 113 llvm::DenseMap<const DeclContext *, NSSymbolMap *> NamespaceCache; 114 }; 115 116 } // namespace stdlib 117 } // namespace tooling 118 } // namespace clang 119 120 namespace llvm { 121 122 template <> struct DenseMapInfo<clang::tooling::stdlib::Header> { 123 static inline clang::tooling::stdlib::Header getEmptyKey() { 124 return clang::tooling::stdlib::Header(-1, 125 clang::tooling::stdlib::Lang::CXX); 126 } 127 static inline clang::tooling::stdlib::Header getTombstoneKey() { 128 return clang::tooling::stdlib::Header(-2, 129 clang::tooling::stdlib::Lang::CXX); 130 } 131 static unsigned getHashValue(const clang::tooling::stdlib::Header &H) { 132 return hash_value(H.ID); 133 } 134 static bool isEqual(const clang::tooling::stdlib::Header &LHS, 135 const clang::tooling::stdlib::Header &RHS) { 136 return LHS == RHS; 137 } 138 }; 139 140 template <> struct DenseMapInfo<clang::tooling::stdlib::Symbol> { 141 static inline clang::tooling::stdlib::Symbol getEmptyKey() { 142 return clang::tooling::stdlib::Symbol(-1, 143 clang::tooling::stdlib::Lang::CXX); 144 } 145 static inline clang::tooling::stdlib::Symbol getTombstoneKey() { 146 return clang::tooling::stdlib::Symbol(-2, 147 clang::tooling::stdlib::Lang::CXX); 148 } 149 static unsigned getHashValue(const clang::tooling::stdlib::Symbol &S) { 150 return hash_value(S.ID); 151 } 152 static bool isEqual(const clang::tooling::stdlib::Symbol &LHS, 153 const clang::tooling::stdlib::Symbol &RHS) { 154 return LHS == RHS; 155 } 156 }; 157 } // namespace llvm 158 159 #endif // LLVM_CLANG_TOOLING_INCLUSIONS_STANDARDLIBRARY_H 160