Skip to content

Infinite loop getting completions when finding preceding matching token in JSDoc #53476

Closed
@dsherret

Description

@dsherret

Bug Report

The infinite loop happens here:

while (true) {
const preceding = findPrecedingToken(token.getFullStart(), sourceFile);
if (!preceding) {
return undefined;
}
token = preceding;
if (token.kind === matchingTokenKind) {
if (remainingMatchingTokens === 0) {
return token;
}
remainingMatchingTokens--;
}
else if (token.kind === tokenKind) {
remainingMatchingTokens++;
}
}

More specifically, findPrecedingToken returns back the current token, so remainingMatchingTokens keeps getting incremented.

🔎 Search Terms

infinite loop completions jsdoc

🕗 Version & Regression Information

5.0.2 and I can reproduce it in main. It probably occurred in older versions.

⏯ Playground Link

I can't reproduce it in the playground.

💻 Code

  1. Take the following starting code:
/// <reference path="./compiler.d.ts" />

(window => {
  /** @type {DenoCore} */
  const core = window.Deno.core;
})();
  1. Type /** @ before window:
/// <reference path="./compiler.d.ts" />

(/** @window => {
  /** @type {DenoCore} */
  const core = window.Deno.core;
})();
  1. Hover over window.

🙁 Actual behavior

Hangs forever.

🙂 Expected behavior

Not hang.

Test case

import * as ts from "../../_namespaces/ts";

describe("unittests:: services:: utilities", () => {
  describe("Test findPrecedingMatchingToken,", () => {
    it("should not infinite loop finding opening brace", () => {
      const sourceFile = ts.createSourceFile("file.ts", `/// <reference path="./compiler.d.ts" />

(/** @window => {
  /** @type {Abcd123} */
  const core = window.Abcd.core;
})();`, ts.ScriptTarget.ESNext, true);
      // can't use ts.getTokenAtPosition because it returns back the wrong token
      const param = ts.forEachChildRecursively(sourceFile, node => node.kind === ts.SyntaxKind.Parameter ? node : undefined)!;
      const jsDoc = param.getChildren()[0];
      const token = jsDoc.getLastToken()!;
      const result = ts.findPrecedingMatchingToken(token, ts.SyntaxKind.OpenBraceToken, sourceFile);
      // will never happen
      console.log(result);
    });
  });
});

I was looking into this a bit, but I need to move on to other things so I'm just logging it.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptDomain: JSDocRelates to JSDoc parsing and type generationFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions