//===- unittests/Serialization/ForceCheckFileInputTest.cpp - CI tests -----===// // // 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/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Serialization/ASTReader.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" using namespace llvm; using namespace clang; namespace { class ForceCheckFileInputTest : public ::testing::Test { void SetUp() override { EXPECT_FALSE(sys::fs::createUniqueDirectory("modules-test", TestDir)); } void TearDown() override { sys::fs::remove_directories(TestDir); } public: SmallString<256> TestDir; void addFile(StringRef Path, StringRef Contents) { EXPECT_FALSE(sys::path::is_absolute(Path)); SmallString<256> AbsPath(TestDir); sys::path::append(AbsPath, Path); EXPECT_FALSE( sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath))); std::error_code EC; llvm::raw_fd_ostream OS(AbsPath, EC); EXPECT_FALSE(EC); OS << Contents; } }; TEST_F(ForceCheckFileInputTest, ForceCheck) { addFile("a.cppm", R"cpp( export module a; export int aa = 43; )cpp"); std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str(); { CreateInvocationOptions CIOpts; CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); IntrusiveRefCntPtr Diags = CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions()); CIOpts.Diags = Diags; const char *Args[] = {"clang++", "-std=c++20", "--precompile", "-working-directory", TestDir.c_str(), "a.cppm"}; std::shared_ptr Invocation = createInvocation(Args, CIOpts); EXPECT_TRUE(Invocation); Invocation->getFrontendOpts().DisableFree = false; auto Buf = CIOpts.VFS->getBufferForFile("a.cppm"); EXPECT_TRUE(Buf); Invocation->getPreprocessorOpts().addRemappedFile("a.cppm", Buf->get()); Buf->release(); CompilerInstance Instance; Instance.setDiagnostics(Diags.get()); Instance.setInvocation(Invocation); Instance.getFrontendOpts().OutputFile = BMIPath; if (auto VFSWithRemapping = createVFSFromCompilerInvocation( Instance.getInvocation(), Instance.getDiagnostics(), CIOpts.VFS)) CIOpts.VFS = VFSWithRemapping; Instance.createFileManager(CIOpts.VFS); Instance.getHeaderSearchOpts().ValidateASTInputFilesContent = true; GenerateReducedModuleInterfaceAction Action; EXPECT_TRUE(Instance.ExecuteAction(Action)); EXPECT_FALSE(Diags->hasErrorOccurred()); } { CreateInvocationOptions CIOpts; CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); IntrusiveRefCntPtr Diags = CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions()); CIOpts.Diags = Diags; std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str(); const char *Args[] = { "clang++", "-std=c++20", "--precompile", "-working-directory", TestDir.c_str(), "a.cppm", "-o", BMIPath.c_str()}; std::shared_ptr Invocation = createInvocation(Args, CIOpts); EXPECT_TRUE(Invocation); Invocation->getFrontendOpts().DisableFree = false; CompilerInstance Clang; Clang.setInvocation(Invocation); Clang.setDiagnostics(Diags.get()); FileManager *FM = Clang.createFileManager(CIOpts.VFS); Clang.createSourceManager(*FM); EXPECT_TRUE(Clang.createTarget()); Clang.createPreprocessor(TU_Complete); Clang.getHeaderSearchOpts().ForceCheckCXX20ModulesInputFiles = true; Clang.getHeaderSearchOpts().ValidateASTInputFilesContent = true; Clang.createASTReader(); addFile("a.cppm", R"cpp( export module a; export int aa = 44; )cpp"); auto ReadResult = Clang.getASTReader()->ReadAST(BMIPath, serialization::MK_MainFile, SourceLocation(), ASTReader::ARR_None); // We shall be able to detect the content change here. EXPECT_NE(ReadResult, ASTReader::Success); } } } // anonymous namespace