Skip to content

Commit fcfcf6e

Browse files
authored
Merge pull request #4267 from DavidGoldman/stable/20211026
Support hermetic index store data via path remappings #4207
2 parents 76db115 + bfd18b8 commit fcfcf6e

18 files changed

+394
-66
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===--- PathRemapper.h - Remap filepath prefixes ---------------*- C++ -*-===//
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+
// This file defines a data structure that stores a string-to-string
10+
// mapping used to transform file paths based on a prefix mapping. It
11+
// is optimized for the common case of having 0, 1, or 2 mappings.
12+
//
13+
// Remappings are stored such that they are applied in the order they
14+
// are passed on the command line, with the first one winning - a path will
15+
// only be remapped by a single mapping, if any, not multiple. The ordering
16+
// would only matter if one source mapping was a prefix of another.
17+
//
18+
//===----------------------------------------------------------------------===//
19+
20+
#ifndef LLVM_CLANG_BASIC_PATHREMAPPER_H
21+
#define LLVM_CLANG_BASIC_PATHREMAPPER_H
22+
23+
#include "clang/Basic/LLVM.h"
24+
#include "llvm/ADT/ArrayRef.h"
25+
#include "llvm/ADT/SmallVector.h"
26+
#include "llvm/ADT/Twine.h"
27+
#include "llvm/Support/Path.h"
28+
29+
#include <string>
30+
#include <utility>
31+
32+
namespace clang {
33+
34+
class PathRemapper {
35+
SmallVector<std::pair<std::string, std::string>, 2> PathMappings;
36+
public:
37+
/// Adds a mapping such that any paths starting with `FromPrefix` have that
38+
/// portion replaced with `ToPrefix`.
39+
void addMapping(StringRef FromPrefix, StringRef ToPrefix) {
40+
PathMappings.emplace_back(FromPrefix.str(), ToPrefix.str());
41+
}
42+
43+
/// Returns a remapped `Path` if it starts with a prefix in the remapper;
44+
/// otherwise the original path is returned.
45+
std::string remapPath(StringRef Path) const {
46+
for (const auto &Mapping : PathMappings)
47+
if (Path.startswith(Mapping.first))
48+
return (Twine(Mapping.second) +
49+
Path.substr(Mapping.first.size())).str();
50+
return Path.str();
51+
}
52+
53+
/// Remaps `PathBuf` if it starts with a prefix in the remapper. Avoids any
54+
/// heap allocations if the path is not remapped.
55+
void remapPath(SmallVectorImpl<char> &PathBuf) const {
56+
for (const auto &E : PathMappings)
57+
if (llvm::sys::path::replace_path_prefix(PathBuf, E.first, E.second))
58+
break;
59+
}
60+
61+
/// Return true if there are no path remappings (meaning remapPath will always
62+
/// return the path given).
63+
bool empty() const {
64+
return PathMappings.empty();
65+
}
66+
67+
ArrayRef<std::pair<std::string, std::string>> getMappings() const {
68+
return PathMappings;
69+
}
70+
};
71+
72+
} // end namespace clang
73+
74+
#endif

clang/include/clang/Index/IndexDataStore.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
#define LLVM_CLANG_INDEX_INDEXDATASTORE_H
1111

1212
#include "clang/Basic/LLVM.h"
13+
#include "clang/Basic/PathRemapper.h"
1314
#include "llvm/ADT/ArrayRef.h"
14-
#include "llvm/ADT/StringRef.h"
1515
#include "llvm/ADT/STLExtras.h"
16+
#include "llvm/ADT/StringRef.h"
1617
#include "llvm/Support/Chrono.h"
1718
#include <functional>
1819
#include <memory>
@@ -25,10 +26,12 @@ class IndexDataStore {
2526
public:
2627
~IndexDataStore();
2728

28-
static std::unique_ptr<IndexDataStore>
29-
create(StringRef IndexStorePath, std::string &Error);
29+
static std::unique_ptr<IndexDataStore> create(StringRef IndexStorePath,
30+
const PathRemapper &Remapper,
31+
std::string &Error);
3032

3133
StringRef getFilePath() const;
34+
const PathRemapper &getPathRemapper() const;
3235
bool foreachUnitName(bool sorted,
3336
llvm::function_ref<bool(StringRef unitName)> receiver);
3437

clang/include/clang/Index/IndexUnitReader.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_CLANG_INDEX_INDEXUNITREADER_H
1111

1212
#include "clang/Basic/LLVM.h"
13+
#include "clang/Basic/PathRemapper.h"
1314
#include "llvm/ADT/StringRef.h"
1415
#include "llvm/ADT/STLExtras.h"
1516
#include "llvm/Support/Chrono.h"
@@ -29,9 +30,10 @@ class IndexUnitReader {
2930

3031
static std::unique_ptr<IndexUnitReader>
3132
createWithUnitFilename(StringRef UnitFilename, StringRef StorePath,
32-
std::string &Error);
33+
const PathRemapper &Remapper, std::string &Error);
3334
static std::unique_ptr<IndexUnitReader>
34-
createWithFilePath(StringRef FilePath, std::string &Error);
35+
createWithFilePath(StringRef FilePath, const PathRemapper &Remapper,
36+
std::string &Error);
3537

3638
static Optional<llvm::sys::TimePoint<>>
3739
getModificationTimeForUnit(StringRef UnitFilename, StringRef StorePath,

clang/include/clang/Index/IndexUnitWriter.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace llvm {
2222
namespace clang {
2323
class FileEntry;
2424
class FileManager;
25+
class PathRemapper;
2526

2627
namespace index {
2728

@@ -57,6 +58,7 @@ class IndexUnitWriter {
5758
std::string TargetTriple;
5859
std::string WorkDir;
5960
std::string SysrootPath;
61+
const PathRemapper &Remapper;
6062
std::function<writer::ModuleInfo(writer::OpaqueModule,
6163
SmallVectorImpl<char> &Scratch)> GetInfoForModuleFn;
6264
struct FileInclude {
@@ -87,6 +89,8 @@ class IndexUnitWriter {
8789
/// \param MainFile the main file for a compiled source file. This should be
8890
/// null for PCH and module units.
8991
/// \param IsSystem true for system module units, false otherwise.
92+
/// \param Remapper Remapper to use to standardize file paths to make them
93+
/// hermetic/reproducible. This applies to all paths emitted in the unit file.
9094
IndexUnitWriter(FileManager &FileMgr,
9195
StringRef StorePath,
9296
StringRef ProviderIdentifier, StringRef ProviderVersion,
@@ -98,6 +102,7 @@ class IndexUnitWriter {
98102
bool IsDebugCompilation,
99103
StringRef TargetTriple,
100104
StringRef SysrootPath,
105+
const PathRemapper &Remapper,
101106
writer::ModuleInfoWriterCallback GetInfoForModule);
102107
~IndexUnitWriter();
103108

@@ -120,7 +125,8 @@ class IndexUnitWriter {
120125
Optional<bool> isUnitUpToDateForOutputFile(StringRef FilePath,
121126
Optional<StringRef> TimeCompareFilePath,
122127
std::string &Error);
123-
static void getUnitNameForAbsoluteOutputFile(StringRef FilePath, SmallVectorImpl<char> &Str);
128+
static void getUnitNameForAbsoluteOutputFile(StringRef FilePath, SmallVectorImpl<char> &Str,
129+
const PathRemapper &Remapper);
124130
static bool initIndexDirectory(StringRef StorePath, std::string &Error);
125131

126132
private:

clang/include/indexstore/IndexStoreCXX.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define LLVM_CLANG_INDEXSTORE_INDEXSTORECXX_H
1515

1616
#include "indexstore/indexstore.h"
17+
#include "clang/Basic/PathRemapper.h"
1718
#include "llvm/ADT/ArrayRef.h"
1819
#include "llvm/ADT/Optional.h"
1920
#include "llvm/ADT/STLExtras.h"
@@ -101,10 +102,16 @@ class IndexStore {
101102
friend class IndexUnitReader;
102103

103104
public:
104-
IndexStore(StringRef path, std::string &error) {
105+
IndexStore(StringRef path, const clang::PathRemapper &remapper,
106+
std::string &error) {
105107
llvm::SmallString<64> buf = path;
106108
indexstore_error_t c_err = nullptr;
107-
obj = indexstore_store_create(buf.c_str(), &c_err);
109+
indexstore_creation_options_t options = indexstore_creation_options_create();
110+
for (const auto &Mapping : remapper.getMappings())
111+
indexstore_creation_options_add_prefix_mapping(options, Mapping.first.c_str(), Mapping.second.c_str());
112+
113+
obj = indexstore_store_create_with_options(buf.c_str(), options, &c_err);
114+
indexstore_creation_options_dispose(options);
108115
if (c_err) {
109116
error = indexstore_error_get_description(c_err);
110117
indexstore_error_dispose(c_err);
@@ -119,8 +126,9 @@ class IndexStore {
119126
indexstore_store_dispose(obj);
120127
}
121128

122-
static IndexStoreRef create(StringRef path, std::string &error) {
123-
auto storeRef = std::make_shared<IndexStore>(path, error);
129+
static IndexStoreRef create(StringRef path, clang::PathRemapper remapper,
130+
std::string &error) {
131+
auto storeRef = std::make_shared<IndexStore>(path, remapper, error);
124132
if (storeRef->isInvalid())
125133
return nullptr;
126134
return storeRef;

clang/include/indexstore/indexstore.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
* INDEXSTORE_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
2626
*/
2727
#define INDEXSTORE_VERSION_MAJOR 0
28-
#define INDEXSTORE_VERSION_MINOR 12
28+
#define INDEXSTORE_VERSION_MINOR 13
2929

3030
#define INDEXSTORE_VERSION_ENCODE(major, minor) ( \
3131
((major) * 10000) \
@@ -129,10 +129,32 @@ INDEXSTORE_PUBLIC unsigned
129129
indexstore_format_version(void);
130130

131131
typedef void *indexstore_t;
132+
typedef void *indexstore_creation_options_t;
133+
134+
INDEXSTORE_PUBLIC indexstore_creation_options_t
135+
indexstore_creation_options_create(void);
136+
137+
INDEXSTORE_PUBLIC void
138+
indexstore_creation_options_dispose(indexstore_creation_options_t);
139+
140+
/// Adds a remapping from \c path_prefix to \c remapped_path_prefix.
141+
///
142+
/// This should be used to convert hermetic or remote paths embedded in the index data to the
143+
/// equivalent paths on the local machine.
144+
INDEXSTORE_PUBLIC void
145+
indexstore_creation_options_add_prefix_mapping(indexstore_creation_options_t options,
146+
const char *path_prefix,
147+
const char *remapped_path_prefix);
132148

133149
INDEXSTORE_PUBLIC indexstore_t
134150
indexstore_store_create(const char *store_path, indexstore_error_t *error);
135151

152+
153+
/// Open the indexstore at the specified path using the specified options, which may be NULL.
154+
INDEXSTORE_PUBLIC indexstore_t
155+
indexstore_store_create_with_options(const char *store_path, indexstore_creation_options_t options,
156+
indexstore_error_t *error);
157+
136158
INDEXSTORE_PUBLIC void
137159
indexstore_store_dispose(indexstore_t);
138160

clang/lib/Index/IndexUnitReader.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,15 @@ class IndexUnitReaderImpl {
4343
bool IsSystemUnit;
4444
bool IsModuleUnit;
4545
bool IsDebugCompilation;
46-
StringRef WorkingDir;
47-
StringRef OutputFile;
48-
StringRef SysrootPath;
46+
std::string WorkingDir;
47+
std::string OutputFile;
48+
std::string SysrootPath;
4949
StringRef ModuleName;
5050
SmallString<128> MainFilePath;
5151
StringRef Target;
5252
std::vector<FileBitPath> Paths;
5353
StringRef PathsBuffer;
54+
const PathRemapper &Remapper;
5455

5556
struct ModuleInfo {
5657
unsigned NameOffset;
@@ -59,6 +60,7 @@ class IndexUnitReaderImpl {
5960
std::vector<ModuleInfo> Modules;
6061
StringRef ModuleNamesBuffer;
6162

63+
IndexUnitReaderImpl(const PathRemapper &remapper) : Remapper(remapper) {}
6264
bool init(std::unique_ptr<MemoryBuffer> Buf, sys::TimePoint<> ModTime,
6365
std::string &Error);
6466

@@ -88,6 +90,10 @@ class IndexUnitReaderImpl {
8890
return PathsBuffer.substr(Offset, Size);
8991
}
9092

93+
std::string getAndRemapPathFromBuffer(size_t Offset, size_t Size) {
94+
return Remapper.remapPath(getPathFromBuffer(Offset, Size));
95+
}
96+
9197
void constructFilePath(SmallVectorImpl<char> &Path, int PathIndex);
9298

9399
StringRef getModuleName(int ModuleIndex);
@@ -205,9 +211,9 @@ class IndexUnitBitstreamVisitor : public BitstreamVisitor<IndexUnitBitstreamVisi
205211
break;
206212
case UNIT_PATH_BUFFER:
207213
Reader.PathsBuffer = Blob;
208-
Reader.WorkingDir = Reader.getPathFromBuffer(WorkDirOffset, WorkDirSize);
209-
Reader.OutputFile = Reader.getPathFromBuffer(OutputFileOffset, OutputFileSize);
210-
Reader.SysrootPath = Reader.getPathFromBuffer(SysrootOffset, SysrootSize);
214+
Reader.WorkingDir = Reader.getAndRemapPathFromBuffer(WorkDirOffset, WorkDirSize);
215+
Reader.OutputFile = Reader.getAndRemapPathFromBuffer(OutputFileOffset, OutputFileSize);
216+
Reader.SysrootPath = Reader.getAndRemapPathFromBuffer(SysrootOffset, SysrootSize);
211217

212218
// now we can populate the main file's path
213219
Reader.constructFilePath(Reader.MainFilePath, MainPathIndex);
@@ -270,7 +276,8 @@ class IndexUnitBlockBitstreamVisitor : public BitstreamVisitor<IndexUnitBlockBit
270276
} // anonymous namespace
271277

272278
bool IndexUnitReaderImpl::init(std::unique_ptr<MemoryBuffer> Buf,
273-
sys::TimePoint<> ModTime, std::string &Error) {
279+
sys::TimePoint<> ModTime,
280+
std::string &Error) {
274281
this->ModTime = ModTime;
275282
this->MemBuf = std::move(Buf);
276283
llvm::BitstreamCursor Stream(*MemBuf);
@@ -374,6 +381,8 @@ void IndexUnitReaderImpl::constructFilePath(SmallVectorImpl<char> &PathBuf,
374381
sys::path::append(PathBuf,
375382
getPathFromBuffer(Path.Dir.Offset, Path.Dir.Size),
376383
getPathFromBuffer(Path.Filename.Offset, Path.Filename.Size));
384+
if (Path.PrefixKind == UNIT_PATH_PREFIX_NONE && !Remapper.empty())
385+
Remapper.remapPath(PathBuf);
377386
}
378387

379388
StringRef IndexUnitReaderImpl::getModuleName(int ModuleIndex) {
@@ -391,15 +400,18 @@ StringRef IndexUnitReaderImpl::getModuleName(int ModuleIndex) {
391400
std::unique_ptr<IndexUnitReader>
392401
IndexUnitReader::createWithUnitFilename(StringRef UnitFilename,
393402
StringRef StorePath,
403+
const PathRemapper &Remapper,
394404
std::string &Error) {
395405
SmallString<128> PathBuf = StorePath;
396406
appendUnitSubDir(PathBuf);
397407
sys::path::append(PathBuf, UnitFilename);
398-
return createWithFilePath(PathBuf.str(), Error);
408+
return createWithFilePath(PathBuf.str(), Remapper, Error);
399409
}
400410

401411
std::unique_ptr<IndexUnitReader>
402-
IndexUnitReader::createWithFilePath(StringRef FilePath, std::string &Error) {
412+
IndexUnitReader::createWithFilePath(StringRef FilePath,
413+
const PathRemapper &Remapper,
414+
std::string &Error) {
403415
int FD;
404416
std::error_code EC = sys::fs::openFileForRead(FilePath, FD);
405417
if (EC) {
@@ -433,7 +445,7 @@ IndexUnitReader::createWithFilePath(StringRef FilePath, std::string &Error) {
433445
return nullptr;
434446
}
435447

436-
std::unique_ptr<IndexUnitReaderImpl> Impl(new IndexUnitReaderImpl());
448+
auto Impl = std::make_unique<IndexUnitReaderImpl>(Remapper);
437449
bool Err = Impl->init(std::move(*ErrOrBuf), FileStat.getLastModificationTime(),
438450
Error);
439451
if (Err)

0 commit comments

Comments
 (0)