1 //===- unittests/Serialization/ForceCheckFileInputTest.cpp - CI tests -----===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/ASTMatchers/ASTMatchFinder.h" 10 #include "clang/ASTMatchers/ASTMatchers.h" 11 #include "clang/Basic/FileManager.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/Frontend/CompilerInvocation.h" 14 #include "clang/Frontend/FrontendActions.h" 15 #include "clang/Frontend/Utils.h" 16 #include "clang/Lex/HeaderSearch.h" 17 #include "clang/Lex/PreprocessorOptions.h" 18 #include "clang/Serialization/ASTReader.h" 19 #include "clang/Tooling/Tooling.h" 20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/Support/FileSystem.h" 22 #include "llvm/Support/raw_ostream.h" 23 24 #include "gtest/gtest.h" 25 26 using namespace llvm; 27 using namespace clang; 28 29 namespace { 30 31 class ForceCheckFileInputTest : public ::testing::Test { 32 void SetUp() override { 33 EXPECT_FALSE(sys::fs::createUniqueDirectory("modules-test", TestDir)); 34 } 35 36 void TearDown() override { sys::fs::remove_directories(TestDir); } 37 38 public: 39 SmallString<256> TestDir; 40 41 void addFile(StringRef Path, StringRef Contents) { 42 EXPECT_FALSE(sys::path::is_absolute(Path)); 43 44 SmallString<256> AbsPath(TestDir); 45 sys::path::append(AbsPath, Path); 46 47 EXPECT_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 EXPECT_FALSE(EC); 53 OS << Contents; 54 } 55 }; 56 57 TEST_F(ForceCheckFileInputTest, ForceCheck) { 58 addFile("a.cppm", R"cpp( 59 export module a; 60 export int aa = 43; 61 )cpp"); 62 63 std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str(); 64 65 { 66 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 67 CompilerInstance::createDiagnostics(new DiagnosticOptions()); 68 CreateInvocationOptions CIOpts; 69 CIOpts.Diags = Diags; 70 CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 71 72 const char *Args[] = {"clang++", "-std=c++20", 73 "--precompile", "-working-directory", 74 TestDir.c_str(), "a.cppm"}; 75 std::shared_ptr<CompilerInvocation> Invocation = 76 createInvocation(Args, CIOpts); 77 EXPECT_TRUE(Invocation); 78 Invocation->getFrontendOpts().DisableFree = false; 79 80 auto Buf = CIOpts.VFS->getBufferForFile("a.cppm"); 81 EXPECT_TRUE(Buf); 82 83 Invocation->getPreprocessorOpts().addRemappedFile("a.cppm", Buf->get()); 84 85 Buf->release(); 86 87 CompilerInstance Instance; 88 Instance.setDiagnostics(Diags.get()); 89 Instance.setInvocation(Invocation); 90 91 Instance.getFrontendOpts().OutputFile = BMIPath; 92 93 if (auto VFSWithRemapping = createVFSFromCompilerInvocation( 94 Instance.getInvocation(), Instance.getDiagnostics(), CIOpts.VFS)) 95 CIOpts.VFS = VFSWithRemapping; 96 Instance.createFileManager(CIOpts.VFS); 97 98 Instance.getHeaderSearchOpts().ValidateASTInputFilesContent = true; 99 100 GenerateReducedModuleInterfaceAction Action; 101 EXPECT_TRUE(Instance.ExecuteAction(Action)); 102 EXPECT_FALSE(Diags->hasErrorOccurred()); 103 } 104 105 { 106 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 107 CompilerInstance::createDiagnostics(new DiagnosticOptions()); 108 CreateInvocationOptions CIOpts; 109 CIOpts.Diags = Diags; 110 CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 111 112 std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str(); 113 const char *Args[] = { 114 "clang++", "-std=c++20", "--precompile", "-working-directory", 115 TestDir.c_str(), "a.cppm", "-o", BMIPath.c_str()}; 116 std::shared_ptr<CompilerInvocation> Invocation = 117 createInvocation(Args, CIOpts); 118 EXPECT_TRUE(Invocation); 119 Invocation->getFrontendOpts().DisableFree = false; 120 121 CompilerInstance Clang; 122 123 Clang.setInvocation(Invocation); 124 Clang.setDiagnostics(Diags.get()); 125 FileManager *FM = Clang.createFileManager(CIOpts.VFS); 126 Clang.createSourceManager(*FM); 127 128 EXPECT_TRUE(Clang.createTarget()); 129 Clang.createPreprocessor(TU_Complete); 130 Clang.getHeaderSearchOpts().ForceCheckCXX20ModulesInputFiles = true; 131 Clang.getHeaderSearchOpts().ValidateASTInputFilesContent = true; 132 Clang.createASTReader(); 133 134 addFile("a.cppm", R"cpp( 135 export module a; 136 export int aa = 44; 137 )cpp"); 138 139 auto ReadResult = 140 Clang.getASTReader()->ReadAST(BMIPath, serialization::MK_MainFile, 141 SourceLocation(), ASTReader::ARR_None); 142 143 // We shall be able to detect the content change here. 144 EXPECT_NE(ReadResult, ASTReader::Success); 145 } 146 } 147 148 } // anonymous namespace 149