diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 74dffc3b00b11..05d85fb708705 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -399,23 +399,40 @@ namespace ts.FindAllReferences { function getPrefixAndSuffixText(entry: Entry, originalNode: Node, checker: TypeChecker): PrefixAndSuffix { if (entry.kind !== EntryKind.Span && isIdentifier(originalNode)) { const { node, kind } = entry; + const parent = node.parent; const name = originalNode.text; - const isShorthandAssignment = isShorthandPropertyAssignment(node.parent); - if (isShorthandAssignment || isObjectBindingElementWithoutPropertyName(node.parent) && node.parent.name === node) { + const isShorthandAssignment = isShorthandPropertyAssignment(parent); + if (isShorthandAssignment || isObjectBindingElementWithoutPropertyName(parent) && parent.name === node) { const prefixColon: PrefixAndSuffix = { prefixText: name + ": " }; const suffixColon: PrefixAndSuffix = { suffixText: ": " + name }; - return kind === EntryKind.SearchedLocalFoundProperty ? prefixColon - : kind === EntryKind.SearchedPropertyFoundLocal ? suffixColon - // In `const o = { x }; o.x`, symbolAtLocation at `x` in `{ x }` is the property symbol. - // For a binding element `const { x } = o;`, symbolAtLocation at `x` is the property symbol. - : isShorthandAssignment ? suffixColon : prefixColon; + if (kind === EntryKind.SearchedLocalFoundProperty) { + return prefixColon; + } + if (kind === EntryKind.SearchedPropertyFoundLocal) { + return suffixColon; + } + + // In `const o = { x }; o.x`, symbolAtLocation at `x` in `{ x }` is the property symbol. + // For a binding element `const { x } = o;`, symbolAtLocation at `x` is the property symbol. + if (isShorthandAssignment) { + const grandParent = parent.parent; + if (isObjectLiteralExpression(grandParent) && + isBinaryExpression(grandParent.parent) && + isModuleExportsAccessExpression(grandParent.parent.left)) { + return prefixColon; + } + return suffixColon; + } + else { + return prefixColon; + } } - else if (isImportSpecifier(entry.node.parent) && !entry.node.parent.propertyName) { + else if (isImportSpecifier(parent) && !parent.propertyName) { // If the original symbol was using this alias, just rename the alias. const originalSymbol = isExportSpecifier(originalNode.parent) ? checker.getExportSpecifierLocalTargetSymbol(originalNode.parent) : checker.getSymbolAtLocation(originalNode); - return contains(originalSymbol!.declarations, entry.node.parent) ? { prefixText: name + " as " } : emptyOptions; + return contains(originalSymbol!.declarations, parent) ? { prefixText: name + " as " } : emptyOptions; } - else if (isExportSpecifier(entry.node.parent) && !entry.node.parent.propertyName) { + else if (isExportSpecifier(parent) && !parent.propertyName) { // If the symbol for the node is same as declared node symbol use prefix text return originalNode === entry.node || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) ? { prefixText: name + " as " } : diff --git a/tests/cases/fourslash/renameModuleExportsProperties1.ts b/tests/cases/fourslash/renameModuleExportsProperties1.ts new file mode 100644 index 0000000000000..29d74bde6cbfd --- /dev/null +++ b/tests/cases/fourslash/renameModuleExportsProperties1.ts @@ -0,0 +1,8 @@ +/// + +////[|class [|{| "contextRangeIndex": 0 |}A|] {}|] +////module.exports = { [|A|] } + +const [r0Def, r0, r1] = test.ranges(); +verify.renameLocations(r0, { ranges: [r0, { range: r1, prefixText: "A: " }], providePrefixAndSuffixTextForRename: true }); +verify.renameLocations(r1, { ranges: [r0, { range: r1, prefixText: "A: " }], providePrefixAndSuffixTextForRename: true }); diff --git a/tests/cases/fourslash/renameModuleExportsProperties2.ts b/tests/cases/fourslash/renameModuleExportsProperties2.ts new file mode 100644 index 0000000000000..fa2c31029e607 --- /dev/null +++ b/tests/cases/fourslash/renameModuleExportsProperties2.ts @@ -0,0 +1,8 @@ +/// + +////[|class [|{| "contextRangeIndex": 0 |}A|] {}|] +////module.exports = { B: [|A|] } + +const [r0Def, r0, r1] = test.ranges(); +verify.renameLocations(r0, [r0, r1]); +verify.renameLocations(r1, [r0, r1]); diff --git a/tests/cases/fourslash/renameModuleExportsProperties3.ts b/tests/cases/fourslash/renameModuleExportsProperties3.ts new file mode 100644 index 0000000000000..2f163c55f0f10 --- /dev/null +++ b/tests/cases/fourslash/renameModuleExportsProperties3.ts @@ -0,0 +1,10 @@ +/// + +// @allowJs: true +// @Filename: a.js +////[|class [|{| "contextRangeIndex": 0 |}A|] {}|] +////module.exports = { [|A|] } + +const [r0Def, r0, r1] = test.ranges(); +verify.renameLocations(r0, { ranges: [r0, { range: r1, prefixText: "A: " }], providePrefixAndSuffixTextForRename: true }); +verify.renameLocations(r1, { ranges: [r0, { range: r1, prefixText: "A: " }], providePrefixAndSuffixTextForRename: true });