[PATCH] D69263: [clangd] Implement cross-file rename.
Ilya Biryukov via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 24 01:34:17 PDT 2019
ilya-biryukov added inline comments.
================
Comment at: clang-tools-extra/clangd/refactor/Rename.cpp:119
+llvm::Optional<ReasonToReject>
+renameableOutsideFile(const NamedDecl &RenameDecl, const SymbolIndex *Index) {
----------------
hokein wrote:
> ilya-biryukov wrote:
> > So `llvm::None` means we do not reject?
> > Probably worth documenting that.
> >
> > Maybe even add an enumerator `ReasonToReject::Accept`, indicating the symbol should be accepted and get rid of `Optional` altogether.
> >
> > Otherwise this leads to code like:
> > ```
> > auto R = renameableOutsideFile(N, I);
> > if (!R) { // negative condition.
> > return doRename(N, I); // But we're running the rename anyway... WAT?
> > }
> > ``
> yeah, returning `None` means that we accept the rename.
>
> Adding `Accept` is not aligning with the mental model, `Accept` doesn't belong to `ReasonToReject` I think. I agree the above given code is misleading, but looking at the current code in this file, it doesn't seem too bad, I think?
>
> ```
> if (auto Reject = renameableOutsideFile(*RenameDecl, RInputs.Index))
> return makeError(*Reject);
> ```
Agreed this aligns with the other functions we have in the file, so let's keep as is.
================
Comment at: clang-tools-extra/clangd/refactor/Rename.cpp:121
+renameableOutsideFile(const NamedDecl &RenameDecl, const SymbolIndex *Index) {
+ if (RenameDecl.getParentFunctionOrMethod())
+ return None; // function-local symbols
----------------
hokein wrote:
> ilya-biryukov wrote:
> > This function resembles `renamableWithinFile`.
> > We should probably share implementation and pass an extra flag. Something like `isRenamable(..., bool IsCrossFile)`.
> >
> > WDYT?
> though they look similar, the logic is quite different, for example, we query the index in within-file rename to detect a symbol is used outside of the file which is not needed for cross-file rename, and cross-file rename allows fewer symbols (as our index doesn't support them), so I don't think we can share a lot of implementation.
Can this be handled with a special flag:
```
bool renameable(NamedDecl &Decl, const SymbolIndex *Index, bool CrossFile) {
if (CrossFileRename) {
// check something special...
}
}
```
Sharing implementation in the same function makes the differences between cross-file and single-file case obvious and also ensures any things that need to be updated for both are shared.
================
Comment at: clang-tools-extra/clangd/refactor/Rename.cpp:317
+ std::string OldName = RenameDecl->getNameAsString();
+ for (const auto &FileAndOccurrences : AffectedFiles) {
+ llvm::StringRef FilePath = FileAndOccurrences.first();
----------------
hokein wrote:
> ilya-biryukov wrote:
> > I feel this code is fundamental to the trade-offs we made for rename.
> > Could we move this to a separate function and add unit-tests for it?
> >
> > You probably want to have something that handles just a single file rather than all edits in all files, to avoid mocking VFS in tests, etc.
> >
> >
> Agree, especially when we start implementing complicated stuff, e.g. range patching heuristics.
>
> Moved it out, but note that I don't plan to add more stuff in this initial patch, so the logic is pretty straightforward, just assembling rename replacement from occurrences.
>
> but note that I don't plan to add more stuff in this initial patch
Should we also check whether the replaced text matches the expected identifier and add unit-tests for this?
Or would you prefer to move all changes to this function to a separate patch?
================
Comment at: clang-tools-extra/clangd/refactor/Rename.cpp:380
+ auto MainFileRenameEdit =
+ renameWithinFile(AST, RenameDecl, RInputs.NewName);
+ if (!MainFileRenameEdit)
----------------
hokein wrote:
> ilya-biryukov wrote:
> > Can we rely on the fact that dynamic index should not be stale for the current file instead?
> > Or don't we have this invariant?
> >
> > We end up having two implementations now: index-based and AST-based. It'd be nice to have just one.
> > If that's not possible in the first revision, could you explain why?
> >
> > Note that moving the current-file rename to index-based implementation is independent of doing cross-file renames. Maybe we should start with it?
> I think we can't get rid of the AST-based rename -- mainly for renaming local symbols (e.g. local variable in function body), as we don't index these symbols...
Thanks, I believe you're right... We can't unify these implementations, at least not in the short term.
So `renameOutsideFile` fails on local symbols and `renameWithinFile` should handle that, right?
Also worth noting that `renameWithinFile` is AST-based and `renameOutsideFile` is index-based.
Could we document that?
================
Comment at: clang-tools-extra/clangd/refactor/Rename.cpp:357
+ // Handle within-file rename.
+ auto Reject = renamableWithinFile(*RenameDecl->getCanonicalDecl(),
+ RInputs.MainFilePath, RInputs.Index);
----------------
Can we avoid duplicating calls to `renamebleWithinFile`? It should be possible to only call `renameOutsideFile` when `CrossFileRename` is enabled and always call `renameWithinFile`. Or is there something I'm missing?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D69263/new/
https://reviews.llvm.org/D69263
More information about the cfe-commits
mailing list