Skip to content

Commit 9380b9f

Browse files
authored
Merge pull request #31568 from andrewbranch/bug/31347
Fix containsPrecedingToken for tokens whose preceding token is a missing node
2 parents 7ff97d1 + 7359ff8 commit 9380b9f

File tree

4 files changed

+34
-14
lines changed

4 files changed

+34
-14
lines changed

src/harness/fourslash.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ Actual: ${stringify(fullActual)}`);
12081208
}
12091209
}
12101210

1211-
public verifySignatureHelpPresence(expectPresent: boolean, triggerReason: ts.SignatureHelpTriggerReason | undefined, markers: ReadonlyArray<string>) {
1211+
public verifySignatureHelpPresence(expectPresent: boolean, triggerReason: ts.SignatureHelpTriggerReason | undefined, markers: ReadonlyArray<string | Marker>) {
12121212
if (markers.length) {
12131213
for (const marker of markers) {
12141214
this.goToMarker(marker);
@@ -3768,15 +3768,15 @@ namespace FourSlashInterface {
37683768
assert(ranges.length !== 0, "Array of ranges is expected to be non-empty");
37693769
}
37703770

3771-
public noSignatureHelp(...markers: string[]): void {
3771+
public noSignatureHelp(...markers: (string | FourSlash.Marker)[]): void {
37723772
this.state.verifySignatureHelpPresence(/*expectPresent*/ false, /*triggerReason*/ undefined, markers);
37733773
}
37743774

3775-
public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: string[]): void {
3775+
public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void {
37763776
this.state.verifySignatureHelpPresence(/*expectPresent*/ false, reason, markers);
37773777
}
37783778

3779-
public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: string[]): void {
3779+
public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void {
37803780
this.state.verifySignatureHelpPresence(/*expectPresent*/ true, reason, markers);
37813781
}
37823782

@@ -5124,7 +5124,7 @@ namespace FourSlashInterface {
51245124
}
51255125

51265126
export interface VerifySignatureHelpOptions {
5127-
readonly marker?: ArrayOrSingle<string>;
5127+
readonly marker?: ArrayOrSingle<string | FourSlash.Marker>;
51285128
/** @default 1 */
51295129
readonly overloadsCount?: number;
51305130
/** @default undefined */

src/services/signatureHelp.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,21 @@ namespace ts.SignatureHelp {
133133
}
134134

135135
function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) {
136-
const precedingToken = Debug.assertDefined(
137-
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
138-
);
139-
140-
return rangeContainsRange(container, precedingToken);
136+
const pos = startingToken.getFullStart();
137+
// There’s a possibility that `startingToken.parent` contains only `startingToken` and
138+
// missing nodes, none of which are valid to be returned by `findPrecedingToken`. In that
139+
// case, the preceding token we want is actually higher up the tree—almost definitely the
140+
// next parent, but theoretically the situation with missing nodes might be happening on
141+
// multiple nested levels.
142+
let currentParent: Node | undefined = startingToken.parent;
143+
while (currentParent) {
144+
const precedingToken = findPrecedingToken(pos, sourceFile, currentParent, /*excludeJsdoc*/ true);
145+
if (precedingToken) {
146+
return rangeContainsRange(container, precedingToken);
147+
}
148+
currentParent = currentParent.parent;
149+
}
150+
return Debug.fail("Could not find preceding token");
141151
}
142152

143153
export interface ArgumentInfoForCompletions {

tests/cases/fourslash/fourslash.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,9 @@ declare namespace FourSlashInterface {
232232
rangesWithSameTextAreRenameLocations(): void;
233233
rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] });
234234
findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]): void;
235-
noSignatureHelp(...markers: string[]): void;
236-
noSignatureHelpForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: string[]): void
237-
signatureHelpPresentForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: string[]): void
235+
noSignatureHelp(...markers: (string | Marker)[]): void;
236+
noSignatureHelpForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: (string | Marker)[]): void
237+
signatureHelpPresentForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: (string | Marker)[]): void
238238
signatureHelp(...options: VerifySignatureHelpOptions[], ): void;
239239
// Checks that there are no compile errors.
240240
noErrors(): void;
@@ -538,7 +538,7 @@ declare namespace FourSlashInterface {
538538
}
539539

540540
interface VerifySignatureHelpOptions {
541-
marker?: ArrayOrSingle<string>;
541+
marker?: ArrayOrSingle<string | Marker>;
542542
/** @default 1 */
543543
overloadsCount?: number;
544544
docComment?: string;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
//@Filename: test.tsx
4+
//@jsx: react
5+
////declare var React: any;
6+
////const z = <div>{[].map(x => </**/
7+
8+
// This test exists because it used to crash: #31347
9+
goTo.marker();
10+
verify.noSignatureHelpForTriggerReason({ kind: "characterTyped", triggerCharacter: "<" });

0 commit comments

Comments
 (0)