Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 63fd70a

Browse files
committed
[ASTUnit] Ensure we set the invocation before creating the FileManager
Ensure we preserve the FileSystemOptions set on the FileManager when re-creating it (as `ASTUnit::Reparse` will clear the currently set FileManager). rdar://110697657
1 parent 9aaaa9f commit 63fd70a

File tree

3 files changed

+118
-1
lines changed

3 files changed

+118
-1
lines changed

clang/lib/Frontend/ASTUnit.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
11451145
// Create the compiler instance to use for building the AST.
11461146
std::unique_ptr<CompilerInstance> Clang(
11471147
new CompilerInstance(std::move(PCHContainerOps)));
1148+
Clang->setInvocation(CCInvocation);
11481149

11491150
// Clean up on error, disengage it if the function returns successfully.
11501151
auto CleanOnError = llvm::make_scope_exit([&]() {
@@ -1171,7 +1172,6 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
11711172
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
11721173
CICleanup(Clang.get());
11731174

1174-
Clang->setInvocation(CCInvocation);
11751175
OriginalSourceFile =
11761176
std::string(Clang->getFrontendOpts().Inputs[0].getFile());
11771177

clang/unittests/Frontend/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_clang_unittest(FrontendTests
1313
CodeGenActionTest.cpp
1414
ParsedSourceLocationTest.cpp
1515
PCHPreambleTest.cpp
16+
ReparseWorkingDirTest.cpp
1617
OutputStreamTest.cpp
1718
TextDiagnosticTest.cpp
1819
UtilsTest.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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

Comments
 (0)