xref: /llvm-project/clang/unittests/Tooling/StandardLibraryTest.cpp (revision 756c20561efa1e58bd7d2a6df1499997b6b52e23)
1 //===- unittest/Tooling/StandardLibrary.cpp -------------------------------===//
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 #include "clang/Tooling/Inclusions/StandardLibrary.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/DeclarationName.h"
13 #include "clang/Testing/TestAST.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/Casting.h"
16 #include "llvm/Support/ScopedPrinter.h"
17 
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 
21 using ::testing::Contains;
22 using ::testing::ElementsAre;
23 
24 namespace clang {
25 namespace tooling {
26 namespace {
27 
lookup(TestAST & AST,llvm::StringRef Name)28 const NamedDecl &lookup(TestAST &AST, llvm::StringRef Name) {
29   TranslationUnitDecl *TU = AST.context().getTranslationUnitDecl();
30   auto Result = TU->lookup(DeclarationName(&AST.context().Idents.get(Name)));
31   assert(!Result.empty() && "Lookup failed");
32   assert(Result.isSingleResult() && "Lookup returned multiple results");
33   return *Result.front();
34 }
35 
TEST(StdlibTest,All)36 TEST(StdlibTest, All) {
37   auto VectorH = stdlib::Header::named("<vector>");
38   EXPECT_TRUE(VectorH);
39   EXPECT_EQ(VectorH->name(), "<vector>");
40   EXPECT_EQ(llvm::to_string(*VectorH), "<vector>");
41   EXPECT_FALSE(stdlib::Header::named("HeadersTests.cpp"));
42 
43   EXPECT_TRUE(stdlib::Header::named("<vector>", stdlib::Lang::CXX));
44   EXPECT_FALSE(stdlib::Header::named("<vector>", stdlib::Lang::C));
45 
46   auto Vector = stdlib::Symbol::named("std::", "vector");
47   EXPECT_TRUE(Vector);
48   EXPECT_EQ(Vector->scope(), "std::");
49   EXPECT_EQ(Vector->name(), "vector");
50   EXPECT_EQ(Vector->qualifiedName(), "std::vector");
51   EXPECT_EQ(llvm::to_string(*Vector), "std::vector");
52   EXPECT_FALSE(stdlib::Symbol::named("std::", "dongle"));
53   EXPECT_FALSE(stdlib::Symbol::named("clang::", "ASTContext"));
54 
55   EXPECT_TRUE(stdlib::Symbol::named("std::", "vector", stdlib::Lang::CXX));
56   EXPECT_FALSE(stdlib::Symbol::named("std::", "vector", stdlib::Lang::C));
57 
58   EXPECT_EQ(Vector->header(), *VectorH);
59   EXPECT_THAT(Vector->headers(), ElementsAre(*VectorH));
60 
61   EXPECT_TRUE(stdlib::Symbol::named("std::", "get"));
62   EXPECT_FALSE(stdlib::Symbol::named("std::", "get")->header());
63 
64   EXPECT_THAT(stdlib::Symbol::named("std::", "basic_iostream")->headers(),
65               ElementsAre(stdlib::Header::named("<istream>"),
66                           stdlib::Header::named("<iostream>"),
67                           stdlib::Header::named("<iosfwd>")));
68   EXPECT_THAT(stdlib::Symbol::named("std::", "size_t")->headers(),
69               ElementsAre(stdlib::Header::named("<cstddef>"),
70                           stdlib::Header::named("<cstdlib>"),
71                           stdlib::Header::named("<cstring>"),
72                           stdlib::Header::named("<cwchar>"),
73                           stdlib::Header::named("<cuchar>"),
74                           stdlib::Header::named("<ctime>"),
75                           stdlib::Header::named("<cstdio>")));
76   EXPECT_EQ(stdlib::Symbol::named("std::", "size_t")->header(),
77             stdlib::Header::named("<cstddef>"));
78 
79   EXPECT_THAT(stdlib::Header::all(), Contains(*VectorH));
80   EXPECT_THAT(stdlib::Symbol::all(), Contains(*Vector));
81   EXPECT_TRUE(stdlib::Header::named("<stdint.h>", stdlib::Lang::CXX));
82   EXPECT_FALSE(stdlib::Header::named("<ios646.h>", stdlib::Lang::CXX));
83 }
84 
TEST(StdlibTest,Experimental)85 TEST(StdlibTest, Experimental) {
86   EXPECT_FALSE(
87       stdlib::Header::named("<experimental/filesystem>", stdlib::Lang::C));
88   EXPECT_TRUE(
89       stdlib::Header::named("<experimental/filesystem>", stdlib::Lang::CXX));
90 
91   auto Symbol = stdlib::Symbol::named("std::experimental::filesystem::",
92                                       "system_complete");
93   EXPECT_TRUE(Symbol);
94   EXPECT_EQ(Symbol->scope(), "std::experimental::filesystem::");
95   EXPECT_EQ(Symbol->name(), "system_complete");
96   EXPECT_EQ(Symbol->header(),
97             stdlib::Header::named("<experimental/filesystem>"));
98   EXPECT_EQ(Symbol->qualifiedName(),
99             "std::experimental::filesystem::system_complete");
100 }
101 
TEST(StdlibTest,CCompat)102 TEST(StdlibTest, CCompat) {
103   EXPECT_THAT(
104       stdlib::Symbol::named("", "int16_t", stdlib::Lang::CXX)->headers(),
105       ElementsAre(stdlib::Header::named("<cstdint>"),
106                   stdlib::Header::named("<stdint.h>")));
107   EXPECT_THAT(
108       stdlib::Symbol::named("std::", "int16_t", stdlib::Lang::CXX)->headers(),
109       ElementsAre(stdlib::Header::named("<cstdint>")));
110 
111   EXPECT_TRUE(stdlib::Header::named("<stdint.h>", stdlib::Lang::C));
112   EXPECT_THAT(
113       stdlib::Symbol::named("", "int16_t", stdlib::Lang::C)->headers(),
114       ElementsAre(stdlib::Header::named("<stdint.h>", stdlib::Lang::C)));
115   EXPECT_FALSE(stdlib::Symbol::named("std::", "int16_t", stdlib::Lang::C));
116 }
117 
TEST(StdlibTest,Recognizer)118 TEST(StdlibTest, Recognizer) {
119   TestAST AST(R"cpp(
120     namespace std {
121     inline namespace inl {
122 
123     template <typename>
124     struct vector { class nested {}; };
125 
126     class secret {};
127 
128     } // inl
129 
130     inline namespace __1 {
131       namespace chrono {
132         inline namespace chrono_inl {
133         class system_clock {};
134         } // chrono_inl
135       } // chrono
136     } // __1
137 
138     } // std
139 
140     // C Standard Library structure defined in <stdlib.h>
141     struct div_t {};
142 
143     class vector {};
144     std::vector<int> vec;
145     std::vector<int>::nested nest;
146     std::secret sec;
147     std::chrono::system_clock clock;
148 
149     div_t div;
150   )cpp");
151 
152   auto &VectorNonstd = lookup(AST, "vector");
153   auto *Vec = cast<VarDecl>(lookup(AST, "vec")).getType()->getAsCXXRecordDecl();
154   auto *Nest =
155       cast<VarDecl>(lookup(AST, "nest")).getType()->getAsCXXRecordDecl();
156   auto *Clock =
157       cast<VarDecl>(lookup(AST, "clock")).getType()->getAsCXXRecordDecl();
158   auto *Sec = cast<VarDecl>(lookup(AST, "sec")).getType()->getAsCXXRecordDecl();
159   auto *CDivT =
160       cast<VarDecl>(lookup(AST, "div")).getType()->getAsCXXRecordDecl();
161 
162   stdlib::Recognizer Recognizer;
163 
164   EXPECT_EQ(Recognizer(&VectorNonstd), std::nullopt);
165   EXPECT_EQ(Recognizer(Vec), stdlib::Symbol::named("std::", "vector"));
166   EXPECT_EQ(Recognizer(Vec),
167             stdlib::Symbol::named("std::", "vector", stdlib::Lang::CXX));
168   EXPECT_EQ(Recognizer(Nest), stdlib::Symbol::named("std::", "vector"));
169   EXPECT_EQ(Recognizer(Clock),
170             stdlib::Symbol::named("std::chrono::", "system_clock"));
171   auto DivT = stdlib::Symbol::named("", "div_t", stdlib::Lang::CXX);
172   EXPECT_TRUE(DivT);
173   EXPECT_EQ(Recognizer(CDivT), DivT);
174   EXPECT_EQ(Recognizer(Sec), std::nullopt);
175 }
176 
TEST(StdlibTest,RecognizerForC99)177 TEST(StdlibTest, RecognizerForC99) {
178   TestInputs Input("typedef char uint8_t;");
179   Input.Language = TestLanguage::Lang_C99;
180   TestAST AST(Input);
181 
182   auto &Uint8T = lookup(AST, "uint8_t");
183   stdlib::Recognizer Recognizer;
184   EXPECT_EQ(Recognizer(&Uint8T),
185             stdlib::Symbol::named("", "uint8_t", stdlib::Lang::C));
186 }
187 
TEST(StdlibTest,SpecialCMappings)188 TEST(StdlibTest, SpecialCMappings) {
189   TestInputs Input("typedef char size_t;");
190   Input.Language = TestLanguage::Lang_C99;
191   TestAST AST(Input);
192 
193   auto &SizeT = lookup(AST, "size_t");
194   stdlib::Recognizer Recognizer;
195   auto ActualSym = Recognizer(&SizeT);
196   assert(ActualSym);
197   EXPECT_EQ(ActualSym, stdlib::Symbol::named("", "size_t", stdlib::Lang::C));
198   EXPECT_EQ(ActualSym->header()->name(), "<stddef.h>");
199 }
200 
201 } // namespace
202 } // namespace tooling
203 } // namespace clang
204