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