Skip to content

Commit 3163fe7

Browse files
authored
Fixed crash when cross-file reusing nodes for class member snippet completions (#58216)
1 parent c3efeb9 commit 3163fe7

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

src/compiler/emitter.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,7 +2088,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
20882088
// SyntaxKind.TemplateMiddle
20892089
// SyntaxKind.TemplateTail
20902090
function emitLiteral(node: LiteralLikeNode, jsxAttributeEscape: boolean) {
2091-
const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape, jsxAttributeEscape);
2091+
const text = getLiteralTextOfNode(node, /*sourceFile*/ undefined, printerOptions.neverAsciiEscape, jsxAttributeEscape);
20922092
if (
20932093
(printerOptions.sourceMap || printerOptions.inlineSourceMap)
20942094
&& (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))
@@ -2641,7 +2641,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
26412641
expression = skipPartiallyEmittedExpressions(expression);
26422642
if (isNumericLiteral(expression)) {
26432643
// check if numeric literal is a decimal literal that was originally written with a dot
2644-
const text = getLiteralTextOfNode(expression as LiteralExpression, /*neverAsciiEscape*/ true, /*jsxAttributeEscape*/ false);
2644+
const text = getLiteralTextOfNode(expression as LiteralExpression, /*sourceFile*/ undefined, /*neverAsciiEscape*/ true, /*jsxAttributeEscape*/ false);
26452645
// If the number will be printed verbatim and it doesn't already contain a dot or an exponent indicator, add one
26462646
// if the expression doesn't have any comments that will be emitted.
26472647
return !(expression.numericLiteralFlags & TokenFlags.WithSpecifier)
@@ -5169,7 +5169,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
51695169
return getSourceTextOfNodeFromSourceFile(sourceFile, node, includeTrivia);
51705170
}
51715171

5172-
function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined, jsxAttributeEscape: boolean): string {
5172+
function getLiteralTextOfNode(node: LiteralLikeNode, sourceFile = currentSourceFile, neverAsciiEscape: boolean | undefined, jsxAttributeEscape: boolean): string {
51735173
if (node.kind === SyntaxKind.StringLiteral && (node as StringLiteral).textSourceNode) {
51745174
const textSourceNode = (node as StringLiteral).textSourceNode!;
51755175
if (isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) || isNumericLiteral(textSourceNode) || isJsxNamespacedName(textSourceNode)) {
@@ -5179,7 +5179,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
51795179
`"${escapeNonAsciiString(text)}"`;
51805180
}
51815181
else {
5182-
return getLiteralTextOfNode(textSourceNode, neverAsciiEscape, jsxAttributeEscape);
5182+
return getLiteralTextOfNode(textSourceNode, getSourceFileOfNode(textSourceNode), neverAsciiEscape, jsxAttributeEscape);
51835183
}
51845184
}
51855185

@@ -5188,7 +5188,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
51885188
| (printerOptions.terminateUnterminatedLiterals ? GetLiteralTextFlags.TerminateUnterminatedLiterals : 0)
51895189
| (printerOptions.target && printerOptions.target >= ScriptTarget.ES2021 ? GetLiteralTextFlags.AllowNumericSeparator : 0);
51905190

5191-
return getLiteralText(node, currentSourceFile, flags);
5191+
return getLiteralText(node, sourceFile, flags);
51925192
}
51935193

51945194
/**
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @strict: true
4+
5+
// @filename: KlassConstructor.ts
6+
7+
//// type GenericConstructor<T> = new (...args: any[]) => T;
8+
//// export type KlassConstructor<Cls extends GenericConstructor<any>> =
9+
//// GenericConstructor<InstanceType<Cls>> & { [k in keyof Cls]: Cls[k] };
10+
11+
// @filename: ElementNode.ts
12+
//// import { KlassConstructor } from "./KlassConstructor";
13+
////
14+
//// export type NodeKey = string;
15+
////
16+
//// export class ElementNode {
17+
//// ["constructor"]!: KlassConstructor<typeof ElementNode>;
18+
//// }
19+
20+
// @filename: CollapsibleContainerNode.ts
21+
//// import { ElementNode, NodeKey } from "./ElementNode";
22+
////
23+
//// export class CollapsibleContainerNode extends ElementNode {
24+
//// __open: boolean;
25+
////
26+
//// /*1*/
27+
//// }
28+
29+
format.setFormatOptions({
30+
insertSpaceAfterConstructor: false,
31+
});
32+
33+
verify.completions({
34+
marker: "1",
35+
preferences: {
36+
includeCompletionsWithClassMemberSnippets: true,
37+
includeCompletionsWithInsertText: true,
38+
},
39+
includes: [{
40+
name: `["constructor"]`,
41+
insertText: `["constructor"]: KlassConstructor<typeof ElementNode>;`,
42+
filterText: `["constructor"]`,
43+
hasAction: true,
44+
source: 'ClassMemberSnippet/'
45+
}],
46+
isNewIdentifierLocation: true,
47+
});

0 commit comments

Comments
 (0)