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:
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:
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