diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 62443ac2049b6..cfc9c629837d4 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -2322,8 +2322,13 @@ export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile, endN /** @internal */ export function createTextSpanFromStringLiteralLikeContent(node: StringLiteralLike) { - if (node.isUnterminated) return undefined; - return createTextSpanFromBounds(node.getStart() + 1, node.getEnd() - 1); + let replacementEnd = node.getEnd() - 1; + if (node.isUnterminated) { + // we return no replacement range only if unterminated string is empty + if (node.getStart() === replacementEnd) return undefined; + replacementEnd = node.getEnd(); + } + return createTextSpanFromBounds(node.getStart() + 1, replacementEnd); } /** @internal */ diff --git a/tests/cases/fourslash/stringCompletionsUnterminated.ts b/tests/cases/fourslash/stringCompletionsUnterminated.ts new file mode 100644 index 0000000000000..4d5736d4795a1 --- /dev/null +++ b/tests/cases/fourslash/stringCompletionsUnterminated.ts @@ -0,0 +1,73 @@ +/// + +// @Filename: file0.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo.b/*0*/|] + +// @Filename: file1.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo.b /*1*/|] + +// @Filename: file2.ts +//// const a = { "foo.bar": 1 } +//// a[ "[|foo.b/*2*/|] + +// @Filename: file3.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo.b/*3*/|]" + +// @Filename: file4.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo./*4*/b|] + +// @Filename: file5.ts +//// const a = { "foo.bar": 1 } +//// a['[|foo./*5*/b|] + +// @Filename: file6.ts +//// const a = { "foo.bar": 1 } +//// a[`[|foo./*6*/b|] + +// @Filename: file7.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo./*7*/|] + +// @Filename: file8.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo/*8*/|] + +// @Filename: file9.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo./*9*/|]" + +// @Filename: file10.ts +//// const a = { "foo.bar": 1 } +//// a["[|foo/*10*/|]" + +// @Filename: empty1.ts +//// const a = { "foo.bar": 1 } +//// a[`/*11*/ + +// @Filename: empty2.ts +//// const a = { "foo.bar": 1 } +//// a["/*12*/ + +// @Filename: empty3.ts +//// const a = { "foo.bar": 1 } +//// a['/*13*/ + +// tests 11-13 should return no replacementSpan +const markers = test.markers(); +const ranges = test.ranges(); + +for (let i = 0; i < markers.length; i++) { + verify.completions({ + marker: markers[i], + includes: [{ + "name": "foo.bar", + "kind": "property", + "kindModifiers": "", + "replacementSpan": ranges[i], + }], + }); +}