xref: /llvm-project/clang/unittests/Sema/SemaNoloadLookupTest.cpp (revision dc580c9cf65d9bdad92e127325b50e712422379b)
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