xref: /llvm-project/clang/unittests/Frontend/ReparseWorkingDirTest.cpp (revision df9a14d7bbf1180e4f1474254c9d7ed6bcb4ce55)
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