|
| 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(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. We use '//root/' to allow the path to be |
| 81 | + // valid on both Windows and Unix. We need the trailing slash for the path |
| 82 | + // to be treated as absolute. |
| 83 | + SmallString<16> WorkingDir; |
| 84 | + llvm::sys::path::append(WorkingDir, "//root", |
| 85 | + llvm::sys::path::get_separator()); |
| 86 | + setWorkingDirectory(WorkingDir); |
| 87 | + |
| 88 | + SmallString<32> Header; |
| 89 | + llvm::sys::path::append(Header, WorkingDir, "headers", "header.h"); |
| 90 | + |
| 91 | + SmallString<32> MainName; |
| 92 | + llvm::sys::path::append(MainName, WorkingDir, "main.cpp"); |
| 93 | + |
| 94 | + AddFile(MainName.str().str(), R"cpp( |
| 95 | +#include "header.h" |
| 96 | +int main() { return foo(); } |
| 97 | +)cpp"); |
| 98 | + AddFile(Header.str().str(), R"h( |
| 99 | +static int foo() { return 0; } |
| 100 | +)h"); |
| 101 | + |
| 102 | + // Parse the main file, ensuring we can include the header. |
| 103 | + std::unique_ptr<ASTUnit> AST(ParseAST(MainName.str())); |
| 104 | + ASSERT_TRUE(AST.get()); |
| 105 | + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); |
| 106 | + |
| 107 | + // Reparse and check that the working directory was preserved. |
| 108 | + ASSERT_TRUE(ReparseAST(AST)); |
| 109 | + |
| 110 | + const auto &FM = AST->getFileManager(); |
| 111 | + const auto &FS = FM.getVirtualFileSystem(); |
| 112 | + ASSERT_EQ(FM.getFileSystemOpts().WorkingDir, WorkingDir); |
| 113 | + ASSERT_EQ(*FS.getCurrentWorkingDirectory(), WorkingDir); |
| 114 | +} |
| 115 | + |
| 116 | +} // end anonymous namespace |
0 commit comments