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