
Starting with 41e3919ded78d8870f7c95e9181c7f7e29aa3cc4 DiagnosticsEngine creation might perform IO. It was implicitly defaulting to getRealFileSystem. This patch makes it explicit by pushing the decision making to callers. It uses ambient VFS if one is available, and keeps using `getRealFileSystem` if there aren't any VFS.
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);
|
|
|
|
CreateInvocationOptions CIOpts;
|
|
CIOpts.VFS = llvm::vfs::getRealFileSystem();
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
|
|
CompilerInstance::createDiagnostics(*CIOpts.VFS,
|
|
new DiagnosticOptions());
|
|
CIOpts.Diags = Diags;
|
|
|
|
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()};
|
|
std::shared_ptr<CompilerInvocation> Invocation =
|
|
createInvocation(Args, CIOpts);
|
|
EXPECT_TRUE(Invocation);
|
|
|
|
CompilerInstance Instance;
|
|
Instance.setDiagnostics(Diags.get());
|
|
Instance.setInvocation(Invocation);
|
|
Instance.getFrontendOpts().OutputFile = CacheBMIPath;
|
|
GenerateReducedModuleInterfaceAction 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
|