diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -316,10 +316,13 @@ return CB(InpAST.takeError()); auto &AST = InpAST->AST; const auto &SM = AST.getSourceManager(); - SourceLocation Loc = - SM.getMacroArgExpandedLocation(getBeginningOfIdentifier( - Pos, AST.getSourceManager(), AST.getLangOpts())); - auto Range = getTokenRange(SM, AST.getLangOpts(), Loc); + const auto *TouchingIdentifier = + getTouchingIdentifier(Pos, SM, AST.getTokens()); + if (!TouchingIdentifier) + return CB(llvm::None); // no rename on non-identifiers. + + auto Range = getTokenRange(AST.getSourceManager(), AST.getLangOpts(), + TouchingIdentifier->location()); if (!Range) return CB(llvm::None); // "rename" is not valid at the position. diff --git a/clang-tools-extra/clangd/SourceCode.h b/clang-tools-extra/clangd/SourceCode.h --- a/clang-tools-extra/clangd/SourceCode.h +++ b/clang-tools-extra/clangd/SourceCode.h @@ -21,6 +21,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" @@ -298,6 +299,12 @@ bool isHeaderFile(llvm::StringRef FileName, llvm::Optional LangOpts = llvm::None); +/// Returns the identifier token that touches the given \p Pos +/// Redturns nullptr if there is none. +const syntax::Token *getTouchingIdentifier(Position Pos, + const SourceManager &SM, + const syntax::TokenBuffer &Tokens); + } // namespace clangd } // namespace clang #endif diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -1127,5 +1127,15 @@ return Lang != types::TY_INVALID && types::onlyPrecompileType(Lang); } +const syntax::Token *getTouchingIdentifier(Position Pos, + const SourceManager &SM, + const syntax::TokenBuffer &Tokens) { + auto Loc = sourceLocationInMainFile(SM, Pos); + if (!Loc) { + elog("Failed to convert position to source location: {0}", Loc.takeError()); + return nullptr; + } + return spelledIdentifierTouching(*Loc, Tokens); +} } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp --- a/clang-tools-extra/clangd/refactor/Rename.cpp +++ b/clang-tools-extra/clangd/refactor/Rename.cpp @@ -448,11 +448,8 @@ return (*Content)->getBuffer().str(); }; // Try to find the tokens adjacent to the cursor position. - auto Loc = sourceLocationInMainFile(SM, RInputs.Pos); - if (!Loc) - return Loc.takeError(); const syntax::Token *IdentifierToken = - spelledIdentifierTouching(*Loc, AST.getTokens()); + getTouchingIdentifier(RInputs.Pos, SM, AST.getTokens()); // Renames should only triggered on identifiers. if (!IdentifierToken) return makeError(ReasonToReject::NoSymbolFound); diff --git a/clang-tools-extra/clangd/test/rename.test b/clang-tools-extra/clangd/test/rename.test --- a/clang-tools-extra/clangd/test/rename.test +++ b/clang-tools-extra/clangd/test/rename.test @@ -21,12 +21,9 @@ # CHECK-NEXT: } --- {"jsonrpc":"2.0","id":2,"method":"textDocument/prepareRename","params":{"textDocument":{"uri":"test:///foo.cpp"},"position":{"line":0,"character":2}}} -# CHECK: "error": { -# CHECK-NEXT: "code": -32001, -# CHECK-NEXT: "message": "Cannot rename symbol: there is no symbol at the given location" -# CHECK-NEXT: }, -# CHECK-NEXT: "id": 2, -# CHECK-NEXT: "jsonrpc": "2.0" +# CHECK: "id": 2, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": null --- {"jsonrpc":"2.0","id":4,"method":"textDocument/rename","params":{"textDocument":{"uri":"test:///foo.cpp"},"position":{"line":0,"character":2},"newName":"bar"}} # CHECK: "error": {