Repository navigation
v2.0.0
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_projectandanalyze_module_options_fortake ahosttoken;AnalyzeModuleOptionscarrieshostbesidehost_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_fileandread_office_modulesread 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-variablefindings. 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 useIdentityLru, which holds its keys alive and stays bounded. HostObjectModeltypes its maps asMapping, 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
.pptis 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 anExOleObjStgrecord. 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.