Add text-based fastpaths into LS token matching (#41924)

* Add text-based fastpaths into LS token matching

* Update src/services/utilities.ts

Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>

* Update src/services/utilities.ts

Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>

* Update src/services/utilities.ts

Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>

* Limit search a bit

* Secretly, this was allowed to be `undefined` and was in fact used as such

Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
Wesley Wigham
2020-12-15 15:40:48 -08:00
committed by GitHub
parent 73df9eaec7
commit b869c9cffa

View File

@@ -1391,7 +1391,23 @@ namespace ts {
return isInsideJsxElementTraversal(getTokenAtPosition(sourceFile, position));
}
export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind, sourceFile: SourceFile) {
export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind.OpenBraceToken | SyntaxKind.OpenParenToken | SyntaxKind.OpenBracketToken, sourceFile: SourceFile) {
const closeTokenText = tokenToString(token.kind)!;
const matchingTokenText = tokenToString(matchingTokenKind)!;
const tokenFullStart = token.getFullStart();
// Text-scan based fast path - can be bamboozled by comments and other trivia, but often provides
// a good, fast approximation without too much extra work in the cases where it fails.
const bestGuessIndex = sourceFile.text.lastIndexOf(matchingTokenText, tokenFullStart);
if (bestGuessIndex === -1) {
return undefined; // if the token text doesn't appear in the file, there can't be a match - super fast bail
}
// we can only use the textual result directly if we didn't have to count any close tokens within the range
if (sourceFile.text.lastIndexOf(closeTokenText, tokenFullStart - 1) < bestGuessIndex) {
const nodeAtGuess = findPrecedingToken(bestGuessIndex + 1, sourceFile);
if (nodeAtGuess && nodeAtGuess.kind === matchingTokenKind) {
return nodeAtGuess;
}
}
const tokenKind = token.kind;
let remainingMatchingTokens = 0;
while (true) {
@@ -1447,7 +1463,14 @@ namespace ts {
}
// Get info for an expression like `f <` that may be the start of type arguments.
export function getPossibleTypeArgumentsInfo(tokenIn: Node, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
// This is a rare case, but one that saves on a _lot_ of work if true - if the source file has _no_ `<` character,
// then there obviously can't be any type arguments - no expensive brace-matching backwards scanning required
if (sourceFile.text.lastIndexOf("<", tokenIn ? tokenIn.pos : sourceFile.text.length) === -1) {
return undefined;
}
let token: Node | undefined = tokenIn;
// This function determines if the node could be type argument position
// Since during editing, when type argument list is not complete,