1 //====-- unittests/Frontend/ReparseWorkingDirTest.cpp - FrontendAction 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/Basic/Diagnostic.h" 10 #include "clang/Basic/FileManager.h" 11 #include "clang/Frontend/ASTUnit.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/Frontend/CompilerInvocation.h" 14 #include "clang/Frontend/FrontendActions.h" 15 #include "clang/Frontend/FrontendOptions.h" 16 #include "clang/Lex/PreprocessorOptions.h" 17 #include "llvm/Support/FileSystem.h" 18 #include "llvm/Support/MemoryBuffer.h" 19 #include "llvm/Support/Path.h" 20 #include "gtest/gtest.h" 21 22 using namespace llvm; 23 using namespace clang; 24 25 namespace { 26 class ReparseWorkingDirTest : public ::testing::Test { 27 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS; 28 std::shared_ptr<PCHContainerOperations> PCHContainerOpts; 29 30 public: 31 void SetUp() override { VFS = new vfs::InMemoryFileSystem(); } 32 void TearDown() override {} 33 34 void setWorkingDirectory(StringRef Path) { 35 VFS->setCurrentWorkingDirectory(Path); 36 } 37 38 void AddFile(const std::string &Filename, const std::string &Contents) { 39 ::time_t now; 40 ::time(&now); 41 VFS->addFile(Filename, now, 42 MemoryBuffer::getMemBufferCopy(Contents, Filename)); 43 } 44 45 std::unique_ptr<ASTUnit> ParseAST(StringRef EntryFile) { 46 PCHContainerOpts = std::make_shared<PCHContainerOperations>(); 47 auto CI = std::make_shared<CompilerInvocation>(); 48 CI->getFrontendOpts().Inputs.push_back(FrontendInputFile( 49 EntryFile, FrontendOptions::getInputKindForExtension( 50 llvm::sys::path::extension(EntryFile).substr(1)))); 51 52 CI->getHeaderSearchOpts().AddPath("headers", 53 frontend::IncludeDirGroup::Quoted, 54 /*isFramework*/ false, 55 /*IgnoreSysRoot*/ false); 56 57 CI->getFileSystemOpts().WorkingDir = *VFS->getCurrentWorkingDirectory(); 58 CI->getTargetOpts().Triple = "i386-unknown-linux-gnu"; 59 60 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 61 CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions, 62 new DiagnosticConsumer)); 63 64 FileManager *FileMgr = new FileManager(CI->getFileSystemOpts(), VFS); 65 66 std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation( 67 CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None, 68 /*PrecompilePreambleAfterNParses=*/1); 69 return AST; 70 } 71 72 bool ReparseAST(const std::unique_ptr<ASTUnit> &AST) { 73 bool reparseFailed = 74 AST->Reparse(PCHContainerOpts, /*RemappedFiles*/ {}, VFS); 75 return !reparseFailed; 76 } 77 }; 78 79 TEST_F(ReparseWorkingDirTest, ReparseWorkingDir) { 80 // Setup the working directory path. 81 SmallString<16> WorkingDir; 82 #ifdef _WIN32 83 WorkingDir = "C:\\"; 84 #else 85 WorkingDir = "/"; 86 #endif 87 llvm::sys::path::append(WorkingDir, "root"); 88 setWorkingDirectory(WorkingDir); 89 90 SmallString<32> Header; 91 llvm::sys::path::append(Header, WorkingDir, "headers", "header.h"); 92 93 SmallString<32> MainName; 94 llvm::sys::path::append(MainName, WorkingDir, "main.cpp"); 95 96 AddFile(MainName.str().str(), R"cpp( 97 #include "header.h" 98 int main() { return foo(); } 99 )cpp"); 100 AddFile(Header.str().str(), R"h( 101 static int foo() { return 0; } 102 )h"); 103 104 // Parse the main file, ensuring we can include the header. 105 std::unique_ptr<ASTUnit> AST(ParseAST(MainName.str())); 106 ASSERT_TRUE(AST.get()); 107 ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); 108 109 // Reparse and check that the working directory was preserved. 110 ASSERT_TRUE(ReparseAST(AST)); 111 112 const auto &FM = AST->getFileManager(); 113 const auto &FS = FM.getVirtualFileSystem(); 114 ASSERT_EQ(FM.getFileSystemOpts().WorkingDir, WorkingDir); 115 ASSERT_EQ(*FS.getCurrentWorkingDirectory(), WorkingDir); 116 } 117 118 } // end anonymous namespace 119