-
Notifications
You must be signed in to change notification settings - Fork 12.8k
allow more cases to not block convert params to destructured object
refactor
#59140
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ import { | |
getTouchingToken, | ||
getTypeNodeIfAccessible, | ||
Identifier, | ||
isCallExpression, | ||
isCallOrNewExpression, | ||
isClassDeclaration, | ||
isConstructorDeclaration, | ||
|
@@ -239,17 +240,21 @@ function getGroupedReferences(functionDeclaration: ValidFunctionDeclaration, pro | |
continue; | ||
} | ||
const call = entryToFunctionCall(entry); | ||
if (call) { | ||
groupedReferences.functionCalls.push(call); | ||
if (call !== undefined) { | ||
if (call !== true) { | ||
groupedReferences.functionCalls.push(call); | ||
} | ||
continue; | ||
} | ||
} | ||
|
||
const contextualSymbol = getSymbolForContextualType(entry.node, checker); | ||
if (contextualSymbol && contains(contextualSymbols, contextualSymbol)) { | ||
const decl = entryToDeclaration(entry); | ||
if (decl) { | ||
groupedReferences.declarations.push(decl); | ||
if (decl !== undefined) { | ||
if (decl !== true) { | ||
groupedReferences.declarations.push(decl); | ||
} | ||
continue; | ||
} | ||
} | ||
|
@@ -271,14 +276,18 @@ function getGroupedReferences(functionDeclaration: ValidFunctionDeclaration, pro | |
continue; | ||
} | ||
const decl = entryToDeclaration(entry); | ||
if (decl) { | ||
groupedReferences.declarations.push(decl); | ||
if (decl !== undefined) { | ||
if (decl !== true) { | ||
groupedReferences.declarations.push(decl); | ||
} | ||
continue; | ||
} | ||
|
||
const call = entryToFunctionCall(entry); | ||
if (call) { | ||
groupedReferences.functionCalls.push(call); | ||
if (call !== undefined) { | ||
if (call !== true) { | ||
groupedReferences.functionCalls.push(call); | ||
} | ||
continue; | ||
} | ||
} | ||
|
@@ -290,8 +299,10 @@ function getGroupedReferences(functionDeclaration: ValidFunctionDeclaration, pro | |
} | ||
|
||
const decl = entryToDeclaration(entry); | ||
if (decl) { | ||
groupedReferences.declarations.push(decl); | ||
if (decl !== undefined) { | ||
if (decl !== true) { | ||
groupedReferences.declarations.push(decl); | ||
} | ||
continue; | ||
} | ||
|
||
|
@@ -355,47 +366,63 @@ function entryToImportOrExport(entry: FindAllReferences.NodeEntry): Node | undef | |
return undefined; | ||
} | ||
|
||
function entryToDeclaration(entry: FindAllReferences.NodeEntry): Node | undefined { | ||
function entryToDeclaration(entry: FindAllReferences.NodeEntry): Node | true | undefined { | ||
// returns a callOrNewExpression if the reference needs to be updated during the refactor | ||
// returns 'true' if the reference will not be updated by the refactor, but should not block the refactor | ||
// returns 'undefined' if the reference should block the refactor | ||
if (isDeclaration(entry.node.parent)) { | ||
return entry.node; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this also needs to be modified to return function /*a*/foo/*b*/(actual: number) {
return actual;
}
const x = foo; That's because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know what I did, but I thought I had tested that case out and it wasn't blocked! I'll add it. |
||
} | ||
else if ( | ||
findAncestor(entry.node.parent, n => { | ||
if (isDeclaration(n)) return true; | ||
if (isPropertyAccessExpression(n) || isElementAccessExpression(n)) return false; | ||
return "quit"; | ||
}) | ||
) { | ||
return true; | ||
} | ||
return undefined; | ||
} | ||
|
||
function entryToFunctionCall(entry: FindAllReferences.NodeEntry): CallExpression | NewExpression | undefined { | ||
function entryToFunctionCall(entry: FindAllReferences.NodeEntry): CallExpression | NewExpression | true | undefined { | ||
// returns a callOrNewExpression if the reference needs to be updated during the refactor | ||
// returns 'true' if the reference will not be updated by the refactor, but should not block the refactor | ||
// returns 'undefined' if the reference should block the refactor | ||
if (entry.node.parent) { | ||
const functionReference = entry.node; | ||
const parent = functionReference.parent; | ||
let callOrNewExpression: CallExpression | NewExpression | undefined; | ||
let matchReference = functionReference; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: could we assign |
||
|
||
switch (parent.kind) { | ||
// foo(...) or super(...) or new Foo(...) | ||
case SyntaxKind.CallExpression: | ||
case SyntaxKind.NewExpression: | ||
const callOrNewExpression = tryCast(parent, isCallOrNewExpression); | ||
if (callOrNewExpression && callOrNewExpression.expression === functionReference) { | ||
return callOrNewExpression; | ||
} | ||
callOrNewExpression = tryCast(parent, isCallOrNewExpression); | ||
break; | ||
// x.foo(...) | ||
case SyntaxKind.PropertyAccessExpression: | ||
const propertyAccessExpression = tryCast(parent, isPropertyAccessExpression); | ||
if (propertyAccessExpression && propertyAccessExpression.parent && propertyAccessExpression.name === functionReference) { | ||
const callOrNewExpression = tryCast(propertyAccessExpression.parent, isCallOrNewExpression); | ||
if (callOrNewExpression && callOrNewExpression.expression === propertyAccessExpression) { | ||
return callOrNewExpression; | ||
} | ||
callOrNewExpression = tryCast(propertyAccessExpression.parent, isCallOrNewExpression); | ||
matchReference = propertyAccessExpression; | ||
} | ||
break; | ||
// x["foo"](...) | ||
case SyntaxKind.ElementAccessExpression: | ||
const elementAccessExpression = tryCast(parent, isElementAccessExpression); | ||
if (elementAccessExpression && elementAccessExpression.parent && elementAccessExpression.argumentExpression === functionReference) { | ||
const callOrNewExpression = tryCast(elementAccessExpression.parent, isCallOrNewExpression); | ||
if (callOrNewExpression && callOrNewExpression.expression === elementAccessExpression) { | ||
return callOrNewExpression; | ||
} | ||
callOrNewExpression = tryCast(elementAccessExpression.parent, isCallOrNewExpression); | ||
matchReference = elementAccessExpression; | ||
} | ||
break; | ||
default: | ||
return undefined; | ||
} | ||
|
||
if (callOrNewExpression === undefined) return undefined; | ||
if (callOrNewExpression.expression === matchReference) return callOrNewExpression; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you move the comments on the |
||
if (isCallExpression(callOrNewExpression) && callOrNewExpression.arguments.some(arg => arg === matchReference)) return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to my comment above, could you add comments here saying that if this is true, we have a reference like |
||
} | ||
return undefined; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// function /*a*/foo/*b*/(actual: number) { | ||
//// return actual; | ||
//// } | ||
//// [1].map(foo); | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Convert parameters to destructured object", | ||
actionName: "Convert parameters to destructured object", | ||
actionDescription: "Convert parameters to destructured object", | ||
newContent: | ||
`function foo({ actual }: { actual: number; }) { | ||
return actual; | ||
} | ||
[1].map(foo);` | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class testClass { | ||
//// /*a*/static foo/*b*/(actual: number) { | ||
//// return actual; | ||
//// } | ||
//// } | ||
//// [1].map(testClass.foo); | ||
//// [2].map(testClass["foo"]); | ||
|
||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Convert parameters to destructured object", | ||
actionName: "Convert parameters to destructured object", | ||
actionDescription: "Convert parameters to destructured object", | ||
newContent: | ||
`class testClass { | ||
static foo({ actual }: { actual: number; }) { | ||
return actual; | ||
} | ||
} | ||
[1].map(testClass.foo); | ||
[2].map(testClass["foo"]);` | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// class testClass { | ||
//// /*a*/static foo/*b*/(actual: number) { | ||
//// return actual; | ||
//// } | ||
//// } | ||
//// const x = testClass.foo; | ||
//// [1].map(x); | ||
//// const y = testClass["foo"]; | ||
//// [2].map(y); | ||
|
||
|
||
|
||
|
||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Convert parameters to destructured object", | ||
actionName: "Convert parameters to destructured object", | ||
actionDescription: "Convert parameters to destructured object", | ||
newContent: | ||
`class testClass { | ||
static foo({ actual }: { actual: number; }) { | ||
return actual; | ||
} | ||
} | ||
const x = testClass.foo; | ||
[1].map(x); | ||
const y = testClass["foo"]; | ||
[2].map(y);` | ||
}); |
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 technically this returns a
Node
whose parent is a declaration.