194 lines · cpp
1//== unittests/Sema/SemaNoloadLookupTest.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/AST/DeclLookups.h"10#include "clang/AST/DeclarationName.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/ASTMatchers/ASTMatchers.h"13#include "clang/Driver/CreateInvocationFromArgs.h"14#include "clang/Frontend/CompilerInstance.h"15#include "clang/Frontend/FrontendAction.h"16#include "clang/Frontend/FrontendActions.h"17#include "clang/Parse/ParseAST.h"18#include "clang/Sema/Lookup.h"19#include "clang/Sema/Sema.h"20#include "clang/Sema/SemaConsumer.h"21#include "clang/Tooling/Tooling.h"22#include "gtest/gtest.h"23 24using namespace llvm;25using namespace clang;26using namespace clang::tooling;27 28namespace {29 30class NoloadLookupTest : public ::testing::Test {31 void SetUp() override {32 ASSERT_FALSE(33 sys::fs::createUniqueDirectory("modules-no-comments-test", TestDir));34 }35 36 void TearDown() override { sys::fs::remove_directories(TestDir); }37 38public:39 SmallString<256> TestDir;40 41 void addFile(StringRef Path, StringRef Contents) {42 ASSERT_FALSE(sys::path::is_absolute(Path));43 44 SmallString<256> AbsPath(TestDir);45 sys::path::append(AbsPath, Path);46 47 ASSERT_FALSE(48 sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));49 50 std::error_code EC;51 llvm::raw_fd_ostream OS(AbsPath, EC);52 ASSERT_FALSE(EC);53 OS << Contents;54 }55 56 std::string GenerateModuleInterface(StringRef ModuleName,57 StringRef Contents) {58 std::string FileName = llvm::Twine(ModuleName + ".cppm").str();59 addFile(FileName, Contents);60 61 CreateInvocationOptions CIOpts;62 CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();63 DiagnosticOptions DiagOpts;64 IntrusiveRefCntPtr<DiagnosticsEngine> Diags =65 CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);66 CIOpts.Diags = Diags;67 68 std::string CacheBMIPath =69 llvm::Twine(TestDir + "/" + ModuleName + ".pcm").str();70 std::string PrebuiltModulePath =71 "-fprebuilt-module-path=" + TestDir.str().str();72 const char *Args[] = {"clang++",73 "-std=c++20",74 "--precompile",75 PrebuiltModulePath.c_str(),76 "-working-directory",77 TestDir.c_str(),78 "-I",79 TestDir.c_str(),80 FileName.c_str()};81 std::shared_ptr<CompilerInvocation> Invocation =82 createInvocation(Args, CIOpts);83 EXPECT_TRUE(Invocation);84 85 CompilerInstance Instance(std::move(Invocation));86 Instance.setDiagnostics(Diags);87 Instance.getFrontendOpts().OutputFile = CacheBMIPath;88 GenerateReducedModuleInterfaceAction Action;89 EXPECT_TRUE(Instance.ExecuteAction(Action));90 EXPECT_FALSE(Diags->hasErrorOccurred());91 92 return CacheBMIPath;93 }94};95 96struct TrivialVisibleDeclConsumer : public VisibleDeclConsumer {97 TrivialVisibleDeclConsumer() {}98 void EnteredContext(DeclContext *Ctx) override {}99 void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,100 bool InBaseClass) override {101 FoundNum++;102 }103 104 int FoundNum = 0;105};106 107class NoloadLookupConsumer : public SemaConsumer {108public:109 void InitializeSema(Sema &S) override { SemaPtr = &S; }110 111 bool HandleTopLevelDecl(DeclGroupRef D) override {112 if (!D.isSingleDecl())113 return true;114 115 Decl *TD = D.getSingleDecl();116 117 auto *ID = dyn_cast<ImportDecl>(TD);118 if (!ID)119 return true;120 121 clang::Module *M = ID->getImportedModule();122 assert(M);123 if (M->Name != "R")124 return true;125 126 auto *Std = SemaPtr->getStdNamespace();127 EXPECT_TRUE(Std);128 TrivialVisibleDeclConsumer Consumer;129 SemaPtr->LookupVisibleDecls(Std, Sema::LookupNameKind::LookupOrdinaryName,130 Consumer,131 /*IncludeGlobalScope=*/true,132 /*IncludeDependentBases=*/false,133 /*LoadExternal=*/false);134 EXPECT_EQ(Consumer.FoundNum, 1);135 return true;136 }137 138private:139 Sema *SemaPtr = nullptr;140};141 142class NoloadLookupAction : public ASTFrontendAction {143 std::unique_ptr<ASTConsumer>144 CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override {145 return std::make_unique<NoloadLookupConsumer>();146 }147};148 149TEST_F(NoloadLookupTest, NonModulesTest) {150 GenerateModuleInterface("M", R"cpp(151module;152namespace std {153 int What();154 155 void bar(int x = What()) {156 }157}158export module M;159export using std::bar;160 )cpp");161 162 GenerateModuleInterface("R", R"cpp(163module;164namespace std {165 class Another;166 int What(Another);167 int What();168}169export module R;170 )cpp");171 172 const char *test_file_contents = R"cpp(173import M;174namespace std {175 void use() {176 bar();177 }178}179import R;180 )cpp";181 std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str();182 EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<NoloadLookupAction>(),183 test_file_contents,184 {185 "-std=c++20",186 DepArg.c_str(),187 "-I",188 TestDir.c_str(),189 },190 "test.cpp"));191}192 193} // namespace194