Skip to content

Support hermetic index store data via path remappings #4207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions clang/include/clang/Basic/PathRemapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===--- PathRemapper.h - Remap filepath prefixes ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a data structure that stores a string-to-string
// mapping used to transform file paths based on a prefix mapping. It
// is optimized for the common case of having 0, 1, or 2 mappings.
//
// Remappings are stored such that they are applied in the order they
// are passed on the command line, with the first one winning - a path will
// only be remapped by a single mapping, if any, not multiple. The ordering
// would only matter if one source mapping was a prefix of another.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_BASIC_PATHREMAPPER_H
#define LLVM_CLANG_BASIC_PATHREMAPPER_H

#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"

#include <string>
#include <utility>

namespace clang {

class PathRemapper {
SmallVector<std::pair<std::string, std::string>, 2> PathMappings;
public:
/// Adds a mapping such that any paths starting with `FromPrefix` have that
/// portion replaced with `ToPrefix`.
void addMapping(StringRef FromPrefix, StringRef ToPrefix) {
PathMappings.emplace_back(FromPrefix.str(), ToPrefix.str());
}

/// Returns a remapped `Path` if it starts with a prefix in the map; otherwise
/// the original path is returned.
std::string remapPath(StringRef Path) const {
for (const auto &Mapping : PathMappings)
if (Path.startswith(Mapping.first))
return (Twine(Mapping.second) +
Path.substr(Mapping.first.size())).str();
return Path.str();
}

/// Return true if there are no path remappings (meaning remapPath will always
/// return the path given).
bool empty() const {
return PathMappings.empty();
}

const SmallVector<std::pair<std::string, std::string>, 2> & getMappings() {
return PathMappings;
}
};

} // end namespace clang

#endif
5 changes: 4 additions & 1 deletion clang/include/clang/Index/IndexDataStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_CLANG_INDEX_INDEXDATASTORE_H

#include "clang/Basic/LLVM.h"
#include "clang/Basic/PathRemapper.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/STLExtras.h"
Expand All @@ -26,9 +27,11 @@ class IndexDataStore {
~IndexDataStore();

static std::unique_ptr<IndexDataStore>
create(StringRef IndexStorePath, std::string &Error);
create(StringRef IndexStorePath, PathRemapper Remapper,
std::string &Error);

StringRef getFilePath() const;
const PathRemapper & getPathRemapper() const;
bool foreachUnitName(bool sorted,
llvm::function_ref<bool(StringRef unitName)> receiver);

Expand Down
7 changes: 5 additions & 2 deletions clang/include/clang/Index/IndexUnitReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#define LLVM_CLANG_INDEX_INDEXUNITREADER_H

#include "clang/Basic/LLVM.h"
#include "clang/Basic/PathRemapper.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Chrono.h"
#include <map>

namespace clang {
namespace index {
Expand All @@ -29,9 +31,10 @@ class IndexUnitReader {

static std::unique_ptr<IndexUnitReader>
createWithUnitFilename(StringRef UnitFilename, StringRef StorePath,
std::string &Error);
const PathRemapper &Remapper, std::string &Error);
static std::unique_ptr<IndexUnitReader>
createWithFilePath(StringRef FilePath, std::string &Error);
createWithFilePath(StringRef FilePath, const PathRemapper &Remapper,
std::string &Error);

static Optional<llvm::sys::TimePoint<>>
getModificationTimeForUnit(StringRef UnitFilename, StringRef StorePath,
Expand Down
9 changes: 8 additions & 1 deletion clang/include/clang/Index/IndexUnitWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
#include <map>
#include <string>
#include <vector>

Expand All @@ -22,6 +23,7 @@ namespace llvm {
namespace clang {
class FileEntry;
class FileManager;
class PathRemapper;

namespace index {

Expand Down Expand Up @@ -57,6 +59,7 @@ class IndexUnitWriter {
std::string TargetTriple;
std::string WorkDir;
std::string SysrootPath;
const PathRemapper &Remapper;
std::function<writer::ModuleInfo(writer::OpaqueModule,
SmallVectorImpl<char> &Scratch)> GetInfoForModuleFn;
struct FileInclude {
Expand Down Expand Up @@ -87,6 +90,8 @@ class IndexUnitWriter {
/// \param MainFile the main file for a compiled source file. This should be
/// null for PCH and module units.
/// \param IsSystem true for system module units, false otherwise.
/// \param Remapper Remapper to use to standardize file paths to make them
/// hermetic/reproducible. This applies to all paths emitted in the unit file.
IndexUnitWriter(FileManager &FileMgr,
StringRef StorePath,
StringRef ProviderIdentifier, StringRef ProviderVersion,
Expand All @@ -98,6 +103,7 @@ class IndexUnitWriter {
bool IsDebugCompilation,
StringRef TargetTriple,
StringRef SysrootPath,
const PathRemapper &Remapper,
writer::ModuleInfoWriterCallback GetInfoForModule);
~IndexUnitWriter();

Expand All @@ -120,7 +126,8 @@ class IndexUnitWriter {
Optional<bool> isUnitUpToDateForOutputFile(StringRef FilePath,
Optional<StringRef> TimeCompareFilePath,
std::string &Error);
static void getUnitNameForAbsoluteOutputFile(StringRef FilePath, SmallVectorImpl<char> &Str);
static void getUnitNameForAbsoluteOutputFile(StringRef FilePath, SmallVectorImpl<char> &Str,
const PathRemapper &Remapper);
static bool initIndexDirectory(StringRef StorePath, std::string &Error);

private:
Expand Down
15 changes: 11 additions & 4 deletions clang/include/indexstore/IndexStoreCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define LLVM_CLANG_INDEXSTORE_INDEXSTORECXX_H

#include "indexstore/indexstore.h"
#include "clang/Basic/PathRemapper.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
Expand Down Expand Up @@ -101,10 +102,15 @@ class IndexStore {
friend class IndexUnitReader;

public:
IndexStore(StringRef path, std::string &error) {
IndexStore(StringRef path, clang::PathRemapper remapper, std::string &error) {
llvm::SmallString<64> buf = path;
indexstore_error_t c_err = nullptr;
obj = indexstore_store_create(buf.c_str(), &c_err);
indexstore_creation_options_t options = indexstore_creation_options_create();
for (const auto &Mapping : remapper.getMappings())
indexstore_creation_options_add_prefix_mapping(options, Mapping.first.c_str(), Mapping.second.c_str());

obj = indexstore_store_create_with_options(buf.c_str(), options, &c_err);
indexstore_creation_options_dispose(options);
if (c_err) {
error = indexstore_error_get_description(c_err);
indexstore_error_dispose(c_err);
Expand All @@ -119,8 +125,9 @@ class IndexStore {
indexstore_store_dispose(obj);
}

static IndexStoreRef create(StringRef path, std::string &error) {
auto storeRef = std::make_shared<IndexStore>(path, error);
static IndexStoreRef create(StringRef path, clang::PathRemapper remapper,
std::string &error) {
auto storeRef = std::make_shared<IndexStore>(path, remapper, error);
if (storeRef->isInvalid())
return nullptr;
return storeRef;
Expand Down
24 changes: 23 additions & 1 deletion clang/include/indexstore/indexstore.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* INDEXSTORE_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
*/
#define INDEXSTORE_VERSION_MAJOR 0
#define INDEXSTORE_VERSION_MINOR 12
#define INDEXSTORE_VERSION_MINOR 13

#define INDEXSTORE_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
Expand Down Expand Up @@ -129,10 +129,32 @@ INDEXSTORE_PUBLIC unsigned
indexstore_format_version(void);

typedef void *indexstore_t;
typedef void *indexstore_creation_options_t;

INDEXSTORE_PUBLIC indexstore_creation_options_t
indexstore_creation_options_create(void);

INDEXSTORE_PUBLIC void
indexstore_creation_options_dispose(indexstore_creation_options_t);

/// Adds a remapping from \c path_prefix to \c remapped_path_prefix.
///
/// This should be used to convert hermetic or remote paths embedded in the index data to the
/// equivalent paths on the local machine.
INDEXSTORE_PUBLIC void
indexstore_creation_options_add_prefix_mapping(indexstore_creation_options_t options,
const char *path_prefix,
const char *remapped_path_prefix);

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


/// Open the indexstore at the specified path using the specified options, which may be NULL.
INDEXSTORE_PUBLIC indexstore_t
indexstore_store_create_with_options(const char *store_path, indexstore_creation_options_t options,
indexstore_error_t *error);

INDEXSTORE_PUBLIC void
indexstore_store_dispose(indexstore_t);

Expand Down
43 changes: 30 additions & 13 deletions clang/lib/Index/IndexUnitReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ class IndexUnitReaderImpl {
bool IsSystemUnit;
bool IsModuleUnit;
bool IsDebugCompilation;
StringRef WorkingDir;
StringRef OutputFile;
StringRef SysrootPath;
SmallString<128> WorkingDir;
SmallString<128> OutputFile;
SmallString<128> SysrootPath;
StringRef ModuleName;
SmallString<128> MainFilePath;
StringRef Target;
std::vector<FileBitPath> Paths;
StringRef PathsBuffer;
const PathRemapper &Remapper;

struct ModuleInfo {
unsigned NameOffset;
Expand All @@ -59,16 +60,17 @@ class IndexUnitReaderImpl {
std::vector<ModuleInfo> Modules;
StringRef ModuleNamesBuffer;

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

StringRef getProviderIdentifier() const { return ProviderIdentifier; }
StringRef getProviderVersion() const { return ProviderVersion; }

sys::TimePoint<> getModificationTime() const { return ModTime; }
StringRef getWorkingDirectory() const { return WorkingDir; }
StringRef getOutputFile() const { return OutputFile; }
StringRef getSysrootPath() const { return SysrootPath; }
StringRef getWorkingDirectory() const { return WorkingDir.str(); }
StringRef getOutputFile() const { return OutputFile.str(); }
StringRef getSysrootPath() const { return SysrootPath.str(); }
StringRef getTarget() const { return Target; }

StringRef getModuleName() const { return ModuleName; }
Expand All @@ -88,6 +90,10 @@ class IndexUnitReaderImpl {
return PathsBuffer.substr(Offset, Size);
}

std::string getAndRemapPathFromBuffer(size_t Offset, size_t Size) {
return Remapper.remapPath(getPathFromBuffer(Offset, Size));
}

void constructFilePath(SmallVectorImpl<char> &Path, int PathIndex);

StringRef getModuleName(int ModuleIndex);
Expand Down Expand Up @@ -205,9 +211,9 @@ class IndexUnitBitstreamVisitor : public BitstreamVisitor<IndexUnitBitstreamVisi
break;
case UNIT_PATH_BUFFER:
Reader.PathsBuffer = Blob;
Reader.WorkingDir = Reader.getPathFromBuffer(WorkDirOffset, WorkDirSize);
Reader.OutputFile = Reader.getPathFromBuffer(OutputFileOffset, OutputFileSize);
Reader.SysrootPath = Reader.getPathFromBuffer(SysrootOffset, SysrootSize);
Reader.WorkingDir = Reader.getAndRemapPathFromBuffer(WorkDirOffset, WorkDirSize);
Reader.OutputFile = Reader.getAndRemapPathFromBuffer(OutputFileOffset, OutputFileSize);
Reader.SysrootPath = Reader.getAndRemapPathFromBuffer(SysrootOffset, SysrootSize);

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

bool IndexUnitReaderImpl::init(std::unique_ptr<MemoryBuffer> Buf,
sys::TimePoint<> ModTime, std::string &Error) {
sys::TimePoint<> ModTime,
std::string &Error) {
this->ModTime = ModTime;
this->MemBuf = std::move(Buf);
llvm::BitstreamCursor Stream(*MemBuf);
Expand Down Expand Up @@ -374,6 +381,13 @@ void IndexUnitReaderImpl::constructFilePath(SmallVectorImpl<char> &PathBuf,
sys::path::append(PathBuf,
getPathFromBuffer(Path.Dir.Offset, Path.Dir.Size),
getPathFromBuffer(Path.Filename.Offset, Path.Filename.Size));
if (Path.PrefixKind == UNIT_PATH_PREFIX_NONE && !Remapper.empty()) {
SmallString<256> PathStr;
PathStr.assign(PathBuf);
std::string Remapped = Remapper.remapPath(PathStr.str());
PathBuf.clear();
PathBuf.append(Remapped.begin(), Remapped.end());
}
}

StringRef IndexUnitReaderImpl::getModuleName(int ModuleIndex) {
Expand All @@ -391,15 +405,18 @@ StringRef IndexUnitReaderImpl::getModuleName(int ModuleIndex) {
std::unique_ptr<IndexUnitReader>
IndexUnitReader::createWithUnitFilename(StringRef UnitFilename,
StringRef StorePath,
const PathRemapper &Remapper,
std::string &Error) {
SmallString<128> PathBuf = StorePath;
appendUnitSubDir(PathBuf);
sys::path::append(PathBuf, UnitFilename);
return createWithFilePath(PathBuf.str(), Error);
return createWithFilePath(PathBuf.str(), Remapper, Error);
}

std::unique_ptr<IndexUnitReader>
IndexUnitReader::createWithFilePath(StringRef FilePath, std::string &Error) {
IndexUnitReader::createWithFilePath(StringRef FilePath,
const PathRemapper &Remapper,
std::string &Error) {
int FD;
std::error_code EC = sys::fs::openFileForRead(FilePath, FD);
if (EC) {
Expand Down Expand Up @@ -433,7 +450,7 @@ IndexUnitReader::createWithFilePath(StringRef FilePath, std::string &Error) {
return nullptr;
}

std::unique_ptr<IndexUnitReaderImpl> Impl(new IndexUnitReaderImpl());
std::unique_ptr<IndexUnitReaderImpl> Impl(new IndexUnitReaderImpl(Remapper));
bool Err = Impl->init(std::move(*ErrOrBuf), FileStat.getLastModificationTime(),
Error);
if (Err)
Expand Down
Loading