Skip to content

v2.0.0

Choose a tag to compare

@WilliamSmithEdward WilliamSmithEdward released this 19 Aug 05:46
· 88 commits to main since this release

VBA is now analyzed against the object model of the Office host it actually belongs to. Ports the XLIDE host-model seam and the Word, PowerPoint and Access models (xlide_vscode 790e6ea and e56098b, its issues #24 and #25).

The false positive this removes

Legal Word VBA, analyzed as a project, previously reported four findings, every one of them wrong:

undeclared-variable  'ActiveDocument'      (twice)
undeclared-variable  'wdOrientPortrait'
member-not-found     'Excel.Range.TypeText'

Under the Word host it reports none.

What is new

  • A host seam. analyze_project and analyze_module_options_for take a host token; AnalyzeModuleOptions carries host beside host_model. Absent means Excel, so every existing caller is unchanged. A named host with no model asserts no host knowledge rather than falling back to Excel's.
  • Word, PowerPoint and Access object models, extracted mechanically from the generated XLIDE host modules by the same pipeline that has always produced the Excel model: 364, 201 and 188 member-bearing types, and 3,742, 1,480 and 1,116 enum constants. Every type is non-exhaustive, so absence never becomes a finding.
  • analyze_office_file and read_office_modules read Excel (.xlsm, .xlsb, .xlam, .xls), Word (.docm, .dotm, .doc), PowerPoint (.pptm, .potm) and Access (.accdb, .mdb, read-only). The extension selects the host, so a Word document is analyzed against Word without the caller saying anything. The CLI accepts them all.

Three defects found while verifying the work

  • An empty model is not uniformly quieter than Excel's. Member lookups go silent, but the rules asking whether a bare name is legal would answer no for every global the host injects, turning an Outlook project's own surface into a wall of undeclared-variable findings. Those rules now stay silent under an unmodelled host, for the same reason they already do on a partial project view.
  • The host-model memos keyed on a bare id(model) in plain dicts holding no reference to the model, so they grew one entry per model object ever seen and a collected model's id could be recycled by a later one, serving one model's index for another. They now use IdentityLru, which holds its keys alive and stays bounded.
  • HostObjectModel types its maps as Mapping, so the frozen empty singleton type-checks and no shared model can be mutated in place.

Compatibility

analyze_workbook and read_workbook_modules keep their Excel-only contract. Word's ThisDocument classifies as a document module through the host-generic VB_PredeclaredId + VB_Exposed pair, since it names no CLSID; a .bas extension or the container's own standard flag still outranks that signature. Differentialled across 116 modules in 16 real workbooks: nothing reclassified, and all 16 stay silent.

Known limits

  • Legacy .ppt is not readable. pyOpenVBA 3.4.0 lists it but reads it as a plain CFB, while the VBA project lives in a zlib-compressed CFB inside an ExOleObjStg record. The extension is rejected up front rather than failing later with a parse error that reads like file corruption. Reported as pyOpenVBA #17.
  • Access is read-only, following pyOpenVBA: Access executes compiled p-code, so a source write would silently change nothing.

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