-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't go past import in cross-project renaming #48758
Conversation
src/services/types.ts
Outdated
@@ -474,7 +474,7 @@ namespace ts { | |||
|
|||
/*@internal*/ | |||
// eslint-disable-next-line @typescript-eslint/unified-signatures | |||
getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly: boolean): readonly DefinitionInfo[] | undefined; | |||
getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly: boolean, skipAlias: boolean): readonly DefinitionInfo[] | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is the best way to add this new parameter, open to feedback on this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit but I think I would make it stopAtAlias
so you can just make it optional instead of defaulting to true
. But wait until the end of the PR review to do this, because the implication of my other feedback may be that not all aliases should be stopped at / skipped.
@@ -430,7 +433,7 @@ namespace ts.server { | |||
|
|||
// After initial references are collected, go over every other project and see if it has a reference for the symbol definition. | |||
if (initialLocation) { | |||
const defaultDefinition = getDefinitionLocation(defaultProject, initialLocation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's where the logic changed: if we're renaming, we don't skip past aliases when getting the definition, because we want to rename the alias itself (I think), and not the original thing (e.g. we don't want to rename the original variable, just its import)
src/services/goToDefinition.ts
Outdated
let fallbackNode = node; | ||
|
||
if (searchOtherFilesOnly && failedAliasResolution) { | ||
// We couldn't resolve the specific import, try on the module specifier. | ||
const importDeclaration = forEach([node, ...symbol?.declarations || emptyArray], n => findAncestor(n, isAnyImportOrBareOrAccessedRequire)); | ||
const moduleSpecifier = importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration); | ||
if (moduleSpecifier) { | ||
({ symbol, failedAliasResolution } = getSymbol(moduleSpecifier, typeChecker)); | ||
({ symbol, failedAliasResolution } = getSymbol(moduleSpecifier, typeChecker, skipAlias)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewbranch I'd like you to take a look at this case and the interaction between searchOtherFilesOnly
and the new skipAlias
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
skipAlias
should always be true
when serachOtherFilesOnly
is true
.
I wish I'd known you were working on the rename logic in session.ts because you probably want to build on top of #48619. It almost certainly doesn't address this problem, and may even make it worse, but it should be much easier to reason about and fix. |
Does that mean I should wait for #48619 to be merged and reimplement this on top of that? |
I was tentatively planning to hold #48619 until 4.8 since it's a bit risky, but I don't think that's essential. If your change needs to get in for 4.7, I don't mind merging it into my branch later - I just got the impression that there were a lot of open questions and I thought I'd jump in and suggest that any rewrite happen on top for #48619. Thoughts on sequencing, @andrewbranch? |
I suspect this can go in for 4.7, and the I’m guessing the merge conflict will likely just be some of the calls you passed the new parameter to in session.ts get deleted altogether. I’ll plan to take a close look at this tomorrow. I want to investigate why |
Ah ok, what I had missed was that the rename location was actually on the namespace import name itself. Go To Definition has the behavior where it will stop at a NamespaceImport but only if you don’t start on the NamespaceImport (that way you can do one jump from a reference to the import, and then another jump to the module it refers to). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is pretty much good—I was confused by the baseline format not showing the prefixText
/suffixText
. It would be great if we could make renameNamedImport.baseline
show up as
/*====== /src/index.ts ======*/
import { [|someExportedVariable as RENAME|] } from '../lib/index';
RENAME;
I also still think I would recommend naming the new go-to-def parameter stopAtAlias
or just keep it as isForRename
since it’s internal.
* Clean up FAR and RenameLocations This change had two goals: 1. Make the code easier to understand, primarily by simplifying the callback structure and minimizing side-effects 2. Improve performance by reducing repeated work, both FAR searches of individual projects and default tsconfig searches This implementation attempts to preserve the merging order found in the original code (someone less relevant in the present state of using syntactic isDefinition). * Stop enforcing search and aggregation order ...in preparation for implementing isDefinition explicitly. Also restore convention of referring to `DocumentPosition`s as "locations". * Introduce LanguageService.updateIsDefinitionOfReferencedSymbols ...to allow use of the checker when computing isDefinition across projects. * Update baselines * Tidy diff * De-dup simplified results * Baseline cross-project isDefinition results * Move de-duping upstream to fix Full output * Add server baseline test to confirm searches are not repeated * Manually merge #48758 * Update baseline for newer fix to #48963
Fixes #45659.
The bug seemed to be caused by the cross-project part of "find all references": in
session.ts
, we try to find references in each project in the solution, other than the original project where the request was made. To accomplish this, we callgetDefinitionAtLocation
, and then try to find references to the resulting definition in other projects.This meant that, in a situation like:
when we tried to rename
lib
inimport * as lib from ...
, we found the original definition (which points to the module/filelib/lib.ts
), and then tried to rename that.The main thing about the bug, in my perspective, is that we should not try to rename the original definition and references to it, and should instead just rename the alias, in this case the namespace import itself (
lib
).This PR accomplishes that by having
getDefinitionAtLocation
stop at aliases, instead of skipping them. The idea is that now we will find cross-project references to the alias that is being renamed, not to the original thing that was aliased.P.S.: the other thing that seemed weird to me is that, when we try to get the definition of the
lib
namespace inimport * as lib ...
, we get a reference to thelib/lib.ts
file, at position 0 (references are represented as a file + position). This PR doesn't fix that, so when invoking find all references onimport * as |lib| ...
, we still get one entry pointing to thelib
file at position 0. But I thought that was a minor problem and something to be fixed in a different PR, if that's the case.