From 32954da6de7bd6d31b4e8d77186fb30bd572735f Mon Sep 17 00:00:00 2001 From: Martin Leduc <31558169+DecimalTurn@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:37:48 -0500 Subject: [PATCH 1/5] test: add error logging check for worksheet assignment --- server/src/test/vbaListener.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/server/src/test/vbaListener.test.ts b/server/src/test/vbaListener.test.ts index fa92252..02b1cf8 100644 --- a/server/src/test/vbaListener.test.ts +++ b/server/src/test/vbaListener.test.ts @@ -103,4 +103,23 @@ describe('VBA Listener Integration', () => { assertNoErrorLogs(logs, 'ParamArray parse'); }); + + it('does not log errors for worksheet assignment', async () => { + const logs: LogNotification[] = []; + const vbaCode = dedent` + Attribute VB_Name = "aaaaaaaaa" + + option explicit + + Public Sub Identifier() + + dim g_vouTempSht As Worksheet + Set g_vouTempSht = g_wb.sheets("科目表") + End Sub + `; + + await parseText('file:///test/WorksheetAssignment.bas', vbaCode, logs); + + assertNoErrorLogs(logs, 'Worksheet assignment parse'); + }); }); From 4ec601060453216817b12f832d391a4f7bc53c38 Mon Sep 17 00:00:00 2001 From: Martin Leduc <31558169+DecimalTurn@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:38:19 -0500 Subject: [PATCH 2/5] fix: avoid cannot add name error --- server/src/project/parser/vbaListener.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/server/src/project/parser/vbaListener.ts b/server/src/project/parser/vbaListener.ts index d4c36c3..18c14db 100644 --- a/server/src/project/parser/vbaListener.ts +++ b/server/src/project/parser/vbaListener.ts @@ -371,8 +371,19 @@ export class VbaListener extends vbaListener { this.registerNameElement(); }; - enterUnrestrictedName = (ctx: UnrestrictedNameContext) => this.addNameElementContext(ctx, 'enterUnrestrictedName'); - enterSimpleNameExpression = (ctx: SimpleNameExpressionContext) => this.addNameElementContext(ctx, 'enterSimpleNameExpression'); + enterUnrestrictedName = (ctx: UnrestrictedNameContext) => { + if (!this.hasActiveNameElement()) { + return; + } + this.addNameElementContext(ctx, 'enterUnrestrictedName'); + }; + + enterSimpleNameExpression = (ctx: SimpleNameExpressionContext) => { + if (!this.hasActiveNameElement()) { + return; + } + this.addNameElementContext(ctx, 'enterSimpleNameExpression'); + }; private addNameElementContext(ctx: UnrestrictedNameContext | SimpleNameExpressionContext | AmbiguousIdentifierContext, source: string) { if (this.verbose) Services.logger.debug(`${source}: ${ctx.getText()}`, this.parserStateStack.length); @@ -385,6 +396,10 @@ export class VbaListener extends vbaListener { nameElement.addName(ctx); } + private hasActiveNameElement(): boolean { + return this.parserState.nameElements.length > 0; + } + /** * Creates and pushes the active name-expression container for the current * parse context. From 826bb9ec6fe740f478de99bacbdaa25215fe44a8 Mon Sep 17 00:00:00 2001 From: Martin Leduc <31558169+DecimalTurn@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:03:37 -0500 Subject: [PATCH 3/5] test: add additional scope checks in 'does not log errors for worksheet assignment' --- server/src/test/vbaListener.test.ts | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/server/src/test/vbaListener.test.ts b/server/src/test/vbaListener.test.ts index 02b1cf8..f2c4392 100644 --- a/server/src/test/vbaListener.test.ts +++ b/server/src/test/vbaListener.test.ts @@ -31,6 +31,28 @@ function assertNoErrorLogs(logs: LogNotification[], context: string): void { ); } +function findScopeItem( + root: ScopeItemCapability, + predicate: (item: ScopeItemCapability) => boolean +): ScopeItemCapability | undefined { + if (predicate(root)) { + return root; + } + + for (const map of root.maps) { + for (const items of map.values()) { + for (const item of items) { + const result = findScopeItem(item, predicate); + if (result) { + return result; + } + } + } + } + + return undefined; +} + function registerTestServices(logs: LogNotification[]): void { container.clearInstances(); @@ -120,6 +142,33 @@ describe('VBA Listener Integration', () => { await parseText('file:///test/WorksheetAssignment.bas', vbaCode, logs); + const projectScope = container.resolve('ProjectScope'); + const subroutineScope = findScopeItem(projectScope, item => + item.type === ScopeType.SUBROUTINE && item.name === 'Identifier' + ); + + assert.ok(subroutineScope, 'Expected to resolve subroutine scope for Identifier'); + + const variableScope = findScopeItem(projectScope, item => + item.type === ScopeType.VARIABLE + && item.name === 'g_vouTempSht' + && item.parent?.name === 'Identifier' + ); + + assert.ok(variableScope, 'Expected to resolve variable scope for g_vouTempSht'); + assert.strictEqual(variableScope?.name, 'g_vouTempSht'); + assert.strictEqual(variableScope?.classTypeName, 'Worksheet'); + + const variableReference = findScopeItem(projectScope, item => + item.type === ScopeType.REFERENCE + && item.name === 'g_vouTempSht' + && item.parent?.name === 'Identifier' + ); + + assert.ok(variableReference, 'Expected to resolve reference scope for g_vouTempSht'); + assert.strictEqual(variableReference?.link?.name, 'g_vouTempSht'); + assert.strictEqual(variableReference?.link?.type, ScopeType.VARIABLE); + assertNoErrorLogs(logs, 'Worksheet assignment parse'); }); }); From 88c2c4d48742cbbe4a40acbfb2a5fe9156a56ece Mon Sep 17 00:00:00 2001 From: Martin Leduc <31558169+DecimalTurn@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:58:37 -0500 Subject: [PATCH 4/5] test: add fixture test with ExternalTypeReferences.bas --- server/src/test/vbaListener.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server/src/test/vbaListener.test.ts b/server/src/test/vbaListener.test.ts index f2c4392..4d9caa4 100644 --- a/server/src/test/vbaListener.test.ts +++ b/server/src/test/vbaListener.test.ts @@ -1,6 +1,8 @@ import 'reflect-metadata'; import { describe, it } from 'mocha'; import * as assert from 'assert'; +import * as fs from 'fs'; +import * as path from 'path'; import dedent from 'dedent'; import { container } from 'tsyringe'; import { CancellationTokenSource, MessageType } from 'vscode-languageserver'; @@ -171,4 +173,15 @@ describe('VBA Listener Integration', () => { assertNoErrorLogs(logs, 'Worksheet assignment parse'); }); + + it('does not log errors for ExternalTypeReferences fixture', async () => { + const logs: LogNotification[] = []; + const fixturePath = path.resolve(process.cwd(), 'test/fixtures/ExternalTypeReferences.bas'); + const vbaCode = fs.readFileSync(fixturePath, 'utf8'); + + await parseText('file:///test/ExternalTypeReferences.bas', vbaCode, logs); + + assertNoErrorLogs(logs, 'ExternalTypeReferences fixture parse'); + }); + }); From a999153fea074a4e64b506d1aca868b8dfc33ab1 Mon Sep 17 00:00:00 2001 From: Martin Leduc <31558169+DecimalTurn@users.noreply.github.com> Date: Sun, 1 Mar 2026 14:56:02 -0500 Subject: [PATCH 5/5] fix: update fixture path to be relative --- server/src/test/vbaListener.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/vbaListener.test.ts b/server/src/test/vbaListener.test.ts index 4d9caa4..d16e096 100644 --- a/server/src/test/vbaListener.test.ts +++ b/server/src/test/vbaListener.test.ts @@ -176,7 +176,7 @@ describe('VBA Listener Integration', () => { it('does not log errors for ExternalTypeReferences fixture', async () => { const logs: LogNotification[] = []; - const fixturePath = path.resolve(process.cwd(), 'test/fixtures/ExternalTypeReferences.bas'); + const fixturePath = path.join(__dirname, '../../../test/fixtures/ExternalTypeReferences.bas'); const vbaCode = fs.readFileSync(fixturePath, 'utf8'); await parseText('file:///test/ExternalTypeReferences.bas', vbaCode, logs);