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 CreateInvocationOptions CIOpts; 67 CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 68 69 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 70 CompilerInstance::createDiagnostics(*CIOpts.VFS, 71 new DiagnosticOptions()); 72 CIOpts.Diags = Diags; 73 74 const char *Args[] = {"clang++", "-std=c++20", 75 "--precompile", "-working-directory", 76 TestDir.c_str(), "a.cppm"}; 77 std::shared_ptr<CompilerInvocation> Invocation = 78 createInvocation(Args, CIOpts); 79 EXPECT_TRUE(Invocation); 80 Invocation->getFrontendOpts().DisableFree = false; 81 82 auto Buf = CIOpts.VFS->getBufferForFile("a.cppm"); 83 EXPECT_TRUE(Buf); 84 85 Invocation->getPreprocessorOpts().addRemappedFile("a.cppm", Buf->get()); 86 87 Buf->release(); 88 89 CompilerInstance Instance; 90 Instance.setDiagnostics(Diags.get()); 91 Instance.setInvocation(Invocation); 92 93 Instance.getFrontendOpts().OutputFile = BMIPath; 94 95 if (auto VFSWithRemapping = createVFSFromCompilerInvocation( 96 Instance.getInvocation(), Instance.getDiagnostics(), CIOpts.VFS)) 97 CIOpts.VFS = VFSWithRemapping; 98 Instance.createFileManager(CIOpts.VFS); 99 100 Instance.getHeaderSearchOpts().ValidateASTInputFilesContent = true; 101 102 GenerateReducedModuleInterfaceAction Action; 103 EXPECT_TRUE(Instance.ExecuteAction(Action)); 104 EXPECT_FALSE(Diags->hasErrorOccurred()); 105 } 106 107 { 108 CreateInvocationOptions CIOpts; 109 CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 110 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 111 CompilerInstance::createDiagnostics(*CIOpts.VFS, 112 new DiagnosticOptions()); 113 CIOpts.Diags = Diags; 114 115 std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str(); 116 const char *Args[] = { 117 "clang++", "-std=c++20", "--precompile", "-working-directory", 118 TestDir.c_str(), "a.cppm", "-o", BMIPath.c_str()}; 119 std::shared_ptr<CompilerInvocation> Invocation = 120 createInvocation(Args, CIOpts); 121 EXPECT_TRUE(Invocation); 122 Invocation->getFrontendOpts().DisableFree = false; 123 124 CompilerInstance Clang; 125 126 Clang.setInvocation(Invocation); 127 Clang.setDiagnostics(Diags.get()); 128 FileManager *FM = Clang.createFileManager(CIOpts.VFS); 129 Clang.createSourceManager(*FM); 130 131 EXPECT_TRUE(Clang.createTarget()); 132 Clang.createPreprocessor(TU_Complete); 133 Clang.getHeaderSearchOpts().ForceCheckCXX20ModulesInputFiles = true; 134 Clang.getHeaderSearchOpts().ValidateASTInputFilesContent = true; 135 Clang.createASTReader(); 136 137 addFile("a.cppm", R"cpp( 138 export module a; 139 export int aa = 44; 140 )cpp"); 141 142 auto ReadResult = 143 Clang.getASTReader()->ReadAST(BMIPath, serialization::MK_MainFile, 144 SourceLocation(), ASTReader::ARR_None); 145 146 // We shall be able to detect the content change here. 147 EXPECT_NE(ReadResult, ASTReader::Success); 148 } 149 } 150 151 } // anonymous namespace 152