|  | //===- unittest/Tooling/StandardLibrary.cpp -------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/Tooling/Inclusions/StandardLibrary.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/Decl.h" | 
|  | #include "clang/AST/DeclarationName.h" | 
|  | #include "clang/Testing/TestAST.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/Support/Casting.h" | 
|  | #include "llvm/Support/ScopedPrinter.h" | 
|  |  | 
|  | #include "gmock/gmock.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | using ::testing::Contains; | 
|  | using ::testing::ElementsAre; | 
|  |  | 
|  | namespace clang { | 
|  | namespace tooling { | 
|  | namespace { | 
|  |  | 
|  | const NamedDecl &lookup(TestAST &AST, llvm::StringRef Name) { | 
|  | TranslationUnitDecl *TU = AST.context().getTranslationUnitDecl(); | 
|  | auto Result = TU->lookup(DeclarationName(&AST.context().Idents.get(Name))); | 
|  | assert(!Result.empty() && "Lookup failed"); | 
|  | assert(Result.isSingleResult() && "Lookup returned multiple results"); | 
|  | return *Result.front(); | 
|  | } | 
|  |  | 
|  | TEST(StdlibTest, All) { | 
|  | auto VectorH = stdlib::Header::named("<vector>"); | 
|  | EXPECT_TRUE(VectorH); | 
|  | EXPECT_EQ(VectorH->name(), "<vector>"); | 
|  | EXPECT_EQ(llvm::to_string(*VectorH), "<vector>"); | 
|  | EXPECT_FALSE(stdlib::Header::named("HeadersTests.cpp")); | 
|  |  | 
|  | EXPECT_TRUE(stdlib::Header::named("<vector>", stdlib::Lang::CXX)); | 
|  | EXPECT_FALSE(stdlib::Header::named("<vector>", stdlib::Lang::C)); | 
|  |  | 
|  | auto Vector = stdlib::Symbol::named("std::", "vector"); | 
|  | EXPECT_TRUE(Vector); | 
|  | EXPECT_EQ(Vector->scope(), "std::"); | 
|  | EXPECT_EQ(Vector->name(), "vector"); | 
|  | EXPECT_EQ(Vector->qualifiedName(), "std::vector"); | 
|  | EXPECT_EQ(llvm::to_string(*Vector), "std::vector"); | 
|  | EXPECT_FALSE(stdlib::Symbol::named("std::", "dongle")); | 
|  | EXPECT_FALSE(stdlib::Symbol::named("clang::", "ASTContext")); | 
|  |  | 
|  | EXPECT_TRUE(stdlib::Symbol::named("std::", "vector", stdlib::Lang::CXX)); | 
|  | EXPECT_FALSE(stdlib::Symbol::named("std::", "vector", stdlib::Lang::C)); | 
|  |  | 
|  | EXPECT_EQ(Vector->header(), *VectorH); | 
|  | EXPECT_THAT(Vector->headers(), ElementsAre(*VectorH)); | 
|  |  | 
|  | EXPECT_TRUE(stdlib::Symbol::named("std::", "get")); | 
|  | EXPECT_FALSE(stdlib::Symbol::named("std::", "get")->header()); | 
|  |  | 
|  | EXPECT_THAT(stdlib::Symbol::named("std::", "basic_iostream")->headers(), | 
|  | ElementsAre(stdlib::Header::named("<istream>"), | 
|  | stdlib::Header::named("<iostream>"), | 
|  | stdlib::Header::named("<iosfwd>"))); | 
|  | EXPECT_THAT(stdlib::Symbol::named("std::", "size_t")->headers(), | 
|  | ElementsAre(stdlib::Header::named("<cstddef>"), | 
|  | stdlib::Header::named("<cstdlib>"), | 
|  | stdlib::Header::named("<cstring>"), | 
|  | stdlib::Header::named("<cwchar>"), | 
|  | stdlib::Header::named("<cuchar>"), | 
|  | stdlib::Header::named("<ctime>"), | 
|  | stdlib::Header::named("<cstdio>"))); | 
|  | EXPECT_EQ(stdlib::Symbol::named("std::", "size_t")->header(), | 
|  | stdlib::Header::named("<cstddef>")); | 
|  |  | 
|  | EXPECT_THAT(stdlib::Header::all(), Contains(*VectorH)); | 
|  | EXPECT_THAT(stdlib::Symbol::all(), Contains(*Vector)); | 
|  | EXPECT_TRUE(stdlib::Header::named("<stdint.h>", stdlib::Lang::CXX)); | 
|  | EXPECT_FALSE(stdlib::Header::named("<ios646.h>", stdlib::Lang::CXX)); | 
|  | } | 
|  |  | 
|  | TEST(StdlibTest, Experimental) { | 
|  | EXPECT_FALSE( | 
|  | stdlib::Header::named("<experimental/filesystem>", stdlib::Lang::C)); | 
|  | EXPECT_TRUE( | 
|  | stdlib::Header::named("<experimental/filesystem>", stdlib::Lang::CXX)); | 
|  |  | 
|  | auto Symbol = stdlib::Symbol::named("std::experimental::filesystem::", | 
|  | "system_complete"); | 
|  | EXPECT_TRUE(Symbol); | 
|  | EXPECT_EQ(Symbol->scope(), "std::experimental::filesystem::"); | 
|  | EXPECT_EQ(Symbol->name(), "system_complete"); | 
|  | EXPECT_EQ(Symbol->header(), | 
|  | stdlib::Header::named("<experimental/filesystem>")); | 
|  | EXPECT_EQ(Symbol->qualifiedName(), | 
|  | "std::experimental::filesystem::system_complete"); | 
|  | } | 
|  |  | 
|  | TEST(StdlibTest, CCompat) { | 
|  | EXPECT_THAT( | 
|  | stdlib::Symbol::named("", "int16_t", stdlib::Lang::CXX)->headers(), | 
|  | ElementsAre(stdlib::Header::named("<cstdint>"), | 
|  | stdlib::Header::named("<stdint.h>"))); | 
|  | EXPECT_THAT( | 
|  | stdlib::Symbol::named("std::", "int16_t", stdlib::Lang::CXX)->headers(), | 
|  | ElementsAre(stdlib::Header::named("<cstdint>"))); | 
|  |  | 
|  | EXPECT_TRUE(stdlib::Header::named("<stdint.h>", stdlib::Lang::C)); | 
|  | EXPECT_THAT( | 
|  | stdlib::Symbol::named("", "int16_t", stdlib::Lang::C)->headers(), | 
|  | ElementsAre(stdlib::Header::named("<stdint.h>", stdlib::Lang::C))); | 
|  | EXPECT_FALSE(stdlib::Symbol::named("std::", "int16_t", stdlib::Lang::C)); | 
|  | } | 
|  |  | 
|  | TEST(StdlibTest, Recognizer) { | 
|  | TestAST AST(R"cpp( | 
|  | namespace std { | 
|  | inline namespace inl { | 
|  |  | 
|  | template <typename> | 
|  | struct vector { class nested {}; }; | 
|  |  | 
|  | class secret {}; | 
|  |  | 
|  | } // inl | 
|  |  | 
|  | inline namespace __1 { | 
|  | namespace chrono { | 
|  | inline namespace chrono_inl { | 
|  | class system_clock {}; | 
|  | } // chrono_inl | 
|  | } // chrono | 
|  | } // __1 | 
|  |  | 
|  | } // std | 
|  |  | 
|  | // C Standard Library structure defined in <stdlib.h> | 
|  | struct div_t {}; | 
|  |  | 
|  | class vector {}; | 
|  | std::vector<int> vec; | 
|  | std::vector<int>::nested nest; | 
|  | std::secret sec; | 
|  | std::chrono::system_clock clock; | 
|  |  | 
|  | div_t div; | 
|  | )cpp"); | 
|  |  | 
|  | auto &VectorNonstd = lookup(AST, "vector"); | 
|  | auto *Vec = cast<VarDecl>(lookup(AST, "vec")).getType()->getAsCXXRecordDecl(); | 
|  | auto *Nest = | 
|  | cast<VarDecl>(lookup(AST, "nest")).getType()->getAsCXXRecordDecl(); | 
|  | auto *Clock = | 
|  | cast<VarDecl>(lookup(AST, "clock")).getType()->getAsCXXRecordDecl(); | 
|  | auto *Sec = cast<VarDecl>(lookup(AST, "sec")).getType()->getAsCXXRecordDecl(); | 
|  | auto *CDivT = | 
|  | cast<VarDecl>(lookup(AST, "div")).getType()->getAsCXXRecordDecl(); | 
|  |  | 
|  | stdlib::Recognizer Recognizer; | 
|  |  | 
|  | EXPECT_EQ(Recognizer(&VectorNonstd), std::nullopt); | 
|  | EXPECT_EQ(Recognizer(Vec), stdlib::Symbol::named("std::", "vector")); | 
|  | EXPECT_EQ(Recognizer(Vec), | 
|  | stdlib::Symbol::named("std::", "vector", stdlib::Lang::CXX)); | 
|  | EXPECT_EQ(Recognizer(Nest), stdlib::Symbol::named("std::", "vector")); | 
|  | EXPECT_EQ(Recognizer(Clock), | 
|  | stdlib::Symbol::named("std::chrono::", "system_clock")); | 
|  | auto DivT = stdlib::Symbol::named("", "div_t", stdlib::Lang::CXX); | 
|  | EXPECT_TRUE(DivT); | 
|  | EXPECT_EQ(Recognizer(CDivT), DivT); | 
|  | EXPECT_EQ(Recognizer(Sec), std::nullopt); | 
|  | } | 
|  |  | 
|  | TEST(StdlibTest, RecognizerForC99) { | 
|  | TestInputs Input("typedef char uint8_t;"); | 
|  | Input.Language = TestLanguage::Lang_C99; | 
|  | TestAST AST(Input); | 
|  |  | 
|  | auto &Uint8T = lookup(AST, "uint8_t"); | 
|  | stdlib::Recognizer Recognizer; | 
|  | EXPECT_EQ(Recognizer(&Uint8T), | 
|  | stdlib::Symbol::named("", "uint8_t", stdlib::Lang::C)); | 
|  | } | 
|  |  | 
|  | TEST(StdlibTest, SpecialCMappings) { | 
|  | TestInputs Input("typedef char size_t;"); | 
|  | Input.Language = TestLanguage::Lang_C99; | 
|  | TestAST AST(Input); | 
|  |  | 
|  | auto &SizeT = lookup(AST, "size_t"); | 
|  | stdlib::Recognizer Recognizer; | 
|  | auto ActualSym = Recognizer(&SizeT); | 
|  | assert(ActualSym); | 
|  | EXPECT_EQ(ActualSym, stdlib::Symbol::named("", "size_t", stdlib::Lang::C)); | 
|  | EXPECT_EQ(ActualSym->header()->name(), "<stddef.h>"); | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  | } // namespace tooling | 
|  | } // namespace clang |