forked from OSchip/llvm-project
[clangd] Remove Tagged and some related APIs from ClangdServer.
Context can do what Tagged was intended to support (snapshot filesystems), and less intrusively. getTaggedFileSystem() no longer needs a filename. Cleanups while here: - code-complete now returns errors as Expected, like other functions - added an alias Callback<T> for the usual callback function type llvm-svn: 327344
This commit is contained in:
parent
1527dec139
commit
a7bb0cc09e
|
@ -330,28 +330,33 @@ void ClangdLSPServer::onCodeAction(CodeActionParams &Params) {
|
|||
|
||||
void ClangdLSPServer::onCompletion(TextDocumentPositionParams &Params) {
|
||||
Server.codeComplete(Params.textDocument.uri.file(), Params.position, CCOpts,
|
||||
[](Tagged<CompletionList> List) { reply(List.Value); });
|
||||
[](llvm::Expected<CompletionList> List) {
|
||||
if (!List)
|
||||
return replyError(ErrorCode::InvalidParams,
|
||||
llvm::toString(List.takeError()));
|
||||
reply(*List);
|
||||
});
|
||||
}
|
||||
|
||||
void ClangdLSPServer::onSignatureHelp(TextDocumentPositionParams &Params) {
|
||||
Server.signatureHelp(Params.textDocument.uri.file(), Params.position,
|
||||
[](llvm::Expected<Tagged<SignatureHelp>> SignatureHelp) {
|
||||
[](llvm::Expected<SignatureHelp> SignatureHelp) {
|
||||
if (!SignatureHelp)
|
||||
return replyError(
|
||||
ErrorCode::InvalidParams,
|
||||
llvm::toString(SignatureHelp.takeError()));
|
||||
reply(SignatureHelp->Value);
|
||||
reply(*SignatureHelp);
|
||||
});
|
||||
}
|
||||
|
||||
void ClangdLSPServer::onGoToDefinition(TextDocumentPositionParams &Params) {
|
||||
Server.findDefinitions(
|
||||
Params.textDocument.uri.file(), Params.position,
|
||||
[](llvm::Expected<Tagged<std::vector<Location>>> Items) {
|
||||
[](llvm::Expected<std::vector<Location>> Items) {
|
||||
if (!Items)
|
||||
return replyError(ErrorCode::InvalidParams,
|
||||
llvm::toString(Items.takeError()));
|
||||
reply(json::ary(Items->Value));
|
||||
reply(json::ary(*Items));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -363,24 +368,24 @@ void ClangdLSPServer::onSwitchSourceHeader(TextDocumentIdentifier &Params) {
|
|||
void ClangdLSPServer::onDocumentHighlight(TextDocumentPositionParams &Params) {
|
||||
Server.findDocumentHighlights(
|
||||
Params.textDocument.uri.file(), Params.position,
|
||||
[](llvm::Expected<Tagged<std::vector<DocumentHighlight>>> Highlights) {
|
||||
[](llvm::Expected<std::vector<DocumentHighlight>> Highlights) {
|
||||
if (!Highlights)
|
||||
return replyError(ErrorCode::InternalError,
|
||||
llvm::toString(Highlights.takeError()));
|
||||
reply(json::ary(Highlights->Value));
|
||||
reply(json::ary(*Highlights));
|
||||
});
|
||||
}
|
||||
|
||||
void ClangdLSPServer::onHover(TextDocumentPositionParams &Params) {
|
||||
Server.findHover(Params.textDocument.uri.file(), Params.position,
|
||||
[](llvm::Expected<Tagged<Hover>> H) {
|
||||
[](llvm::Expected<Hover> H) {
|
||||
if (!H) {
|
||||
replyError(ErrorCode::InternalError,
|
||||
llvm::toString(H.takeError()));
|
||||
return;
|
||||
}
|
||||
|
||||
reply(H->Value);
|
||||
reply(*H);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -437,12 +442,12 @@ std::vector<Fix> ClangdLSPServer::getFixes(StringRef File,
|
|||
return FixItsIter->second;
|
||||
}
|
||||
|
||||
void ClangdLSPServer::onDiagnosticsReady(
|
||||
PathRef File, Tagged<std::vector<Diag>> Diagnostics) {
|
||||
void ClangdLSPServer::onDiagnosticsReady(PathRef File,
|
||||
std::vector<Diag> Diagnostics) {
|
||||
json::ary DiagnosticsJSON;
|
||||
|
||||
DiagnosticToReplacementMap LocalFixIts; // Temporary storage
|
||||
for (auto &Diag : Diagnostics.Value) {
|
||||
for (auto &Diag : Diagnostics) {
|
||||
toLSPDiags(Diag, [&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes) {
|
||||
DiagnosticsJSON.push_back(json::obj{
|
||||
{"range", Diag.range},
|
||||
|
|
|
@ -46,8 +46,7 @@ public:
|
|||
|
||||
private:
|
||||
// Implement DiagnosticsConsumer.
|
||||
void onDiagnosticsReady(PathRef File,
|
||||
Tagged<std::vector<Diag>> Diagnostics) override;
|
||||
void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override;
|
||||
|
||||
// Implement ProtocolCallbacks.
|
||||
void onInitialize(InitializeParams &Params) override;
|
||||
|
|
|
@ -65,9 +65,8 @@ public:
|
|||
|
||||
} // namespace
|
||||
|
||||
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
|
||||
RealFileSystemProvider::getTaggedFileSystem(PathRef File) {
|
||||
return make_tagged(vfs::getRealFileSystem(), VFSTag());
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> RealFileSystemProvider::getFileSystem() {
|
||||
return vfs::getRealFileSystem();
|
||||
}
|
||||
|
||||
ClangdServer::Options ClangdServer::optsForTest() {
|
||||
|
@ -119,9 +118,8 @@ void ClangdServer::setRootPath(PathRef RootPath) {
|
|||
void ClangdServer::addDocument(PathRef File, StringRef Contents,
|
||||
WantDiagnostics WantDiags) {
|
||||
DocVersion Version = DraftMgr.updateDraft(File, Contents);
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
scheduleReparseAndDiags(File, VersionedDraft{Version, Contents.str()},
|
||||
WantDiags, std::move(TaggedFS));
|
||||
WantDiags, FSProvider.getFileSystem());
|
||||
}
|
||||
|
||||
void ClangdServer::removeDocument(PathRef File) {
|
||||
|
@ -139,34 +137,29 @@ void ClangdServer::forceReparse(PathRef File) {
|
|||
// remove any cahced flags.
|
||||
CompileArgs.invalidate(File);
|
||||
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
scheduleReparseAndDiags(File, std::move(FileContents), WantDiagnostics::Yes,
|
||||
std::move(TaggedFS));
|
||||
FSProvider.getFileSystem());
|
||||
}
|
||||
|
||||
void ClangdServer::codeComplete(
|
||||
PathRef File, Position Pos, const clangd::CodeCompleteOptions &Opts,
|
||||
UniqueFunction<void(Tagged<CompletionList>)> Callback,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
|
||||
using CallbackType = UniqueFunction<void(Tagged<CompletionList>)>;
|
||||
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
if (UsedFS)
|
||||
*UsedFS = TaggedFS.Value;
|
||||
|
||||
void ClangdServer::codeComplete(PathRef File, Position Pos,
|
||||
const clangd::CodeCompleteOptions &Opts,
|
||||
Callback<CompletionList> CB) {
|
||||
// Copy completion options for passing them to async task handler.
|
||||
auto CodeCompleteOpts = Opts;
|
||||
if (!CodeCompleteOpts.Index) // Respect overridden index.
|
||||
CodeCompleteOpts.Index = Index;
|
||||
|
||||
VersionedDraft Latest = DraftMgr.getDraft(File);
|
||||
// FIXME(sammccall): return error for consistency?
|
||||
assert(Latest.Draft && "codeComplete called for non-added document");
|
||||
if (!Latest.Draft)
|
||||
return CB(llvm::make_error<llvm::StringError>(
|
||||
"codeComplete called for non-added document",
|
||||
llvm::errc::invalid_argument));
|
||||
|
||||
// Copy PCHs to avoid accessing this->PCHs concurrently
|
||||
std::shared_ptr<PCHContainerOperations> PCHs = this->PCHs;
|
||||
auto Task = [PCHs, Pos, TaggedFS, CodeCompleteOpts](
|
||||
std::string Contents, Path File, CallbackType Callback,
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto Task = [PCHs, Pos, FS, CodeCompleteOpts](
|
||||
std::string Contents, Path File, Callback<CompletionList> CB,
|
||||
llvm::Expected<InputsAndPreamble> IP) {
|
||||
assert(IP && "error when trying to read preamble for codeComplete");
|
||||
auto PreambleData = IP->Preamble;
|
||||
|
@ -176,49 +169,41 @@ void ClangdServer::codeComplete(
|
|||
// both the old and the new version in case only one of them matches.
|
||||
CompletionList Result = clangd::codeComplete(
|
||||
File, Command, PreambleData ? &PreambleData->Preamble : nullptr,
|
||||
Contents, Pos, TaggedFS.Value, PCHs, CodeCompleteOpts);
|
||||
|
||||
Callback(make_tagged(std::move(Result), std::move(TaggedFS.Tag)));
|
||||
Contents, Pos, FS, PCHs, CodeCompleteOpts);
|
||||
CB(std::move(Result));
|
||||
};
|
||||
|
||||
WorkScheduler.runWithPreamble(
|
||||
"CodeComplete", File,
|
||||
Bind(Task, std::move(*Latest.Draft), File.str(), std::move(Callback)));
|
||||
Bind(Task, std::move(*Latest.Draft), File.str(), std::move(CB)));
|
||||
}
|
||||
|
||||
void ClangdServer::signatureHelp(
|
||||
PathRef File, Position Pos,
|
||||
UniqueFunction<void(llvm::Expected<Tagged<SignatureHelp>>)> Callback,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
if (UsedFS)
|
||||
*UsedFS = TaggedFS.Value;
|
||||
|
||||
void ClangdServer::signatureHelp(PathRef File, Position Pos,
|
||||
Callback<SignatureHelp> CB) {
|
||||
VersionedDraft Latest = DraftMgr.getDraft(File);
|
||||
if (!Latest.Draft)
|
||||
return Callback(llvm::make_error<llvm::StringError>(
|
||||
return CB(llvm::make_error<llvm::StringError>(
|
||||
"signatureHelp is called for non-added document",
|
||||
llvm::errc::invalid_argument));
|
||||
|
||||
auto PCHs = this->PCHs;
|
||||
auto Action = [Pos, TaggedFS, PCHs](std::string Contents, Path File,
|
||||
decltype(Callback) Callback,
|
||||
llvm::Expected<InputsAndPreamble> IP) {
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto Action = [Pos, FS, PCHs](std::string Contents, Path File,
|
||||
Callback<SignatureHelp> CB,
|
||||
llvm::Expected<InputsAndPreamble> IP) {
|
||||
if (!IP)
|
||||
return Callback(IP.takeError());
|
||||
return CB(IP.takeError());
|
||||
|
||||
auto PreambleData = IP->Preamble;
|
||||
auto &Command = IP->Inputs.CompileCommand;
|
||||
Callback(make_tagged(
|
||||
clangd::signatureHelp(File, Command,
|
||||
PreambleData ? &PreambleData->Preamble : nullptr,
|
||||
Contents, Pos, TaggedFS.Value, PCHs),
|
||||
TaggedFS.Tag));
|
||||
CB(clangd::signatureHelp(File, Command,
|
||||
PreambleData ? &PreambleData->Preamble : nullptr,
|
||||
Contents, Pos, FS, PCHs));
|
||||
};
|
||||
|
||||
WorkScheduler.runWithPreamble(
|
||||
"SignatureHelp", File,
|
||||
Bind(Action, std::move(*Latest.Draft), File.str(), std::move(Callback)));
|
||||
Bind(Action, std::move(*Latest.Draft), File.str(), std::move(CB)));
|
||||
}
|
||||
|
||||
llvm::Expected<tooling::Replacements>
|
||||
|
@ -247,15 +232,13 @@ ClangdServer::formatOnType(StringRef Code, PathRef File, Position Pos) {
|
|||
return formatCode(Code, File, {tooling::Range(PreviousLBracePos, Len)});
|
||||
}
|
||||
|
||||
void ClangdServer::rename(
|
||||
PathRef File, Position Pos, llvm::StringRef NewName,
|
||||
UniqueFunction<void(Expected<std::vector<tooling::Replacement>>)>
|
||||
Callback) {
|
||||
void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName,
|
||||
Callback<std::vector<tooling::Replacement>> CB) {
|
||||
auto Action = [Pos](Path File, std::string NewName,
|
||||
decltype(Callback) Callback,
|
||||
Callback<std::vector<tooling::Replacement>> CB,
|
||||
Expected<InputsAndAST> InpAST) {
|
||||
if (!InpAST)
|
||||
return Callback(InpAST.takeError());
|
||||
return CB(InpAST.takeError());
|
||||
auto &AST = InpAST->AST;
|
||||
|
||||
RefactoringResultCollector ResultCollector;
|
||||
|
@ -263,7 +246,7 @@ void ClangdServer::rename(
|
|||
const FileEntry *FE =
|
||||
SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
|
||||
if (!FE)
|
||||
return Callback(llvm::make_error<llvm::StringError>(
|
||||
return CB(llvm::make_error<llvm::StringError>(
|
||||
"rename called for non-added document",
|
||||
llvm::errc::invalid_argument));
|
||||
SourceLocation SourceLocationBeg =
|
||||
|
@ -274,13 +257,13 @@ void ClangdServer::rename(
|
|||
auto Rename = clang::tooling::RenameOccurrences::initiate(
|
||||
Context, SourceRange(SourceLocationBeg), NewName);
|
||||
if (!Rename)
|
||||
return Callback(Rename.takeError());
|
||||
return CB(Rename.takeError());
|
||||
|
||||
Rename->invoke(ResultCollector, Context);
|
||||
|
||||
assert(ResultCollector.Result.hasValue());
|
||||
if (!ResultCollector.Result.getValue())
|
||||
return Callback(ResultCollector.Result->takeError());
|
||||
return CB(ResultCollector.Result->takeError());
|
||||
|
||||
std::vector<tooling::Replacement> Replacements;
|
||||
for (const tooling::AtomicChange &Change : ResultCollector.Result->get()) {
|
||||
|
@ -299,12 +282,11 @@ void ClangdServer::rename(
|
|||
Replacements.push_back(Rep);
|
||||
}
|
||||
}
|
||||
return Callback(Replacements);
|
||||
return CB(std::move(Replacements));
|
||||
};
|
||||
|
||||
WorkScheduler.runWithAST(
|
||||
"Rename", File,
|
||||
Bind(Action, File.str(), NewName.str(), std::move(Callback)));
|
||||
"Rename", File, Bind(Action, File.str(), NewName.str(), std::move(CB)));
|
||||
}
|
||||
|
||||
/// Creates a `HeaderFile` from \p Header which can be either a URI or a literal
|
||||
|
@ -335,9 +317,9 @@ ClangdServer::insertInclude(PathRef File, StringRef Code,
|
|||
if (!ResolvedPreferred)
|
||||
return ResolvedPreferred.takeError();
|
||||
tooling::CompileCommand CompileCommand = CompileArgs.getCompileCommand(File);
|
||||
auto Include = calculateIncludePath(
|
||||
File, Code, *ResolvedOrginal, *ResolvedPreferred, CompileCommand,
|
||||
FSProvider.getTaggedFileSystem(File).Value);
|
||||
auto Include =
|
||||
calculateIncludePath(File, Code, *ResolvedOrginal, *ResolvedPreferred,
|
||||
CompileCommand, FSProvider.getFileSystem());
|
||||
if (!Include)
|
||||
return Include.takeError();
|
||||
if (Include->empty())
|
||||
|
@ -387,21 +369,17 @@ void ClangdServer::dumpAST(PathRef File,
|
|||
WorkScheduler.runWithAST("DumpAST", File, Bind(Action, std::move(Callback)));
|
||||
}
|
||||
|
||||
void ClangdServer::findDefinitions(
|
||||
PathRef File, Position Pos,
|
||||
UniqueFunction<void(llvm::Expected<Tagged<std::vector<Location>>>)>
|
||||
Callback) {
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
auto Action = [Pos, TaggedFS](decltype(Callback) Callback,
|
||||
llvm::Expected<InputsAndAST> InpAST) {
|
||||
void ClangdServer::findDefinitions(PathRef File, Position Pos,
|
||||
Callback<std::vector<Location>> CB) {
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto Action = [Pos, FS](Callback<std::vector<Location>> CB,
|
||||
llvm::Expected<InputsAndAST> InpAST) {
|
||||
if (!InpAST)
|
||||
return Callback(InpAST.takeError());
|
||||
auto Result = clangd::findDefinitions(InpAST->AST, Pos);
|
||||
Callback(make_tagged(std::move(Result), TaggedFS.Tag));
|
||||
return CB(InpAST.takeError());
|
||||
CB(clangd::findDefinitions(InpAST->AST, Pos));
|
||||
};
|
||||
|
||||
WorkScheduler.runWithAST("Definitions", File,
|
||||
Bind(Action, std::move(Callback)));
|
||||
WorkScheduler.runWithAST("Definitions", File, Bind(Action, std::move(CB)));
|
||||
}
|
||||
|
||||
llvm::Optional<Path> ClangdServer::switchSourceHeader(PathRef Path) {
|
||||
|
@ -444,7 +422,7 @@ llvm::Optional<Path> ClangdServer::switchSourceHeader(PathRef Path) {
|
|||
SmallString<128> NewPath = StringRef(Path);
|
||||
|
||||
// Instance of vfs::FileSystem, used for file existence checks.
|
||||
auto FS = FSProvider.getTaggedFileSystem(Path).Value;
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
|
||||
// Loop through switched extension candidates.
|
||||
for (StringRef NewExt : NewExts) {
|
||||
|
@ -467,9 +445,8 @@ llvm::Expected<tooling::Replacements>
|
|||
ClangdServer::formatCode(llvm::StringRef Code, PathRef File,
|
||||
ArrayRef<tooling::Range> Ranges) {
|
||||
// Call clang-format.
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
auto Style =
|
||||
format::getStyle("file", File, "LLVM", Code, TaggedFS.Value.get());
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto Style = format::getStyle("file", File, "LLVM", Code, FS.get());
|
||||
if (!Style)
|
||||
return Style.takeError();
|
||||
|
||||
|
@ -486,62 +463,51 @@ ClangdServer::formatCode(llvm::StringRef Code, PathRef File,
|
|||
}
|
||||
|
||||
void ClangdServer::findDocumentHighlights(
|
||||
PathRef File, Position Pos,
|
||||
UniqueFunction<void(llvm::Expected<Tagged<std::vector<DocumentHighlight>>>)>
|
||||
Callback) {
|
||||
PathRef File, Position Pos, Callback<std::vector<DocumentHighlight>> CB) {
|
||||
auto FileContents = DraftMgr.getDraft(File);
|
||||
if (!FileContents.Draft)
|
||||
return Callback(llvm::make_error<llvm::StringError>(
|
||||
return CB(llvm::make_error<llvm::StringError>(
|
||||
"findDocumentHighlights called on non-added file",
|
||||
llvm::errc::invalid_argument));
|
||||
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
|
||||
auto Action = [TaggedFS, Pos](decltype(Callback) Callback,
|
||||
llvm::Expected<InputsAndAST> InpAST) {
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto Action = [FS, Pos](Callback<std::vector<DocumentHighlight>> CB,
|
||||
llvm::Expected<InputsAndAST> InpAST) {
|
||||
if (!InpAST)
|
||||
return Callback(InpAST.takeError());
|
||||
auto Result = clangd::findDocumentHighlights(InpAST->AST, Pos);
|
||||
Callback(make_tagged(std::move(Result), TaggedFS.Tag));
|
||||
return CB(InpAST.takeError());
|
||||
CB(clangd::findDocumentHighlights(InpAST->AST, Pos));
|
||||
};
|
||||
|
||||
WorkScheduler.runWithAST("Highlights", File,
|
||||
Bind(Action, std::move(Callback)));
|
||||
WorkScheduler.runWithAST("Highlights", File, Bind(Action, std::move(CB)));
|
||||
}
|
||||
|
||||
void ClangdServer::findHover(
|
||||
PathRef File, Position Pos,
|
||||
UniqueFunction<void(llvm::Expected<Tagged<Hover>>)> Callback) {
|
||||
void ClangdServer::findHover(PathRef File, Position Pos, Callback<Hover> CB) {
|
||||
Hover FinalHover;
|
||||
auto FileContents = DraftMgr.getDraft(File);
|
||||
if (!FileContents.Draft)
|
||||
return Callback(llvm::make_error<llvm::StringError>(
|
||||
return CB(llvm::make_error<llvm::StringError>(
|
||||
"findHover called on non-added file", llvm::errc::invalid_argument));
|
||||
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
|
||||
auto Action = [Pos, TaggedFS](decltype(Callback) Callback,
|
||||
llvm::Expected<InputsAndAST> InpAST) {
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto Action = [Pos, FS](Callback<Hover> CB,
|
||||
llvm::Expected<InputsAndAST> InpAST) {
|
||||
if (!InpAST)
|
||||
return Callback(InpAST.takeError());
|
||||
|
||||
Hover Result = clangd::getHover(InpAST->AST, Pos);
|
||||
Callback(make_tagged(std::move(Result), TaggedFS.Tag));
|
||||
return CB(InpAST.takeError());
|
||||
CB(clangd::getHover(InpAST->AST, Pos));
|
||||
};
|
||||
|
||||
WorkScheduler.runWithAST("Hover", File, Bind(Action, std::move(Callback)));
|
||||
WorkScheduler.runWithAST("Hover", File, Bind(Action, std::move(CB)));
|
||||
}
|
||||
|
||||
void ClangdServer::scheduleReparseAndDiags(
|
||||
PathRef File, VersionedDraft Contents, WantDiagnostics WantDiags,
|
||||
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> FS) {
|
||||
tooling::CompileCommand Command = CompileArgs.getCompileCommand(File);
|
||||
|
||||
DocVersion Version = Contents.Version;
|
||||
Path FileStr = File.str();
|
||||
VFSTag Tag = std::move(TaggedFS.Tag);
|
||||
|
||||
auto Callback = [this, Version, FileStr, Tag](std::vector<Diag> Diags) {
|
||||
auto Callback = [this, Version, FileStr](std::vector<Diag> Diags) {
|
||||
// We need to serialize access to resulting diagnostics to avoid calling
|
||||
// `onDiagnosticsReady` in the wrong order.
|
||||
std::lock_guard<std::mutex> DiagsLock(DiagnosticsMutex);
|
||||
|
@ -554,13 +520,11 @@ void ClangdServer::scheduleReparseAndDiags(
|
|||
return;
|
||||
LastReportedDiagsVersion = Version;
|
||||
|
||||
DiagConsumer.onDiagnosticsReady(
|
||||
FileStr, make_tagged(std::move(Diags), std::move(Tag)));
|
||||
DiagConsumer.onDiagnosticsReady(FileStr, std::move(Diags));
|
||||
};
|
||||
|
||||
WorkScheduler.update(File,
|
||||
ParseInputs{std::move(Command),
|
||||
std::move(TaggedFS.Value),
|
||||
ParseInputs{std::move(Command), std::move(FS),
|
||||
std::move(*Contents.Draft)},
|
||||
WantDiags, std::move(Callback));
|
||||
}
|
||||
|
|
|
@ -35,63 +35,29 @@ class PCHContainerOperations;
|
|||
|
||||
namespace clangd {
|
||||
|
||||
/// A tag supplied by the FileSytemProvider.
|
||||
typedef std::string VFSTag;
|
||||
|
||||
/// A value of an arbitrary type and VFSTag that was supplied by the
|
||||
/// FileSystemProvider when this value was computed.
|
||||
template <class T> class Tagged {
|
||||
public:
|
||||
// MSVC requires future<> arguments to be default-constructible.
|
||||
Tagged() = default;
|
||||
|
||||
template <class U>
|
||||
Tagged(U &&Value, VFSTag Tag)
|
||||
: Value(std::forward<U>(Value)), Tag(std::move(Tag)) {}
|
||||
|
||||
template <class U>
|
||||
Tagged(const Tagged<U> &Other) : Value(Other.Value), Tag(Other.Tag) {}
|
||||
|
||||
template <class U>
|
||||
Tagged(Tagged<U> &&Other)
|
||||
: Value(std::move(Other.Value)), Tag(std::move(Other.Tag)) {}
|
||||
|
||||
T Value = T();
|
||||
VFSTag Tag = VFSTag();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Tagged<typename std::decay<T>::type> make_tagged(T &&Value, VFSTag Tag) {
|
||||
return Tagged<typename std::decay<T>::type>(std::forward<T>(Value), Tag);
|
||||
}
|
||||
|
||||
class DiagnosticsConsumer {
|
||||
public:
|
||||
virtual ~DiagnosticsConsumer() = default;
|
||||
|
||||
/// Called by ClangdServer when \p Diagnostics for \p File are ready.
|
||||
virtual void onDiagnosticsReady(PathRef File,
|
||||
Tagged<std::vector<Diag>> Diagnostics) = 0;
|
||||
std::vector<Diag> Diagnostics) = 0;
|
||||
};
|
||||
|
||||
class FileSystemProvider {
|
||||
public:
|
||||
virtual ~FileSystemProvider() = default;
|
||||
/// Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.
|
||||
/// Name of the file that will be parsed is passed in \p File.
|
||||
///
|
||||
/// \return A filesystem that will be used for all file accesses in clangd.
|
||||
/// A Tag returned by this method will be propagated to all results of clangd
|
||||
/// that will use this filesystem.
|
||||
virtual Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
|
||||
getTaggedFileSystem(PathRef File) = 0;
|
||||
/// Context::current() will be the context passed to the clang entrypoint,
|
||||
/// such as addDocument(), and will also be propagated to result callbacks.
|
||||
/// Embedders may use this to isolate filesystem accesses.
|
||||
virtual IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() = 0;
|
||||
};
|
||||
|
||||
class RealFileSystemProvider : public FileSystemProvider {
|
||||
public:
|
||||
/// \return getRealFileSystem() tagged with default tag, i.e. VFSTag()
|
||||
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
|
||||
getTaggedFileSystem(PathRef File) override;
|
||||
/// Returns getRealFileSystem().
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override;
|
||||
};
|
||||
|
||||
/// Provides API to manage ASTs for a collection of C++ files and request
|
||||
|
@ -137,10 +103,6 @@ public:
|
|||
/// those arguments for subsequent reparses. However, ClangdServer will check
|
||||
/// if compilation arguments changed on calls to forceReparse().
|
||||
///
|
||||
/// FSProvider provides a vfs::FileSystem for each parsing request. Results of
|
||||
/// code completion and diagnostics also include a tag, that \p FSProvider
|
||||
/// returns along with the vfs::FileSystem.
|
||||
///
|
||||
/// After each parsing request finishes, ClangdServer reports diagnostics to
|
||||
/// \p DiagConsumer. Note that a callback to \p DiagConsumer happens on a
|
||||
/// worker thread. Therefore, instances of \p DiagConsumer must properly
|
||||
|
@ -186,39 +148,29 @@ public:
|
|||
/// when codeComplete results become available.
|
||||
void codeComplete(PathRef File, Position Pos,
|
||||
const clangd::CodeCompleteOptions &Opts,
|
||||
UniqueFunction<void(Tagged<CompletionList>)> Callback,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
|
||||
Callback<CompletionList> CB);
|
||||
|
||||
/// Provide signature help for \p File at \p Pos. If \p OverridenContents is
|
||||
/// not None, they will used only for signature help, i.e. no diagnostics
|
||||
/// update will be scheduled and a draft for \p File will not be updated. If
|
||||
/// If \p UsedFS is non-null, it will be overwritten by vfs::FileSystem used
|
||||
/// for signature help. This method should only be called for tracked files.
|
||||
void signatureHelp(
|
||||
PathRef File, Position Pos,
|
||||
UniqueFunction<void(llvm::Expected<Tagged<SignatureHelp>>)> Callback,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
|
||||
void signatureHelp(PathRef File, Position Pos, Callback<SignatureHelp> CB);
|
||||
|
||||
/// Get definition of symbol at a specified \p Line and \p Column in \p File.
|
||||
void findDefinitions(
|
||||
PathRef File, Position Pos,
|
||||
UniqueFunction<void(llvm::Expected<Tagged<std::vector<Location>>>)>
|
||||
Callback);
|
||||
void findDefinitions(PathRef File, Position Pos,
|
||||
Callback<std::vector<Location>> CB);
|
||||
|
||||
/// Helper function that returns a path to the corresponding source file when
|
||||
/// given a header file and vice versa.
|
||||
llvm::Optional<Path> switchSourceHeader(PathRef Path);
|
||||
|
||||
/// Get document highlights for a given position.
|
||||
void findDocumentHighlights(
|
||||
PathRef File, Position Pos,
|
||||
UniqueFunction<
|
||||
void(llvm::Expected<Tagged<std::vector<DocumentHighlight>>>)>
|
||||
Callback);
|
||||
void findDocumentHighlights(PathRef File, Position Pos,
|
||||
Callback<std::vector<DocumentHighlight>> CB);
|
||||
|
||||
/// Get code hover for a given position.
|
||||
void findHover(PathRef File, Position Pos,
|
||||
UniqueFunction<void(llvm::Expected<Tagged<Hover>>)> Callback);
|
||||
void findHover(PathRef File, Position Pos, Callback<Hover> CB);
|
||||
|
||||
/// Run formatting for \p Rng inside \p File with content \p Code.
|
||||
llvm::Expected<tooling::Replacements> formatRange(StringRef Code,
|
||||
|
@ -236,8 +188,7 @@ public:
|
|||
/// Rename all occurrences of the symbol at the \p Pos in \p File to
|
||||
/// \p NewName.
|
||||
void rename(PathRef File, Position Pos, llvm::StringRef NewName,
|
||||
UniqueFunction<void(Expected<std::vector<tooling::Replacement>>)>
|
||||
Callback);
|
||||
Callback<std::vector<tooling::Replacement>> CB);
|
||||
|
||||
/// Inserts a new #include into \p File, if it's not present in \p Code.
|
||||
///
|
||||
|
@ -289,10 +240,9 @@ private:
|
|||
formatCode(llvm::StringRef Code, PathRef File,
|
||||
ArrayRef<tooling::Range> Ranges);
|
||||
|
||||
void
|
||||
scheduleReparseAndDiags(PathRef File, VersionedDraft Contents,
|
||||
WantDiagnostics WD,
|
||||
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS);
|
||||
void scheduleReparseAndDiags(PathRef File, VersionedDraft Contents,
|
||||
WantDiagnostics WD,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> FS);
|
||||
|
||||
CompileArgsCache CompileArgs;
|
||||
DiagnosticsConsumer &DiagConsumer;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
@ -27,6 +28,9 @@ namespace clangd {
|
|||
/// A move-only type-erasing function wrapper. Similar to `std::function`, but
|
||||
/// allows to store move-only callables.
|
||||
template <class> class UniqueFunction;
|
||||
/// A Callback<T> is a void function that accepts Expected<T>.
|
||||
/// This is accepted by ClangdServer functions that logically return T.
|
||||
template <typename T> using Callback = UniqueFunction<void(llvm::Expected<T>)>;
|
||||
|
||||
template <class Ret, class... Args> class UniqueFunction<Ret(Args...)> {
|
||||
public:
|
||||
|
|
|
@ -76,16 +76,15 @@ public:
|
|||
/// If an error occurs during processing, it is forwarded to the \p Action
|
||||
/// callback.
|
||||
void runWithAST(llvm::StringRef Name, PathRef File,
|
||||
UniqueFunction<void(llvm::Expected<InputsAndAST>)> Action);
|
||||
Callback<InputsAndAST> Action);
|
||||
|
||||
/// Schedule an async read of the Preamble. Preamble passed to \p Action may
|
||||
/// be built for any version of the file, callers must not rely on it being
|
||||
/// consistent with the current version of the file.
|
||||
/// If an error occurs during processing, it is forwarded to the \p Action
|
||||
/// callback.
|
||||
void runWithPreamble(
|
||||
llvm::StringRef Name, PathRef File,
|
||||
UniqueFunction<void(llvm::Expected<InputsAndPreamble>)> Action);
|
||||
void runWithPreamble(llvm::StringRef Name, PathRef File,
|
||||
Callback<InputsAndPreamble> Action);
|
||||
|
||||
/// Wait until there are no scheduled or running tasks.
|
||||
/// Mostly useful for synchronizing tests.
|
||||
|
|
|
@ -54,12 +54,10 @@ static bool diagsContainErrors(const std::vector<Diag> &Diagnostics) {
|
|||
class ErrorCheckingDiagConsumer : public DiagnosticsConsumer {
|
||||
public:
|
||||
void onDiagnosticsReady(PathRef File,
|
||||
Tagged<std::vector<Diag>> Diagnostics) override {
|
||||
bool HadError = diagsContainErrors(Diagnostics.Value);
|
||||
|
||||
std::vector<Diag> Diagnostics) override {
|
||||
bool HadError = diagsContainErrors(Diagnostics);
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
HadErrorInLastDiags = HadError;
|
||||
LastVFSTag = Diagnostics.Tag;
|
||||
}
|
||||
|
||||
bool hadErrorInLastDiags() {
|
||||
|
@ -67,12 +65,9 @@ public:
|
|||
return HadErrorInLastDiags;
|
||||
}
|
||||
|
||||
VFSTag lastVFSTag() { return LastVFSTag; }
|
||||
|
||||
private:
|
||||
std::mutex Mutex;
|
||||
bool HadErrorInLastDiags = false;
|
||||
VFSTag LastVFSTag = VFSTag();
|
||||
};
|
||||
|
||||
/// For each file, record whether the last published diagnostics contained at
|
||||
|
@ -80,8 +75,8 @@ private:
|
|||
class MultipleErrorCheckingDiagConsumer : public DiagnosticsConsumer {
|
||||
public:
|
||||
void onDiagnosticsReady(PathRef File,
|
||||
Tagged<std::vector<Diag>> Diagnostics) override {
|
||||
bool HadError = diagsContainErrors(Diagnostics.Value);
|
||||
std::vector<Diag> Diagnostics) override {
|
||||
bool HadError = diagsContainErrors(Diagnostics);
|
||||
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
LastDiagsHadError[File] = HadError;
|
||||
|
@ -149,7 +144,6 @@ protected:
|
|||
FS.Files[testPath(FileWithContents.first)] = FileWithContents.second;
|
||||
|
||||
auto SourceFilename = testPath(SourceFileRelPath);
|
||||
FS.ExpectedFile = SourceFilename;
|
||||
Server.addDocument(SourceFilename, SourceContents);
|
||||
auto Result = dumpASTWithoutMemoryLocs(Server, SourceFilename);
|
||||
EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
|
||||
|
@ -208,7 +202,6 @@ int b = a;
|
|||
|
||||
FS.Files[testPath("foo.h")] = "int a;";
|
||||
FS.Files[FooCpp] = SourceContents;
|
||||
FS.ExpectedFile = FooCpp;
|
||||
|
||||
Server.addDocument(FooCpp, SourceContents);
|
||||
auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
|
||||
|
@ -245,7 +238,6 @@ int b = a;
|
|||
|
||||
FS.Files[FooH] = "int a;";
|
||||
FS.Files[FooCpp] = SourceContents;
|
||||
FS.ExpectedFile = FooCpp;
|
||||
|
||||
Server.addDocument(FooCpp, SourceContents);
|
||||
auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
|
||||
|
@ -268,29 +260,33 @@ int b = a;
|
|||
EXPECT_NE(DumpParse1, DumpParseDifferent);
|
||||
}
|
||||
|
||||
TEST_F(ClangdVFSTest, CheckVersions) {
|
||||
MockFSProvider FS;
|
||||
ErrorCheckingDiagConsumer DiagConsumer;
|
||||
TEST_F(ClangdVFSTest, PropagatesContexts) {
|
||||
static Key<int> Secret;
|
||||
struct FSProvider : public FileSystemProvider {
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override {
|
||||
Got = Context::current().getExisting(Secret);
|
||||
return buildTestFS({});
|
||||
}
|
||||
int Got;
|
||||
} FS;
|
||||
struct DiagConsumer : public DiagnosticsConsumer {
|
||||
void onDiagnosticsReady(PathRef File,
|
||||
std::vector<Diag> Diagnostics) override {
|
||||
Got = Context::current().getExisting(Secret);
|
||||
}
|
||||
int Got;
|
||||
} DiagConsumer;
|
||||
MockCompilationDatabase CDB;
|
||||
|
||||
// Verify that the context is plumbed to the FS provider and diagnostics.
|
||||
ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
|
||||
|
||||
auto FooCpp = testPath("foo.cpp");
|
||||
const auto SourceContents = "int a;";
|
||||
FS.Files[FooCpp] = SourceContents;
|
||||
FS.ExpectedFile = FooCpp;
|
||||
|
||||
// Use default completion options.
|
||||
clangd::CodeCompleteOptions CCOpts;
|
||||
|
||||
FS.Tag = "123";
|
||||
runAddDocument(Server, FooCpp, SourceContents);
|
||||
EXPECT_EQ(runCodeComplete(Server, FooCpp, Position(), CCOpts).Tag, FS.Tag);
|
||||
EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
|
||||
|
||||
FS.Tag = "321";
|
||||
runAddDocument(Server, FooCpp, SourceContents);
|
||||
EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
|
||||
EXPECT_EQ(runCodeComplete(Server, FooCpp, Position(), CCOpts).Tag, FS.Tag);
|
||||
{
|
||||
WithContextValue Entrypoint(Secret, 42);
|
||||
Server.addDocument(testPath("foo.cpp"), "void main(){}");
|
||||
}
|
||||
ASSERT_TRUE(Server.blockUntilIdleForTest());
|
||||
EXPECT_EQ(FS.Got, 42);
|
||||
EXPECT_EQ(DiagConsumer.Got, 42);
|
||||
}
|
||||
|
||||
// Only enable this test on Unix
|
||||
|
@ -362,7 +358,6 @@ struct bar { T x; };
|
|||
)cpp";
|
||||
|
||||
FS.Files[FooCpp] = "";
|
||||
FS.ExpectedFile = FooCpp;
|
||||
|
||||
// First parse files in C mode and check they produce errors.
|
||||
CDB.ExtraClangFlags = {"-xc"};
|
||||
|
@ -405,7 +400,6 @@ this
|
|||
int main() { return 0; }
|
||||
)cpp";
|
||||
FS.Files[FooCpp] = "";
|
||||
FS.ExpectedFile = FooCpp;
|
||||
|
||||
// Parse with define, we expect to see the errors.
|
||||
CDB.ExtraClangFlags = {"-DWITH_ERROR"};
|
||||
|
@ -474,8 +468,8 @@ int hello;
|
|||
|
||||
auto Locations = runFindDefinitions(Server, FooCpp, FooSource.point());
|
||||
EXPECT_TRUE(bool(Locations));
|
||||
EXPECT_THAT(Locations->Value, ElementsAre(Location{URIForFile{FooCpp},
|
||||
FooSource.range("one")}));
|
||||
EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
|
||||
FooSource.range("one")}));
|
||||
|
||||
// Undefine MACRO, close baz.cpp.
|
||||
CDB.ExtraClangFlags.clear();
|
||||
|
@ -489,8 +483,8 @@ int hello;
|
|||
|
||||
Locations = runFindDefinitions(Server, FooCpp, FooSource.point());
|
||||
EXPECT_TRUE(bool(Locations));
|
||||
EXPECT_THAT(Locations->Value, ElementsAre(Location{URIForFile{FooCpp},
|
||||
FooSource.range("two")}));
|
||||
EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
|
||||
FooSource.range("two")}));
|
||||
}
|
||||
|
||||
TEST_F(ClangdVFSTest, MemoryUsage) {
|
||||
|
@ -550,13 +544,13 @@ TEST_F(ClangdVFSTest, InvalidCompileCommand) {
|
|||
EXPECT_ERROR(runRename(Server, FooCpp, Position(), "new_name"));
|
||||
// FIXME: codeComplete and signatureHelp should also return errors when they
|
||||
// can't parse the file.
|
||||
EXPECT_THAT(
|
||||
runCodeComplete(Server, FooCpp, Position(), clangd::CodeCompleteOptions())
|
||||
.Value.items,
|
||||
IsEmpty());
|
||||
EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Position(),
|
||||
clangd::CodeCompleteOptions()))
|
||||
.items,
|
||||
IsEmpty());
|
||||
auto SigHelp = runSignatureHelp(Server, FooCpp, Position());
|
||||
ASSERT_TRUE(bool(SigHelp)) << "signatureHelp returned an error";
|
||||
EXPECT_THAT(SigHelp->Value.signatures, IsEmpty());
|
||||
EXPECT_THAT(SigHelp->signatures, IsEmpty());
|
||||
}
|
||||
|
||||
class ClangdThreadingTest : public ClangdVFSTest {};
|
||||
|
@ -609,13 +603,13 @@ int d;
|
|||
TestDiagConsumer() : Stats(FilesCount, FileStat()) {}
|
||||
|
||||
void onDiagnosticsReady(PathRef File,
|
||||
Tagged<std::vector<Diag>> Diagnostics) override {
|
||||
std::vector<Diag> Diagnostics) override {
|
||||
StringRef FileIndexStr = llvm::sys::path::stem(File);
|
||||
ASSERT_TRUE(FileIndexStr.consume_front("Foo"));
|
||||
|
||||
unsigned long FileIndex = std::stoul(FileIndexStr.str());
|
||||
|
||||
bool HadError = diagsContainErrors(Diagnostics.Value);
|
||||
bool HadError = diagsContainErrors(Diagnostics);
|
||||
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
if (HadError)
|
||||
|
@ -739,8 +733,8 @@ int d;
|
|||
// requests as opposed to AddDocument/RemoveDocument, which are implicitly
|
||||
// cancelled by any subsequent AddDocument/RemoveDocument request to the
|
||||
// same file.
|
||||
runCodeComplete(Server, FilePaths[FileIndex], Pos,
|
||||
clangd::CodeCompleteOptions());
|
||||
cantFail(runCodeComplete(Server, FilePaths[FileIndex], Pos,
|
||||
clangd::CodeCompleteOptions()));
|
||||
};
|
||||
|
||||
auto FindDefinitionsRequest = [&]() {
|
||||
|
@ -876,7 +870,7 @@ TEST_F(ClangdThreadingTest, NoConcurrentDiagnostics) {
|
|||
NoConcurrentAccessDiagConsumer(std::promise<void> StartSecondReparse)
|
||||
: StartSecondReparse(std::move(StartSecondReparse)) {}
|
||||
|
||||
void onDiagnosticsReady(PathRef, Tagged<std::vector<Diag>>) override {
|
||||
void onDiagnosticsReady(PathRef, std::vector<Diag>) override {
|
||||
++Count;
|
||||
std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock_t());
|
||||
ASSERT_TRUE(Lock.owns_lock())
|
||||
|
|
|
@ -62,7 +62,7 @@ using ::testing::UnorderedElementsAre;
|
|||
|
||||
class IgnoreDiagnostics : public DiagnosticsConsumer {
|
||||
void onDiagnosticsReady(PathRef File,
|
||||
Tagged<std::vector<Diag>> Diagnostics) override {}
|
||||
std::vector<Diag> Diagnostics) override {}
|
||||
};
|
||||
|
||||
// GMock helpers for matching completion items.
|
||||
|
@ -121,7 +121,8 @@ CompletionList completions(StringRef Text,
|
|||
auto File = testPath("foo.cpp");
|
||||
Annotations Test(Text);
|
||||
runAddDocument(Server, File, Test.code());
|
||||
auto CompletionList = runCodeComplete(Server, File, Test.point(), Opts).Value;
|
||||
auto CompletionList =
|
||||
cantFail(runCodeComplete(Server, File, Test.point(), Opts));
|
||||
// Sanity-check that filterText is valid.
|
||||
EXPECT_THAT(CompletionList.items, Each(NameContainsFilter()));
|
||||
return CompletionList;
|
||||
|
@ -536,15 +537,16 @@ TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
|
|||
|
||||
auto I = memIndex({var("ns::index")});
|
||||
Opts.Index = I.get();
|
||||
auto WithIndex = runCodeComplete(Server, File, Test.point(), Opts).Value;
|
||||
auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
|
||||
EXPECT_THAT(WithIndex.items,
|
||||
UnorderedElementsAre(Named("local"), Named("index")));
|
||||
auto ClassFromPreamble =
|
||||
runCodeComplete(Server, File, Test.point("2"), Opts).Value;
|
||||
cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
|
||||
EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
|
||||
|
||||
Opts.Index = nullptr;
|
||||
auto WithoutIndex = runCodeComplete(Server, File, Test.point(), Opts).Value;
|
||||
auto WithoutIndex =
|
||||
cantFail(runCodeComplete(Server, File, Test.point(), Opts));
|
||||
EXPECT_THAT(WithoutIndex.items,
|
||||
UnorderedElementsAre(Named("local"), Named("preamble")));
|
||||
}
|
||||
|
@ -575,7 +577,7 @@ TEST(CompletionTest, DynamicIndexMultiFile) {
|
|||
)cpp");
|
||||
runAddDocument(Server, File, Test.code());
|
||||
|
||||
auto Results = runCodeComplete(Server, File, Test.point(), {}).Value;
|
||||
auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
|
||||
// "XYZ" and "foo" are not included in the file being completed but are still
|
||||
// visible through the index.
|
||||
EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
|
||||
|
@ -614,9 +616,7 @@ SignatureHelp signatures(StringRef Text) {
|
|||
auto File = testPath("foo.cpp");
|
||||
Annotations Test(Text);
|
||||
runAddDocument(Server, File, Test.code());
|
||||
auto R = runSignatureHelp(Server, File, Test.point());
|
||||
assert(R);
|
||||
return R.get().Value;
|
||||
return cantFail(runSignatureHelp(Server, File, Test.point()));
|
||||
}
|
||||
|
||||
MATCHER_P(ParamsAre, P, "") {
|
||||
|
|
|
@ -29,7 +29,7 @@ protected:
|
|||
bool ExpectError = false) {
|
||||
if (Preferred.empty())
|
||||
Preferred = Original;
|
||||
auto VFS = FS.getTaggedFileSystem(MainFile).Value;
|
||||
auto VFS = FS.getFileSystem();
|
||||
auto Cmd = CDB.getCompileCommand(MainFile);
|
||||
assert(static_cast<bool>(Cmd));
|
||||
VFS->setCurrentWorkingDirectory(Cmd->Directory);
|
||||
|
|
|
@ -67,31 +67,31 @@ template <typename T> CaptureProxy<T> capture(llvm::Optional<T> &Target) {
|
|||
}
|
||||
} // namespace
|
||||
|
||||
Tagged<CompletionList> runCodeComplete(ClangdServer &Server, PathRef File,
|
||||
Position Pos,
|
||||
clangd::CodeCompleteOptions Opts) {
|
||||
llvm::Optional<Tagged<CompletionList>> Result;
|
||||
llvm::Expected<CompletionList>
|
||||
runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,
|
||||
clangd::CodeCompleteOptions Opts) {
|
||||
llvm::Optional<llvm::Expected<CompletionList>> Result;
|
||||
Server.codeComplete(File, Pos, Opts, capture(Result));
|
||||
return std::move(*Result);
|
||||
}
|
||||
|
||||
llvm::Expected<Tagged<SignatureHelp>>
|
||||
runSignatureHelp(ClangdServer &Server, PathRef File, Position Pos) {
|
||||
llvm::Optional<llvm::Expected<Tagged<SignatureHelp>>> Result;
|
||||
llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,
|
||||
PathRef File, Position Pos) {
|
||||
llvm::Optional<llvm::Expected<SignatureHelp>> Result;
|
||||
Server.signatureHelp(File, Pos, capture(Result));
|
||||
return std::move(*Result);
|
||||
}
|
||||
|
||||
llvm::Expected<Tagged<std::vector<Location>>>
|
||||
llvm::Expected<std::vector<Location>>
|
||||
runFindDefinitions(ClangdServer &Server, PathRef File, Position Pos) {
|
||||
llvm::Optional<llvm::Expected<Tagged<std::vector<Location>>>> Result;
|
||||
llvm::Optional<llvm::Expected<std::vector<Location>>> Result;
|
||||
Server.findDefinitions(File, Pos, capture(Result));
|
||||
return std::move(*Result);
|
||||
}
|
||||
|
||||
llvm::Expected<Tagged<std::vector<DocumentHighlight>>>
|
||||
llvm::Expected<std::vector<DocumentHighlight>>
|
||||
runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos) {
|
||||
llvm::Optional<llvm::Expected<Tagged<std::vector<DocumentHighlight>>>> Result;
|
||||
llvm::Optional<llvm::Expected<std::vector<DocumentHighlight>>> Result;
|
||||
Server.findDocumentHighlights(File, Pos, capture(Result));
|
||||
return std::move(*Result);
|
||||
}
|
||||
|
|
|
@ -21,17 +21,17 @@ namespace clangd {
|
|||
// Calls addDocument and then blockUntilIdleForTest.
|
||||
void runAddDocument(ClangdServer &Server, PathRef File, StringRef Contents);
|
||||
|
||||
Tagged<CompletionList> runCodeComplete(ClangdServer &Server, PathRef File,
|
||||
Position Pos,
|
||||
clangd::CodeCompleteOptions Opts);
|
||||
llvm::Expected<CompletionList>
|
||||
runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,
|
||||
clangd::CodeCompleteOptions Opts);
|
||||
|
||||
llvm::Expected<Tagged<SignatureHelp>>
|
||||
runSignatureHelp(ClangdServer &Server, PathRef File, Position Pos);
|
||||
llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,
|
||||
PathRef File, Position Pos);
|
||||
|
||||
llvm::Expected<Tagged<std::vector<Location>>>
|
||||
llvm::Expected<std::vector<Location>>
|
||||
runFindDefinitions(ClangdServer &Server, PathRef File, Position Pos);
|
||||
|
||||
llvm::Expected<Tagged<std::vector<DocumentHighlight>>>
|
||||
llvm::Expected<std::vector<DocumentHighlight>>
|
||||
runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos);
|
||||
|
||||
llvm::Expected<std::vector<tooling::Replacement>>
|
||||
|
|
|
@ -26,16 +26,6 @@ buildTestFS(StringMap<std::string> const &Files) {
|
|||
return MemFS;
|
||||
}
|
||||
|
||||
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
|
||||
MockFSProvider::getTaggedFileSystem(PathRef File) {
|
||||
if (ExpectedFile) {
|
||||
EXPECT_EQ(*ExpectedFile, File);
|
||||
}
|
||||
|
||||
auto FS = buildTestFS(Files);
|
||||
return make_tagged(FS, Tag);
|
||||
}
|
||||
|
||||
MockCompilationDatabase::MockCompilationDatabase(bool UseRelPaths)
|
||||
: ExtraClangFlags({"-ffreestanding"}), UseRelPaths(UseRelPaths) {
|
||||
// -ffreestanding avoids implicit stdc-predef.h.
|
||||
|
|
|
@ -26,13 +26,12 @@ buildTestFS(llvm::StringMap<std::string> const &Files);
|
|||
// A VFS provider that returns TestFSes containing a provided set of files.
|
||||
class MockFSProvider : public FileSystemProvider {
|
||||
public:
|
||||
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
|
||||
getTaggedFileSystem(PathRef File) override;
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override {
|
||||
return buildTestFS(Files);
|
||||
}
|
||||
|
||||
llvm::Optional<std::string> ExpectedFile;
|
||||
// If relative paths are used, they are resolved with testPath().
|
||||
llvm::StringMap<std::string> Files;
|
||||
VFSTag Tag = VFSTag();
|
||||
};
|
||||
|
||||
// A Compilation database that returns a fixed set of compile flags.
|
||||
|
|
|
@ -42,7 +42,7 @@ using testing::UnorderedElementsAreArray;
|
|||
|
||||
class IgnoreDiagnostics : public DiagnosticsConsumer {
|
||||
void onDiagnosticsReady(PathRef File,
|
||||
Tagged<std::vector<Diag>> Diagnostics) override {}
|
||||
std::vector<Diag> Diagnostics) override {}
|
||||
};
|
||||
|
||||
// FIXME: this is duplicated with FileIndexTests. Share it.
|
||||
|
@ -266,9 +266,8 @@ int baz = f^oo;
|
|||
runFindDefinitions(Server, FooCpp, SourceAnnotations.point());
|
||||
EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
|
||||
EXPECT_THAT(
|
||||
Locations->Value,
|
||||
ElementsAre(Location{URIForFile{FooCpp}, SourceAnnotations.range()}));
|
||||
EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
|
||||
SourceAnnotations.range()}));
|
||||
}
|
||||
|
||||
TEST(Hover, All) {
|
||||
|
@ -609,38 +608,38 @@ TEST(GoToInclude, All) {
|
|||
auto Locations =
|
||||
runFindDefinitions(Server, FooCpp, SourceAnnotations.point());
|
||||
ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
EXPECT_THAT(Locations->Value,
|
||||
EXPECT_THAT(*Locations,
|
||||
ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
|
||||
|
||||
// Test include in preamble, last char.
|
||||
Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("2"));
|
||||
ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
EXPECT_THAT(Locations->Value,
|
||||
EXPECT_THAT(*Locations,
|
||||
ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
|
||||
|
||||
Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("3"));
|
||||
ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
EXPECT_THAT(Locations->Value,
|
||||
EXPECT_THAT(*Locations,
|
||||
ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
|
||||
|
||||
// Test include outside of preamble.
|
||||
Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("6"));
|
||||
ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
EXPECT_THAT(Locations->Value,
|
||||
EXPECT_THAT(*Locations,
|
||||
ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
|
||||
|
||||
// Test a few positions that do not result in Locations.
|
||||
Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("4"));
|
||||
ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
EXPECT_THAT(Locations->Value, IsEmpty());
|
||||
EXPECT_THAT(*Locations, IsEmpty());
|
||||
|
||||
Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("5"));
|
||||
ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
EXPECT_THAT(Locations->Value, IsEmpty());
|
||||
EXPECT_THAT(*Locations, IsEmpty());
|
||||
|
||||
Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("7"));
|
||||
ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
||||
EXPECT_THAT(Locations->Value, IsEmpty());
|
||||
EXPECT_THAT(*Locations, IsEmpty());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in New Issue