From d2737044fafa735ddd9165870df95e0637a6a855 Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Mon, 28 Mar 2022 15:23:25 -0700
Subject: [PATCH 1/2] Add failing test case
---
.../completionsOverridingMethodCrash1.ts | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 tests/cases/fourslash/completionsOverridingMethodCrash1.ts
diff --git a/tests/cases/fourslash/completionsOverridingMethodCrash1.ts b/tests/cases/fourslash/completionsOverridingMethodCrash1.ts
new file mode 100644
index 0000000000000..49233409b485a
--- /dev/null
+++ b/tests/cases/fourslash/completionsOverridingMethodCrash1.ts
@@ -0,0 +1,28 @@
+///
+
+// @newline: LF
+// @Filename: a.ts
+////declare class Component {
+//// setState(stateHandler: ((oldState: T, newState: T) => void)): void;
+////}
+////
+////class SubComponent extends Component<{}> {
+//// /*$*/
+////}
+
+verify.completions({
+ marker: "$",
+ isNewIdentifierLocation: true,
+ preferences: {
+ includeCompletionsWithInsertText: true,
+ includeCompletionsWithSnippetText: false,
+ includeCompletionsWithClassMemberSnippets: true,
+ },
+ includes: [
+ {
+ name: "setState",
+ sortText: completion.SortText.ClassMemberSnippets,
+ insertText: "setState(stateHandler: (oldState: {}, newState: {}) => void): void {\n}",
+ }
+ ]
+});
From 944315e1753132bed70021145a3a3e2c0248fa5f Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Wed, 30 Mar 2022 13:39:24 -0700
Subject: [PATCH 2/2] Ensure that we copy empty NodeArrays during transform
---
src/compiler/checker.ts | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 1cd7e00d0dd6c..ec9a5fe31499d 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -5239,7 +5239,18 @@ namespace ts {
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
return node;
}
- return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext)), node);
+ return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext, deepCloneOrReuseNodes)), node);
+ }
+
+ function deepCloneOrReuseNodes(nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray;
+ function deepCloneOrReuseNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined;
+ function deepCloneOrReuseNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined {
+ if (nodes && nodes.length === 0) {
+ // Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements,
+ // which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding.
+ return setTextRange(factory.createNodeArray(/*nodes*/ undefined, nodes.hasTrailingComma), nodes);
+ }
+ return visitNodes(nodes, visitor, test, start, count);
}
}