Skip to content

v2.1.0

Choose a tag to compare

@WilliamSmithEdward WilliamSmithEdward released this 05 Sep 07:11
· 85 commits to main since this release

Sync to XLIDE 6.1.2, the analyzer's first data re-pin since 3.1.4. Upstream had moved 192 commits, 53 of them touching the analyzer.

Verified by a differential against the upstream analyzer over the whole oracle corpus: 418 of 418 cases identical, in both directions — nothing upstream reports that this misses, nothing this reports that upstream does not.

Fixed: arms of one #If chain are alternatives, not duplicates

Only one arm of a chain is ever built, so two declarations in different arms are not duplicates. With a compiler constant the analyzer cannot evaluate, the ordinary idiom reported findings on legal code:

#If CUSTOMFLAG Then
Public Const MODE As String = "a"
#Else
Public Const MODE As String = "b"
#End If

That reported duplicate-module-variable, and the same shape around a Sub reported duplicate-procedure. The tracker gains mutually_exclusive and in_same_branch, and eight rule sites now use them: duplicate procedures, module members, declarations and labels, undefined labels, For/Next pairing, Else branch order, and Option and Implements placement.

A #Const directive may also precede Option Explicit now. A directive is not a declaration, and the live VBE compiles it there.

Added: ambiguous-project-procedure

VBA is content for two modules to export the same public procedure name, but refuses to compile an unqualified call to that name from a module declaring neither. The finding sits at the call site, not the declarations, because a project that exports a name twice and always qualifies its calls is legal VBA and common. Silent when the call is qualified, when the calling module declares the name itself, when a local shadows it, or when only one module exports it.

Changed: missing-return-assignment covers typed functions

The rule previously reported only untyped functions. It now covers every Function and Property Get, so a typed Function that never assigns its return reports. An empty member of a module another module declares with Implements stays silent, since that is a contract for an implementer to fill in; a body whose work is to raise stays silent too.

This reports on code that was previously quiet. The rule is warning severity and can be turned off through severity_overrides.

The widening is also where the interesting work was. It reported 145 findings across 16 real workbooks that were previously silent, while upstream reported none on the same input, so the divergence was local. Three detector gaps, each isolated to a minimal case:

  • assigning a field of the returned value (MsToSystemTime.wYear = ...) is a return assignment
  • so is an assignment inside a single-line If, whose branches the statement walk never entered
  • a name that SPELLS a keyword is still an assignment target, so Function Read() assigning Read = True read as never assigning its return

All 16 workbooks are silent again.

Data

Re-pinned to XLIDE 6.1.2: 418 oracle cases (was 415), 122 audited codes (was 121), 119 rules (was 118). The host models grew with upstream's move to the whole documented object model, Excel 229 to 651 types and Word 364 to 627, which takes the wheel from 0.94 MB to 1.84 MB. The models still load lazily, so import cost is unchanged.

Known limits

Upstream's form-control member work is not ported, and the oracle corpus carries no UserForm designer cases, so that area is untested here rather than verified.

3,033 tests green; ruff and mypy clean; CI green across Python 3.10 to 3.13 and the language matrix on Linux and Windows.