Skip to content

Commit e536f0b

Browse files
authored
Merge pull request #5113 from bnbarham/cherry-fm
[stable/20220421] Cherry-pick FileManager and FileEntry updates
2 parents 2a2fa8e + 3203f9c commit e536f0b

File tree

8 files changed

+116
-57
lines changed

8 files changed

+116
-57
lines changed

clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "clang/Tooling/ReplacementsYaml.h"
2525
#include "llvm/ADT/ArrayRef.h"
2626
#include "llvm/ADT/Optional.h"
27+
#include "llvm/ADT/StringSet.h"
2728
#include "llvm/Support/FileSystem.h"
2829
#include "llvm/Support/MemoryBuffer.h"
2930
#include "llvm/Support/Path.h"
@@ -140,7 +141,7 @@ std::error_code collectReplacementsFromDirectory(
140141
static llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
141142
groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs,
142143
const clang::SourceManager &SM) {
143-
std::set<StringRef> Warned;
144+
llvm::StringSet<> Warned;
144145
llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
145146
GroupedReplacements;
146147

@@ -156,11 +157,15 @@ groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs,
156157
const tooling::TranslationUnitDiagnostics *SourceTU,
157158
const llvm::Optional<std::string> BuildDir) {
158159
// Use the file manager to deduplicate paths. FileEntries are
159-
// automatically canonicalized.
160-
auto PrevWorkingDir = SM.getFileManager().getFileSystemOpts().WorkingDir;
160+
// automatically canonicalized. Since relative paths can come from different
161+
// build directories, make them absolute immediately.
162+
SmallString<128> Path = R.getFilePath();
161163
if (BuildDir)
162-
SM.getFileManager().getFileSystemOpts().WorkingDir = std::move(*BuildDir);
163-
if (auto Entry = SM.getFileManager().getFile(R.getFilePath())) {
164+
llvm::sys::fs::make_absolute(*BuildDir, Path);
165+
else
166+
SM.getFileManager().makeAbsolutePath(Path);
167+
168+
if (auto Entry = SM.getFileManager().getFile(Path)) {
164169
if (SourceTU) {
165170
auto &Replaces = DiagReplacements[*Entry];
166171
auto It = Replaces.find(R);
@@ -171,11 +176,10 @@ groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs,
171176
return;
172177
}
173178
GroupedReplacements[*Entry].push_back(R);
174-
} else if (Warned.insert(R.getFilePath()).second) {
179+
} else if (Warned.insert(Path).second) {
175180
errs() << "Described file '" << R.getFilePath()
176181
<< "' doesn't exist. Ignoring...\n";
177182
}
178-
SM.getFileManager().getFileSystemOpts().WorkingDir = PrevWorkingDir;
179183
};
180184

181185
for (const auto &TU : TUs)

clang/include/clang/Basic/FileEntry.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,21 @@ class FileEntry;
5959
/// accessed by the FileManager's client.
6060
class FileEntryRef {
6161
public:
62-
StringRef getName() const { return ME->first(); }
62+
/// The name of this FileEntry. If a VFS uses 'use-external-name', this is
63+
/// the redirected name. See getRequestedName().
64+
StringRef getName() const { return getBaseMapEntry().first(); }
65+
66+
/// The name of this FileEntry, as originally requested without applying any
67+
/// remappings for VFS 'use-external-name'.
68+
///
69+
/// FIXME: this should be the semantics of getName(). See comment in
70+
/// FileManager::getFileRef().
71+
StringRef getNameAsRequested() const { return ME->first(); }
72+
6373
const FileEntry &getFileEntry() const {
64-
return *ME->second->V.get<FileEntry *>();
74+
return *getBaseMapEntry().second->V.get<FileEntry *>();
6575
}
66-
DirectoryEntryRef getDir() const { return *ME->second->Dir; }
76+
DirectoryEntryRef getDir() const { return *getBaseMapEntry().second->Dir; }
6777

6878
inline off_t getSize() const;
6979
inline unsigned getUID() const;
@@ -150,13 +160,20 @@ class FileEntryRef {
150160
explicit FileEntryRef(const MapEntry &ME) : ME(&ME) {
151161
assert(ME.second && "Expected payload");
152162
assert(ME.second->V && "Expected non-null");
153-
assert(ME.second->V.is<FileEntry *>() && "Expected FileEntry");
154163
}
155164

156165
/// Expose the underlying MapEntry to simplify packing in a PointerIntPair or
157166
/// PointerUnion and allow construction in Optional.
158167
const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; }
159168

169+
/// Retrieve the base MapEntry after redirects.
170+
const MapEntry &getBaseMapEntry() const {
171+
const MapEntry *ME = this->ME;
172+
while (const void *Next = ME->second->V.dyn_cast<const void *>())
173+
ME = static_cast<const MapEntry *>(Next);
174+
return *ME;
175+
}
176+
160177
private:
161178
friend class FileMgr::MapEntryOptionalStorage<FileEntryRef>;
162179
struct optional_none_tag {};

clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,11 @@ class ModuleDepCollector final : public DependencyCollector {
233233
/// Checks whether the module is known as being prebuilt.
234234
bool isPrebuiltModule(const Module *M);
235235

236+
/// Adds \p Path to \c FileDeps, making it absolute if necessary.
237+
void addFileDep(StringRef Path);
238+
/// Adds \p Path to \c MD.FileDeps, making it absolute if necessary.
239+
void addFileDep(ModuleDeps &MD, StringRef Path);
240+
236241
/// Constructs a CompilerInvocation that can be used to build the given
237242
/// module, excluding paths to discovered modular dependencies that are yet to
238243
/// be built.

clang/lib/Basic/FileManager.cpp

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
213213
if (!SeenFileInsertResult.first->second)
214214
return llvm::errorCodeToError(
215215
SeenFileInsertResult.first->second.getError());
216-
// Construct and return and FileEntryRef, unless it's a redirect to another
217-
// filename.
218-
FileEntryRef::MapValue Value = *SeenFileInsertResult.first->second;
219-
if (LLVM_LIKELY(Value.V.is<FileEntry *>()))
220-
return FileEntryRef(*SeenFileInsertResult.first);
221-
return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>(
222-
Value.V.get<const void *>()));
216+
return FileEntryRef(*SeenFileInsertResult.first);
223217
}
224218

225219
// We've not seen this before. Fill it in.
@@ -275,8 +269,8 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
275269
if (!UFE)
276270
UFE = new (FilesAlloc.Allocate()) FileEntry();
277271

278-
if (Status.getName() == Filename) {
279-
// The name matches. Set the FileEntry.
272+
if (!Status.ExposesExternalVFSPath || Status.getName() == Filename) {
273+
// Use the requested name. Set the FileEntry.
280274
NamedFileEnt->second = FileEntryRef::MapValue(*UFE, DirInfo);
281275
} else {
282276
// Name mismatch. We need a redirect. First grab the actual entry we want
@@ -293,25 +287,9 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
293287
// filesystems behave and confuses parts of clang expect to see the
294288
// name-as-accessed on the \a FileEntryRef.
295289
//
296-
// Further, it isn't *just* external names, but will also give back absolute
297-
// paths when a relative path was requested - the check is comparing the
298-
// name from the status, which is passed an absolute path resolved from the
299-
// current working directory. `clang-apply-replacements` appears to depend
300-
// on this behaviour, though it's adjusting the working directory, which is
301-
// definitely not supported. Once that's fixed this hack should be able to
302-
// be narrowed to only when there's an externally mapped name given back.
303-
//
304290
// A potential plan to remove this is as follows -
305-
// - Add API to determine if the name has been rewritten by the VFS.
306-
// - Fix `clang-apply-replacements` to pass down the absolute path rather
307-
// than changing the CWD. Narrow this hack down to just externally
308-
// mapped paths.
309-
// - Expose the requested filename. One possibility would be to allow
310-
// redirection-FileEntryRefs to be returned, rather than returning
311-
// the pointed-at-FileEntryRef, and customizing `getName()` to look
312-
// through the indirection.
313291
// - Update callers such as `HeaderSearch::findUsableModuleForHeader()`
314-
// to explicitly use the requested filename rather than just using
292+
// to explicitly use the `getNameAsRequested()` rather than just using
315293
// `getName()`.
316294
// - Add a `FileManager::getExternalPath` API for explicitly getting the
317295
// remapped external filename when there is one available. Adopt it in
@@ -342,9 +320,6 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
342320
// Cache the redirection in the previously-inserted entry, still available
343321
// in the tentative return value.
344322
NamedFileEnt->second = FileEntryRef::MapValue(Redirection);
345-
346-
// Fix the tentative return value.
347-
NamedFileEnt = &Redirection;
348323
}
349324

350325
FileEntryRef ReturnedRef(*NamedFileEnt);

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,26 @@ namespace {
2929
class DependencyConsumerForwarder : public DependencyFileGenerator {
3030
public:
3131
DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
32-
DependencyConsumer &C,
32+
StringRef WorkingDirectory, DependencyConsumer &C,
3333
bool EmitDependencyFile)
34-
: DependencyFileGenerator(*Opts), Opts(std::move(Opts)), C(C),
35-
EmitDependencyFile(EmitDependencyFile) {}
34+
: DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory),
35+
Opts(std::move(Opts)), C(C), EmitDependencyFile(EmitDependencyFile) {}
3636

3737
void finishedMainFile(DiagnosticsEngine &Diags) override {
3838
C.handleDependencyOutputOpts(*Opts);
3939
llvm::SmallString<256> CanonPath;
4040
for (const auto &File : getDependencies()) {
4141
CanonPath = File;
4242
llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
43+
llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath);
4344
C.handleFileDependency(CanonPath);
4445
}
4546
if (EmitDependencyFile)
4647
DependencyFileGenerator::finishedMainFile(Diags);
4748
}
4849

4950
private:
51+
StringRef WorkingDirectory;
5052
std::unique_ptr<DependencyOutputOptions> Opts;
5153
DependencyConsumer &C;
5254
bool EmitDependencyFile = false;
@@ -310,8 +312,8 @@ class DependencyScanningAction : public tooling::ToolAction {
310312
case ScanningOutputFormat::Tree:
311313
ScanInstance.addDependencyCollector(
312314
std::make_shared<DependencyConsumerForwarder>(
313-
std::move(Opts), static_cast<DependencyConsumer &>(Consumer),
314-
EmitDependencyFile));
315+
std::move(Opts), WorkingDirectory,
316+
static_cast<DependencyConsumer &>(Consumer), EmitDependencyFile));
315317
break;
316318
case ScanningOutputFormat::IncludeTree: {
317319
ScanInstance.addDependencyCollector(

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,7 @@ void ModuleDepCollectorPP::FileChanged(SourceLocation Loc,
243243
// We do not want #line markers to affect dependency generation!
244244
if (Optional<StringRef> Filename =
245245
SM.getNonBuiltinFilenameForID(SM.getFileID(SM.getExpansionLoc(Loc))))
246-
MDC.FileDeps.push_back(
247-
std::string(llvm::sys::path::remove_leading_dotslash(*Filename)));
246+
MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
248247
}
249248

250249
void ModuleDepCollectorPP::InclusionDirective(
@@ -255,7 +254,7 @@ void ModuleDepCollectorPP::InclusionDirective(
255254
if (!File && !Imported) {
256255
// This is a non-modular include that HeaderSearch failed to find. Add it
257256
// here as `FileChanged` will never see it.
258-
MDC.FileDeps.push_back(std::string(FileName));
257+
MDC.addFileDep(FileName);
259258
}
260259
handleImport(Imported);
261260
}
@@ -285,8 +284,7 @@ void ModuleDepCollectorPP::EndOfMainFile() {
285284
->getName());
286285

287286
if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
288-
MDC.FileDeps.push_back(
289-
MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
287+
MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
290288

291289
for (const Module *M : DirectModularDeps) {
292290
// A top-level module might not be actually imported as a module when
@@ -349,10 +347,10 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
349347
// handle it like normal. With explicitly built modules we don't need
350348
// to play VFS tricks, so replace it with the correct module map.
351349
if (IF.getFile()->getName().endswith("__inferred_module.map")) {
352-
MD.FileDeps.insert(ModuleMap->getName());
350+
MDC.addFileDep(MD, ModuleMap->getName());
353351
return;
354352
}
355-
MD.FileDeps.insert(IF.getFile()->getName());
353+
MDC.addFileDep(MD, IF.getFile()->getName());
356354
});
357355

358356
// We usually don't need to list the module map files of our dependencies when
@@ -497,3 +495,24 @@ bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
497495
PrebuiltModuleFileIt->second == M->getASTFile()->getName());
498496
return true;
499497
}
498+
499+
static StringRef makeAbsolute(CompilerInstance &CI, StringRef Path,
500+
SmallVectorImpl<char> &Storage) {
501+
if (llvm::sys::path::is_absolute(Path))
502+
return Path;
503+
Storage.assign(Path.begin(), Path.end());
504+
CI.getFileManager().makeAbsolutePath(Storage);
505+
return StringRef(Storage.data(), Storage.size());
506+
}
507+
508+
void ModuleDepCollector::addFileDep(StringRef Path) {
509+
llvm::SmallString<256> Storage;
510+
Path = makeAbsolute(ScanInstance, Path, Storage);
511+
FileDeps.push_back(std::string(Path));
512+
}
513+
514+
void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
515+
llvm::SmallString<256> Storage;
516+
Path = makeAbsolute(ScanInstance, Path, Storage);
517+
MD.FileDeps.insert(Path);
518+
}

clang/unittests/Basic/FileEntryTest.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ class FileEntryTestHelper {
5050
const_cast<FileEntry &>(Base.getFileEntry()), DR)})
5151
.first);
5252
}
53+
FileEntryRef addFileRedirect(StringRef Name, FileEntryRef Base) {
54+
return FileEntryRef(
55+
*Files
56+
.insert({Name, FileEntryRef::MapValue(
57+
const_cast<FileEntryRef::MapEntry &>(
58+
Base.getMapEntry()))})
59+
.first);
60+
}
5361
};
5462

5563
namespace {
@@ -58,13 +66,23 @@ TEST(FileEntryTest, FileEntryRef) {
5866
FileEntryRef R1 = Refs.addFile("1");
5967
FileEntryRef R2 = Refs.addFile("2");
6068
FileEntryRef R1Also = Refs.addFileAlias("1-also", R1);
69+
FileEntryRef R1Redirect = Refs.addFileRedirect("1-redirect", R1);
70+
FileEntryRef R1Redirect2 = Refs.addFileRedirect("1-redirect2", R1Redirect);
6171

6272
EXPECT_EQ("1", R1.getName());
6373
EXPECT_EQ("2", R2.getName());
6474
EXPECT_EQ("1-also", R1Also.getName());
75+
EXPECT_EQ("1", R1Redirect.getName());
76+
EXPECT_EQ("1", R1Redirect2.getName());
77+
78+
EXPECT_EQ("1", R1.getNameAsRequested());
79+
EXPECT_EQ("1-redirect", R1Redirect.getNameAsRequested());
80+
EXPECT_EQ("1-redirect2", R1Redirect2.getNameAsRequested());
6581

6682
EXPECT_NE(&R1.getFileEntry(), &R2.getFileEntry());
6783
EXPECT_EQ(&R1.getFileEntry(), &R1Also.getFileEntry());
84+
EXPECT_EQ(&R1.getFileEntry(), &R1Redirect.getFileEntry());
85+
EXPECT_EQ(&R1Redirect.getFileEntry(), &R1Redirect2.getFileEntry());
6886

6987
const FileEntry *CE1 = R1;
7088
EXPECT_EQ(CE1, &R1.getFileEntry());
@@ -93,13 +111,17 @@ TEST(FileEntryTest, equals) {
93111
FileEntryRef R1 = Refs.addFile("1");
94112
FileEntryRef R2 = Refs.addFile("2");
95113
FileEntryRef R1Also = Refs.addFileAlias("1-also", R1);
114+
FileEntryRef R1Redirect = Refs.addFileRedirect("1-redirect", R1);
115+
FileEntryRef R1Redirect2 = Refs.addFileRedirect("1-redirect2", R1Redirect);
96116

97117
EXPECT_EQ(R1, &R1.getFileEntry());
98118
EXPECT_EQ(&R1.getFileEntry(), R1);
99119
EXPECT_EQ(R1, R1Also);
100120
EXPECT_NE(R1, &R2.getFileEntry());
101121
EXPECT_NE(&R2.getFileEntry(), R1);
102122
EXPECT_NE(R1, R2);
123+
EXPECT_EQ(R1, R1Redirect);
124+
EXPECT_EQ(R1, R1Redirect2);
103125

104126
OptionalFileEntryRefDegradesToFileEntryPtr M1 = R1;
105127

@@ -114,11 +136,16 @@ TEST(FileEntryTest, isSameRef) {
114136
FileEntryRef R1 = Refs.addFile("1");
115137
FileEntryRef R2 = Refs.addFile("2");
116138
FileEntryRef R1Also = Refs.addFileAlias("1-also", R1);
139+
FileEntryRef R1Redirect = Refs.addFileRedirect("1-redirect", R1);
140+
FileEntryRef R1Redirect2 = Refs.addFileRedirect("1-redirect2", R1Redirect);
117141

118142
EXPECT_TRUE(R1.isSameRef(FileEntryRef(R1)));
119143
EXPECT_TRUE(R1.isSameRef(FileEntryRef(R1.getMapEntry())));
120144
EXPECT_FALSE(R1.isSameRef(R2));
121145
EXPECT_FALSE(R1.isSameRef(R1Also));
146+
EXPECT_FALSE(R1.isSameRef(R1Redirect));
147+
EXPECT_FALSE(R1.isSameRef(R1Redirect2));
148+
EXPECT_FALSE(R1Redirect.isSameRef(R1Redirect2));
122149
}
123150

124151
TEST(FileEntryTest, DenseMapInfo) {

0 commit comments

Comments
 (0)