From 67c0d674c7b693908125deefe54dba3be575acaf Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Fri, 2 Oct 2026 16:08:56 -0400 Subject: [PATCH 1/2] Avoid building the same Location twice Hoist repeated util.getLocation() calls on the same token/node into a local in inlay hints, semantic tokens, the doc parser, and BrsFile's function scope declarations. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../inlayHints/InlayHintProcessor.ts | 6 ++++-- .../BrsFileSemanticTokensProcessor.ts | 5 +++-- src/files/BrsFile.ts | 20 +++++++++++-------- src/parser/BrightScriptDocParser.ts | 14 +++++++------ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/bscPlugin/inlayHints/InlayHintProcessor.ts b/src/bscPlugin/inlayHints/InlayHintProcessor.ts index fcb95c8cf..a3a26500d 100644 --- a/src/bscPlugin/inlayHints/InlayHintProcessor.ts +++ b/src/bscPlugin/inlayHints/InlayHintProcessor.ts @@ -37,13 +37,15 @@ export class InlayHintProcessor { file.ast.walk(createVisitor({ CallExpression: (call) => { - if (!util.getLocation(call)?.range || !util.rangesIntersectOrTouch(util.getLocation(call).range, range)) { + const callRange = util.getLocation(call)?.range; + if (!callRange || !util.rangesIntersectOrTouch(callRange, range)) { return; } this.emitParameterNameHints(file, call); }, CallfuncExpression: (call) => { - if (!util.getLocation(call)?.range || !util.rangesIntersectOrTouch(util.getLocation(call).range, range)) { + const callRange = util.getLocation(call)?.range; + if (!callRange || !util.rangesIntersectOrTouch(callRange, range)) { return; } this.emitParameterNameHintsForCallfunc(file, call); diff --git a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts index 761e18a90..cb42d4aa3 100644 --- a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts +++ b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts @@ -98,8 +98,9 @@ export class BrsFileSemanticTokensProcessor { private addToken(locatable: Locatable, type: SemanticTokenTypes, modifiers: SemanticTokenModifiers[] = []) { //only keep a single token per range. Last-in wins - this.result.set(util.rangeToString(util.getLocation(locatable).range), { - range: util.getLocation(locatable).range, + const range = util.getLocation(locatable).range; + this.result.set(util.rangeToString(range), { + range: range, tokenType: type, tokenModifiers: modifiers }); diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 4528826b4..7c954e541 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -597,9 +597,10 @@ export class BrsFile implements BscFile { //add every parameter for (let param of func.parameters) { + const nameRange = util.getLocation(param.tokens.name)?.range; scope.variableDeclarations.push({ - nameRange: util.getLocation(param.tokens.name)?.range, - lineIndex: util.getLocation(param.tokens.name)?.range?.start.line, + nameRange: nameRange, + lineIndex: nameRange?.start.line, name: param.tokens.name.text, getType: () => { return param.getType({ flags: SymbolTypeFlag.typetime }); @@ -610,18 +611,20 @@ export class BrsFile implements BscFile { //add all of ForEachStatement loop varibales func.body?.walk(createVisitor({ ForEachStatement: (stmt) => { + const nameRange = util.getLocation(stmt.tokens.item)?.range; scope.variableDeclarations.push({ - nameRange: util.getLocation(stmt.tokens.item)?.range, - lineIndex: util.getLocation(stmt.tokens.item)?.range?.start.line, + nameRange: nameRange, + lineIndex: nameRange?.start.line, name: stmt.tokens.item.text, getType: () => stmt.getType({ flags: SymbolTypeFlag.runtime }) }); }, LabelStatement: (stmt) => { const { name: identifier } = stmt.tokens; + const nameRange = util.getLocation(identifier)?.range; scope.labelStatements.push({ - nameRange: util.getLocation(identifier)?.range, - lineIndex: util.getLocation(identifier)?.range?.start.line, + nameRange: nameRange, + lineIndex: nameRange?.start.line, name: identifier.text }); } @@ -648,9 +651,10 @@ export class BrsFile implements BscFile { //skip variable declarations that are outside of any scope if (scope) { const variableName = statement.tokens.name; + const nameRange = util.getLocation(variableName)?.range; scope.variableDeclarations.push({ - nameRange: util.getLocation(variableName)?.range, - lineIndex: util.getLocation(variableName)?.range?.start.line, + nameRange: nameRange, + lineIndex: nameRange?.start.line, name: variableName.text, getType: () => { return statement.getType({ flags: SymbolTypeFlag.runtime }); diff --git a/src/parser/BrightScriptDocParser.ts b/src/parser/BrightScriptDocParser.ts index 49aefe062..f323ce648 100644 --- a/src/parser/BrightScriptDocParser.ts +++ b/src/parser/BrightScriptDocParser.ts @@ -99,7 +99,8 @@ export class BrightScriptDocParser { } public getTypeLocationFromToken(token: Token): Location { - if (!util.getLocation(token)) { + const location = util.getLocation(token); + if (!location) { return undefined; } const startCurly = token.text.indexOf('{'); @@ -107,16 +108,17 @@ export class BrightScriptDocParser { if (startCurly === -1 || endCurly === -1 || endCurly <= startCurly) { return undefined; } + const start = location.range.start; return { - uri: util.getLocation(token).uri, + uri: location.uri, range: { start: { - line: util.getLocation(token).range.start.line, - character: util.getLocation(token).range.start.character + startCurly + 1 + line: start.line, + character: start.character + startCurly + 1 }, end: { - line: util.getLocation(token).range.start.line, - character: util.getLocation(token).range.start.character + endCurly + line: start.line, + character: start.character + endCurly } } }; From ad41f8f152198cbd82d71f00f29b4c2d1ff85184 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Thu, 15 Oct 2026 16:14:35 -0400 Subject: [PATCH 2/2] Build the namespace statement range once per lookup Co-Authored-By: Claude Opus 5.5 --- src/files/BrsFile.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 8538e70a7..29aa54deb 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -750,9 +750,10 @@ export class BrsFile implements BscFile { return this.cache.getOrAdd(`namespaceStatementForPosition-${position.line}:${position.character}`, () => { let mostSpecificNamespace: NamespaceStatement; for (const statement of this._cachedLookups.namespaceStatements) { - if (util.rangeContains(util.getLocation(statement)?.range, position)) { + const statementRange = util.getLocation(statement)?.range; + if (util.rangeContains(statementRange, position)) { if (mostSpecificNamespace) { - if (util.isRangeInRange(util.getLocation(statement)?.range, util.getLocation(mostSpecificNamespace)?.range)) { + if (util.isRangeInRange(statementRange, util.getLocation(mostSpecificNamespace)?.range)) { mostSpecificNamespace = statement; } } else {