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