162e4c22cSHamish Knight //====-- unittests/Frontend/ReparseWorkingDirTest.cpp - FrontendAction tests =// 262e4c22cSHamish Knight // 362e4c22cSHamish Knight // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 462e4c22cSHamish Knight // See https://llvm.org/LICENSE.txt for license information. 562e4c22cSHamish Knight // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 662e4c22cSHamish Knight // 762e4c22cSHamish Knight //===----------------------------------------------------------------------===// 862e4c22cSHamish Knight 962e4c22cSHamish Knight #include "clang/Basic/Diagnostic.h" 1062e4c22cSHamish Knight #include "clang/Basic/FileManager.h" 1162e4c22cSHamish Knight #include "clang/Frontend/ASTUnit.h" 1262e4c22cSHamish Knight #include "clang/Frontend/CompilerInstance.h" 1362e4c22cSHamish Knight #include "clang/Frontend/CompilerInvocation.h" 1462e4c22cSHamish Knight #include "clang/Frontend/FrontendActions.h" 1562e4c22cSHamish Knight #include "clang/Frontend/FrontendOptions.h" 1662e4c22cSHamish Knight #include "clang/Lex/PreprocessorOptions.h" 1762e4c22cSHamish Knight #include "llvm/Support/FileSystem.h" 1862e4c22cSHamish Knight #include "llvm/Support/MemoryBuffer.h" 1962e4c22cSHamish Knight #include "llvm/Support/Path.h" 2062e4c22cSHamish Knight #include "gtest/gtest.h" 2162e4c22cSHamish Knight 2262e4c22cSHamish Knight using namespace llvm; 2362e4c22cSHamish Knight using namespace clang; 2462e4c22cSHamish Knight 2562e4c22cSHamish Knight namespace { 2662e4c22cSHamish Knight class ReparseWorkingDirTest : public ::testing::Test { 2762e4c22cSHamish Knight IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS; 2862e4c22cSHamish Knight std::shared_ptr<PCHContainerOperations> PCHContainerOpts; 2962e4c22cSHamish Knight 3062e4c22cSHamish Knight public: 3162e4c22cSHamish Knight void SetUp() override { VFS = new vfs::InMemoryFileSystem(); } 3262e4c22cSHamish Knight void TearDown() override {} 3362e4c22cSHamish Knight 3462e4c22cSHamish Knight void setWorkingDirectory(StringRef Path) { 3562e4c22cSHamish Knight VFS->setCurrentWorkingDirectory(Path); 3662e4c22cSHamish Knight } 3762e4c22cSHamish Knight 3862e4c22cSHamish Knight void AddFile(const std::string &Filename, const std::string &Contents) { 3962e4c22cSHamish Knight ::time_t now; 4062e4c22cSHamish Knight ::time(&now); 4162e4c22cSHamish Knight VFS->addFile(Filename, now, 4262e4c22cSHamish Knight MemoryBuffer::getMemBufferCopy(Contents, Filename)); 4362e4c22cSHamish Knight } 4462e4c22cSHamish Knight 4562e4c22cSHamish Knight std::unique_ptr<ASTUnit> ParseAST(StringRef EntryFile) { 4662e4c22cSHamish Knight PCHContainerOpts = std::make_shared<PCHContainerOperations>(); 4762e4c22cSHamish Knight auto CI = std::make_shared<CompilerInvocation>(); 4862e4c22cSHamish Knight CI->getFrontendOpts().Inputs.push_back(FrontendInputFile( 4962e4c22cSHamish Knight EntryFile, FrontendOptions::getInputKindForExtension( 5062e4c22cSHamish Knight llvm::sys::path::extension(EntryFile).substr(1)))); 5162e4c22cSHamish Knight 5262e4c22cSHamish Knight CI->getHeaderSearchOpts().AddPath("headers", 5362e4c22cSHamish Knight frontend::IncludeDirGroup::Quoted, 5462e4c22cSHamish Knight /*isFramework*/ false, 5562e4c22cSHamish Knight /*IgnoreSysRoot*/ false); 5662e4c22cSHamish Knight 5762e4c22cSHamish Knight CI->getFileSystemOpts().WorkingDir = *VFS->getCurrentWorkingDirectory(); 5862e4c22cSHamish Knight CI->getTargetOpts().Triple = "i386-unknown-linux-gnu"; 5962e4c22cSHamish Knight 6062e4c22cSHamish Knight IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 61*df9a14d7SKadir Cetinkaya CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions, 6262e4c22cSHamish Knight new DiagnosticConsumer)); 6362e4c22cSHamish Knight 6462e4c22cSHamish Knight FileManager *FileMgr = new FileManager(CI->getFileSystemOpts(), VFS); 6562e4c22cSHamish Knight 6662e4c22cSHamish Knight std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation( 6762e4c22cSHamish Knight CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None, 6862e4c22cSHamish Knight /*PrecompilePreambleAfterNParses=*/1); 6962e4c22cSHamish Knight return AST; 7062e4c22cSHamish Knight } 7162e4c22cSHamish Knight 7262e4c22cSHamish Knight bool ReparseAST(const std::unique_ptr<ASTUnit> &AST) { 7362e4c22cSHamish Knight bool reparseFailed = 7462e4c22cSHamish Knight AST->Reparse(PCHContainerOpts, /*RemappedFiles*/ {}, VFS); 7562e4c22cSHamish Knight return !reparseFailed; 7662e4c22cSHamish Knight } 7762e4c22cSHamish Knight }; 7862e4c22cSHamish Knight 7962e4c22cSHamish Knight TEST_F(ReparseWorkingDirTest, ReparseWorkingDir) { 8062e4c22cSHamish Knight // Setup the working directory path. 8162e4c22cSHamish Knight SmallString<16> WorkingDir; 8262e4c22cSHamish Knight #ifdef _WIN32 8362e4c22cSHamish Knight WorkingDir = "C:\\"; 8462e4c22cSHamish Knight #else 8562e4c22cSHamish Knight WorkingDir = "/"; 8662e4c22cSHamish Knight #endif 8762e4c22cSHamish Knight llvm::sys::path::append(WorkingDir, "root"); 8862e4c22cSHamish Knight setWorkingDirectory(WorkingDir); 8962e4c22cSHamish Knight 9062e4c22cSHamish Knight SmallString<32> Header; 9162e4c22cSHamish Knight llvm::sys::path::append(Header, WorkingDir, "headers", "header.h"); 9262e4c22cSHamish Knight 9362e4c22cSHamish Knight SmallString<32> MainName; 9462e4c22cSHamish Knight llvm::sys::path::append(MainName, WorkingDir, "main.cpp"); 9562e4c22cSHamish Knight 9662e4c22cSHamish Knight AddFile(MainName.str().str(), R"cpp( 9762e4c22cSHamish Knight #include "header.h" 9862e4c22cSHamish Knight int main() { return foo(); } 9962e4c22cSHamish Knight )cpp"); 10062e4c22cSHamish Knight AddFile(Header.str().str(), R"h( 10162e4c22cSHamish Knight static int foo() { return 0; } 10262e4c22cSHamish Knight )h"); 10362e4c22cSHamish Knight 10462e4c22cSHamish Knight // Parse the main file, ensuring we can include the header. 10562e4c22cSHamish Knight std::unique_ptr<ASTUnit> AST(ParseAST(MainName.str())); 10662e4c22cSHamish Knight ASSERT_TRUE(AST.get()); 10762e4c22cSHamish Knight ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); 10862e4c22cSHamish Knight 10962e4c22cSHamish Knight // Reparse and check that the working directory was preserved. 11062e4c22cSHamish Knight ASSERT_TRUE(ReparseAST(AST)); 11162e4c22cSHamish Knight 11262e4c22cSHamish Knight const auto &FM = AST->getFileManager(); 11362e4c22cSHamish Knight const auto &FS = FM.getVirtualFileSystem(); 11462e4c22cSHamish Knight ASSERT_EQ(FM.getFileSystemOpts().WorkingDir, WorkingDir); 11562e4c22cSHamish Knight ASSERT_EQ(*FS.getCurrentWorkingDirectory(), WorkingDir); 11662e4c22cSHamish Knight } 11762e4c22cSHamish Knight 11862e4c22cSHamish Knight } // end anonymous namespace 119