[clangd] Cleanup: stop passing around list of supported URI schemes.

Summary:
Instead of passing around a list of supported URI schemes in clangd, we
expose an interface to convert a path to URI using any compatible scheme
that has been registered. It favors customized schemes and falls
back to "file" when no other scheme works.

Changes in this patch are:
- URI::create(AbsPath, URISchemes) -> URI::create(AbsPath). The new API finds a
compatible scheme from the registry.
- Remove URISchemes option everywhere (ClangdServer, SymbolCollecter, FileIndex etc).
- Unit tests will use "unittest" by default.
- Move "test" scheme from ClangdLSPServer to ClangdMain.cpp, and only
register the test scheme when lit-test or enable-lit-scheme is set.
(The new flag is added to make lit protocol.test work; I wonder if there
is alternative here.)

Reviewers: sammccall

Reviewed By: sammccall

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits

Differential Revision: https://reviews.llvm.org/D54800

llvm-svn: 347467
This commit is contained in:
Eric Liu 2018-11-22 15:02:05 +00:00
parent 5628c1455f
commit c0ac4bb17c
26 changed files with 166 additions and 228 deletions

View File

@ -23,43 +23,6 @@ namespace clang {
namespace clangd {
namespace {
/// \brief Supports a test URI scheme with relaxed constraints for lit tests.
/// The path in a test URI will be combined with a platform-specific fake
/// directory to form an absolute path. For example, test:///a.cpp is resolved
/// C:\clangd-test\a.cpp on Windows and /clangd-test/a.cpp on Unix.
class TestScheme : public URIScheme {
public:
Expected<std::string> getAbsolutePath(StringRef /*Authority*/, StringRef Body,
StringRef /*HintPath*/) const override {
using namespace llvm::sys;
// Still require "/" in body to mimic file scheme, as we want lengths of an
// equivalent URI in both schemes to be the same.
if (!Body.startswith("/"))
return make_error<StringError>(
"Expect URI body to be an absolute path starting with '/': " + Body,
inconvertibleErrorCode());
Body = Body.ltrim('/');
#ifdef _WIN32
constexpr char TestDir[] = "C:\\clangd-test";
#else
constexpr char TestDir[] = "/clangd-test";
#endif
SmallVector<char, 16> Path(Body.begin(), Body.end());
path::native(Path);
auto Err = fs::make_absolute(TestDir, Path);
if (Err)
llvm_unreachable("Failed to make absolute path in test scheme.");
return std::string(Path.begin(), Path.end());
}
Expected<URI> uriFromAbsolutePath(StringRef AbsolutePath) const override {
llvm_unreachable("Clangd must never create a test URI.");
}
};
static URISchemeRegistry::Add<TestScheme>
X("test", "Test scheme for clangd lit tests.");
SymbolKindBitset defaultSymbolKinds() {
SymbolKindBitset Defaults;
for (size_t I = SymbolKindMin; I <= static_cast<size_t>(SymbolKind::Array);

View File

@ -106,8 +106,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
ResourceDir(Opts.ResourceDir ? *Opts.ResourceDir
: getStandardResourceDir()),
DynamicIdx(Opts.BuildDynamicSymbolIndex
? new FileIndex(Opts.URISchemes,
Opts.HeavyweightDynamicSymbolIndex)
? new FileIndex(Opts.HeavyweightDynamicSymbolIndex)
: nullptr),
WorkspaceRoot(Opts.WorkspaceRoot),
PCHs(std::make_shared<PCHContainerOperations>()),

View File

@ -79,10 +79,6 @@ public:
/// FIXME: we should make this true if it isn't too slow to build!.
bool HeavyweightDynamicSymbolIndex = false;
/// URI schemes to use when building the dynamic index.
/// If empty, the default schemes in SymbolCollector will be used.
std::vector<std::string> URISchemes;
/// If set, use this index to augment code completion results.
SymbolIndex *StaticIndex = nullptr;

View File

@ -195,12 +195,15 @@ Expected<URI> URI::create(StringRef AbsolutePath, StringRef Scheme) {
return S->get()->uriFromAbsolutePath(AbsolutePath);
}
Expected<URI> URI::create(StringRef AbsolutePath,
const std::vector<std::string> &Schemes) {
URI URI::create(StringRef AbsolutePath) {
if (!sys::path::is_absolute(AbsolutePath))
return make_string_error("Not a valid absolute path: " + AbsolutePath);
for (const auto &Scheme : Schemes) {
auto URI = URI::create(AbsolutePath, Scheme);
llvm_unreachable(
("Not a valid absolute path: " + AbsolutePath).str().c_str());
for (auto &Entry : URISchemeRegistry::entries()) {
if (Entry.getName() == "file")
continue;
auto URI = Entry.instantiate()->uriFromAbsolutePath(AbsolutePath);
// For some paths, conversion to different URI schemes is impossible. These
// should be just skipped.
if (!URI) {
@ -208,10 +211,10 @@ Expected<URI> URI::create(StringRef AbsolutePath,
consumeError(URI.takeError());
continue;
}
return URI;
return std::move(*URI);
}
return make_string_error("Couldn't convert " + AbsolutePath +
" to any given scheme: " + join(Schemes, ", "));
// Fallback to file: scheme which should work for any paths.
return URI::createFile(AbsolutePath);
}
URI URI::createFile(StringRef AbsolutePath) {

View File

@ -45,10 +45,9 @@ public:
static llvm::Expected<URI> create(llvm::StringRef AbsolutePath,
llvm::StringRef Scheme);
// Similar to above except this uses the first scheme in \p Schemes that
// works.
static llvm::Expected<URI> create(llvm::StringRef AbsolutePath,
const std::vector<std::string> &Schemes);
// Similar to above except this picks a registered scheme that works. If none
// works, this falls back to "file" scheme.
static URI create(llvm::StringRef AbsolutePath);
/// This creates a file:// URI for \p AbsolutePath. The path must be absolute.
static URI createFile(llvm::StringRef AbsolutePath);

View File

@ -36,11 +36,10 @@ namespace clangd {
BackgroundIndex::BackgroundIndex(
Context BackgroundContext, StringRef ResourceDir,
const FileSystemProvider &FSProvider, ArrayRef<std::string> URISchemes,
const FileSystemProvider &FSProvider,
BackgroundIndexStorage::Factory IndexStorageFactory, size_t ThreadPoolSize)
: SwapIndex(make_unique<MemIndex>()), ResourceDir(ResourceDir),
FSProvider(FSProvider), BackgroundContext(std::move(BackgroundContext)),
URISchemes(URISchemes),
IndexStorageFactory(std::move(IndexStorageFactory)) {
assert(ThreadPoolSize > 0 && "Thread pool size can't be zero.");
assert(this->IndexStorageFactory && "Storage factory can not be null!");
@ -341,7 +340,6 @@ Error BackgroundIndex::index(tooling::CompileCommand Cmd,
"Couldn't build compiler instance");
SymbolCollector::Options IndexOpts;
IndexOpts.URISchemes = URISchemes;
StringMap<FileDigest> FilesToUpdate;
IndexOpts.FileFilter = createFileFilter(DigestsSnapshot, FilesToUpdate);
SymbolSlab Symbols;
@ -379,8 +377,7 @@ Error BackgroundIndex::index(tooling::CompileCommand Cmd,
// FIXME: this should rebuild once-in-a-while, not after every file.
// At that point we should use Dex, too.
vlog("Rebuilding automatic index");
reset(IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge,
URISchemes));
reset(IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge));
return Error::success();
}

View File

@ -63,7 +63,7 @@ class BackgroundIndex : public SwapIndex {
public:
// FIXME: resource-dir injection should be hoisted somewhere common.
BackgroundIndex(Context BackgroundContext, llvm::StringRef ResourceDir,
const FileSystemProvider &, ArrayRef<std::string> URISchemes,
const FileSystemProvider &,
BackgroundIndexStorage::Factory IndexStorageFactory,
size_t ThreadPoolSize = llvm::hardware_concurrency());
~BackgroundIndex(); // Blocks while the current task finishes.
@ -95,7 +95,6 @@ private:
std::string ResourceDir;
const FileSystemProvider &FSProvider;
Context BackgroundContext;
std::vector<std::string> URISchemes;
// index state
llvm::Error index(tooling::CompileCommand,

View File

@ -30,8 +30,7 @@ namespace clangd {
static std::pair<SymbolSlab, RefSlab>
indexSymbols(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
ArrayRef<Decl *> DeclsToIndex, bool IsIndexMainAST,
ArrayRef<std::string> URISchemes) {
ArrayRef<Decl *> DeclsToIndex, bool IsIndexMainAST) {
SymbolCollector::Options CollectorOpts;
// FIXME(ioeric): we might also want to collect include headers. We would need
// to make sure all includes are canonicalized (with CanonicalIncludes), which
@ -41,8 +40,6 @@ indexSymbols(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
CollectorOpts.CollectIncludePath = false;
CollectorOpts.CountReferences = false;
CollectorOpts.Origin = SymbolOrigin::Dynamic;
if (!URISchemes.empty())
CollectorOpts.URISchemes = URISchemes;
index::IndexingOptions IndexOpts;
// We only need declarations, because we don't count references.
@ -75,20 +72,19 @@ indexSymbols(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
return {std::move(Syms), std::move(Refs)};
}
std::pair<SymbolSlab, RefSlab>
indexMainDecls(ParsedAST &AST, ArrayRef<std::string> URISchemes) {
std::pair<SymbolSlab, RefSlab> indexMainDecls(ParsedAST &AST) {
return indexSymbols(AST.getASTContext(), AST.getPreprocessorPtr(),
AST.getLocalTopLevelDecls(),
/*IsIndexMainAST=*/true, URISchemes);
/*IsIndexMainAST=*/true);
}
SymbolSlab indexHeaderSymbols(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
ArrayRef<std::string> URISchemes) {
SymbolSlab indexHeaderSymbols(ASTContext &AST,
std::shared_ptr<Preprocessor> PP) {
std::vector<Decl *> DeclsToIndex(
AST.getTranslationUnitDecl()->decls().begin(),
AST.getTranslationUnitDecl()->decls().end());
return indexSymbols(AST, std::move(PP), DeclsToIndex,
/*IsIndexMainAST=*/false, URISchemes)
/*IsIndexMainAST=*/false)
.first;
}
@ -106,8 +102,7 @@ void FileSymbols::update(PathRef Path, std::unique_ptr<SymbolSlab> Symbols,
}
std::unique_ptr<SymbolIndex>
FileSymbols::buildIndex(IndexType Type, DuplicateHandling DuplicateHandle,
ArrayRef<std::string> URISchemes) {
FileSymbols::buildIndex(IndexType Type, DuplicateHandling DuplicateHandle) {
std::vector<std::shared_ptr<SymbolSlab>> SymbolSlabs;
std::vector<std::shared_ptr<RefSlab>> RefSlabs;
{
@ -191,35 +186,34 @@ FileSymbols::buildIndex(IndexType Type, DuplicateHandling DuplicateHandle,
make_pointee_range(AllSymbols), std::move(AllRefs),
std::make_tuple(std::move(SymbolSlabs), std::move(RefSlabs),
std::move(RefsStorage), std::move(SymsStorage)),
StorageSize, std::move(URISchemes));
StorageSize);
}
llvm_unreachable("Unknown clangd::IndexType");
}
FileIndex::FileIndex(std::vector<std::string> URISchemes, bool UseDex)
FileIndex::FileIndex(bool UseDex)
: MergedIndex(&MainFileIndex, &PreambleIndex), UseDex(UseDex),
URISchemes(std::move(URISchemes)),
PreambleIndex(llvm::make_unique<MemIndex>()),
MainFileIndex(llvm::make_unique<MemIndex>()) {}
void FileIndex::updatePreamble(PathRef Path, ASTContext &AST,
std::shared_ptr<Preprocessor> PP) {
auto Symbols = indexHeaderSymbols(AST, std::move(PP), URISchemes);
auto Symbols = indexHeaderSymbols(AST, std::move(PP));
PreambleSymbols.update(Path,
llvm::make_unique<SymbolSlab>(std::move(Symbols)),
llvm::make_unique<RefSlab>());
PreambleIndex.reset(
PreambleSymbols.buildIndex(UseDex ? IndexType::Heavy : IndexType::Light,
DuplicateHandling::PickOne, URISchemes));
DuplicateHandling::PickOne));
}
void FileIndex::updateMain(PathRef Path, ParsedAST &AST) {
auto Contents = indexMainDecls(AST, URISchemes);
auto Contents = indexMainDecls(AST);
MainFileSymbols.update(
Path, llvm::make_unique<SymbolSlab>(std::move(Contents.first)),
llvm::make_unique<RefSlab>(std::move(Contents.second)));
MainFileIndex.reset(MainFileSymbols.buildIndex(
IndexType::Light, DuplicateHandling::PickOne, URISchemes));
MainFileIndex.reset(
MainFileSymbols.buildIndex(IndexType::Light, DuplicateHandling::PickOne));
}
} // namespace clangd

View File

@ -65,8 +65,7 @@ public:
// The index keeps the symbols alive.
std::unique_ptr<SymbolIndex>
buildIndex(IndexType,
DuplicateHandling DuplicateHandle = DuplicateHandling::PickOne,
ArrayRef<std::string> URISchemes = {});
DuplicateHandling DuplicateHandle = DuplicateHandling::PickOne);
private:
mutable std::mutex Mutex;
@ -81,9 +80,7 @@ private:
/// FIXME: Expose an interface to remove files that are closed.
class FileIndex : public MergedIndex {
public:
/// If URISchemes is empty, the default schemes in SymbolCollector will be
/// used.
FileIndex(std::vector<std::string> URISchemes = {}, bool UseDex = true);
FileIndex(bool UseDex = true);
/// Update preamble symbols of file \p Path with all declarations in \p AST
/// and macros in \p PP.
@ -96,7 +93,6 @@ public:
private:
bool UseDex; // FIXME: this should be always on.
std::vector<std::string> URISchemes;
// Contains information from each file's preamble only.
// These are large, but update fairly infrequently (preambles are stable).
@ -125,15 +121,12 @@ private:
/// Retrieves symbols and refs of local top level decls in \p AST (i.e.
/// `AST.getLocalTopLevelDecls()`).
/// Exposed to assist in unit tests.
/// If URISchemes is empty, the default schemes in SymbolCollector will be used.
std::pair<SymbolSlab, RefSlab>
indexMainDecls(ParsedAST &AST, llvm::ArrayRef<std::string> URISchemes = {});
std::pair<SymbolSlab, RefSlab> indexMainDecls(ParsedAST &AST);
/// Idex declarations from \p AST and macros from \p PP that are declared in
/// included headers.
/// If URISchemes is empty, the default schemes in SymbolCollector will be used.
SymbolSlab indexHeaderSymbols(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
llvm::ArrayRef<std::string> URISchemes = {});
SymbolSlab indexHeaderSymbols(ASTContext &AST,
std::shared_ptr<Preprocessor> PP);
} // namespace clangd
} // namespace clang

View File

@ -488,9 +488,7 @@ Expected<IndexFileIn> readIndexFile(StringRef Data) {
}
}
std::unique_ptr<SymbolIndex> loadIndex(StringRef SymbolFilename,
ArrayRef<std::string> URISchemes,
bool UseDex) {
std::unique_ptr<SymbolIndex> loadIndex(StringRef SymbolFilename, bool UseDex) {
trace::Span OverallTracer("LoadIndex");
auto Buffer = MemoryBuffer::getFile(SymbolFilename);
if (!Buffer) {
@ -517,9 +515,8 @@ std::unique_ptr<SymbolIndex> loadIndex(StringRef SymbolFilename,
size_t NumRefs = Refs.numRefs();
trace::Span Tracer("BuildIndex");
auto Index =
UseDex ? dex::Dex::build(std::move(Symbols), std::move(Refs), URISchemes)
: MemIndex::build(std::move(Symbols), std::move(Refs));
auto Index = UseDex ? dex::Dex::build(std::move(Symbols), std::move(Refs))
: MemIndex::build(std::move(Symbols), std::move(Refs));
vlog("Loaded {0} from {1} with estimated memory usage {2} bytes\n"
" - number of symbols: {3}\n"
" - number of refs: {4}\n",

View File

@ -70,7 +70,6 @@ std::string toYAML(const std::pair<SymbolID, ArrayRef<Ref>> &);
// Build an in-memory static index from an index file.
// The size should be relatively small, so data can be managed in memory.
std::unique_ptr<SymbolIndex> loadIndex(llvm::StringRef Filename,
llvm::ArrayRef<std::string> URISchemes,
bool UseDex = true);
} // namespace clangd

View File

@ -83,16 +83,7 @@ Optional<std::string> toURI(const SourceManager &SM, StringRef Path,
}
sys::path::remove_dots(AbsolutePath, /*remove_dot_dot=*/true);
std::string ErrMsg;
for (const auto &Scheme : Opts.URISchemes) {
auto U = URI::create(AbsolutePath, Scheme);
if (U)
return U->toString();
ErrMsg += toString(U.takeError()) + "\n";
}
log("Failed to create an URI for file {0}: {1}", AbsolutePath, ErrMsg);
return None;
return URI::create(AbsolutePath).toString();
}
// All proto generated headers should start with this line.

View File

@ -48,10 +48,6 @@ public:
/// with symbols' paths to get absolute paths. This must be an absolute
/// path.
std::string FallbackDir;
/// Specifies URI schemes that can be used to generate URIs for file paths
/// in symbols. The list of schemes will be tried in order until a working
/// scheme is found. If no scheme works, symbol location will be dropped.
std::vector<std::string> URISchemes = {"file"};
bool CollectIncludePath = false;
/// If set, this is used to map symbol #include path to a potentially
/// different #include path.

View File

@ -25,12 +25,10 @@ namespace clang {
namespace clangd {
namespace dex {
std::unique_ptr<SymbolIndex> Dex::build(SymbolSlab Symbols, RefSlab Refs,
ArrayRef<std::string> URISchemes) {
std::unique_ptr<SymbolIndex> Dex::build(SymbolSlab Symbols, RefSlab Refs) {
auto Size = Symbols.bytes() + Refs.bytes();
auto Data = std::make_pair(std::move(Symbols), std::move(Refs));
return llvm::make_unique<Dex>(Data.first, Data.second, std::move(Data), Size,
std::move(URISchemes));
return llvm::make_unique<Dex>(Data.first, Data.second, std::move(Data), Size);
}
namespace {
@ -62,24 +60,18 @@ std::vector<Token> generateSearchTokens(const Symbol &Sym) {
}
// Constructs BOOST iterators for Path Proximities.
std::unique_ptr<Iterator> createFileProximityIterator(
ArrayRef<std::string> ProximityPaths, ArrayRef<std::string> URISchemes,
const DenseMap<Token, PostingList> &InvertedIndex, const Corpus &Corpus) {
std::unique_ptr<Iterator>
createFileProximityIterator(ArrayRef<std::string> ProximityPaths,
const DenseMap<Token, PostingList> &InvertedIndex,
const Corpus &Corpus) {
std::vector<std::unique_ptr<Iterator>> BoostingIterators;
// Deduplicate parent URIs extracted from the ProximityPaths.
StringSet<> ParentURIs;
StringMap<SourceParams> Sources;
for (const auto &Path : ProximityPaths) {
Sources[Path] = SourceParams();
auto PathURI = URI::create(Path, URISchemes);
if (!PathURI) {
elog("Given ProximityPath {0} is can not be converted to any known URI "
"scheme. fuzzyFind request will ignore it.",
Path);
consumeError(PathURI.takeError());
continue;
}
const auto PathProximityURIs = generateProximityURIs(PathURI->toString());
auto PathURI = URI::create(Path);
const auto PathProximityURIs = generateProximityURIs(PathURI.toString());
for (const auto &ProximityURI : PathProximityURIs)
ParentURIs.insert(ProximityURI);
}
@ -184,8 +176,8 @@ bool Dex::fuzzyFind(const FuzzyFindRequest &Req,
Criteria.push_back(Corpus.unionOf(move(ScopeIterators)));
// Add proximity paths boosting (all symbols, some boosted).
Criteria.push_back(createFileProximityIterator(Req.ProximityPaths, URISchemes,
InvertedIndex, Corpus));
Criteria.push_back(
createFileProximityIterator(Req.ProximityPaths, InvertedIndex, Corpus));
if (Req.RestrictForCodeCompletion)
Criteria.push_back(iterator(RestrictedForCodeCompletion));

View File

@ -43,15 +43,7 @@ class Dex : public SymbolIndex {
public:
// All data must outlive this index.
template <typename SymbolRange, typename RefsRange>
Dex(SymbolRange &&Symbols, RefsRange &&Refs,
llvm::ArrayRef<std::string> Schemes)
: Corpus(0), URISchemes(Schemes) {
// If Schemes don't contain any items, fall back to SymbolCollector's
// default URI schemes.
if (URISchemes.empty()) {
SymbolCollector::Options Opts;
URISchemes = Opts.URISchemes;
}
Dex(SymbolRange &&Symbols, RefsRange &&Refs) : Corpus(0) {
for (auto &&Sym : Symbols)
this->Symbols.push_back(&Sym);
for (auto &&Ref : Refs)
@ -61,17 +53,15 @@ public:
// Symbols and Refs are owned by BackingData, Index takes ownership.
template <typename SymbolRange, typename RefsRange, typename Payload>
Dex(SymbolRange &&Symbols, RefsRange &&Refs, Payload &&BackingData,
size_t BackingDataSize, llvm::ArrayRef<std::string> URISchemes)
: Dex(std::forward<SymbolRange>(Symbols), std::forward<RefsRange>(Refs),
URISchemes) {
size_t BackingDataSize)
: Dex(std::forward<SymbolRange>(Symbols), std::forward<RefsRange>(Refs)) {
KeepAlive = std::shared_ptr<void>(
std::make_shared<Payload>(std::move(BackingData)), nullptr);
this->BackingDataSize = BackingDataSize;
}
/// Builds an index from slabs. The index takes ownership of the slab.
static std::unique_ptr<SymbolIndex>
build(SymbolSlab, RefSlab, llvm::ArrayRef<std::string> URISchemes);
static std::unique_ptr<SymbolIndex> build(SymbolSlab, RefSlab);
bool
fuzzyFind(const FuzzyFindRequest &Req,
@ -106,8 +96,6 @@ private:
std::shared_ptr<void> KeepAlive; // poor man's move-only std::any
// Size of memory retained by KeepAlive.
size_t BackingDataSize = 0;
std::vector<std::string> URISchemes;
};
/// Returns Search Token for a number of parent directories of given Path.

View File

@ -257,7 +257,7 @@ struct {
};
std::unique_ptr<SymbolIndex> openIndex(StringRef Index) {
return loadIndex(Index, /*URISchemes=*/{}, /*UseDex=*/true);
return loadIndex(Index, /*UseDex=*/true);
}
} // namespace

View File

@ -83,11 +83,16 @@ static cl::opt<Logger::Level> LogLevel(
clEnumValN(Logger::Debug, "verbose", "Low level details")),
cl::init(Logger::Info));
static cl::opt<bool> Test(
"lit-test",
cl::desc(
"Abbreviation for -input-style=delimited -pretty -run-synchronously. "
"Intended to simplify lit tests."),
static cl::opt<bool>
Test("lit-test",
cl::desc("Abbreviation for -input-style=delimited -pretty "
"-run-synchronously -enable-test-scheme. "
"Intended to simplify lit tests."),
cl::init(false), cl::Hidden);
static cl::opt<bool> EnableTestScheme(
"enable-test-uri-scheme",
cl::desc("Enable 'test:' URI scheme. Only use in lit tests."),
cl::init(false), cl::Hidden);
enum PCHStorageFlag { Disk, Memory };
@ -177,6 +182,55 @@ static cl::opt<bool> EnableFunctionArgSnippets(
"placeholders for method parameters."),
cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets));
namespace {
/// \brief Supports a test URI scheme with relaxed constraints for lit tests.
/// The path in a test URI will be combined with a platform-specific fake
/// directory to form an absolute path. For example, test:///a.cpp is resolved
/// C:\clangd-test\a.cpp on Windows and /clangd-test/a.cpp on Unix.
class TestScheme : public URIScheme {
public:
Expected<std::string> getAbsolutePath(StringRef /*Authority*/, StringRef Body,
StringRef /*HintPath*/) const override {
using namespace llvm::sys;
// Still require "/" in body to mimic file scheme, as we want lengths of an
// equivalent URI in both schemes to be the same.
if (!Body.startswith("/"))
return make_error<StringError>(
"Expect URI body to be an absolute path starting with '/': " + Body,
inconvertibleErrorCode());
Body = Body.ltrim('/');
SmallVector<char, 16> Path(Body.begin(), Body.end());
path::native(Path);
auto Err = fs::make_absolute(TestScheme::TestDir, Path);
if (Err)
llvm_unreachable("Failed to make absolute path in test scheme.");
return std::string(Path.begin(), Path.end());
}
Expected<URI> uriFromAbsolutePath(StringRef AbsolutePath) const override {
StringRef Body = AbsolutePath;
if (!Body.consume_front(TestScheme::TestDir)) {
return make_error<StringError>("Path " + AbsolutePath +
" doesn't start with root " + TestDir,
inconvertibleErrorCode());
}
return URI("test", /*Authority=*/"", sys::path::convert_to_slash(Body));
}
private:
const static char TestDir[];
};
#ifdef _WIN32
const char TestScheme::TestDir[] = "C:\\clangd-test";
#else
const char TestScheme::TestDir[] = "/clangd-test";
#endif
}
int main(int argc, char *argv[]) {
sys::PrintStackTraceOnErrorSignal(argv[0]);
cl::SetVersionPrinter([](raw_ostream &OS) {
@ -195,6 +249,10 @@ int main(int argc, char *argv[]) {
InputStyle = JSONStreamStyle::Delimited;
PrettyPrint = true;
}
if (Test || EnableTestScheme) {
static URISchemeRegistry::Add<TestScheme> X(
"test", "Test scheme for clangd lit tests.");
}
if (!RunSynchronously && WorkerThreadsCount == 0) {
errs() << "A number of worker threads cannot be 0. Did you mean to "
@ -292,8 +350,8 @@ int main(int argc, char *argv[]) {
// Load the index asynchronously. Meanwhile SwapIndex returns no results.
SwapIndex *Placeholder;
StaticIdx.reset(Placeholder = new SwapIndex(llvm::make_unique<MemIndex>()));
AsyncIndexLoad = runAsync<void>([Placeholder, &Opts] {
if (auto Idx = loadIndex(IndexFile, Opts.URISchemes, /*UseDex=*/true))
AsyncIndexLoad = runAsync<void>([Placeholder] {
if (auto Idx = loadIndex(IndexFile, /*UseDex=*/true))
Placeholder->reset(std::move(Idx));
});
if (RunSynchronously)

View File

@ -1,5 +1,5 @@
# RUN: not clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s
# RUN: not clangd -pretty -run-synchronously < %s 2>&1 | FileCheck -check-prefix=STDERR %s
# RUN: not clangd -pretty -run-synchronously -enable-test-uri-scheme < %s | FileCheck -strict-whitespace %s
# RUN: not clangd -pretty -run-synchronously -enable-test-uri-scheme < %s 2>&1 | FileCheck -check-prefix=STDERR %s
# vim: fileformat=dos
# It is absolutely vital that this file has CRLF line endings.
#

View File

@ -80,7 +80,7 @@ TEST(BackgroundIndexTest, IndexTwoFiles) {
llvm::StringMap<std::string> Storage;
size_t CacheHits = 0;
MemoryShardStorage MSS(Storage, CacheHits);
BackgroundIndex Idx(Context::empty(), "", FS, /*URISchemes=*/{"unittest"},
BackgroundIndex Idx(Context::empty(), "", FS,
[&](llvm::StringRef) { return &MSS; });
tooling::CompileCommand Cmd;
@ -136,7 +136,7 @@ TEST(BackgroundIndexTest, ShardStorageWriteTest) {
Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
// Check nothing is loaded from Storage, but A.cc and A.h has been stored.
{
BackgroundIndex Idx(Context::empty(), "", FS, /*URISchemes=*/{"unittest"},
BackgroundIndex Idx(Context::empty(), "", FS,
[&](llvm::StringRef) { return &MSS; });
Idx.enqueue(testPath("root"), Cmd);
Idx.blockUntilIdleForTest();

View File

@ -581,7 +581,7 @@ TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
IgnoreDiagnostics DiagConsumer;
ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
auto BarURI = URI::createFile(BarHeader).toString();
auto BarURI = URI::create(BarHeader).toString();
Symbol Sym = cls("ns::X");
Sym.CanonicalDeclaration.FileURI = BarURI.c_str();
Sym.IncludeHeaders.emplace_back(BarURI, 1);
@ -613,7 +613,7 @@ TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
Symbol SymX = cls("ns::X");
Symbol SymY = cls("ns::Y");
std::string BarHeader = testPath("bar.h");
auto BarURI = URI::createFile(BarHeader).toString();
auto BarURI = URI::create(BarHeader).toString();
SymX.CanonicalDeclaration.FileURI = BarURI.c_str();
SymY.CanonicalDeclaration.FileURI = BarURI.c_str();
SymX.IncludeHeaders.emplace_back("<bar>", 1);
@ -1251,7 +1251,7 @@ TEST(CompletionTest, OverloadBundling) {
UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
// Differences in header-to-insert suppress bundling.
std::string DeclFile = URI::createFile(testPath("foo")).toString();
std::string DeclFile = URI::create(testPath("foo")).toString();
NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile.c_str();
NoArgsGFunc.IncludeHeaders.emplace_back("<foo>", 1);
EXPECT_THAT(
@ -1957,7 +1957,7 @@ TEST(CompletionTest, EnableSpeculativeIndexRequest) {
}
TEST(CompletionTest, InsertTheMostPopularHeader) {
std::string DeclFile = URI::createFile(testPath("foo")).toString();
std::string DeclFile = URI::create(testPath("foo")).toString();
Symbol sym = func("Func");
sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
sym.IncludeHeaders.emplace_back("\"foo.h\"", 2);
@ -1979,7 +1979,7 @@ TEST(CompletionTest, NoInsertIncludeIfOnePresent) {
IgnoreDiagnostics DiagConsumer;
ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
std::string DeclFile = URI::createFile(testPath("foo")).toString();
std::string DeclFile = URI::create(testPath("foo")).toString();
Symbol sym = func("Func");
sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
sym.IncludeHeaders.emplace_back("\"foo.h\"", 2);

View File

@ -33,8 +33,6 @@ namespace clangd {
namespace dex {
namespace {
std::vector<std::string> URISchemes = {"unittest"};
//===----------------------------------------------------------------------===//
// Query iterator tests.
//===----------------------------------------------------------------------===//
@ -457,8 +455,7 @@ TEST(DexSearchTokens, SymbolPath) {
//===----------------------------------------------------------------------===//
TEST(Dex, Lookup) {
auto I = Dex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab(),
URISchemes);
auto I = Dex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab());
EXPECT_THAT(lookup(*I, SymbolID("ns::abc")), UnorderedElementsAre("ns::abc"));
EXPECT_THAT(lookup(*I, {SymbolID("ns::abc"), SymbolID("ns::xyz")}),
UnorderedElementsAre("ns::abc", "ns::xyz"));
@ -471,7 +468,7 @@ TEST(Dex, FuzzyFind) {
auto Index =
Dex::build(generateSymbols({"ns::ABC", "ns::BCD", "::ABC",
"ns::nested::ABC", "other::ABC", "other::A"}),
RefSlab(), URISchemes);
RefSlab());
FuzzyFindRequest Req;
Req.Query = "ABC";
Req.Scopes = {"ns::"};
@ -493,7 +490,7 @@ TEST(Dex, FuzzyFind) {
}
TEST(DexTest, DexLimitedNumMatches) {
auto I = Dex::build(generateNumSymbols(0, 100), RefSlab(), URISchemes);
auto I = Dex::build(generateNumSymbols(0, 100), RefSlab());
FuzzyFindRequest Req;
Req.Query = "5";
Req.AnyScope = true;
@ -508,7 +505,7 @@ TEST(DexTest, DexLimitedNumMatches) {
TEST(DexTest, FuzzyMatch) {
auto I = Dex::build(
generateSymbols({"LaughingOutLoud", "LionPopulation", "LittleOldLady"}),
RefSlab(), URISchemes);
RefSlab());
FuzzyFindRequest Req;
Req.Query = "lol";
Req.AnyScope = true;
@ -518,8 +515,7 @@ TEST(DexTest, FuzzyMatch) {
}
TEST(DexTest, ShortQuery) {
auto I =
Dex::build(generateSymbols({"OneTwoThreeFour"}), RefSlab(), URISchemes);
auto I = Dex::build(generateSymbols({"OneTwoThreeFour"}), RefSlab());
FuzzyFindRequest Req;
Req.AnyScope = true;
bool Incomplete;
@ -541,8 +537,7 @@ TEST(DexTest, ShortQuery) {
}
TEST(DexTest, MatchQualifiedNamesWithoutSpecificScope) {
auto I = Dex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab(),
URISchemes);
auto I = Dex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab());
FuzzyFindRequest Req;
Req.AnyScope = true;
Req.Query = "y";
@ -550,8 +545,7 @@ TEST(DexTest, MatchQualifiedNamesWithoutSpecificScope) {
}
TEST(DexTest, MatchQualifiedNamesWithGlobalScope) {
auto I = Dex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab(),
URISchemes);
auto I = Dex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab());
FuzzyFindRequest Req;
Req.Query = "y";
Req.Scopes = {""};
@ -559,9 +553,8 @@ TEST(DexTest, MatchQualifiedNamesWithGlobalScope) {
}
TEST(DexTest, MatchQualifiedNamesWithOneScope) {
auto I =
Dex::build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"}),
RefSlab(), URISchemes);
auto I = Dex::build(
generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"}), RefSlab());
FuzzyFindRequest Req;
Req.Query = "y";
Req.Scopes = {"a::"};
@ -570,7 +563,7 @@ TEST(DexTest, MatchQualifiedNamesWithOneScope) {
TEST(DexTest, MatchQualifiedNamesWithMultipleScopes) {
auto I = Dex::build(
generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"}), RefSlab(), URISchemes);
generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"}), RefSlab());
FuzzyFindRequest Req;
Req.Query = "y";
Req.Scopes = {"a::", "b::"};
@ -578,7 +571,7 @@ TEST(DexTest, MatchQualifiedNamesWithMultipleScopes) {
}
TEST(DexTest, NoMatchNestedScopes) {
auto I = Dex::build(generateSymbols({"a::y1", "a::b::y2"}), RefSlab(), URISchemes);
auto I = Dex::build(generateSymbols({"a::y1", "a::b::y2"}), RefSlab());
FuzzyFindRequest Req;
Req.Query = "y";
Req.Scopes = {"a::"};
@ -587,7 +580,7 @@ TEST(DexTest, NoMatchNestedScopes) {
TEST(DexTest, WildcardScope) {
auto I =
Dex::build(generateSymbols({"a::y1", "a::b::y2", "c::y3"}), RefSlab(), URISchemes);
Dex::build(generateSymbols({"a::y1", "a::b::y2", "c::y3"}), RefSlab());
FuzzyFindRequest Req;
Req.AnyScope = true;
Req.Query = "y";
@ -597,7 +590,7 @@ TEST(DexTest, WildcardScope) {
}
TEST(DexTest, IgnoreCases) {
auto I = Dex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab(), URISchemes);
auto I = Dex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab());
FuzzyFindRequest Req;
Req.Query = "AB";
Req.Scopes = {"ns::"};
@ -606,15 +599,14 @@ TEST(DexTest, IgnoreCases) {
TEST(DexTest, UnknownPostingList) {
// Regression test: we used to ignore unknown scopes and accept any symbol.
auto I = Dex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab(),
URISchemes);
auto I = Dex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab());
FuzzyFindRequest Req;
Req.Scopes = {"ns2::"};
EXPECT_THAT(match(*I, Req), UnorderedElementsAre());
}
TEST(DexTest, Lookup) {
auto I = Dex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab(), URISchemes);
auto I = Dex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab());
EXPECT_THAT(lookup(*I, SymbolID("ns::abc")), UnorderedElementsAre("ns::abc"));
EXPECT_THAT(lookup(*I, {SymbolID("ns::abc"), SymbolID("ns::xyz")}),
UnorderedElementsAre("ns::abc", "ns::xyz"));
@ -629,7 +621,7 @@ TEST(DexTest, SymbolIndexOptionsFilter) {
CodeCompletionSymbol.Flags = Symbol::SymbolFlag::IndexedForCodeCompletion;
NonCodeCompletionSymbol.Flags = Symbol::SymbolFlag::None;
std::vector<Symbol> Symbols{CodeCompletionSymbol, NonCodeCompletionSymbol};
Dex I(Symbols, RefSlab(), URISchemes);
Dex I(Symbols, RefSlab());
FuzzyFindRequest Req;
Req.AnyScope = true;
Req.RestrictForCodeCompletion = false;
@ -645,7 +637,7 @@ TEST(DexTest, ProximityPathsBoosting) {
CloseSymbol.CanonicalDeclaration.FileURI = "unittest:///a/b/c/d/e/f/file.h";
std::vector<Symbol> Symbols{CloseSymbol, RootSymbol};
Dex I(Symbols, RefSlab(), URISchemes);
Dex I(Symbols, RefSlab());
FuzzyFindRequest Req;
Req.AnyScope = true;
@ -682,7 +674,7 @@ TEST(DexTests, Refs) {
RefsRequest Req;
Req.IDs.insert(Foo.ID);
Req.Filter = RefKind::Declaration | RefKind::Definition;
Dex(std::vector<Symbol>{Foo, Bar}, Refs, {}).refs(Req, [&](const Ref &R) {
Dex(std::vector<Symbol>{Foo, Bar}, Refs).refs(Req, [&](const Ref &R) {
Files.push_back(R.Location.FileURI);
});

View File

@ -152,7 +152,7 @@ void update(FileIndex &M, StringRef Basename, StringRef Code) {
}
TEST(FileIndexTest, CustomizedURIScheme) {
FileIndex M({"unittest"});
FileIndex M;
update(M, "f", "class string {};");
EXPECT_THAT(runFuzzyFind(M, ""), ElementsAre(DeclURI("unittest:///f.h")));
@ -302,7 +302,7 @@ TEST(FileIndexTest, Refs) {
RefsRequest Request;
Request.IDs = {Foo.ID};
FileIndex Index(/*URISchemes*/ {"unittest"});
FileIndex Index;
// Add test.cc
TestTU Test;
Test.HeaderCode = HeaderCode;

View File

@ -44,7 +44,6 @@ ClangdServer::Options optsForTests() {
auto ServerOpts = ClangdServer::optsForTest();
ServerOpts.WorkspaceRoot = testRoot();
ServerOpts.BuildDynamicSymbolIndex = true;
ServerOpts.URISchemes = {"unittest", "file"};
return ServerOpts;
}

View File

@ -253,8 +253,8 @@ TEST(MergeTest, PreferSymbolWithDefn) {
}
TEST(MergeIndexTest, Refs) {
FileIndex Dyn({"unittest"});
FileIndex StaticIndex({"unittest"});
FileIndex Dyn;
FileIndex StaticIndex;
MergedIndex Merge(&Dyn, &StaticIndex);
const char *HeaderCode = "class Foo;";

View File

@ -227,8 +227,8 @@ public:
: InMemoryFileSystem(new vfs::InMemoryFileSystem),
TestHeaderName(testPath("symbol.h")),
TestFileName(testPath("symbol.cc")) {
TestHeaderURI = URI::createFile(TestHeaderName).toString();
TestFileURI = URI::createFile(TestFileName).toString();
TestHeaderURI = URI::create(TestHeaderName).toString();
TestFileURI = URI::create(TestFileName).toString();
}
bool runSymbolCollector(StringRef HeaderCode, StringRef MainCode,
@ -391,7 +391,7 @@ TEST_F(SymbolCollectorTest, ObjCSymbols) {
- (void)someMethodName3:(void*)name3;
@end
)";
TestFileName = "test.m";
TestFileName = testPath("test.m");
runSymbolCollector(Header, /*Main=*/"", {"-fblocks", "-xobjective-c++"});
EXPECT_THAT(Symbols,
UnorderedElementsAre(
@ -534,16 +534,15 @@ TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
TestHeaderName = "x.h";
TestFileName = "x.cpp";
TestHeaderURI = URI::createFile(testPath(TestHeaderName)).toString();
TestHeaderURI = URI::create(testPath(TestHeaderName)).toString();
CollectorOpts.FallbackDir = testRoot();
runSymbolCollector("class Foo {};", /*Main=*/"");
EXPECT_THAT(Symbols,
UnorderedElementsAre(AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
}
TEST_F(SymbolCollectorTest, CustomURIScheme) {
TEST_F(SymbolCollectorTest, UnittestURIScheme) {
// Use test URI scheme from URITests.cpp
CollectorOpts.URISchemes.insert(CollectorOpts.URISchemes.begin(), "unittest");
TestHeaderName = testPath("x.h");
TestFileName = testPath("x.cpp");
runSymbolCollector("class Foo {};", /*Main=*/"");
@ -551,21 +550,6 @@ TEST_F(SymbolCollectorTest, CustomURIScheme) {
AllOf(QName("Foo"), DeclURI("unittest:///x.h"))));
}
TEST_F(SymbolCollectorTest, InvalidURIScheme) {
// Use test URI scheme from URITests.cpp
CollectorOpts.URISchemes = {"invalid"};
runSymbolCollector("class Foo {};", /*Main=*/"");
EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("Foo"), DeclURI(""))));
}
TEST_F(SymbolCollectorTest, FallbackToFileURI) {
// Use test URI scheme from URITests.cpp
CollectorOpts.URISchemes = {"invalid", "file"};
runSymbolCollector("class Foo {};", /*Main=*/"");
EXPECT_THAT(Symbols, UnorderedElementsAre(
AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
}
TEST_F(SymbolCollectorTest, IncludeEnums) {
const std::string Header = R"(
enum {
@ -606,7 +590,7 @@ TEST_F(SymbolCollectorTest, NamelessSymbols) {
QName("(anonymous struct)::a")));
}
TEST_F(SymbolCollectorTest, SymbolFormedFromMacro) {
TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
Annotations Header(R"(
#define FF(name) \
@ -765,7 +749,7 @@ TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
// bits/basic_string.h$ should be mapped to <string>
TestHeaderName = "/nasty/bits/basic_string.h";
TestFileName = "/nasty/bits/basic_string.cpp";
TestHeaderURI = URI::createFile(TestHeaderName).toString();
TestHeaderURI = URI::create(TestHeaderName).toString();
runSymbolCollector("class string {};", /*Main=*/"");
EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("string"),
DeclURI(TestHeaderURI),
@ -835,7 +819,7 @@ TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
Includes.addMapping(TestHeaderName, "<canonical>");
CollectorOpts.Includes = &Includes;
auto IncFile = testPath("test.inc");
auto IncURI = URI::createFile(IncFile).toString();
auto IncURI = URI::create(IncFile).toString();
InMemoryFileSystem->addFile(IncFile, 0,
MemoryBuffer::getMemBuffer("class X {};"));
runSymbolCollector("#include \"test.inc\"\nclass Y {};", /*Main=*/"",
@ -852,9 +836,9 @@ TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
CanonicalIncludes Includes;
CollectorOpts.Includes = &Includes;
TestFileName = testPath("main.h");
TestFileURI = URI::createFile(TestFileName).toString();
TestFileURI = URI::create(TestFileName).toString();
auto IncFile = testPath("test.inc");
auto IncURI = URI::createFile(IncFile).toString();
auto IncURI = URI::create(IncFile).toString();
InMemoryFileSystem->addFile(IncFile, 0,
MemoryBuffer::getMemBuffer("class X {};"));
runSymbolCollector("", /*Main=*/"#include \"test.inc\"",
@ -868,9 +852,9 @@ TEST_F(SymbolCollectorTest, MainFileIsHeaderWithoutExtensionWhenSkipIncFile) {
CanonicalIncludes Includes;
CollectorOpts.Includes = &Includes;
TestFileName = testPath("no_ext_main");
TestFileURI = URI::createFile(TestFileName).toString();
TestFileURI = URI::create(TestFileName).toString();
auto IncFile = testPath("test.inc");
auto IncURI = URI::createFile(IncFile).toString();
auto IncURI = URI::create(IncFile).toString();
InMemoryFileSystem->addFile(IncFile, 0,
MemoryBuffer::getMemBuffer("class X {};"));
runSymbolCollector("", /*Main=*/"#include \"test.inc\"",
@ -884,7 +868,7 @@ TEST_F(SymbolCollectorTest, FallbackToIncFileWhenIncludingFileIsCC) {
CanonicalIncludes Includes;
CollectorOpts.Includes = &Includes;
auto IncFile = testPath("test.inc");
auto IncURI = URI::createFile(IncFile).toString();
auto IncURI = URI::create(IncFile).toString();
InMemoryFileSystem->addFile(IncFile, 0,
MemoryBuffer::getMemBuffer("class X {};"));
runSymbolCollector("", /*Main=*/"#include \"test.inc\"",

View File

@ -59,8 +59,7 @@ SymbolSlab TestTU::headerSymbols() const {
std::unique_ptr<SymbolIndex> TestTU::index() const {
auto AST = build();
auto Idx = llvm::make_unique<FileIndex>(
/*URISchemes=*/std::vector<std::string>{}, /*UseDex=*/true);
auto Idx = llvm::make_unique<FileIndex>(/*UseDex=*/true);
Idx->updatePreamble(Filename, AST.getASTContext(), AST.getPreprocessorPtr());
Idx->updateMain(Filename, AST);
return std::move(Idx);