194 lines
5.5 KiB
C++
194 lines
5.5 KiB
C++
|
//== unittests/Sema/SemaNoloadLookupTest.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/AST/DeclLookups.h"
|
||
|
#include "clang/AST/DeclarationName.h"
|
||
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
||
|
#include "clang/Frontend/CompilerInstance.h"
|
||
|
#include "clang/Frontend/FrontendAction.h"
|
||
|
#include "clang/Frontend/FrontendActions.h"
|
||
|
#include "clang/Parse/ParseAST.h"
|
||
|
#include "clang/Sema/Lookup.h"
|
||
|
#include "clang/Sema/Sema.h"
|
||
|
#include "clang/Sema/SemaConsumer.h"
|
||
|
#include "clang/Tooling/Tooling.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
using namespace clang;
|
||
|
using namespace clang::tooling;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
class NoloadLookupTest : public ::testing::Test {
|
||
|
void SetUp() override {
|
||
|
ASSERT_FALSE(
|
||
|
sys::fs::createUniqueDirectory("modules-no-comments-test", TestDir));
|
||
|
}
|
||
|
|
||
|
void TearDown() override { sys::fs::remove_directories(TestDir); }
|
||
|
|
||
|
public:
|
||
|
SmallString<256> TestDir;
|
||
|
|
||
|
void addFile(StringRef Path, StringRef Contents) {
|
||
|
ASSERT_FALSE(sys::path::is_absolute(Path));
|
||
|
|
||
|
SmallString<256> AbsPath(TestDir);
|
||
|
sys::path::append(AbsPath, Path);
|
||
|
|
||
|
ASSERT_FALSE(
|
||
|
sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));
|
||
|
|
||
|
std::error_code EC;
|
||
|
llvm::raw_fd_ostream OS(AbsPath, EC);
|
||
|
ASSERT_FALSE(EC);
|
||
|
OS << Contents;
|
||
|
}
|
||
|
|
||
|
std::string GenerateModuleInterface(StringRef ModuleName,
|
||
|
StringRef Contents) {
|
||
|
std::string FileName = llvm::Twine(ModuleName + ".cppm").str();
|
||
|
addFile(FileName, Contents);
|
||
|
|
||
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
|
||
|
CompilerInstance::createDiagnostics(new DiagnosticOptions());
|
||
|
CreateInvocationOptions CIOpts;
|
||
|
CIOpts.Diags = Diags;
|
||
|
CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
|
||
|
|
||
|
std::string CacheBMIPath =
|
||
|
llvm::Twine(TestDir + "/" + ModuleName + " .pcm").str();
|
||
|
std::string PrebuiltModulePath =
|
||
|
"-fprebuilt-module-path=" + TestDir.str().str();
|
||
|
const char *Args[] = {"clang++",
|
||
|
"-std=c++20",
|
||
|
"--precompile",
|
||
|
PrebuiltModulePath.c_str(),
|
||
|
"-working-directory",
|
||
|
TestDir.c_str(),
|
||
|
"-I",
|
||
|
TestDir.c_str(),
|
||
|
FileName.c_str(),
|
||
|
"-o",
|
||
|
CacheBMIPath.c_str()};
|
||
|
std::shared_ptr<CompilerInvocation> Invocation =
|
||
|
createInvocation(Args, CIOpts);
|
||
|
EXPECT_TRUE(Invocation);
|
||
|
|
||
|
CompilerInstance Instance;
|
||
|
Instance.setDiagnostics(Diags.get());
|
||
|
Instance.setInvocation(Invocation);
|
||
|
GenerateModuleInterfaceAction Action;
|
||
|
EXPECT_TRUE(Instance.ExecuteAction(Action));
|
||
|
EXPECT_FALSE(Diags->hasErrorOccurred());
|
||
|
|
||
|
return CacheBMIPath;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct TrivialVisibleDeclConsumer : public VisibleDeclConsumer {
|
||
|
TrivialVisibleDeclConsumer() {}
|
||
|
void EnteredContext(DeclContext *Ctx) override {}
|
||
|
void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
|
||
|
bool InBaseClass) override {
|
||
|
FoundNum++;
|
||
|
}
|
||
|
|
||
|
int FoundNum = 0;
|
||
|
};
|
||
|
|
||
|
class NoloadLookupConsumer : public SemaConsumer {
|
||
|
public:
|
||
|
void InitializeSema(Sema &S) override { SemaPtr = &S; }
|
||
|
|
||
|
bool HandleTopLevelDecl(DeclGroupRef D) override {
|
||
|
if (!D.isSingleDecl())
|
||
|
return true;
|
||
|
|
||
|
Decl *TD = D.getSingleDecl();
|
||
|
|
||
|
auto *ID = dyn_cast<ImportDecl>(TD);
|
||
|
if (!ID)
|
||
|
return true;
|
||
|
|
||
|
clang::Module *M = ID->getImportedModule();
|
||
|
assert(M);
|
||
|
if (M->Name != "R")
|
||
|
return true;
|
||
|
|
||
|
auto *Std = SemaPtr->getStdNamespace();
|
||
|
EXPECT_TRUE(Std);
|
||
|
TrivialVisibleDeclConsumer Consumer;
|
||
|
SemaPtr->LookupVisibleDecls(Std, Sema::LookupNameKind::LookupOrdinaryName,
|
||
|
Consumer,
|
||
|
/*IncludeGlobalScope=*/true,
|
||
|
/*IncludeDependentBases=*/false,
|
||
|
/*LoadExternal=*/false);
|
||
|
EXPECT_EQ(Consumer.FoundNum, 1);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
Sema *SemaPtr = nullptr;
|
||
|
};
|
||
|
|
||
|
class NoloadLookupAction : public ASTFrontendAction {
|
||
|
std::unique_ptr<ASTConsumer>
|
||
|
CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override {
|
||
|
return std::make_unique<NoloadLookupConsumer>();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
TEST_F(NoloadLookupTest, NonModulesTest) {
|
||
|
GenerateModuleInterface("M", R"cpp(
|
||
|
module;
|
||
|
namespace std {
|
||
|
int What();
|
||
|
|
||
|
void bar(int x = What()) {
|
||
|
}
|
||
|
}
|
||
|
export module M;
|
||
|
export using std::bar;
|
||
|
)cpp");
|
||
|
|
||
|
GenerateModuleInterface("R", R"cpp(
|
||
|
module;
|
||
|
namespace std {
|
||
|
class Another;
|
||
|
int What(Another);
|
||
|
int What();
|
||
|
}
|
||
|
export module R;
|
||
|
)cpp");
|
||
|
|
||
|
const char *test_file_contents = R"cpp(
|
||
|
import M;
|
||
|
namespace std {
|
||
|
void use() {
|
||
|
bar();
|
||
|
}
|
||
|
}
|
||
|
import R;
|
||
|
)cpp";
|
||
|
std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str();
|
||
|
EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<NoloadLookupAction>(),
|
||
|
test_file_contents,
|
||
|
{
|
||
|
"-std=c++20",
|
||
|
DepArg.c_str(),
|
||
|
"-I",
|
||
|
TestDir.c_str(),
|
||
|
},
|
||
|
"test.cpp"));
|
||
|
}
|
||
|
|
||
|
} // namespace
|