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