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
22using namespace llvm;
23using namespace clang;
24
25namespace {
26class ReparseWorkingDirTest : public ::testing::Test {
27 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS;
28 std::shared_ptr<PCHContainerOperations> PCHContainerOpts;
29
30public:
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(timer: &now);
41 VFS->addFile(Path: Filename, ModificationTime: now,
42 Buffer: MemoryBuffer::getMemBufferCopy(InputData: Contents, BufferName: 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(Elt: FrontendInputFile(
49 EntryFile, FrontendOptions::getInputKindForExtension(
50 Extension: llvm::sys::path::extension(path: EntryFile).substr(Start: 1))));
51
52 CI->getHeaderSearchOpts().AddPath(Path: "headers",
53 Group: frontend::IncludeDirGroup::Quoted,
54 /*isFramework*/ 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(Opts: new DiagnosticOptions,
62 Client: new DiagnosticConsumer));
63
64 FileManager *FileMgr = new FileManager(CI->getFileSystemOpts(), VFS);
65
66 std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
67 CI, PCHContainerOps: PCHContainerOpts, Diags, FileMgr, OnlyLocalDecls: false, CaptureDiagnostics: 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(PCHContainerOps: PCHContainerOpts, /*RemappedFiles*/ {}, VFS);
75 return !reparseFailed;
76 }
77};
78
79TEST_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(path&: WorkingDir, a: "root");
88 setWorkingDirectory(WorkingDir);
89
90 SmallString<32> Header;
91 llvm::sys::path::append(path&: Header, a: WorkingDir, b: "headers", c: "header.h");
92
93 SmallString<32> MainName;
94 llvm::sys::path::append(path&: MainName, a: WorkingDir, b: "main.cpp");
95
96 AddFile(Filename: MainName.str().str(), Contents: R"cpp(
97#include "header.h"
98int main() { return foo(); }
99)cpp");
100 AddFile(Filename: Header.str().str(), Contents: R"h(
101static 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(EntryFile: 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

source code of clang/unittests/Frontend/ReparseWorkingDirTest.cpp