hokein created this revision. hokein added a reviewer: sammccall. Herald added subscribers: kadircet, arphaman, jkorous, MaskRay, ilya-biryukov. Herald added a project: clang.
"prepareRename" request is added in LSP v3.12.0. No test yet, but want some early feedback. Unfortunately, due to the bug in VSCode LSP[1], the rename dialog still shows up when we return null in prepareRename. The fix is not released in the latest version. [1]: https://github.com/microsoft/vscode-languageserver-node/issues/447 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D63126 Files: clang-tools-extra/clangd/ClangdLSPServer.cpp clang-tools-extra/clangd/ClangdLSPServer.h clang-tools-extra/clangd/ClangdServer.cpp clang-tools-extra/clangd/ClangdServer.h clang-tools-extra/clangd/Protocol.cpp clang-tools-extra/clangd/Protocol.h clang-tools-extra/clangd/refactor/Rename.cpp clang-tools-extra/clangd/refactor/Rename.h
Index: clang-tools-extra/clangd/refactor/Rename.h =================================================================== --- clang-tools-extra/clangd/refactor/Rename.h +++ clang-tools-extra/clangd/refactor/Rename.h @@ -16,6 +16,20 @@ namespace clang { namespace clangd { +// Contains information about the symbol being renamed. +struct PrepareRename { + /// The unqualified symbol name. + std::string Name; + /// The range of the symbol at the Pos; + Range NameRange; + /// Whether the symbol is local (e.g. function-local). + bool IsLocal; +}; + +/// Test the validity of a rename operation at a specified \Pos. +/// Returns null if the rename operation is not valid. +llvm::Optional<PrepareRename> prepareRenameAt(ParsedAST &AST, Position Pos); + /// Renames all occurrences of the symbol at \p Pos to \p NewName. /// Occurrences outside the current file are not modified. llvm::Expected<tooling::Replacements> renameWithinFile(ParsedAST &AST, Index: clang-tools-extra/clangd/refactor/Rename.cpp =================================================================== --- clang-tools-extra/clangd/refactor/Rename.cpp +++ clang-tools-extra/clangd/refactor/Rename.cpp @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "refactor/Rename.h" +#include "AST.h" #include "clang/Tooling/Refactoring/RefactoringResultConsumer.h" #include "clang/Tooling/Refactoring/Rename/RenamingAction.h" +#include "clang/Tooling/Refactoring/Rename/USRFinder.h" namespace clang { namespace clangd { @@ -84,5 +86,28 @@ return FilteredChanges; } +static Range getTokenRange(SourceLocation Loc, const ASTContext &Ctx) { + SourceLocation End = Lexer::getLocForEndOfToken( + Loc, 0, Ctx.getSourceManager(), Ctx.getLangOpts()); + return halfOpenToRange(Ctx.getSourceManager(), + CharSourceRange::getCharRange(Loc, End)); +} + +llvm::Optional<PrepareRename> prepareRenameAt(ParsedAST &AST, Position Pos) { + ASTContext &ASTCtx = AST.getASTContext(); + SourceLocation SourceLocationBeg = clangd::getBeginningOfIdentifier( + AST, Pos, AST.getSourceManager().getMainFileID()); + const NamedDecl *D = + clang::tooling::getNamedDeclAt(ASTCtx, SourceLocationBeg); + if (!D) + return llvm::None; + PrepareRename Result; + Result.Name = printName(ASTCtx, *D); + Result.NameRange = getTokenRange(SourceLocationBeg, ASTCtx); + /// FIXME: we should include the TU-scoped symbols (e.g. static function). + Result.IsLocal = D->getParentFunctionOrMethod(); + return Result; +} + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/Protocol.h =================================================================== --- clang-tools-extra/clangd/Protocol.h +++ clang-tools-extra/clangd/Protocol.h @@ -406,6 +406,10 @@ /// The content format that should be used for Hover requests. MarkupKind HoverContentFormat = MarkupKind::PlainText; + + /// The client supports testing for validity of rename operations + /// before execution. + bool RenamePrepareSupport = false; }; bool fromJSON(const llvm::json::Value &, ClientCapabilities &); Index: clang-tools-extra/clangd/Protocol.cpp =================================================================== --- clang-tools-extra/clangd/Protocol.cpp +++ clang-tools-extra/clangd/Protocol.cpp @@ -339,6 +339,10 @@ if (!fromJSON(*OffsetEncoding, *R.offsetEncoding)) return false; } + if (auto *Rename = O->getObject("rename")) { + if (auto RenameSupport = Rename->getBoolean("prepareSupport")) + R.RenamePrepareSupport = *RenameSupport; + } return true; } Index: clang-tools-extra/clangd/ClangdServer.h =================================================================== --- clang-tools-extra/clangd/ClangdServer.h +++ clang-tools-extra/clangd/ClangdServer.h @@ -23,6 +23,7 @@ #include "index/Background.h" #include "index/FileIndex.h" #include "index/Index.h" +#include "refactor/Rename.h" #include "refactor/Tweak.h" #include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/Core/Replacement.h" @@ -219,6 +220,10 @@ PathRef File, Position Pos, StringRef TriggerText); + /// Test the validity of a rename operation. + void prepareRename(PathRef File, Position Pos, + Callback<llvm::Optional<PrepareRename>> CB); + /// 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, Index: clang-tools-extra/clangd/ClangdServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdServer.cpp +++ clang-tools-extra/clangd/ClangdServer.cpp @@ -270,6 +270,17 @@ return Result; } +void ClangdServer::prepareRename(PathRef File, Position Pos, + Callback<llvm::Optional<PrepareRename>> CB) { + auto Action = [Pos](Callback<llvm::Optional<PrepareRename>> CB, + llvm::Expected<InputsAndAST> InpAST) { + if (!InpAST) + return CB(InpAST.takeError()); + CB(clangd::prepareRenameAt(InpAST->AST, Pos)); + }; + WorkScheduler.runWithAST("PrepareRename", File, Bind(Action, std::move(CB))); +} + void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName, Callback<std::vector<TextEdit>> CB) { auto Action = [Pos](Path File, std::string NewName, Index: clang-tools-extra/clangd/ClangdLSPServer.h =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.h +++ clang-tools-extra/clangd/ClangdLSPServer.h @@ -92,6 +92,8 @@ void onCommand(const ExecuteCommandParams &, Callback<llvm::json::Value>); void onWorkspaceSymbol(const WorkspaceSymbolParams &, Callback<std::vector<SymbolInformation>>); + void onPrepareRename(const TextDocumentPositionParams &, + Callback<llvm::Optional<Range>>); void onRename(const RenameParams &, Callback<WorkspaceEdit>); void onHover(const TextDocumentPositionParams &, Callback<llvm::Optional<Hover>>); Index: clang-tools-extra/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -390,6 +390,8 @@ }}, {"typeHierarchyProvider", true}, }}}}; + if (Params.capabilities.RenamePrepareSupport) + Result["renameProvider"] = llvm::json::Object{{"prepareProvider", true}}; if (NegotiatedOffsetEncoding) Result["offsetEncoding"] = *NegotiatedOffsetEncoding; Reply(std::move(Result)); @@ -525,6 +527,25 @@ std::move(Reply))); } +void ClangdLSPServer::onPrepareRename(const TextDocumentPositionParams &Params, + Callback<llvm::Optional<Range>> Reply) { + Server->prepareRename( + Params.textDocument.uri.file(), Params.position, + Bind( + [](decltype(Reply) Reply, + llvm::Expected<llvm::Optional<PrepareRename>> R) { + if (!R) + return Reply(R.takeError()); + if (!*R) + return Reply(llvm::None); + + Range Result; + Result = (*R)->NameRange; + Reply(std::move(Result)); + }, + std::move(Reply))); +} + void ClangdLSPServer::onRename(const RenameParams &Params, Callback<WorkspaceEdit> Reply) { Path File = Params.textDocument.uri.file(); @@ -960,6 +981,7 @@ MsgHandler->bind("textDocument/declaration", &ClangdLSPServer::onGoToDeclaration); MsgHandler->bind("textDocument/references", &ClangdLSPServer::onReference); MsgHandler->bind("textDocument/switchSourceHeader", &ClangdLSPServer::onSwitchSourceHeader); + MsgHandler->bind("textDocument/prepareRename", &ClangdLSPServer::onPrepareRename); MsgHandler->bind("textDocument/rename", &ClangdLSPServer::onRename); MsgHandler->bind("textDocument/hover", &ClangdLSPServer::onHover); MsgHandler->bind("textDocument/documentSymbol", &ClangdLSPServer::onDocumentSymbol);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits