Skip to content

Commit b869c9c

Browse files
Add text-based fastpaths into LS token matching (microsoft#41924)
* Add text-based fastpaths into LS token matching * Update src/services/utilities.ts Co-authored-by: Daniel Rosenwasser <[email protected]> * Update src/services/utilities.ts Co-authored-by: Daniel Rosenwasser <[email protected]> * Update src/services/utilities.ts Co-authored-by: Daniel Rosenwasser <[email protected]> * Limit search a bit * Secretly, this was allowed to be `undefined` and was in fact used as such Co-authored-by: Daniel Rosenwasser <[email protected]>
1 parent 73df9ea commit b869c9c

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

src/services/utilities.ts

+25-2
Original file line numberDiff line numberDiff line change
@@ -1391,7 +1391,23 @@ namespace ts {
13911391
return isInsideJsxElementTraversal(getTokenAtPosition(sourceFile, position));
13921392
}
13931393

1394-
export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind, sourceFile: SourceFile) {
1394+
export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind.OpenBraceToken | SyntaxKind.OpenParenToken | SyntaxKind.OpenBracketToken, sourceFile: SourceFile) {
1395+
const closeTokenText = tokenToString(token.kind)!;
1396+
const matchingTokenText = tokenToString(matchingTokenKind)!;
1397+
const tokenFullStart = token.getFullStart();
1398+
// Text-scan based fast path - can be bamboozled by comments and other trivia, but often provides
1399+
// a good, fast approximation without too much extra work in the cases where it fails.
1400+
const bestGuessIndex = sourceFile.text.lastIndexOf(matchingTokenText, tokenFullStart);
1401+
if (bestGuessIndex === -1) {
1402+
return undefined; // if the token text doesn't appear in the file, there can't be a match - super fast bail
1403+
}
1404+
// we can only use the textual result directly if we didn't have to count any close tokens within the range
1405+
if (sourceFile.text.lastIndexOf(closeTokenText, tokenFullStart - 1) < bestGuessIndex) {
1406+
const nodeAtGuess = findPrecedingToken(bestGuessIndex + 1, sourceFile);
1407+
if (nodeAtGuess && nodeAtGuess.kind === matchingTokenKind) {
1408+
return nodeAtGuess;
1409+
}
1410+
}
13951411
const tokenKind = token.kind;
13961412
let remainingMatchingTokens = 0;
13971413
while (true) {
@@ -1447,7 +1463,14 @@ namespace ts {
14471463
}
14481464

14491465
// Get info for an expression like `f <` that may be the start of type arguments.
1450-
export function getPossibleTypeArgumentsInfo(tokenIn: Node, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
1466+
export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
1467+
// This is a rare case, but one that saves on a _lot_ of work if true - if the source file has _no_ `<` character,
1468+
// then there obviously can't be any type arguments - no expensive brace-matching backwards scanning required
1469+
1470+
if (sourceFile.text.lastIndexOf("<", tokenIn ? tokenIn.pos : sourceFile.text.length) === -1) {
1471+
return undefined;
1472+
}
1473+
14511474
let token: Node | undefined = tokenIn;
14521475
// This function determines if the node could be type argument position
14531476
// Since during editing, when type argument list is not complete,

0 commit comments

Comments
 (0)