diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp index 65e75629cea..983fa623d03 100644 --- a/src/libs/languageserverprotocol/lsptypes.cpp +++ b/src/libs/languageserverprotocol/lsptypes.cpp @@ -62,7 +62,7 @@ void WorkspaceEdit::setChanges(const Changes &changes) QJsonArray edits; for (const TextEdit &edit : it.value()) edits.append(QJsonValue(edit)); - changesObject.insert(it.key().toFilePath().toString(), edits); + changesObject.insert(QJsonValue(it.key()).toString(), edits); } insert(changesKey, changesObject); } @@ -345,36 +345,46 @@ bool DocumentFilter::applies(const Utils::FilePath &fileName, const Utils::MimeT return !contains(schemeKey) && !contains(languageKey) && !contains(patternKey); } -Utils::Link Location::toLink() const +Utils::Link Location::toLink(const DocumentUri::PathMapper &mapToHostPath) const { if (!isValid()) return Utils::Link(); - // Ensure %xx like %20 are really decoded using fromPercentEncoding - // Else, a path with spaces would keep its %20 which would cause failure - // to open the file by the text editor. This is the cases with compilers in - // C:\Programs Files on Windows. - auto file = uri().toString(QUrl::PrettyDecoded | QUrl::PreferLocalFile); - // fromPercentEncoding convert %xx encoding to raw values and then interpret - // the result as utf-8, so toUtf8() must be used here. - file = QUrl::fromPercentEncoding(file.toUtf8()); - return Utils::Link(Utils::FilePath::fromString(file), + return Utils::Link(uri().toFilePath(mapToHostPath), range().start().line() + 1, range().start().character()); } +// Ensure %xx like %20 are really decoded using fromPercentEncoding +// Else, a path with spaces would keep its %20 which would cause failure +// to open the file by the text editor. This is the cases with compilers in +// C:\Programs Files on Windows. DocumentUri::DocumentUri(const QString &other) : QUrl(QUrl::fromPercentEncoding(other.toUtf8())) { } -DocumentUri::DocumentUri(const Utils::FilePath &other) - : QUrl(QUrl::fromLocalFile(other.toString())) +DocumentUri::DocumentUri(const Utils::FilePath &other, const PathMapper &mapToServerPath) + : QUrl(QUrl::fromLocalFile(mapToServerPath(other).path())) { } -Utils::FilePath DocumentUri::toFilePath() const +Utils::FilePath DocumentUri::toFilePath(const PathMapper &mapToHostPath) const { - return isLocalFile() ? Utils::FilePath::fromUserInput(QUrl(*this).toLocalFile()) - : Utils::FilePath(); + if (isLocalFile()) { + const Utils::FilePath serverPath = Utils::FilePath::fromUserInput(toLocalFile()); + QTC_ASSERT(mapToHostPath, return serverPath); + return mapToHostPath(serverPath); + } + return Utils::FilePath(); +} + +DocumentUri DocumentUri::fromProtocol(const QString &uri) +{ + return DocumentUri(uri); +} + +DocumentUri DocumentUri::fromFilePath(const Utils::FilePath &file, const PathMapper &mapToServerPath) +{ + return DocumentUri(file, mapToServerPath); } MarkupKind::MarkupKind(const QJsonValue &value) diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index 0c848130cea..03df5751fbe 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -27,16 +27,17 @@ class LANGUAGESERVERPROTOCOL_EXPORT DocumentUri : public QUrl { public: DocumentUri() = default; - Utils::FilePath toFilePath() const; + using PathMapper = std::function; + Utils::FilePath toFilePath(const PathMapper &mapToHostPath) const; - static DocumentUri fromProtocol(const QString &uri) { return DocumentUri(uri); } - static DocumentUri fromFilePath(const Utils::FilePath &file) { return DocumentUri(file); } + static DocumentUri fromProtocol(const QString &uri); + static DocumentUri fromFilePath(const Utils::FilePath &file, const PathMapper &mapToServerPath); operator QJsonValue() const { return QJsonValue(toString()); } private: DocumentUri(const QString &other); - DocumentUri(const Utils::FilePath &other); + DocumentUri(const Utils::FilePath &other, const PathMapper &mapToServerPath); friend class LanguageClientValue; }; @@ -137,7 +138,7 @@ public: Range range() const { return typedValue(rangeKey); } void setRange(const Range &range) { insert(rangeKey, range); } - Utils::Link toLink() const; + Utils::Link toLink(const DocumentUri::PathMapper &mapToHostPath) const; bool isValid() const override { return contains(uriKey) && contains(rangeKey); } }; diff --git a/src/plugins/clangcodemodel/clangdast.cpp b/src/plugins/clangcodemodel/clangdast.cpp index 9aebc8759b4..7e1b3bc0ac4 100644 --- a/src/plugins/clangcodemodel/clangdast.cpp +++ b/src/plugins/clangcodemodel/clangdast.cpp @@ -387,7 +387,7 @@ MessageId requestAst(Client *client, const FilePath &filePath, const Range range explicit AstRequest(const AstParams ¶ms) : Request("textDocument/ast", params) {} }; - AstRequest request(AstParams(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath)), + AstRequest request(AstParams(TextDocumentIdentifier(client->hostPathToServerUri(filePath)), range)); request.setResponseCallback([handler, reqId = request.id()](AstRequest::Response response) { const auto result = response.result(); diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 14566d42a64..8cf8fe15122 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -274,7 +274,7 @@ public: QTextCursor adjustedCursor(const QTextCursor &cursor, const TextDocument *doc); void setHelpItemForTooltip(const MessageId &token, - const DocumentUri &uri, + const Utils::FilePath &filePath, const QString &fqn = {}, HelpItem::Category category = HelpItem::Unknown, const QString &type = {}); @@ -409,8 +409,8 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir) d->handleSemanticTokens(doc, tokens, version, force); }); hoverHandler()->setHelpItemProvider([this](const HoverRequest::Response &response, - const DocumentUri &uri) { - gatherHelpItemForTooltip(response, uri); + const Utils::FilePath &filePath) { + gatherHelpItemForTooltip(response, filePath); }); connect(this, &Client::workDone, this, @@ -462,7 +462,7 @@ void ClangdClient::openExtraFile(const Utils::FilePath &filePath, const QString return; TextDocumentItem item; item.setLanguageId("cpp"); - item.setUri(DocumentUri::fromFilePath(filePath)); + item.setUri(hostPathToServerUri(filePath)); item.setText(!content.isEmpty() ? content : QString::fromUtf8(cxxFile.readAll())); item.setVersion(0); sendMessage(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)), @@ -480,7 +480,7 @@ void ClangdClient::closeExtraFile(const Utils::FilePath &filePath) return; d->openedExtraFiles.erase(it); sendMessage(DidCloseTextDocumentNotification(DidCloseTextDocumentParams( - TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)})), + TextDocumentIdentifier{hostPathToServerUri(filePath)})), SendDocUpdates::Ignore); } @@ -533,7 +533,7 @@ void ClangdClient::handleDiagnostics(const PublishDiagnosticsParams ¶ms) { const DocumentUri &uri = params.uri(); Client::handleDiagnostics(params); - const int docVersion = documentVersion(uri.toFilePath()); + const int docVersion = documentVersion(uri); if (params.version().value_or(docVersion) != docVersion) return; for (const Diagnostic &diagnostic : params.diagnostics()) { @@ -593,11 +593,10 @@ class ClangdDiagnosticManager : public LanguageClient::DiagnosticManager return doc && doc->filePath() == filePath; } - void showDiagnostics(const DocumentUri &uri, int version) override + void showDiagnostics(const Utils::FilePath &filePath, int version) override { - const Utils::FilePath filePath = uri.toFilePath(); getClient()->clearTasks(filePath); - DiagnosticManager::showDiagnostics(uri, version); + DiagnosticManager::showDiagnostics(filePath, version); if (isCurrentDocument(filePath)) getClient()->switchIssuePaneEntries(filePath); } @@ -851,7 +850,7 @@ MessageId ClangdClient::getAndHandleAst(const TextDocOrFile &doc, const AstHandl MessageId ClangdClient::requestSymbolInfo(const Utils::FilePath &filePath, const Position &position, const SymbolInfoHandler &handler) { - const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); + const TextDocumentIdentifier docId(hostPathToServerUri(filePath)); const TextDocumentPositionParams params(docId, position); SymbolInfoRequest symReq(params); symReq.setResponseCallback([handler, reqId = symReq.id()] @@ -932,15 +931,16 @@ void ClangdClient::switchHeaderSource(const Utils::FilePath &filePath, bool inNe { public: using Request::Request; - explicit SwitchSourceHeaderRequest(const Utils::FilePath &filePath) - : Request("textDocument/switchSourceHeader", - TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))) {} + explicit SwitchSourceHeaderRequest(const DocumentUri &uri) + : Request("textDocument/switchSourceHeader", TextDocumentIdentifier(uri)) + {} }; - SwitchSourceHeaderRequest req(filePath); - req.setResponseCallback([inNextSplit](const SwitchSourceHeaderRequest::Response &response) { + SwitchSourceHeaderRequest req(hostPathToServerUri(filePath)); + req.setResponseCallback([inNextSplit, pathMapper = hostPathMapper()]( + const SwitchSourceHeaderRequest::Response &response) { if (const std::optional result = response.result()) { const DocumentUri uri = DocumentUri::fromProtocol(result->toString()); - const Utils::FilePath filePath = uri.toFilePath(); + const Utils::FilePath filePath = uri.toFilePath(pathMapper); if (!filePath.isEmpty()) CppEditor::openEditor(filePath, inNextSplit); } @@ -976,7 +976,7 @@ void ClangdClient::findLocalUsages(TextDocument *document, const QTextCursor &cu } void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverResponse, - const DocumentUri &uri) + const Utils::FilePath &filePath) { if (const std::optional result = hoverResponse.result()) { if (auto hover = std::get_if(&(*result))) { @@ -994,7 +994,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR const QString macroName = markupString.mid(nameStart, closingQuoteIndex - nameStart); d->setHelpItemForTooltip(hoverResponse.id(), - uri, + filePath, macroName, HelpItem::Macro); return; @@ -1006,11 +1006,12 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR cleanString.remove('`'); const QStringList lines = cleanString.trimmed().split('\n'); if (!lines.isEmpty()) { - const auto filePath = Utils::FilePath::fromUserInput(lines.last().simplified()); - if (filePath.exists()) { + const auto markupFilePath = Utils::FilePath::fromUserInput( + lines.last().simplified()); + if (markupFilePath.exists()) { d->setHelpItemForTooltip(hoverResponse.id(), - uri, - filePath.fileName(), + filePath, + markupFilePath.fileName(), HelpItem::Brief); return; } @@ -1019,9 +1020,10 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR } } - const TextDocument * const doc = documentForFilePath(uri.toFilePath()); + const TextDocument * const doc = documentForFilePath(filePath); QTC_ASSERT(doc, return); - const auto astHandler = [this, uri, hoverResponse](const ClangdAstNode &ast, const MessageId &) { + const auto astHandler = [this, filePath, hoverResponse](const ClangdAstNode &ast, + const MessageId &) { const MessageId id = hoverResponse.id(); Range range; if (const std::optional result = hoverResponse.result()) { @@ -1030,7 +1032,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR } const ClangdAstPath path = getAstPath(ast, range); if (path.isEmpty()) { - d->setHelpItemForTooltip(id, uri); + d->setHelpItemForTooltip(id, filePath); return; } ClangdAstNode node = path.last(); @@ -1054,7 +1056,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR type = type.left(angleBracketIndex); }; - if (gatherMemberFunctionOverrideHelpItemForTooltip(id, uri, path)) + if (gatherMemberFunctionOverrideHelpItemForTooltip(id, filePath, path)) return; const bool isMemberFunction = node.role() == "expression" && node.kind() == "Member" @@ -1062,9 +1064,8 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR const bool isFunction = node.role() == "expression" && node.kind() == "DeclRef" && type.contains('('); if (isMemberFunction || isFunction) { - const auto symbolInfoHandler = [this, id, uri, type, isFunction](const QString &name, - const QString &prefix, - const MessageId &) { + const auto symbolInfoHandler = [this, id, filePath, type, isFunction] + (const QString &name, const QString &prefix, const MessageId &) { qCDebug(clangdLog) << "handling symbol info reply"; const QString fqn = prefix + name; @@ -1074,12 +1075,12 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR // with mainOverload = true, such information would get ignored anyway. if (!fqn.isEmpty()) d->setHelpItemForTooltip(id, - uri, + filePath, fqn, HelpItem::Function, isFunction ? type : "()"); }; - requestSymbolInfo(uri.toFilePath(), range.start(), symbolInfoHandler); + requestSymbolInfo(filePath, range.start(), symbolInfoHandler); return; } if ((node.role() == "expression" && node.kind() == "DeclRef") @@ -1088,7 +1089,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR || node.kind() == "Field"))) { if (node.arcanaContains("EnumConstant")) { d->setHelpItemForTooltip(id, - uri, + filePath, node.detail().value_or(QString()), HelpItem::Enum, type); @@ -1103,12 +1104,12 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR && type != "double" && !type.contains(" double") && type != "float" && type != "bool") { d->setHelpItemForTooltip(id, - uri, + filePath, type, node.qdocCategoryForDeclaration( HelpItem::ClassOrNamespace)); } else { - d->setHelpItemForTooltip(id, uri); + d->setHelpItemForTooltip(id, filePath); } return; } @@ -1121,19 +1122,22 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR ns.prepend("::").prepend(name); } } - d->setHelpItemForTooltip(id, uri, ns, HelpItem::ClassOrNamespace); + d->setHelpItemForTooltip(id, filePath, ns, HelpItem::ClassOrNamespace); return; } if (node.role() == "type") { if (node.kind() == "Enum") { - d->setHelpItemForTooltip(id, uri, node.detail().value_or(QString()), HelpItem::Enum); + d->setHelpItemForTooltip(id, + filePath, + node.detail().value_or(QString()), + HelpItem::Enum); } else if (node.kind() == "Record" || node.kind() == "TemplateSpecialization") { stripTemplatePartOffType(); - d->setHelpItemForTooltip(id, uri, type, HelpItem::ClassOrNamespace); + d->setHelpItemForTooltip(id, filePath, type, HelpItem::ClassOrNamespace); } else if (node.kind() == "Typedef") { - d->setHelpItemForTooltip(id, uri, type, HelpItem::Typedef); + d->setHelpItemForTooltip(id, filePath, type, HelpItem::Typedef); } else { - d->setHelpItemForTooltip(id, uri); + d->setHelpItemForTooltip(id, filePath); } return; } @@ -1141,23 +1145,23 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR const QString name = node.detail().value_or(QString()); if (!name.isEmpty()) type = name; - d->setHelpItemForTooltip(id, uri, type, HelpItem::ClassOrNamespace); + d->setHelpItemForTooltip(id, filePath, type, HelpItem::ClassOrNamespace); } if (node.role() == "specifier" && node.kind() == "NamespaceAlias") { d->setHelpItemForTooltip(id, - uri, + filePath, node.detail().value_or(QString()).chopped(2), HelpItem::ClassOrNamespace); return; } - d->setHelpItemForTooltip(id, uri); + d->setHelpItemForTooltip(id, filePath); }; d->getAndHandleAst(doc, astHandler, AstCallbackMode::SyncIfPossible); } bool ClangdClient::gatherMemberFunctionOverrideHelpItemForTooltip( const LanguageServerProtocol::MessageId &token, - const DocumentUri &uri, + const Utils::FilePath &filePath, const QList &path) { // Heuristic: If we encounter a member function re-declaration, continue under the @@ -1196,7 +1200,7 @@ bool ClangdClient::gatherMemberFunctionOverrideHelpItemForTooltip( if (!baseClassNode.detail()) return false; d->setHelpItemForTooltip(token, - uri, + filePath, *baseClassNode.detail() + "::" + *methodNode.detail(), HelpItem::Function, "()"); @@ -1320,7 +1324,7 @@ QTextCursor ClangdClient::Private::adjustedCursor(const QTextCursor &cursor, } void ClangdClient::Private::setHelpItemForTooltip(const MessageId &token, - const DocumentUri &uri, + const Utils::FilePath &filePath, const QString &fqn, HelpItem::Category category, const QString &type) @@ -1344,7 +1348,7 @@ void ClangdClient::Private::setHelpItemForTooltip(const MessageId &token, if (category == HelpItem::Enum && !type.isEmpty()) mark = type; - const HelpItem helpItem(helpIds, uri.toFilePath(), mark, category); + const HelpItem helpItem(helpIds, filePath, mark, category); if (isTesting) emit q->helpItemGathered(helpItem); else diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index c8fd0fe43cf..d0695e273d1 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -74,10 +74,9 @@ public: void gatherHelpItemForTooltip( const LanguageServerProtocol::HoverRequest::Response &hoverResponse, - const LanguageServerProtocol::DocumentUri &uri); - bool gatherMemberFunctionOverrideHelpItemForTooltip( - const LanguageServerProtocol::MessageId &token, - const LanguageServerProtocol::DocumentUri &uri, + const Utils::FilePath &filePath); + bool gatherMemberFunctionOverrideHelpItemForTooltip(const LanguageServerProtocol::MessageId &token, + const Utils::FilePath &uri, const QList &path); void setVirtualRanges(const Utils::FilePath &filePath, diff --git a/src/plugins/clangcodemodel/clangdfindreferences.cpp b/src/plugins/clangcodemodel/clangdfindreferences.cpp index 1d9e8e2047b..b654ce7f52f 100644 --- a/src/plugins/clangcodemodel/clangdfindreferences.cpp +++ b/src/plugins/clangcodemodel/clangdfindreferences.cpp @@ -193,7 +193,7 @@ ClangdFindReferences::ClangdFindReferences(ClangdClient *client, const Link &lin client->openExtraFile(link.targetFilePath, contents); d->checkUnusedData->openedExtraFileForLink = true; } - const TextDocumentIdentifier documentId(DocumentUri::fromFilePath(link.targetFilePath)); + const TextDocumentIdentifier documentId(client->hostPathToServerUri(link.targetFilePath)); const Position pos(link.targetLine - 1, link.targetColumn); ReferenceParams params(TextDocumentPositionParams(documentId, pos)); params.setContext(ReferenceParams::ReferenceContext(true)); @@ -280,7 +280,7 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList for (const Location &loc : locations) fileData[loc.uri()].rangesAndLineText.push_back({loc.range(), {}}); for (auto it = fileData.begin(); it != fileData.end();) { - const Utils::FilePath filePath = it.key().toFilePath(); + const Utils::FilePath filePath = client()->serverUriToHostPath(it.key()); if (!filePath.exists()) { // https://github.com/clangd/clangd/issues/935 it = fileData.erase(it); continue; @@ -303,19 +303,19 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList } for (auto it = fileData.begin(); it != fileData.end(); ++it) { - const FilePath filePath = it.key().toFilePath(); + const FilePath filePath = client()->serverUriToHostPath(it.key()); const TextDocument * const doc = client()->documentForFilePath(filePath); const bool openExtraFile = !doc && (!checkUnusedData || !checkUnusedData->openedExtraFileForLink || checkUnusedData->link.targetFilePath != filePath); if (openExtraFile) - client()->openExtraFile(it.key().toFilePath(), it->fileContent); + client()->openExtraFile(filePath, it->fileContent); it->fileContent.clear(); const auto docVariant = doc ? ClangdClient::TextDocOrFile(doc) - : ClangdClient::TextDocOrFile(it.key().toFilePath()); - const auto astHandler = [sentinel = QPointer(q), this, loc = it.key()]( + : ClangdClient::TextDocOrFile(filePath); + const auto astHandler = [sentinel = QPointer(q), this, loc = it.key(), filePath]( const ClangdAstNode &ast, const MessageId &reqId) { - qCDebug(clangdLog) << "AST for" << loc.toFilePath(); + qCDebug(clangdLog) << "AST for" << filePath; if (!sentinel) return; if (!search || canceled) @@ -324,7 +324,7 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList data.ast = ast; pendingAstRequests.removeOne(reqId); qCDebug(clangdLog) << pendingAstRequests.size() << "AST requests still pending"; - addSearchResultsForFile(loc.toFilePath(), data); + addSearchResultsForFile(filePath, data); fileData.remove(loc); if (pendingAstRequests.isEmpty() && !canceled) { qCDebug(clangdLog) << "retrieved all ASTs"; @@ -335,7 +335,7 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList docVariant, astHandler, ClangdClient::AstCallbackMode::AlwaysAsync, {}); pendingAstRequests << reqId; if (openExtraFile) - client()->closeExtraFile(it.key().toFilePath()); + client()->closeExtraFile(filePath); } } @@ -370,7 +370,7 @@ void ClangdFindReferences::Private::reportAllSearchResultsAndFinish() { if (!checkUnusedData) { for (auto it = fileData.begin(); it != fileData.end(); ++it) - addSearchResultsForFile(it.key().toFilePath(), it.value()); + addSearchResultsForFile(client()->serverUriToHostPath(it.key()), it.value()); } finishSearch(); } @@ -647,7 +647,7 @@ public: Private(ClangdFindLocalReferences *q, TextDocument *document, const QTextCursor &cursor, const RenameCallback &callback) : q(q), document(document), cursor(cursor), callback(callback), - uri(DocumentUri::fromFilePath(document->filePath())), + uri(client()->hostPathToServerUri(document->filePath())), revision(document->document()->revision()) {} @@ -749,7 +749,12 @@ void ClangdFindLocalReferences::Private::checkDefinitionAst(const ClangdAstNode void ClangdFindLocalReferences::Private::handleReferences(const QList &references) { qCDebug(clangdLog) << "found" << references.size() << "local references"; - const Utils::Links links = Utils::transform(references, &Location::toLink); + + const auto transformLocation = [mapper = client()->hostPathMapper()](const Location &loc) { + return loc.toLink(mapper); + }; + + const Utils::Links links = Utils::transform(references, transformLocation); // The callback only uses the symbol length, so we just create a dummy. // Note that the calculation will be wrong for identifiers with diff --git a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp index 4d796482f7b..d9895073390 100644 --- a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp +++ b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp @@ -72,7 +72,7 @@ public: CppEditorWidget *editorWidget, const FilePath &filePath, const LinkHandler &callback, bool openInSplit) : q(q), client(client), cursor(cursor), editorWidget(editorWidget), - uri(DocumentUri::fromFilePath(filePath)), callback(callback), + uri(client->hostPathToServerUri(filePath)), callback(callback), virtualFuncAssistProvider(q), docRevision(editorWidget ? editorWidget->textDocument()->document()->revision() : -1), openInSplit(openInSplit) {} @@ -246,7 +246,7 @@ void ClangdFollowSymbol::Private::sendGotoImplementationRequest(const Link &link if (!client->documentForFilePath(link.targetFilePath) && addOpenFile(link.targetFilePath)) client->openExtraFile(link.targetFilePath); const Position position(link.targetLine - 1, link.targetColumn); - const TextDocumentIdentifier documentId(DocumentUri::fromFilePath(link.targetFilePath)); + const TextDocumentIdentifier documentId(client->hostPathToServerUri(link.targetFilePath)); GotoImplementationRequest req(TextDocumentPositionParams(documentId, position)); req.setResponseCallback([sentinel = QPointer(q), this, reqId = req.id()] (const GotoImplementationRequest::Response &response) { @@ -363,12 +363,13 @@ void ClangdFollowSymbol::Private::goToTypeDefinition() if (!sentinel) return; Link link; + if (const std::optional &result = response.result()) { if (const auto ploc = std::get_if(&*result)) { - link = {ploc->toLink()}; + link = {ploc->toLink(client->hostPathMapper())}; } else if (const auto plloc = std::get_if>(&*result)) { if (!plloc->empty()) - link = plloc->first().toLink(); + link = plloc->first().toLink(client->hostPathMapper()); } } q->emitDone(link); @@ -399,12 +400,15 @@ void ClangdFollowSymbol::Private::handleGotoDefinitionResult() void ClangdFollowSymbol::Private::handleGotoImplementationResult( const GotoImplementationRequest::Response &response) { + auto transformLink = [mapper = client->hostPathMapper()](const Location &loc) { + return loc.toLink(mapper); + }; if (const std::optional &result = response.result()) { QList newLinks; if (const auto ploc = std::get_if(&*result)) - newLinks = {ploc->toLink()}; + newLinks = {transformLink(*ploc)}; if (const auto plloc = std::get_if>(&*result)) - newLinks = transform(*plloc, &Location::toLink); + newLinks = transform(*plloc, transformLink); for (const Link &link : std::as_const(newLinks)) { if (!allLinks.contains(link)) { allLinks << link; @@ -465,33 +469,34 @@ void ClangdFollowSymbol::Private::handleGotoImplementationResult( if (link == defLink) continue; - const TextDocumentIdentifier doc(DocumentUri::fromFilePath(link.targetFilePath)); + const TextDocumentIdentifier doc(client->hostPathToServerUri(link.targetFilePath)); const TextDocumentPositionParams params(doc, pos); GotoDefinitionRequest defReq(params); - defReq.setResponseCallback([this, link, sentinel = QPointer(q), reqId = defReq.id()] - (const GotoDefinitionRequest::Response &response) { - qCDebug(clangdLog) << "handling additional go to definition reply for" - << link.targetFilePath << link.targetLine; - if (!sentinel) - return; - Link newLink; - if (std::optional _result = response.result()) { - const GotoResult result = _result.value(); - if (const auto ploc = std::get_if(&result)) { - newLink = ploc->toLink(); - } else if (const auto plloc = std::get_if>(&result)) { - if (!plloc->isEmpty()) - newLink = plloc->value(0).toLink(); + defReq.setResponseCallback( + [this, link, transformLink, sentinel = QPointer(q), reqId = defReq.id()]( + const GotoDefinitionRequest::Response &response) { + qCDebug(clangdLog) << "handling additional go to definition reply for" + << link.targetFilePath << link.targetLine; + if (!sentinel) + return; + Link newLink; + if (std::optional _result = response.result()) { + const GotoResult result = _result.value(); + if (const auto ploc = std::get_if(&result)) { + newLink = transformLink(*ploc); + } else if (const auto plloc = std::get_if>(&result)) { + if (!plloc->isEmpty()) + newLink = transformLink(plloc->value(0)); + } } - } - qCDebug(clangdLog) << "def link is" << newLink.targetFilePath << newLink.targetLine; - declDefMap.insert(link, newLink); - pendingGotoDefRequests.removeOne(reqId); - if (pendingSymbolInfoRequests.isEmpty() && pendingGotoDefRequests.isEmpty() + qCDebug(clangdLog) << "def link is" << newLink.targetFilePath << newLink.targetLine; + declDefMap.insert(link, newLink); + pendingGotoDefRequests.removeOne(reqId); + if (pendingSymbolInfoRequests.isEmpty() && pendingGotoDefRequests.isEmpty() && defLinkNode.isValid()) { - handleDocumentInfoResults(); - } - }); + handleDocumentInfoResults(); + } + }); pendingGotoDefRequests << defReq.id(); qCDebug(clangdLog) << "sending additional go to definition request" << link.targetFilePath << link.targetLine; diff --git a/src/plugins/clangcodemodel/clangdquickfixes.cpp b/src/plugins/clangcodemodel/clangdquickfixes.cpp index 06e1c43f8ea..8d7ad13771f 100644 --- a/src/plugins/clangcodemodel/clangdquickfixes.cpp +++ b/src/plugins/clangcodemodel/clangdquickfixes.cpp @@ -24,11 +24,10 @@ void ClangdQuickFixFactory::match(const CppEditor::Internal::CppQuickFixInterfac if (!client) return; - const auto uri = DocumentUri::fromFilePath(interface.filePath()); QTextCursor cursor(interface.textDocument()); cursor.setPosition(interface.position()); cursor.select(QTextCursor::LineUnderCursor); - const QList &diagnostics = client->diagnosticsAt(uri, cursor); + const QList &diagnostics = client->diagnosticsAt(interface.filePath(), cursor); for (const Diagnostic &diagnostic : diagnostics) { ClangdDiagnostic clangdDiagnostic(diagnostic); if (const auto actions = clangdDiagnostic.codeActions()) { diff --git a/src/plugins/clangcodemodel/clangdswitchdecldef.cpp b/src/plugins/clangcodemodel/clangdswitchdecldef.cpp index a60395292c1..4ec04afdd51 100644 --- a/src/plugins/clangcodemodel/clangdswitchdecldef.cpp +++ b/src/plugins/clangcodemodel/clangdswitchdecldef.cpp @@ -31,7 +31,7 @@ class ClangdSwitchDeclDef::Private public: Private(ClangdSwitchDeclDef * q, ClangdClient *client, TextDocument *doc, const QTextCursor &cursor, CppEditorWidget *editorWidget, const LinkHandler &callback) - : q(q), client(client), document(doc), uri(DocumentUri::fromFilePath(doc->filePath())), + : q(q), client(client), document(doc), uri(client->hostPathToServerUri(doc->filePath())), cursor(cursor), editorWidget(editorWidget), callback(callback) {} diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index d29fef23928..0d59b9dbe27 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -163,7 +163,9 @@ ClangSourceRange convertRange(const FilePath &filePath, const Range &src) return ClangSourceRange(start, end); } -ClangDiagnostic convertDiagnostic(const ClangdDiagnostic &src, const FilePath &filePath) +ClangDiagnostic convertDiagnostic(const ClangdDiagnostic &src, + const FilePath &filePath, + const DocumentUri::PathMapper &mapper) { ClangDiagnostic target; target.location = convertRange(filePath, src.range()).start; @@ -226,7 +228,8 @@ ClangDiagnostic convertDiagnostic(const ClangdDiagnostic &src, const FilePath &f for (auto it = changes->cbegin(); it != changes->cend(); ++it) { for (const TextEdit &textEdit : it.value()) { fixItDiag.fixIts << ClangFixIt(textEdit.newText(), - convertRange(it.key().toFilePath(), textEdit.range())); + convertRange(it.key().toFilePath(mapper), + textEdit.range())); } } target.children << fixItDiag; @@ -270,7 +273,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath, ClangdClient *client) : TextEditor::TextMark(filePath, int(diagnostic.range().start().line() + 1), client->id()) , m_lspDiagnostic(diagnostic) - , m_diagnostic(convertDiagnostic(ClangdDiagnostic(diagnostic), filePath)) + , m_diagnostic(convertDiagnostic(ClangdDiagnostic(diagnostic), filePath, client->hostPathMapper())) , m_client(client) { setSettingsPage(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID); @@ -319,8 +322,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath, bool ClangdTextMark::addToolTipContent(QLayout *target) const { const auto canApplyFixIt = [c = m_client, diag = m_lspDiagnostic, fp = fileName()] { - return QTC_GUARD(c) && c->reachable() - && c->hasDiagnostic(DocumentUri::fromFilePath(fp), diag); + return QTC_GUARD(c) && c->reachable() && c->hasDiagnostic(fp, diag); }; const QString clientName = QTC_GUARD(m_client) ? m_client->name() : "clangd [unknown]"; target->addWidget(ClangDiagnosticWidget::createWidget({m_diagnostic}, diff --git a/src/plugins/coco/cocolanguageclient.cpp b/src/plugins/coco/cocolanguageclient.cpp index 8db497d10e9..ef9704a2537 100644 --- a/src/plugins/coco/cocolanguageclient.cpp +++ b/src/plugins/coco/cocolanguageclient.cpp @@ -209,12 +209,12 @@ private: return {}; } - void setDiagnostics(const DocumentUri &uri, + void setDiagnostics(const FilePath &filePath, const QList &diagnostics, const std::optional &version) override { - DiagnosticManager::setDiagnostics(uri, diagnostics, version); - showDiagnostics(uri, client()->documentVersion(uri.toFilePath())); + DiagnosticManager::setDiagnostics(filePath, diagnostics, version); + showDiagnostics(filePath, client()->documentVersion(filePath)); } }; @@ -227,7 +227,7 @@ void CocoLanguageClient::handleDiagnostics(const PublishDiagnosticsParams ¶m { using namespace TextEditor; Client::handleDiagnostics(params); - TextDocument *document = documentForFilePath(params.uri().toFilePath()); + TextDocument *document = documentForFilePath(serverUriToHostPath(params.uri())); for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(document)) editor->editorWidget()->addHoverHandler(hoverHandler()); } diff --git a/src/plugins/cppeditor/builtineditordocumentparser.cpp b/src/plugins/cppeditor/builtineditordocumentparser.cpp index 8c04afae336..e4384905e42 100644 --- a/src/plugins/cppeditor/builtineditordocumentparser.cpp +++ b/src/plugins/cppeditor/builtineditordocumentparser.cpp @@ -5,8 +5,8 @@ #include "cppsourceprocessor.h" -#include #include +#include #include #include @@ -23,9 +23,12 @@ static QByteArray overwrittenToolchainDefines(const ProjectPart &projectPart) // MSVC's predefined macros like __FUNCSIG__ expand to itself. // We can't parse this, so redefine to the empty string literal. if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { - defines += "#define __FUNCSIG__ \"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"\n" - "#define __FUNCDNAME__ \"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"\n" - "#define __FUNCTION__ \"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"\n"; + defines += "#define __FUNCSIG__ \"void __cdecl " + "someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"\n" + "#define __FUNCDNAME__ " + "\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"\n" + "#define __FUNCTION__ " + "\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"\n"; } return defines; @@ -63,11 +66,11 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface &futur LanguageFeatures features = LanguageFeatures::defaultFeatures(); baseState.projectPartInfo = determineProjectPart(filePath().toString(), - baseConfig.preferredProjectPartId, - baseState.projectPartInfo, - updateParams.activeProject, - updateParams.languagePreference, - updateParams.projectsUpdated); + baseConfig.preferredProjectPartId, + baseState.projectPartInfo, + updateParams.activeProject, + updateParams.languagePreference, + updateParams.projectsUpdated); emit projectPartInfoUpdated(baseState.projectPartInfo); if (state.forceSnapshotInvalidation) { @@ -131,8 +134,8 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface &futur if (invalidateSnapshot) { state.snapshot = Snapshot(); if (!baseState.editorDefines.isEmpty()) { - workingCopy.insert(CppModelManager::editorConfigurationFileName(), - baseState.editorDefines); + workingCopy.insert(CppModelManager::editorConfigurationFileName(), + baseState.editorDefines); } } else { // Remove changed files from the snapshot @@ -177,9 +180,7 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface &futur doc->releaseSourceAndAST(); }); sourceProcessor.setFileSizeLimitInMb(m_fileSizeLimitInMb); - sourceProcessor.setCancelChecker([future]() { - return future.isCanceled(); - }); + sourceProcessor.setCancelChecker([future]() { return future.isCanceled(); }); Snapshot globalSnapshot = modelManager->snapshot(); globalSnapshot.remove(filePath()); @@ -201,7 +202,9 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface &futur sourceProcessor.run(filePath(), transform(includedFiles, &FilePath::fromString)); state.snapshot = sourceProcessor.snapshot(); Snapshot newSnapshot = state.snapshot.simplified(state.snapshot.document(filePath())); - for (Snapshot::const_iterator i = state.snapshot.begin(), ei = state.snapshot.end(); i != ei; ++i) { + for (Snapshot::const_iterator i = state.snapshot.begin(), ei = state.snapshot.end(); + i != ei; + ++i) { if (Client::isInjectedFile(i.key().toString())) newSnapshot.insert(i.value()); } diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 5c99329675a..91fe7a2d808 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -139,6 +139,7 @@ public: , m_hoverHandler(q) , m_symbolSupport(q) , m_tokenSupport(q) + , m_serverDeviceTemplate(clientInterface->serverDeviceTemplate()) { using namespace ProjectExplorer; @@ -329,6 +330,7 @@ public: LanguageServerProtocol::ClientInfo m_clientInfo; QJsonValue m_configuration; int m_completionResultsLimit = -1; + const Utils::FilePath m_serverDeviceTemplate; }; Client::Client(BaseClientInterface *clientInterface) @@ -500,11 +502,11 @@ void Client::initialize() params.setCapabilities(d->m_clientCapabilities); params.setInitializationOptions(d->m_initializationOptions); if (d->m_project) - params.setRootUri(DocumentUri::fromFilePath(d->m_project->projectDirectory())); + params.setRootUri(hostPathToServerUri(d->m_project->projectDirectory())); const QList workspaces - = Utils::transform(SessionManager::projects(), [](Project *pro) { - return WorkSpaceFolder(DocumentUri::fromFilePath(pro->projectDirectory()), + = Utils::transform(SessionManager::projects(), [this](Project *pro) { + return WorkSpaceFolder(hostPathToServerUri(pro->projectDirectory()), pro->displayName()); }); if (workspaces.isEmpty()) @@ -746,7 +748,6 @@ void ClientPrivate::requestDocumentHighlights(TextEditor::TextEditorWidget *widg { QTimer *timer = m_documentHighlightsTimer[widget]; if (!timer) { - const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath()); if (m_highlightRequests.contains(widget)) q->cancelRequest(m_highlightRequests.take(widget)); timer = new QTimer; @@ -771,7 +772,7 @@ void ClientPrivate::requestDocumentHighlights(TextEditor::TextEditorWidget *widg void ClientPrivate::requestDocumentHighlightsNow(TextEditor::TextEditorWidget *widget) { QTC_ASSERT(q->reachable(), return); - const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath()); + const auto uri = q->hostPathToServerUri(widget->textDocument()->filePath()); if (m_dynamicCapabilities.isRegistered(DocumentHighlightsRequest::methodName).value_or(false)) { TextDocumentRegistrationOptions option( m_dynamicCapabilities.option(DocumentHighlightsRequest::methodName)); @@ -833,9 +834,8 @@ void ClientPrivate::requestDocumentHighlightsNow(TextEditor::TextEditorWidget *w void Client::activateDocument(TextEditor::TextDocument *document) { const FilePath &filePath = document->filePath(); - auto uri = DocumentUri::fromFilePath(filePath); if (d->m_diagnosticManager) - d->m_diagnosticManager->showDiagnostics(uri, d->m_documentVersions.value(filePath)); + d->m_diagnosticManager->showDiagnostics(filePath, d->m_documentVersions.value(filePath)); d->m_tokenSupport.updateSemanticTokens(document); // only replace the assist provider if the language server support it d->updateCompletionProvider(document); @@ -897,7 +897,7 @@ void ClientPrivate::sendOpenNotification(const FilePath &filePath, const QString { TextDocumentItem item; item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(mimeType)); - item.setUri(DocumentUri::fromFilePath(filePath)); + item.setUri(q->hostPathToServerUri(filePath)); item.setText(content); item.setVersion(version); q->sendMessage(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)), @@ -907,7 +907,7 @@ void ClientPrivate::sendOpenNotification(const FilePath &filePath, const QString void ClientPrivate::sendCloseNotification(const FilePath &filePath) { q->sendMessage(DidCloseTextDocumentNotification(DidCloseTextDocumentParams( - TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)})), + TextDocumentIdentifier{q->hostPathToServerUri(filePath)})), Client::SendDocUpdates::Ignore); } @@ -950,7 +950,7 @@ void Client::setShadowDocument(const Utils::FilePath &filePath, const QString &c } else { shadowIt.value().first = content; if (!shadowIt.value().second.isEmpty()) { - VersionedTextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); + VersionedTextDocumentIdentifier docId(hostPathToServerUri(filePath)); docId.setVersion(++d->m_documentVersions[filePath]); const DidChangeTextDocumentParams params(docId, content); sendMessage(DidChangeTextDocumentNotification(params), SendDocUpdates::Ignore); @@ -981,7 +981,6 @@ void ClientPrivate::openShadowDocument(const TextEditor::TextDocument *requringD shadowIt.value().second << requringDoc; if (shadowIt.value().second.size() > 1) return; - const auto uri = DocumentUri::fromFilePath(shadowIt.key()); const QString mimeType = mimeTypeForFile(shadowIt.key(), MimeMatchMode::MatchExtension).name(); sendOpenNotification(shadowIt.key(), mimeType, shadowIt.value().first, ++m_documentVersions[shadowIt.key()]); @@ -1021,7 +1020,7 @@ void Client::documentContentsSaved(TextEditor::TextDocument *document) if (!send) return; DidSaveTextDocumentParams params( - TextDocumentIdentifier(DocumentUri::fromFilePath(document->filePath()))); + TextDocumentIdentifier(hostPathToServerUri(document->filePath()))); d->openRequiredShadowDocuments(document); if (includeText) params.setText(document->plainText()); @@ -1053,7 +1052,7 @@ void Client::documentWillSave(Core::IDocument *document) if (!send) return; const WillSaveTextDocumentParams params( - TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))); + TextDocumentIdentifier(hostPathToServerUri(filePath))); sendMessage(WillSaveTextDocumentNotification(params)); } @@ -1241,7 +1240,7 @@ void ClientPrivate::requestCodeActions(const DocumentUri &uri, const Range &range, const QList &diagnostics) { - const Utils::FilePath fileName = uri.toFilePath(); + const Utils::FilePath fileName = q->serverUriToHostPath(uri); TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath(fileName); if (!doc) return; @@ -1273,8 +1272,11 @@ void Client::requestCodeActions(const CodeActionRequest &request) if (!request.isValid(nullptr)) return; - const Utils::FilePath fileName - = request.params().value_or(CodeActionParams()).textDocument().uri().toFilePath(); + const Utils::FilePath fileName = request.params() + .value_or(CodeActionParams()) + .textDocument() + .uri() + .toFilePath(hostPathMapper()); const QString method(CodeActionRequest::methodName); if (std::optional registered = d->m_dynamicCapabilities.isRegistered(method)) { @@ -1349,7 +1351,7 @@ void Client::projectOpened(ProjectExplorer::Project *project) if (!d->sendWorkspceFolderChanges()) return; WorkspaceFoldersChangeEvent event; - event.setAdded({WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), + event.setAdded({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()), project->displayName())}); DidChangeWorkspaceFoldersParams params; params.setEvent(event); @@ -1361,7 +1363,7 @@ void Client::projectClosed(ProjectExplorer::Project *project) { if (d->sendWorkspceFolderChanges()) { WorkspaceFoldersChangeEvent event; - event.setRemoved({WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), + event.setRemoved({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()), project->displayName())}); DidChangeWorkspaceFoldersParams params; params.setEvent(event); @@ -1420,7 +1422,7 @@ bool Client::isSupportedFile(const Utils::FilePath &filePath, const QString &mim bool Client::isSupportedUri(const DocumentUri &uri) const { - const FilePath &filePath = uri.toFilePath(); + const FilePath &filePath = serverUriToHostPath(uri); return d->m_languagFilter.isSupported(filePath, Utils::mimeTypeForFile(filePath).name()); } @@ -1434,18 +1436,18 @@ void Client::removeAssistProcessor(TextEditor::IAssistProcessor *processor) d->m_runningAssistProcessors.remove(processor); } -QList Client::diagnosticsAt(const DocumentUri &uri, const QTextCursor &cursor) const +QList Client::diagnosticsAt(const FilePath &filePath, const QTextCursor &cursor) const { if (d->m_diagnosticManager) - return d->m_diagnosticManager->diagnosticsAt(uri, cursor); + return d->m_diagnosticManager->diagnosticsAt(filePath, cursor); return {}; } -bool Client::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, +bool Client::hasDiagnostic(const FilePath &filePath, const LanguageServerProtocol::Diagnostic &diag) const { if (d->m_diagnosticManager) - return d->m_diagnosticManager->hasDiagnostic(uri, documentForFilePath(uri.toFilePath()), diag); + return d->m_diagnosticManager->hasDiagnostic(filePath, documentForFilePath(filePath), diag); return false; } @@ -1708,7 +1710,7 @@ void ClientPrivate::sendPostponedDocumentUpdates(Schedule semanticTokensSchedule [this](const auto &elem) { TextEditor::TextDocument * const document = elem.first; const FilePath &filePath = document->filePath(); - const auto uri = DocumentUri::fromFilePath(filePath); + const LanguageServerProtocol::DocumentUri uri = q->hostPathToServerUri(filePath); VersionedTextDocumentIdentifier docId(uri); docId.setVersion(m_documentVersions[filePath]); DidChangeTextDocumentParams params; @@ -1867,8 +1869,8 @@ void ClientPrivate::handleMethod(const QString &method, const MessageId &id, con } else { response.setResult(Utils::transform( projects, - [](ProjectExplorer::Project *project) { - return WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), + [this](ProjectExplorer::Project *project) { + return WorkSpaceFolder(q->hostPathToServerUri(project->projectDirectory()), project->displayName()); })); } @@ -1906,9 +1908,10 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams ¶ms) const QList &diagnostics = params.diagnostics(); if (!d->m_diagnosticManager) d->m_diagnosticManager = createDiagnosticManager(); - d->m_diagnosticManager->setDiagnostics(uri, diagnostics, params.version()); - if (LanguageClientManager::clientForUri(uri) == this) { - d->m_diagnosticManager->showDiagnostics(uri, d->m_documentVersions.value(uri.toFilePath())); + const FilePath &path = serverUriToHostPath(uri); + d->m_diagnosticManager->setDiagnostics(path, diagnostics, params.version()); + if (LanguageClientManager::clientForFilePath(path) == this) { + d->m_diagnosticManager->showDiagnostics(path, d->m_documentVersions.value(path)); if (d->m_autoRequestCodeActions) requestCodeActions(uri, diagnostics); } @@ -1932,6 +1935,11 @@ int Client::documentVersion(const Utils::FilePath &filePath) const return d->m_documentVersions.value(filePath); } +int Client::documentVersion(const LanguageServerProtocol::DocumentUri &uri) const +{ + return documentVersion(serverUriToHostPath(uri)); +} + void Client::setDocumentChangeUpdateThreshold(int msecs) { d->m_documentUpdateTimer.setInterval(msecs); @@ -2071,6 +2079,25 @@ bool Client::fileBelongsToProject(const Utils::FilePath &filePath) const return project() && project()->isKnownFile(filePath); } +DocumentUri::PathMapper Client::hostPathMapper() const +{ + return [serverDeviceTemplate = d->m_serverDeviceTemplate](const Utils::FilePath &serverPath) { + return serverDeviceTemplate.withNewPath(serverPath.path()); + }; +} + +FilePath Client::serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const +{ + return uri.toFilePath(hostPathMapper()); +} + +DocumentUri Client::hostPathToServerUri(const Utils::FilePath &path) const +{ + return DocumentUri::fromFilePath(path, [&](const Utils::FilePath &clientPath){ + return clientPath.onDevice(d->m_serverDeviceTemplate); + }); +} + } // namespace LanguageClient #include diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 7061b9514ec..1921e01fe7e 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -126,6 +126,7 @@ public: void cursorPositionChanged(TextEditor::TextEditorWidget *widget); bool documentUpdatePostponed(const Utils::FilePath &fileName) const; int documentVersion(const Utils::FilePath &filePath) const; + int documentVersion(const LanguageServerProtocol::DocumentUri &uri) const; void setDocumentChangeUpdateThreshold(int msecs); // workspace control @@ -151,10 +152,9 @@ public: SymbolSupport &symbolSupport(); DocumentSymbolCache *documentSymbolCache(); HoverHandler *hoverHandler(); - QList diagnosticsAt( - const LanguageServerProtocol::DocumentUri &uri, - const QTextCursor &cursor) const; - bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, + QList diagnosticsAt(const Utils::FilePath &filePath, + const QTextCursor &cursor) const; + bool hasDiagnostic(const Utils::FilePath &filePath, const LanguageServerProtocol::Diagnostic &diag) const; bool hasDiagnostics(const TextEditor::TextDocument *document) const; void setSemanticTokensHandler(const SemanticTokensHandler &handler); @@ -166,6 +166,10 @@ public: virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const; virtual bool fileBelongsToProject(const Utils::FilePath &filePath) const; + LanguageServerProtocol::DocumentUri::PathMapper hostPathMapper() const; + Utils::FilePath serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const; + LanguageServerProtocol::DocumentUri hostPathToServerUri(const Utils::FilePath &path) const; + // logging enum class LogTarget { Console, Ui }; void setLogTarget(LogTarget target); diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp index cb199538e9f..a1c23f858cb 100644 --- a/src/plugins/languageclient/diagnosticmanager.cpp +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -56,12 +56,12 @@ DiagnosticManager::~DiagnosticManager() clearDiagnostics(); } -void DiagnosticManager::setDiagnostics(const DocumentUri &uri, +void DiagnosticManager::setDiagnostics(const FilePath &filePath, const QList &diagnostics, const std::optional &version) { - hideDiagnostics(uri.toFilePath()); - m_diagnostics[uri] = {version, filteredDiagnostics(diagnostics)}; + hideDiagnostics(filePath); + m_diagnostics[filePath] = {version, filteredDiagnostics(diagnostics)}; } void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath) @@ -89,12 +89,11 @@ void DiagnosticManager::disableDiagnostics(TextEditor::TextDocument *document) marks.enabled = false; } -void DiagnosticManager::showDiagnostics(const DocumentUri &uri, int version) +void DiagnosticManager::showDiagnostics(const FilePath &filePath, int version) { - const FilePath &filePath = uri.toFilePath(); if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) { QList extraSelections; - const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(uri); + const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(filePath); if (versionedDiagnostics.version.value_or(version) == version && !versionedDiagnostics.diagnostics.isEmpty()) { Marks &marks = m_marks[filePath]; @@ -167,17 +166,17 @@ void DiagnosticManager::forAllMarks(std::function void DiagnosticManager::clearDiagnostics() { - for (const DocumentUri &uri : m_diagnostics.keys()) - hideDiagnostics(uri.toFilePath()); + for (const Utils::FilePath &path : m_diagnostics.keys()) + hideDiagnostics(path); m_diagnostics.clear(); QTC_ASSERT(m_marks.isEmpty(), m_marks.clear()); } -QList DiagnosticManager::diagnosticsAt(const DocumentUri &uri, +QList DiagnosticManager::diagnosticsAt(const FilePath &filePath, const QTextCursor &cursor) const { - const int documentRevision = m_client->documentVersion(uri.toFilePath()); - auto it = m_diagnostics.find(uri); + const int documentRevision = m_client->documentVersion(filePath); + auto it = m_diagnostics.find(filePath); if (it == m_diagnostics.end()) return {}; if (documentRevision != it->version.value_or(documentRevision)) @@ -187,16 +186,16 @@ QList DiagnosticManager::diagnosticsAt(const DocumentUri &uri, }); } -bool DiagnosticManager::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, +bool DiagnosticManager::hasDiagnostic(const FilePath &filePath, const TextDocument *doc, const LanguageServerProtocol::Diagnostic &diag) const { if (!doc) return false; - const auto it = m_diagnostics.find(uri); + const auto it = m_diagnostics.find(filePath); if (it == m_diagnostics.end()) return {}; - const int revision = m_client->documentVersion(uri.toFilePath()); + const int revision = m_client->documentVersion(filePath); if (revision != it->version.value_or(revision)) return false; return it->diagnostics.contains(diag); @@ -205,7 +204,7 @@ bool DiagnosticManager::hasDiagnostic(const LanguageServerProtocol::DocumentUri bool DiagnosticManager::hasDiagnostics(const TextDocument *doc) const { const FilePath docPath = doc->filePath(); - const auto it = m_diagnostics.find(DocumentUri::fromFilePath(docPath)); + const auto it = m_diagnostics.find(docPath); if (it == m_diagnostics.end()) return {}; const int revision = m_client->documentVersion(docPath); diff --git a/src/plugins/languageclient/diagnosticmanager.h b/src/plugins/languageclient/diagnosticmanager.h index 3898327619f..121dc66c8ca 100644 --- a/src/plugins/languageclient/diagnosticmanager.h +++ b/src/plugins/languageclient/diagnosticmanager.h @@ -30,11 +30,11 @@ public: explicit DiagnosticManager(Client *client); ~DiagnosticManager() override; - virtual void setDiagnostics(const LanguageServerProtocol::DocumentUri &uri, + virtual void setDiagnostics(const Utils::FilePath &filePath, const QList &diagnostics, const std::optional &version); - virtual void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri, int version); + virtual void showDiagnostics(const Utils::FilePath &filePath, int version); virtual void hideDiagnostics(const Utils::FilePath &filePath); virtual QList filteredDiagnostics( const QList &diagnostics) const; @@ -43,9 +43,9 @@ public: void clearDiagnostics(); QList diagnosticsAt( - const LanguageServerProtocol::DocumentUri &uri, + const Utils::FilePath &filePath, const QTextCursor &cursor) const; - bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, + bool hasDiagnostic(const Utils::FilePath &filePath, const TextEditor::TextDocument *doc, const LanguageServerProtocol::Diagnostic &diag) const; bool hasDiagnostics(const TextEditor::TextDocument *doc) const; @@ -71,7 +71,7 @@ private: std::optional version; QList diagnostics; }; - QMap m_diagnostics; + QMap m_diagnostics; class Marks { public: diff --git a/src/plugins/languageclient/documentsymbolcache.cpp b/src/plugins/languageclient/documentsymbolcache.cpp index 465c3c4f690..40485b7c62e 100644 --- a/src/plugins/languageclient/documentsymbolcache.cpp +++ b/src/plugins/languageclient/documentsymbolcache.cpp @@ -18,8 +18,8 @@ DocumentSymbolCache::DocumentSymbolCache(Client *client) { auto connectDocument = [this](Core::IDocument *document) { connect(document, &Core::IDocument::contentsChanged, this, [document, this]() { - const auto uri = DocumentUri::fromFilePath(document->filePath()); - m_cache.remove(DocumentUri::fromFilePath(document->filePath())); + const auto uri = m_client->hostPathToServerUri(document->filePath()); + m_cache.remove(uri); auto requestIdIt = m_runningRequests.find(uri); if (requestIdIt != m_runningRequests.end()) { m_client->cancelRequest(requestIdIt.value()); @@ -54,7 +54,8 @@ void DocumentSymbolCache::requestSymbols(const DocumentUri &uri, Schedule schedu bool clientSupportsDocumentSymbols(const Client *client, const DocumentUri &uri) { QTC_ASSERT(client, return false); - const auto doc = TextEditor::TextDocument::textDocumentForFilePath(uri.toFilePath()); + const auto doc = TextEditor::TextDocument::textDocumentForFilePath( + uri.toFilePath(client->hostPathMapper())); return client->supportsDocumentSymbols(doc); } diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index 23d6b3e3b2c..30ed1c0d544 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -446,7 +446,7 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform() params.setPosition({line, column}); params.setContext(context); params.setTextDocument( - TextDocumentIdentifier(DocumentUri::fromFilePath(interface()->filePath()))); + TextDocumentIdentifier(m_client->hostPathToServerUri(interface()->filePath()))); if (const int limit = m_client->completionResultsLimit(); limit >= 0) params.setLimit(limit); CompletionRequest completionRequest(params); diff --git a/src/plugins/languageclient/languageclientformatter.cpp b/src/plugins/languageclient/languageclientformatter.cpp index f67302aa0e7..ab5fbe70ae3 100644 --- a/src/plugins/languageclient/languageclientformatter.cpp +++ b/src/plugins/languageclient/languageclientformatter.cpp @@ -73,7 +73,7 @@ QFutureWatcher *LanguageClientFormatter::format( return nullptr; } DocumentRangeFormattingParams params; - const DocumentUri uri = DocumentUri::fromFilePath(filePath); + const DocumentUri uri = m_client->hostPathToServerUri(filePath); params.setTextDocument(TextDocumentIdentifier(uri)); params.setOptions(formattingOptions(tabSettings)); if (!cursor.hasSelection()) { diff --git a/src/plugins/languageclient/languageclientfunctionhint.cpp b/src/plugins/languageclient/languageclientfunctionhint.cpp index ba877dd7c02..7863750041c 100644 --- a/src/plugins/languageclient/languageclientfunctionhint.cpp +++ b/src/plugins/languageclient/languageclientfunctionhint.cpp @@ -72,7 +72,7 @@ IAssistProposal *FunctionHintProcessor::perform() m_pos = interface()->position(); QTextCursor cursor(interface()->textDocument()); cursor.setPosition(m_pos); - auto uri = DocumentUri::fromFilePath(interface()->filePath()); + auto uri = m_client->hostPathToServerUri(interface()->filePath()); SignatureHelpRequest request((TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(cursor)))); request.setResponseCallback([this](auto response) { this->handleSignatureResponse(response); }); m_client->addAssistProcessor(this); diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp index 9204a1ec04c..75d2edc61a9 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.cpp +++ b/src/plugins/languageclient/languageclienthoverhandler.cpp @@ -55,7 +55,7 @@ void HoverHandler::setHelpItem(const LanguageServerProtocol::MessageId &msgId, bool HoverHandler::reportDiagnostics(const QTextCursor &cursor) { - const QList &diagnostics = m_client->diagnosticsAt(m_uri, cursor); + const QList &diagnostics = m_client->diagnosticsAt(m_filePath, cursor); if (diagnostics.isEmpty()) return false; @@ -76,7 +76,7 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, report(Priority_None); return; } - m_uri = DocumentUri::fromFilePath(editorWidget->textDocument()->filePath()); + m_filePath = editorWidget->textDocument()->filePath(); m_response = {}; m_report = report; @@ -108,8 +108,9 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, return; } - HoverRequest request{TextDocumentPositionParams(TextDocumentIdentifier(m_uri), - Position(cursor))}; + HoverRequest request{ + TextDocumentPositionParams(TextDocumentIdentifier(m_client->hostPathToServerUri(m_filePath)), + Position(cursor))}; m_currentRequest = request.id(); request.setResponseCallback( [this, cursor](const HoverRequest::Response &response) { handleResponse(response, cursor); }); @@ -127,7 +128,7 @@ void HoverHandler::handleResponse(const HoverRequest::Response &response, const if (auto hover = std::get_if(&(*result))) { if (m_helpItemProvider) { m_response = response; - m_helpItemProvider(response, m_uri); + m_helpItemProvider(response, m_filePath); return; } setContent(hover->content()); diff --git a/src/plugins/languageclient/languageclienthoverhandler.h b/src/plugins/languageclient/languageclienthoverhandler.h index 08840d406f5..4aa8099a591 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.h +++ b/src/plugins/languageclient/languageclienthoverhandler.h @@ -15,7 +15,7 @@ namespace LanguageClient { class Client; using HelpItemProvider = std::function; + const Utils::FilePath &path)>; class LANGUAGECLIENT_EXPORT HoverHandler final : public TextEditor::BaseHoverHandler { @@ -49,7 +49,7 @@ private: QPointer m_client; std::optional m_currentRequest; - LanguageServerProtocol::DocumentUri m_uri; + Utils::FilePath m_filePath; LanguageServerProtocol::HoverRequest::Response m_response; TextEditor::BaseHoverHandler::ReportPriority m_report; HelpItemProvider m_helpItemProvider; diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index 38d9db03ecf..4dbcf93f4ae 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -131,6 +131,11 @@ void StdIOClientInterface::setEnvironment(const Utils::Environment &environment) m_env = environment; } +Utils::FilePath StdIOClientInterface::serverDeviceTemplate() const +{ + return m_cmd.executable(); +} + void StdIOClientInterface::sendData(const QByteArray &data) { if (!m_process || m_process->state() != QProcess::Running) { diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 7e90c99c236..b8b8c558053 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -28,6 +28,8 @@ public: void sendMessage(const LanguageServerProtocol::JsonRpcMessage message); void start() { startImpl(); } + virtual Utils::FilePath serverDeviceTemplate() const = 0; + void resetBuffer(); signals: @@ -66,6 +68,8 @@ public: void setWorkingDirectory(const Utils::FilePath &workingDirectory); void setEnvironment(const Utils::Environment &environment); + Utils::FilePath serverDeviceTemplate() const override; + protected: void sendData(const QByteArray &data) final; Utils::CommandLine m_cmd; diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 7f50391ea1f..f3e32813d9e 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -391,11 +391,6 @@ Client *LanguageClientManager::clientForFilePath(const Utils::FilePath &filePath return clientForDocument(TextEditor::TextDocument::textDocumentForFilePath(filePath)); } -Client *LanguageClientManager::clientForUri(const DocumentUri &uri) -{ - return clientForFilePath(uri.toFilePath()); -} - const QList LanguageClientManager::clientsForProject( const ProjectExplorer::Project *project) { diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index 7ce055f1fb2..09815f29df4 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -64,7 +64,6 @@ public: static const BaseSettings *settingForClient(Client *setting); static Client *clientForDocument(TextEditor::TextDocument *document); static Client *clientForFilePath(const Utils::FilePath &filePath); - static Client *clientForUri(const LanguageServerProtocol::DocumentUri &uri); static const QList clientsForProject(const ProjectExplorer::Project *project); template static bool hasClients(); diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 0387ebdd21a..5ed70ae0e00 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -195,14 +195,14 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, : m_client(client) , m_editor(editor) , m_view(this) - , m_uri(DocumentUri::fromFilePath(editor->textDocument()->filePath())) + , m_uri(m_client->hostPathToServerUri(editor->textDocument()->filePath())) { connect(client->documentSymbolCache(), &DocumentSymbolCache::gotSymbols, this, &LanguageClientOutlineWidget::handleResponse); connect(client, &Client::documentUpdated, this, [this](TextEditor::TextDocument *document) { - if (m_client && m_uri == DocumentUri::fromFilePath(document->filePath())) + if (m_client && m_uri == m_client->hostPathToServerUri(document->filePath())) m_client->documentSymbolCache()->requestSymbols(m_uri, Schedule::Delayed); }); @@ -375,7 +375,7 @@ Utils::TreeViewComboBox *LanguageClientOutlineWidgetFactory::createComboBox( OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor) : m_client(client) , m_editorWidget(editor->editorWidget()) - , m_uri(DocumentUri::fromFilePath(editor->document()->filePath())) + , m_uri(m_client->hostPathToServerUri(editor->document()->filePath())) { m_model.setSymbolStringifier(client->symbolStringifier()); m_proxyModel.setSourceModel(&m_model); diff --git a/src/plugins/languageclient/languageclientquickfix.cpp b/src/plugins/languageclient/languageclientquickfix.cpp index e04e7306c73..6093b50405d 100644 --- a/src/plugins/languageclient/languageclientquickfix.cpp +++ b/src/plugins/languageclient/languageclientquickfix.cpp @@ -60,10 +60,11 @@ IAssistProposal *LanguageClientQuickFixAssistProcessor::perform() cursor.select(QTextCursor::LineUnderCursor); Range range(cursor); params.setRange(range); - auto uri = DocumentUri::fromFilePath(interface()->filePath()); + const Utils::FilePath filePath = interface()->filePath(); + const DocumentUri &uri = m_client->hostPathToServerUri(filePath); params.setTextDocument(TextDocumentIdentifier(uri)); CodeActionParams::CodeActionContext context; - context.setDiagnostics(m_client->diagnosticsAt(uri, cursor)); + context.setDiagnostics(m_client->diagnosticsAt(filePath, cursor)); params.setContext(context); CodeActionRequest request(params); diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp index 163162d8b0e..30144313325 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.cpp +++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp @@ -56,7 +56,9 @@ public: } m_renameFilesCheckBox.setText(tr("Re&name %n files", nullptr, filesToRename.size())); const auto filesForUser = Utils::transform(filesToRename, - [](const Utils::FilePath &fp) { return fp.toUserOutput(); }); + [](const Utils::FilePath &fp) { + return fp.toUserOutput(); + }); m_renameFilesCheckBox.setToolTip(tr("Files:\n%1").arg(filesForUser.join('\n'))); m_renameFilesCheckBox.setVisible(true); } @@ -69,7 +71,8 @@ private: }; } // anonymous namespace -SymbolSupport::SymbolSupport(Client *client) : m_client(client) +SymbolSupport::SymbolSupport(Client *client) + : m_client(client) {} template @@ -104,16 +107,17 @@ static void sendTextDocumentPositionParamsRequest(Client *client, static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response &response, Utils::LinkHandler callback, - std::optional linkUnderCursor) + std::optional linkUnderCursor, + const Client *client) { if (std::optional result = response.result()) { if (std::holds_alternative(*result)) { callback({}); } else if (auto ploc = std::get_if(&*result)) { - callback(linkUnderCursor.value_or(ploc->toLink())); + callback(linkUnderCursor.value_or(ploc->toLink(client->hostPathMapper()))); } else if (auto plloc = std::get_if>(&*result)) { if (!plloc->isEmpty()) - callback(linkUnderCursor.value_or(plloc->value(0).toLink())); + callback(linkUnderCursor.value_or(plloc->value(0).toLink(client->hostPathMapper()))); else callback({}); } @@ -123,9 +127,10 @@ static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response & } static TextDocumentPositionParams generateDocPosParams(TextEditor::TextDocument *document, - const QTextCursor &cursor) + const QTextCursor &cursor, + const Client *client) { - const DocumentUri uri = DocumentUri::fromFilePath(document->filePath()); + const DocumentUri uri = client->hostPathToServerUri(document->filePath()); const TextDocumentIdentifier documentId(uri); const Position pos(cursor); return TextDocumentPositionParams(documentId, pos); @@ -138,7 +143,7 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document, { if (!m_client->reachable()) return; - GotoDefinitionRequest request(generateDocPosParams(document, cursor)); + GotoDefinitionRequest request(generateDocPosParams(document, cursor, m_client)); std::optional linkUnderCursor; if (!resolveTarget) { QTextCursor linkCursor = cursor; @@ -150,16 +155,15 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document, link.linkTextEnd = linkCursor.selectionEnd(); linkUnderCursor = link; } - request.setResponseCallback( - [callback, linkUnderCursor](const GotoDefinitionRequest::Response &response) { - handleGotoDefinitionResponse(response, callback, linkUnderCursor); - }); + request.setResponseCallback([callback, linkUnderCursor, client = m_client]( + const GotoDefinitionRequest::Response &response) { + handleGotoDefinitionResponse(response, callback, linkUnderCursor, client); + }); sendTextDocumentPositionParamsRequest(m_client, request, m_client->dynamicCapabilities(), m_client->capabilities()); - } bool SymbolSupport::supportsFindUsages(TextEditor::TextDocument *document) const @@ -212,9 +216,9 @@ QStringList SymbolSupport::getFileContents(const Utils::FilePath &filePath) } QList generateSearchResultItems( - const QMap> &rangesInDocument, - Core::SearchResult *search = nullptr, - bool limitToProjects = false) + const QMap> &rangesInDocument, + Core::SearchResult *search = nullptr, + bool limitToProjects = false) { QList result; const bool renaming = search && search->supportsReplace(); @@ -232,11 +236,11 @@ QList generateSearchResultItems( item.setFilePath(filePath); item.setUseTextEditorFont(true); if (renaming && limitToProjects) { - const bool fileBelongsToProject - = ProjectExplorer::SessionManager::projectForFile(filePath); + const bool fileBelongsToProject = ProjectExplorer::SessionManager::projectForFile( + filePath); item.setSelectForReplacement(fileBelongsToProject); - if (fileBelongsToProject && filePath.baseName().compare(oldSymbolName, - Qt::CaseInsensitive) == 0) { + if (fileBelongsToProject + && filePath.baseName().compare(oldSymbolName, Qt::CaseInsensitive) == 0) { fileRenameCandidates << filePath; } } @@ -260,13 +264,13 @@ QList generateSearchResultItems( } QList generateSearchResultItems( - const LanguageClientArray &locations) + const LanguageClientArray &locations, const DocumentUri::PathMapper &pathMapper) { if (locations.isNull()) return {}; QMap> rangesInDocument; for (const Location &location : locations.toList()) - rangesInDocument[location.uri().toFilePath()] + rangesInDocument[location.uri().toFilePath(pathMapper)] << ItemData{SymbolSupport::convertRange(location.range()), {}}; return generateSearchResultItems(rangesInDocument); } @@ -284,7 +288,8 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re if (result) { Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch( tr("Find References with %1 for:").arg(m_client->name()), "", wordUnderCursor); - search->addResults(generateSearchResultItems(*result), Core::SearchResult::AddOrdered); + search->addResults(generateSearchResultItems(*result, m_client->hostPathMapper()), + Core::SearchResult::AddOrdered); connect(search, &Core::SearchResult::activated, [](const Core::SearchResultItem &item) { Core::EditorManager::openEditorAtSearchResult(item); }); @@ -293,18 +298,19 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re } } -std::optional SymbolSupport::findUsages( - TextEditor::TextDocument *document, const QTextCursor &cursor, const ResultHandler &handler) +std::optional SymbolSupport::findUsages(TextEditor::TextDocument *document, + const QTextCursor &cursor, + const ResultHandler &handler) { if (!supportsFindUsages(document)) return {}; - ReferenceParams params(generateDocPosParams(document, cursor)); + ReferenceParams params(generateDocPosParams(document, cursor, m_client)); params.setContext(ReferenceParams::ReferenceContext(true)); FindReferencesRequest request(params); QTextCursor termCursor(cursor); termCursor.select(QTextCursor::WordUnderCursor); request.setResponseCallback([this, wordUnderCursor = termCursor.selectedText(), handler]( - const FindReferencesRequest::Response &response) { + const FindReferencesRequest::Response &response) { handleFindReferencesResponse(response, wordUnderCursor, handler); }); @@ -355,10 +361,12 @@ bool SymbolSupport::supportsRename(TextEditor::TextDocument *document) return LanguageClient::supportsRename(m_client, document, prepareSupported); } -void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, const QTextCursor &cursor, - const QString &newSymbolName, bool preferLowerCaseFileNames) +void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, + const QTextCursor &cursor, + const QString &newSymbolName, + bool preferLowerCaseFileNames) { - const TextDocumentPositionParams params = generateDocPosParams(document, cursor); + const TextDocumentPositionParams params = generateDocPosParams(document, cursor, m_client); QTextCursor tc = cursor; tc.select(QTextCursor::WordUnderCursor); const QString oldSymbolName = tc.selectedText(); @@ -370,26 +378,25 @@ void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, const QText if (!LanguageClient::supportsRename(m_client, document, prepareSupported)) { const QString error = tr("Renaming is not supported with %1").arg(m_client->name()); createSearch(params, placeholder, {}, {})->finishSearch(true, error); - } else if (prepareSupported) { + } else if (prepareSupported) { requestPrepareRename(document, - generateDocPosParams(document, cursor), + generateDocPosParams(document, cursor, m_client), placeholder, oldSymbolName, preferLowerCaseFileNames); } else { - startRenameSymbol(generateDocPosParams(document, cursor), + startRenameSymbol(generateDocPosParams(document, cursor, m_client), placeholder, oldSymbolName, preferLowerCaseFileNames); } } -void SymbolSupport::requestPrepareRename( - TextEditor::TextDocument *document, - const TextDocumentPositionParams ¶ms, - const QString &placeholder, - const QString &oldSymbolName, - bool preferLowerCaseFileNames) +void SymbolSupport::requestPrepareRename(TextEditor::TextDocument *document, + const TextDocumentPositionParams ¶ms, + const QString &placeholder, + const QString &oldSymbolName, + bool preferLowerCaseFileNames) { PrepareRenameRequest request(params); request.setResponseCallback([this, @@ -409,7 +416,9 @@ void SymbolSupport::requestPrepareRename( if (result.has_value()) { if (std::holds_alternative(*result)) { auto placeHolderResult = std::get(*result); - startRenameSymbol(params, placeHolderResult.placeHolder(), oldSymbolName, + startRenameSymbol(params, + placeHolderResult.placeHolder(), + oldSymbolName, preferLowerCaseFileNames); } else if (std::holds_alternative(*result)) { auto range = std::get(*result); @@ -425,10 +434,7 @@ void SymbolSupport::requestPrepareRename( reportedSymbolName, preferLowerCaseFileNames); } else { - startRenameSymbol(params, - placeholder, - oldSymbolName, - preferLowerCaseFileNames); + startRenameSymbol(params, placeholder, oldSymbolName, preferLowerCaseFileNames); } } } @@ -453,7 +459,8 @@ void SymbolSupport::requestRename(const TextDocumentPositionParams &positionPara QList generateReplaceItems(const WorkspaceEdit &edits, Core::SearchResult *search, - bool limitToProjects) + bool limitToProjects, + const DocumentUri::PathMapper &pathMapper) { auto convertEdits = [](const QList &edits) { return Utils::transform(edits, [](const TextEdit &edit) { @@ -464,22 +471,21 @@ QList generateReplaceItems(const WorkspaceEdit &edits, auto documentChanges = edits.documentChanges().value_or(QList()); if (!documentChanges.isEmpty()) { for (const TextDocumentEdit &documentChange : std::as_const(documentChanges)) { - rangesInDocument[documentChange.textDocument().uri().toFilePath()] = convertEdits( - documentChange.edits()); + rangesInDocument[documentChange.textDocument().uri().toFilePath(pathMapper)] + = convertEdits(documentChange.edits()); } } else { auto changes = edits.changes().value_or(WorkspaceEdit::Changes()); for (auto it = changes.begin(), end = changes.end(); it != end; ++it) - rangesInDocument[it.key().toFilePath()] = convertEdits(it.value()); + rangesInDocument[it.key().toFilePath(pathMapper)] = convertEdits(it.value()); } return generateSearchResultItems(rangesInDocument, search, limitToProjects); } -Core::SearchResult *SymbolSupport::createSearch( - const TextDocumentPositionParams &positionParams, - const QString &placeholder, - const QString &oldSymbolName, - bool preferLowerCaseFileNames) +Core::SearchResult *SymbolSupport::createSearch(const TextDocumentPositionParams &positionParams, + const QString &placeholder, + const QString &oldSymbolName, + bool preferLowerCaseFileNames) { Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch( tr("Find References with %1 for:").arg(m_client->name()), @@ -500,18 +506,22 @@ Core::SearchResult *SymbolSupport::createSearch( search->setSearchAgainEnabled(true); search->setReplaceEnabled(false); }); - connect(search, &Core::SearchResult::searchAgainRequested, this, + connect(search, + &Core::SearchResult::searchAgainRequested, + this, [this, positionParams, search]() { search->restart(); requestRename(positionParams, search->textToReplace(), search); }); - connect(search, &Core::SearchResult::replaceButtonClicked, this, + connect(search, + &Core::SearchResult::replaceButtonClicked, + this, [this, positionParams, search](const QString & /*replaceText*/, const QList &checkedItems) { applyRename(checkedItems, search); }); - connect(this, &QObject::destroyed, search, [search, clientName = m_client->name()](){ + connect(this, &QObject::destroyed, search, [search, clientName = m_client->name()]() { search->restart(); // clears potential current results search->finishSearch(true, tr("%1 is not reachable anymore.").arg(clientName)); }); @@ -520,11 +530,13 @@ Core::SearchResult *SymbolSupport::createSearch( } void SymbolSupport::startRenameSymbol(const TextDocumentPositionParams &positionParams, - const QString &placeholder, const QString &oldSymbolName, + const QString &placeholder, + const QString &oldSymbolName, bool preferLowerCaseFileNames) { - requestRename(positionParams, placeholder, createSearch( - positionParams, placeholder, oldSymbolName, preferLowerCaseFileNames)); + requestRename(positionParams, + placeholder, + createSearch(positionParams, placeholder, oldSymbolName, preferLowerCaseFileNames)); } void SymbolSupport::handleRenameResponse(Core::SearchResult *search, @@ -539,7 +551,10 @@ void SymbolSupport::handleRenameResponse(Core::SearchResult *search, const std::optional &edits = response.result(); if (edits.has_value()) { - search->addResults(generateReplaceItems(*edits, search, m_limitRenamingToProjects), + search->addResults(generateReplaceItems(*edits, + search, + m_limitRenamingToProjects, + m_client->hostPathMapper()), Core::SearchResult::AddOrdered); qobject_cast(search->additionalReplaceWidget())->showLabel(false); search->setReplaceEnabled(true); @@ -554,22 +569,21 @@ void SymbolSupport::applyRename(const QList &checkedItem Core::SearchResult *search) { QSet affectedNonOpenFilePaths; - QMap> editsForDocuments; + QMap> editsForDocuments; for (const Core::SearchResultItem &item : checkedItems) { const auto filePath = Utils::FilePath::fromString(item.path().value(0)); if (!m_client->documentForFilePath(filePath)) affectedNonOpenFilePaths << filePath; TextEdit edit(item.userData().toJsonObject()); if (edit.isValid()) - editsForDocuments[DocumentUri::fromFilePath(filePath)] << edit; + editsForDocuments[filePath] << edit; } for (auto it = editsForDocuments.begin(), end = editsForDocuments.end(); it != end; ++it) applyTextEdits(m_client, it.key(), it.value()); if (!affectedNonOpenFilePaths.isEmpty()) { - Core::DocumentManager::notifyFilesChangedInternally( - Utils::toList(affectedNonOpenFilePaths)); + Core::DocumentManager::notifyFilesChangedInternally(Utils::toList(affectedNonOpenFilePaths)); } const auto extraWidget = qobject_cast(search->additionalReplaceWidget()); @@ -579,10 +593,14 @@ void SymbolSupport::applyRename(const QList &checkedItem const QVariantList userData = search->userData().toList(); QTC_ASSERT(userData.size() == 3, return); const Utils::FilePaths filesToRename = Utils::transform(userData.at(2).toStringList(), - [](const QString &f) { return Utils::FilePath::fromString(f); }); - ProjectExplorer::ProjectExplorerPlugin::renameFilesForSymbol( - userData.at(0).toString(), search->textToReplace(), - filesToRename, userData.at(1).toBool()); + [](const QString &f) { + return Utils::FilePath::fromString( + f); + }); + ProjectExplorer::ProjectExplorerPlugin::renameFilesForSymbol(userData.at(0).toString(), + search->textToReplace(), + filesToRename, + userData.at(1).toBool()); } Core::Search::TextRange SymbolSupport::convertRange(const Range &range) diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index f85d62a4c28..8803a12289f 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -62,7 +62,7 @@ bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit) if (edits.isEmpty()) return true; const DocumentUri &uri = edit.textDocument().uri(); - const FilePath &filePath = uri.toFilePath(); + const FilePath &filePath = client->serverUriToHostPath(uri); LanguageClientValue version = edit.textDocument().version(); if (!version.isNull() && version.value(0) < client->documentVersion(filePath)) return false; @@ -70,13 +70,20 @@ bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit) } bool applyTextEdits(const Client *client, const DocumentUri &uri, const QList &edits) +{ + return applyTextEdits(client, client->serverUriToHostPath(uri), edits); +} + +bool applyTextEdits(const Client *client, + const Utils::FilePath &filePath, + const QList &edits) { if (edits.isEmpty()) return true; RefactoringChangesData * const backend = client->createRefactoringChangesBackend(); RefactoringChanges changes(backend); RefactoringFilePtr file; - file = changes.file(uri.toFilePath()); + file = changes.file(filePath); file->setChangeSet(editsToChangeSet(edits, file->document())); if (backend) { for (const TextEdit &edit : edits) @@ -130,7 +137,7 @@ void updateCodeActionRefactoringMarker(Client *client, const QList &actions, const DocumentUri &uri) { - TextDocument* doc = TextDocument::textDocumentForFilePath(uri.toFilePath()); + TextDocument* doc = TextDocument::textDocumentForFilePath(client->serverUriToHostPath(uri)); if (!doc) return; const QVector editors = BaseTextEditor::textEditorsForDocument(doc); diff --git a/src/plugins/languageclient/languageclientutils.h b/src/plugins/languageclient/languageclientutils.h index bccfdd533fd..6438f09f675 100644 --- a/src/plugins/languageclient/languageclientutils.h +++ b/src/plugins/languageclient/languageclientutils.h @@ -32,6 +32,9 @@ applyTextDocumentEdit(const Client *client, const LanguageServerProtocol::TextDo bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client, const LanguageServerProtocol::DocumentUri &uri, const QList &edits); +bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client, + const Utils::FilePath &filePath, + const QList &edits); void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulatorInterface &manipulator, const LanguageServerProtocol::TextEdit &edit, bool newTextIsSnippet = false); diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index f297a359db1..bee8bc05008 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -9,9 +9,13 @@ #include "languageclientutils.h" #include + +#include #include + #include #include + #include #include @@ -43,6 +47,7 @@ void DocumentLocatorFilter::updateCurrentClient() TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument(); if (Client *client = LanguageClientManager::clientForDocument(document); client && (client->locatorsEnabled() || m_forced)) { + setEnabled(!m_forced); if (m_symbolCache != client->documentSymbolCache()) { disconnect(m_updateSymbolsConnection); @@ -52,12 +57,14 @@ void DocumentLocatorFilter::updateCurrentClient() } m_resetSymbolsConnection = connect(document, &Core::IDocument::contentsChanged, this, &DocumentLocatorFilter::resetSymbols); - m_currentUri = DocumentUri::fromFilePath(document->filePath()); + m_currentUri = client->hostPathToServerUri(document->filePath()); + m_pathMapper = client->hostPathMapper(); } else { disconnect(m_updateSymbolsConnection); m_symbolCache.clear(); m_currentUri.clear(); setEnabled(false); + m_pathMapper = DocumentUri::PathMapper(); } } @@ -78,7 +85,8 @@ void DocumentLocatorFilter::resetSymbols() } static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, - Core::ILocatorFilter *filter) + Core::ILocatorFilter *filter, + DocumentUri::PathMapper pathMapper) { Core::LocatorFilterEntry entry; entry.filter = filter; @@ -86,14 +94,14 @@ static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &in if (std::optional container = info.containerName()) entry.extraInfo = container.value_or(QString()); entry.displayIcon = symbolIcon(info.kind()); - entry.internalData = QVariant::fromValue(info.location().toLink()); + entry.internalData = QVariant::fromValue(info.location().toLink(pathMapper)); return entry; - } Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info) { - return LanguageClient::generateLocatorEntry(info, this); + QTC_ASSERT(m_pathMapper, return {}); + return LanguageClient::generateLocatorEntry(info, this, m_pathMapper); } QList DocumentLocatorFilter::generateLocatorEntries( @@ -203,8 +211,11 @@ void DocumentLocatorFilter::accept(const Core::LocatorFilterEntry &selection, int * /*selectionLength*/) const { if (selection.internalData.canConvert()) { + QTC_ASSERT(m_pathMapper, return); auto lineColumn = qvariant_cast(selection.internalData); - const Utils::Link link(m_currentUri.toFilePath(), lineColumn.line + 1, lineColumn.column); + const Utils::Link link(m_currentUri.toFilePath(m_pathMapper), + lineColumn.line + 1, + lineColumn.column); Core::EditorManager::openEditorAt(link, {}, Core::EditorManager::AllowExternalEditor); } else if (selection.internalData.canConvert()) { Core::EditorManager::openEditorAt(qvariant_cast(selection.internalData), @@ -293,15 +304,14 @@ QList WorkspaceLocatorFilter::matchesFor( if (!m_filterKinds.isEmpty()) { - m_results = Utils::filtered(m_results, [&](const SymbolInformation &info) { - return m_filterKinds.contains(SymbolKind(info.kind())); + m_results = Utils::filtered(m_results, [&](const SymbolInfoWithPathMapper &info) { + return m_filterKinds.contains(SymbolKind(info.symbol.kind())); }); } - return Utils::transform(m_results, - [this](const SymbolInformation &info) { - return generateLocatorEntry(info, this); - }) - .toList(); + auto generateEntry = [this](const SymbolInfoWithPathMapper &info) { + return generateLocatorEntry(info.symbol, this, info.mapper); + }; + return Utils::transform(m_results, generateEntry).toList(); } void WorkspaceLocatorFilter::accept(const Core::LocatorFilterEntry &selection, @@ -322,7 +332,10 @@ void WorkspaceLocatorFilter::handleResponse(Client *client, m_pendingRequests.remove(client); auto result = response.result().value_or(LanguageClientArray()); if (!result.isNull()) - m_results.append(result.toList().toVector()); + m_results.append( + Utils::transform(result.toList().toVector(), [client](const SymbolInformation &info) { + return SymbolInfoWithPathMapper{info, client->hostPathMapper()}; + })); if (m_pendingRequests.isEmpty()) emit allRequestsFinished(QPrivateSignal()); } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index afb8630795a..11a664380da 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -7,8 +7,9 @@ #include "languageclient_global.h" #include -#include + #include +#include #include #include @@ -67,6 +68,7 @@ private: QMetaObject::Connection m_updateSymbolsConnection; QMetaObject::Connection m_resetSymbolsConnection; std::optional m_currentSymbols; + LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper; bool m_forced = false; }; @@ -101,8 +103,15 @@ private: const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); QMutex m_mutex; + + struct SymbolInfoWithPathMapper + { + LanguageServerProtocol::SymbolInformation symbol; + LanguageServerProtocol::DocumentUri::PathMapper mapper; + }; + QMap m_pendingRequests; - QVector m_results; + QVector m_results; QVector m_filterKinds; qint64 m_maxResultCount = 0; }; diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp index bf54ee91e0e..1f1ddb832a7 100644 --- a/src/plugins/languageclient/semantichighlightsupport.cpp +++ b/src/plugins/languageclient/semantichighlightsupport.cpp @@ -60,7 +60,7 @@ void SemanticTokenSupport::reloadSemanticTokensImpl(TextDocument *textDocument, if (supportedRequests.testFlag(SemanticRequestType::None)) return; const Utils::FilePath filePath = textDocument->filePath(); - const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); + const TextDocumentIdentifier docId(m_client->hostPathToServerUri(filePath)); auto responseCallback = [this, remainingRerequests, filePath, @@ -128,7 +128,7 @@ void SemanticTokenSupport::updateSemanticTokensImpl(TextDocument *textDocument, if (documentVersion == versionedToken.version) return; SemanticTokensDeltaParams params; - params.setTextDocument(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))); + params.setTextDocument(TextDocumentIdentifier(m_client->hostPathToServerUri(filePath))); params.setPreviousResultId(previousResultId); SemanticTokensFullDeltaRequest request(params); request.setResponseCallback( diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index aa66af328f3..d6ce45d3b62 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -213,7 +213,7 @@ void PyLSClient::openDocument(TextEditor::TextDocument *document) const FilePath workspacePath = documentPath.parentDir(); if (!m_extraWorkspaceDirs.contains(workspacePath)) { WorkspaceFoldersChangeEvent event; - event.setAdded({WorkSpaceFolder(DocumentUri::fromFilePath(workspacePath), + event.setAdded({WorkSpaceFolder(hostPathToServerUri(workspacePath), workspacePath.fileName())}); DidChangeWorkspaceFoldersParams params; params.setEvent(event); diff --git a/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp b/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp index 75732e98bf5..449125d06cd 100644 --- a/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp +++ b/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp @@ -476,7 +476,7 @@ void tst_LanguageServerProtocol::documentUri_data() QTest::newRow("home dir") - << DocumentUri::fromFilePath(Utils::FilePath::fromString(QDir::homePath())) + << DocumentUri::fromFilePath(Utils::FilePath::fromString(QDir::homePath()), [](auto in){ return in;}) << true << Utils::FilePath::fromUserInput(QDir::homePath()) << QString(filePrefix + QDir::homePath()); @@ -484,7 +484,7 @@ void tst_LanguageServerProtocol::documentUri_data() const QString argv0 = QFileInfo(qApp->arguments().first()).absoluteFilePath(); const auto argv0FileName = Utils::FilePath::fromUserInput(argv0); QTest::newRow("argv0 file name") - << DocumentUri::fromFilePath(argv0FileName) + << DocumentUri::fromFilePath(argv0FileName, [](auto in){ return in;}) << true << argv0FileName << QString(filePrefix + QDir::fromNativeSeparators(argv0)); @@ -514,7 +514,7 @@ void tst_LanguageServerProtocol::documentUri() QFETCH(QString, string); QCOMPARE(uri.isValid(), isValid); - QCOMPARE(uri.toFilePath(), fileName); + QCOMPARE(uri.toFilePath([](auto in){ return in;}), fileName); QCOMPARE(uri.toString(), string); }