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