160eb1da3SChuanqi Xu //== unittests/Sema/SemaNoloadLookupTest.cpp -------------------------========// 260eb1da3SChuanqi Xu // 360eb1da3SChuanqi Xu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 460eb1da3SChuanqi Xu // See https://llvm.org/LICENSE.txt for license information. 560eb1da3SChuanqi Xu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 660eb1da3SChuanqi Xu // 760eb1da3SChuanqi Xu //===----------------------------------------------------------------------===// 860eb1da3SChuanqi Xu 960eb1da3SChuanqi Xu #include "clang/AST/DeclLookups.h" 1060eb1da3SChuanqi Xu #include "clang/AST/DeclarationName.h" 1160eb1da3SChuanqi Xu #include "clang/ASTMatchers/ASTMatchFinder.h" 1260eb1da3SChuanqi Xu #include "clang/ASTMatchers/ASTMatchers.h" 1360eb1da3SChuanqi Xu #include "clang/Frontend/CompilerInstance.h" 1460eb1da3SChuanqi Xu #include "clang/Frontend/FrontendAction.h" 1560eb1da3SChuanqi Xu #include "clang/Frontend/FrontendActions.h" 1660eb1da3SChuanqi Xu #include "clang/Parse/ParseAST.h" 1760eb1da3SChuanqi Xu #include "clang/Sema/Lookup.h" 1860eb1da3SChuanqi Xu #include "clang/Sema/Sema.h" 1960eb1da3SChuanqi Xu #include "clang/Sema/SemaConsumer.h" 2060eb1da3SChuanqi Xu #include "clang/Tooling/Tooling.h" 2160eb1da3SChuanqi Xu #include "gtest/gtest.h" 2260eb1da3SChuanqi Xu 2360eb1da3SChuanqi Xu using namespace llvm; 2460eb1da3SChuanqi Xu using namespace clang; 2560eb1da3SChuanqi Xu using namespace clang::tooling; 2660eb1da3SChuanqi Xu 2760eb1da3SChuanqi Xu namespace { 2860eb1da3SChuanqi Xu 2960eb1da3SChuanqi Xu class NoloadLookupTest : public ::testing::Test { 3060eb1da3SChuanqi Xu void SetUp() override { 3160eb1da3SChuanqi Xu ASSERT_FALSE( 3260eb1da3SChuanqi Xu sys::fs::createUniqueDirectory("modules-no-comments-test", TestDir)); 3360eb1da3SChuanqi Xu } 3460eb1da3SChuanqi Xu 3560eb1da3SChuanqi Xu void TearDown() override { sys::fs::remove_directories(TestDir); } 3660eb1da3SChuanqi Xu 3760eb1da3SChuanqi Xu public: 3860eb1da3SChuanqi Xu SmallString<256> TestDir; 3960eb1da3SChuanqi Xu 4060eb1da3SChuanqi Xu void addFile(StringRef Path, StringRef Contents) { 4160eb1da3SChuanqi Xu ASSERT_FALSE(sys::path::is_absolute(Path)); 4260eb1da3SChuanqi Xu 4360eb1da3SChuanqi Xu SmallString<256> AbsPath(TestDir); 4460eb1da3SChuanqi Xu sys::path::append(AbsPath, Path); 4560eb1da3SChuanqi Xu 4660eb1da3SChuanqi Xu ASSERT_FALSE( 4760eb1da3SChuanqi Xu sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath))); 4860eb1da3SChuanqi Xu 4960eb1da3SChuanqi Xu std::error_code EC; 5060eb1da3SChuanqi Xu llvm::raw_fd_ostream OS(AbsPath, EC); 5160eb1da3SChuanqi Xu ASSERT_FALSE(EC); 5260eb1da3SChuanqi Xu OS << Contents; 5360eb1da3SChuanqi Xu } 5460eb1da3SChuanqi Xu 5560eb1da3SChuanqi Xu std::string GenerateModuleInterface(StringRef ModuleName, 5660eb1da3SChuanqi Xu StringRef Contents) { 5760eb1da3SChuanqi Xu std::string FileName = llvm::Twine(ModuleName + ".cppm").str(); 5860eb1da3SChuanqi Xu addFile(FileName, Contents); 5960eb1da3SChuanqi Xu 60a1153cd6SSylvestre Ledru CreateInvocationOptions CIOpts; 61*dc580c9cSJames Y Knight CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 62df9a14d7SKadir Cetinkaya IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 63df9a14d7SKadir Cetinkaya CompilerInstance::createDiagnostics(*CIOpts.VFS, 64df9a14d7SKadir Cetinkaya new DiagnosticOptions()); 6560eb1da3SChuanqi Xu CIOpts.Diags = Diags; 6660eb1da3SChuanqi Xu 6760eb1da3SChuanqi Xu std::string CacheBMIPath = 6860eb1da3SChuanqi Xu llvm::Twine(TestDir + "/" + ModuleName + ".pcm").str(); 6960eb1da3SChuanqi Xu std::string PrebuiltModulePath = 7060eb1da3SChuanqi Xu "-fprebuilt-module-path=" + TestDir.str().str(); 7160eb1da3SChuanqi Xu const char *Args[] = {"clang++", 7260eb1da3SChuanqi Xu "-std=c++20", 7360eb1da3SChuanqi Xu "--precompile", 7460eb1da3SChuanqi Xu PrebuiltModulePath.c_str(), 7560eb1da3SChuanqi Xu "-working-directory", 7660eb1da3SChuanqi Xu TestDir.c_str(), 7760eb1da3SChuanqi Xu "-I", 7860eb1da3SChuanqi Xu TestDir.c_str(), 79da00c60dSChuanqi Xu FileName.c_str()}; 8060eb1da3SChuanqi Xu std::shared_ptr<CompilerInvocation> Invocation = 8160eb1da3SChuanqi Xu createInvocation(Args, CIOpts); 8260eb1da3SChuanqi Xu EXPECT_TRUE(Invocation); 8360eb1da3SChuanqi Xu 8460eb1da3SChuanqi Xu CompilerInstance Instance; 8560eb1da3SChuanqi Xu Instance.setDiagnostics(Diags.get()); 8660eb1da3SChuanqi Xu Instance.setInvocation(Invocation); 87da00c60dSChuanqi Xu Instance.getFrontendOpts().OutputFile = CacheBMIPath; 88da00c60dSChuanqi Xu GenerateReducedModuleInterfaceAction Action; 8960eb1da3SChuanqi Xu EXPECT_TRUE(Instance.ExecuteAction(Action)); 9060eb1da3SChuanqi Xu EXPECT_FALSE(Diags->hasErrorOccurred()); 9160eb1da3SChuanqi Xu 9260eb1da3SChuanqi Xu return CacheBMIPath; 9360eb1da3SChuanqi Xu } 9460eb1da3SChuanqi Xu }; 9560eb1da3SChuanqi Xu 9660eb1da3SChuanqi Xu struct TrivialVisibleDeclConsumer : public VisibleDeclConsumer { 9760eb1da3SChuanqi Xu TrivialVisibleDeclConsumer() {} 9860eb1da3SChuanqi Xu void EnteredContext(DeclContext *Ctx) override {} 9960eb1da3SChuanqi Xu void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, 10060eb1da3SChuanqi Xu bool InBaseClass) override { 10160eb1da3SChuanqi Xu FoundNum++; 10260eb1da3SChuanqi Xu } 10360eb1da3SChuanqi Xu 10460eb1da3SChuanqi Xu int FoundNum = 0; 10560eb1da3SChuanqi Xu }; 10660eb1da3SChuanqi Xu 10760eb1da3SChuanqi Xu class NoloadLookupConsumer : public SemaConsumer { 10860eb1da3SChuanqi Xu public: 10960eb1da3SChuanqi Xu void InitializeSema(Sema &S) override { SemaPtr = &S; } 11060eb1da3SChuanqi Xu 11160eb1da3SChuanqi Xu bool HandleTopLevelDecl(DeclGroupRef D) override { 11260eb1da3SChuanqi Xu if (!D.isSingleDecl()) 11360eb1da3SChuanqi Xu return true; 11460eb1da3SChuanqi Xu 11560eb1da3SChuanqi Xu Decl *TD = D.getSingleDecl(); 11660eb1da3SChuanqi Xu 11760eb1da3SChuanqi Xu auto *ID = dyn_cast<ImportDecl>(TD); 11860eb1da3SChuanqi Xu if (!ID) 11960eb1da3SChuanqi Xu return true; 12060eb1da3SChuanqi Xu 1211c6c01fbSJustin Bogner clang::Module *M = ID->getImportedModule(); 12260eb1da3SChuanqi Xu assert(M); 12360eb1da3SChuanqi Xu if (M->Name != "R") 12460eb1da3SChuanqi Xu return true; 12560eb1da3SChuanqi Xu 12660eb1da3SChuanqi Xu auto *Std = SemaPtr->getStdNamespace(); 12760eb1da3SChuanqi Xu EXPECT_TRUE(Std); 12860eb1da3SChuanqi Xu TrivialVisibleDeclConsumer Consumer; 12960eb1da3SChuanqi Xu SemaPtr->LookupVisibleDecls(Std, Sema::LookupNameKind::LookupOrdinaryName, 13060eb1da3SChuanqi Xu Consumer, 13160eb1da3SChuanqi Xu /*IncludeGlobalScope=*/true, 13260eb1da3SChuanqi Xu /*IncludeDependentBases=*/false, 13360eb1da3SChuanqi Xu /*LoadExternal=*/false); 13460eb1da3SChuanqi Xu EXPECT_EQ(Consumer.FoundNum, 1); 13560eb1da3SChuanqi Xu return true; 13660eb1da3SChuanqi Xu } 13760eb1da3SChuanqi Xu 13860eb1da3SChuanqi Xu private: 13960eb1da3SChuanqi Xu Sema *SemaPtr = nullptr; 14060eb1da3SChuanqi Xu }; 14160eb1da3SChuanqi Xu 14260eb1da3SChuanqi Xu class NoloadLookupAction : public ASTFrontendAction { 14360eb1da3SChuanqi Xu std::unique_ptr<ASTConsumer> 14460eb1da3SChuanqi Xu CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override { 14560eb1da3SChuanqi Xu return std::make_unique<NoloadLookupConsumer>(); 14660eb1da3SChuanqi Xu } 14760eb1da3SChuanqi Xu }; 14860eb1da3SChuanqi Xu 14960eb1da3SChuanqi Xu TEST_F(NoloadLookupTest, NonModulesTest) { 15060eb1da3SChuanqi Xu GenerateModuleInterface("M", R"cpp( 15160eb1da3SChuanqi Xu module; 15260eb1da3SChuanqi Xu namespace std { 15360eb1da3SChuanqi Xu int What(); 15460eb1da3SChuanqi Xu 15560eb1da3SChuanqi Xu void bar(int x = What()) { 15660eb1da3SChuanqi Xu } 15760eb1da3SChuanqi Xu } 15860eb1da3SChuanqi Xu export module M; 15960eb1da3SChuanqi Xu export using std::bar; 16060eb1da3SChuanqi Xu )cpp"); 16160eb1da3SChuanqi Xu 16260eb1da3SChuanqi Xu GenerateModuleInterface("R", R"cpp( 16360eb1da3SChuanqi Xu module; 16460eb1da3SChuanqi Xu namespace std { 16560eb1da3SChuanqi Xu class Another; 16660eb1da3SChuanqi Xu int What(Another); 16760eb1da3SChuanqi Xu int What(); 16860eb1da3SChuanqi Xu } 16960eb1da3SChuanqi Xu export module R; 17060eb1da3SChuanqi Xu )cpp"); 17160eb1da3SChuanqi Xu 17260eb1da3SChuanqi Xu const char *test_file_contents = R"cpp( 17360eb1da3SChuanqi Xu import M; 17460eb1da3SChuanqi Xu namespace std { 17560eb1da3SChuanqi Xu void use() { 17660eb1da3SChuanqi Xu bar(); 17760eb1da3SChuanqi Xu } 17860eb1da3SChuanqi Xu } 17960eb1da3SChuanqi Xu import R; 18060eb1da3SChuanqi Xu )cpp"; 18160eb1da3SChuanqi Xu std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str(); 18260eb1da3SChuanqi Xu EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<NoloadLookupAction>(), 18360eb1da3SChuanqi Xu test_file_contents, 18460eb1da3SChuanqi Xu { 18560eb1da3SChuanqi Xu "-std=c++20", 18660eb1da3SChuanqi Xu DepArg.c_str(), 18760eb1da3SChuanqi Xu "-I", 18860eb1da3SChuanqi Xu TestDir.c_str(), 18960eb1da3SChuanqi Xu }, 19060eb1da3SChuanqi Xu "test.cpp")); 19160eb1da3SChuanqi Xu } 19260eb1da3SChuanqi Xu 19360eb1da3SChuanqi Xu } // namespace 194