This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Implement rename by using SelectionTree and findExplicitReferences.
ClosedPublic

Authored by hokein on Nov 7 2019, 1:23 AM.

Details

Summary

With the new implemenation, we will have better coverage of various AST
nodes, and fix some known/potential bugs.

Also added the existing clang-renamae tests. Known changed behavior:

  1. "~Fo^o()" will not trigger the rename, will fix afterwards
  2. references in macro bodies would not rename now

This fixes:

Diff Detail

Event Timeline

hokein created this revision.Nov 7 2019, 1:23 AM
Herald added a project: Restricted Project. · View Herald TranscriptNov 7 2019, 1:23 AM

It's a bit unclear how we manage to still rename overrides. Is this handled by the USR-generating functions?
Could we factor out the part that collects NamedDecls and use those instead of the USRs instead?

clang-tools-extra/clangd/ClangdServer.cpp
326 ↗(On Diff #228188)

I would argue rename should not work in that case.
Could we check that the cursor is actually on the name token of the NamedDecl and not rename if it isn't?

clang-tools-extra/clangd/refactor/Rename.cpp
191

Why USRs? Could we just check whether the ND.getCanonicalDecl() is there instead?

clang-tools-extra/clangd/unittests/RenameTests.cpp
97

Could we stop at B?
I don't think C->D cover any more code paths, they merely add some noise to the test, making it harder to read.

109

NIT: alternatively, just do A().foo() to make the test smaller

131

Could you also check that destructors are renamed properly?

131

NIT: maybe remove the bodies of the functions that don't have references to Foo?
They seem to merely add noise, don't think they improve coverage.

185

The FIXME is a bit unclear. Could you explain in more detail?

214

I would argue we should fail in that case and not rename.
If we change the macro body, there's a chance other usages that we didn't want to update will also be updated.

However, if the current rename does that, also happy to keep as is. Up to you.

369

NIT: also mention in the documentation comment above that rename is run on all points.

hokein updated this revision to Diff 228243.Nov 7 2019, 7:33 AM
hokein marked 11 inline comments as done.

simplify the testcases.

hokein added a comment.Nov 7 2019, 7:34 AM

It's a bit unclear how we manage to still rename overrides. Is this handled by the USR-generating functions?
Could we factor out the part that collects NamedDecls and use those instead of the USRs instead?

Yes, it is handled by the tooling USR-generating function. I would not touch that part, I plan to get rid of that API in a followup.

clang-tools-extra/clangd/ClangdServer.cpp
326 ↗(On Diff #228188)

you are probably right, we only allow rename which is triggered on the name token. Will update the patch.

clang-tools-extra/clangd/refactor/Rename.cpp
191

checking ND.getCanonicalDecl() is not enough, thinking about virtual methods.

tooling::getUSRsForDeclaration does all the black-magic things here, it returns all rename-related decls.

clang-tools-extra/clangd/unittests/RenameTests.cpp
97

Stopped C.

131

Done. Add a new test for constructor/destructor case.

185

sorry, I forgot this.

This is a tricky case, if the cursor is on cxx initializer list, SelectionTree will return the CXXConsturctorExpr node of Baz, it actually rename the class Baz instead of renaming the Foo field.

214

I was also surprised with this testcase, but it aligns with what the current rename does.

ilya-biryukov added inline comments.Nov 8 2019, 12:56 AM
clang-tools-extra/clangd/ClangdServer.cpp
326 ↗(On Diff #228188)

Definitely think we should do it before landing the patch.
Otherwise we'll introduce regressions.

clang-tools-extra/clangd/refactor/Rename.cpp
191

Could you add a comment that we need this to handle virtual methods?

204

Are we sure that USRs will always work here?
I would be protective here, surely there are unhandled cases.

260–261

This seems to assume all occurrences are outside macros.
Won't it break in presence of macros?
Do we have tests when the renamed token is:

  • inside macro body
  • inside macro arguments

?

NIT: a typo in the description:
s/Aslo/Also

hokein updated this revision to Diff 228948.Nov 12 2019, 1:11 PM
hokein marked 4 inline comments as done.
  • make rename only work when the position is on the name range of the decl
  • add more testsj
hokein added inline comments.Nov 12 2019, 1:12 PM
clang-tools-extra/clangd/ClangdServer.cpp
326 ↗(On Diff #228188)

Done.

clang-tools-extra/clangd/refactor/Rename.cpp
260–261

if Loc is a macro location, tooling::Replacement will use the spelling location, so if the spelling location is in the main file, the code is correct, we have test cases for it.

but we will fail on cases like below, we should fix this, note that this issue exists even before this patch. Updated the comment here.

// foo.h
#define MACRO foo

// foo.cc
void f() {
  int fo^o = 2;
  MACRO;
}

Build result: pass - 59990 tests passed, 0 failed and 763 were skipped.
Log files: console-log.txt, CMakeCache.txt

hokein edited the summary of this revision. (Show Details)Nov 12 2019, 1:29 PM
ilya-biryukov added inline comments.Nov 13 2019, 1:55 AM
clang-tools-extra/clangd/refactor/Rename.cpp
260–261

Renaming the spelling location seems like a bad idea in this case, I would argue we shouldn't rename in macro bodies (see the relevant comment on the test-case, let's move discussion there maybe?)

It would also be good to handle rename in macros outside tooling::Replacement, it's an important decision and I we should not blindly stick to the default behavior of tooling::Replacement without explicitly explaining why it's the best thing for rename.

clang-tools-extra/clangd/unittests/RenameTests.cpp
202

I would argue we should never rename in macro bodies.
That might cause problems in other uses of the macro as the token might refer to a completely different thing in some other place.
It's also a pretty rare case, so failing here instead of breaking code seems like the proper trade-off.

Are we keen on supporting this? If yes, why?

234

Could we also check partial and full specializations work?

template <>
class Foo<bool> {};

template <class T>
class Foo<T*> {};

Foo<int> x;
Foo<bool> y;
Foo<int*> z;
313

Why does this have to be a macro? This test does not seem to test macros in any way?

Maybe inline the macro?

hokein updated this revision to Diff 229530.Nov 15 2019, 6:33 AM
hokein marked 6 inline comments as done.

address review comments:

  • don't rename inside macro body
  • fixed a corner case where the rename occurrence may come from a non-preamble #include
  • add more tests, and simplify the testcases.
hokein edited the summary of this revision. (Show Details)Nov 15 2019, 6:44 AM
hokein added inline comments.
clang-tools-extra/clangd/refactor/Rename.cpp
260–261

Yes, I agree. There was a FIXME about this, I was planning to fix this in a follow-up, but now it is fixed.

clang-tools-extra/clangd/unittests/RenameTests.cpp
202

+1 on your suggestion.. The new code should handle this case as well.

234

added.

313

this was from the original clang-rename test, didn't know the intention about it.

Build result: pass - 60093 tests passed, 0 failed and 729 were skipped.
Log files: console-log.txt, CMakeCache.txt

hokein updated this revision to Diff 229766.Nov 18 2019, 1:33 AM

rebase: renaming the filed on cxx initializer list e.g. "Foo() : Fie^ld()" is fixed in SelectionTree.

hokein edited the summary of this revision. (Show Details)Nov 18 2019, 1:33 AM

Build result: fail - 60148 tests passed, 1 failed and 729 were skipped.

failed: LLVM.Bindings/Go/go.test

Log files: console-log.txt, CMakeCache.txt

Thanks, LG. The only important is about testing the foo.inc case separately from the rest of rename tests.

clang-tools-extra/clangd/refactor/Rename.cpp
180

NIT: inline this into the single caller.
Should simplify the code.

253

NIT: could probably shorten the whole sentence to We traverse only main file decls, but locations could come from an #include file, e.g.

clang-tools-extra/clangd/unittests/RenameTests.cpp
45

NIT: Keep periods at the end

363

Maybe test this separately? It's only used in one test.
Having this added for all tests cases is somewhat confusing.

hokein updated this revision to Diff 229822.Nov 18 2019, 5:49 AM
hokein marked 4 inline comments as done.

Address comments.

clang-tools-extra/clangd/unittests/RenameTests.cpp
363

moved to a separate test.

This revision is now accepted and ready to land.Nov 18 2019, 6:19 AM
This revision was automatically updated to reflect the committed changes.
thakis added a subscriber: thakis.Nov 18 2019, 3:47 PM

The test fails on Windows:

http://45.33.8.238/win/2544/step_7.txt

Failing Tests (2):
    Clangd Unit Tests :: ./ClangdTests.exe/RenameTest.Renameable
    Clangd Unit Tests :: ./ClangdTests.exe/RenameTest.WithinFileRename

I'm guessing this needs the -fno-delayed-template-parsing treatment (look for that in other files in clangd/unittests)