pyvbaanalysis 2.1.1__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.gitignore +3 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/CHANGELOG.md +216 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/CONTRIBUTING.md +61 -7
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/PKG-INFO +16 -3
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/README.md +13 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/docs/api-reference.md +26 -11
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/docs/diagnostics-catalogue.md +17 -5
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/docs/usage.md +33 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyproject.toml +4 -2
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/__init__.py +1 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/cli.py +5 -4
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/event_handlers.py +14 -8
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/member_access.py +408 -99
- pyvbaanalysis-2.2.0/pyvbaanalysis/data/access_host_model.json +1 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/diagnostic_influence_audit.json +159 -2
- pyvbaanalysis-2.2.0/pyvbaanalysis/data/excel_closed_types.json +31 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/excel_host_model.json +1 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/manifest.json +35 -10
- pyvbaanalysis-2.2.0/pyvbaanalysis/data/msforms_members.json +1 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/data/powerpoint_host_model.json +1 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/rule_metadata.json +139 -1
- pyvbaanalysis-2.2.0/pyvbaanalysis/data/vb6_host_model.json +1 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/data/vba_runtime_tables.json +1 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/vbe_oracle_cases.json +286 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/data/word_host_model.json +1 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/__init__.py +8 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/analyze_module.py +36 -8
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/argument_inference.py +289 -14
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/call_extraction.py +9 -5
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/callable_signatures.py +255 -15
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/const_expr.py +62 -4
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/context.py +23 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/dataflow.py +53 -18
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/model.py +36 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/registry.py +74 -7
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rule_metadata.py +3 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/argument_types.py +19 -4
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/arrays.py +32 -5
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/assignments.py +50 -15
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/call_arity.py +77 -8
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/control_flow.py +33 -22
- pyvbaanalysis-2.2.0/pyvbaanalysis/diagnostics/rules/dead_code.py +562 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/declarations.py +139 -30
- pyvbaanalysis-2.2.0/pyvbaanalysis/diagnostics/rules/doc_comments.py +372 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/duplicates.py +55 -33
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/expressions.py +5 -7
- pyvbaanalysis-2.2.0/pyvbaanalysis/diagnostics/rules/missing_reference.py +136 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/module_kind.py +5 -3
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/object_state.py +44 -19
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/parameter_defaults.py +8 -7
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/runtime_values.py +7 -8
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/shared.py +153 -12
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/type_of_is.py +15 -64
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/undeclared.py +95 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/walker.py +1 -1
- pyvbaanalysis-2.2.0/pyvbaanalysis/docs/__init__.py +19 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/docs/doc_comment.py +231 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/host/__init__.py +8 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/host/host_libraries.py +92 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/host/host_model.py +88 -3
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/host/host_registry.py +76 -2
- pyvbaanalysis-2.2.0/pyvbaanalysis/host/msforms.py +91 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/host/type_extensibility.py +74 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/token_helpers.py +43 -2
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/parse_module.py +7 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/project.py +18 -3
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/__init__.py +4 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/workbook.py +103 -37
- pyvbaanalysis-2.2.0/pyvbaanalysis/references/__init__.py +10 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/references/reference_kinds.py +365 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/runtime/__init__.py +4 -0
- pyvbaanalysis-2.2.0/pyvbaanalysis/runtime/vba_runtime.py +190 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/__init__.py +2 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/build_module_symbols.py +2 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/project_index.py +241 -4
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/symbol_model.py +30 -1
- pyvbaanalysis-2.2.0/pyvbaanalysis/symbols/user_form_controls.py +145 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/types/__init__.py +1 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/types/type_inference.py +2 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/types/type_names.py +3 -18
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/oracle_support.py +11 -17
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_cli.py +4 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_conditional_arms.py +3 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_dataflow.py +21 -14
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_evidence.py +2 -2
- pyvbaanalysis-2.2.0/tests/test_host_libraries.py +176 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_host_seam.py +38 -10
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_parser.py +19 -8
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_reader.py +34 -2
- pyvbaanalysis-2.2.0/tests/test_reference_kinds.py +175 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_registry_parity.py +9 -2
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rule_metadata.py +15 -5
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_assignments_types.py +68 -4
- pyvbaanalysis-2.2.0/tests/test_rules_call_arity.py +102 -0
- pyvbaanalysis-2.2.0/tests/test_rules_dead_code.py +347 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_declarations.py +40 -0
- pyvbaanalysis-2.2.0/tests/test_rules_doc_comments.py +197 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_event_handler_module_scope.py +29 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_member_not_found.py +68 -43
- pyvbaanalysis-2.2.0/tests/test_rules_missing_reference.py +152 -0
- pyvbaanalysis-2.2.0/tests/test_upstream_sync_10_5_0.py +278 -0
- pyvbaanalysis-2.2.0/tests/test_upstream_sync_10_6_0.py +246 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_upstream_sync_6_1_2.py +3 -1
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/extract_event_definitions.mjs +9 -7
- pyvbaanalysis-2.2.0/tools/extract_host_model.mjs +64 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/extract_rule_metadata.mjs +6 -3
- pyvbaanalysis-2.2.0/tools/extract_runtime_tables.mjs +20 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/generate_manifest.py +16 -6
- pyvbaanalysis-2.2.0/tools/pin_analyzer.py +127 -0
- pyvbaanalysis-2.2.0/tools/vendor_data.py +106 -0
- pyvbaanalysis-2.2.0/tools/xlide_source.mjs +52 -0
- pyvbaanalysis-2.1.1/pyvbaanalysis/data/access_host_model.json +0 -1
- pyvbaanalysis-2.1.1/pyvbaanalysis/data/powerpoint_host_model.json +0 -1
- pyvbaanalysis-2.1.1/pyvbaanalysis/data/vba_runtime_tables.json +0 -1
- pyvbaanalysis-2.1.1/pyvbaanalysis/data/word_host_model.json +0 -1
- pyvbaanalysis-2.1.1/pyvbaanalysis/runtime/vba_runtime.py +0 -329
- pyvbaanalysis-2.1.1/tests/test_rules_call_arity.py +0 -60
- pyvbaanalysis-2.1.1/tools/extract_host_model.mjs +0 -31
- pyvbaanalysis-2.1.1/tools/extract_runtime_tables.mjs +0 -10
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.gitattributes +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.github/dependabot.yml +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.github/workflows/ci.yml +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.github/workflows/publish.yml +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/LICENSE +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/__main__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/call/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/call/call_context.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/cursor_context.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/type_completion.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/conditional/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/conditional/conditional_compilation.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/constants/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/constants/integer_constant_expression.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/event_definitions.json +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/exprwalk.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/inline_suppression.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/argument_shape.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/binary_operand_scalar.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/late_binding.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/lexical.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/numeric_literals.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/evidence.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/flow/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/flow/procedure_labels.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/flow/procedure_unstructured.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/identity_cache.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/keyword_table.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/stripped_lines.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/token_kinds.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/tokenize.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/trivia.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/__init__.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/fixed_length_string.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/nodes.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/parse_expression.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/parser_state.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/type_declaration_suffix.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/py.typed +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/loose_file.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/vbe_module.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/name_resolution.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/conftest.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_conditional_compilation.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_diagnostics_engine.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_host_model.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_inline_suppression.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_integer_constant_expression.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_language_matrix.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_lexer.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_member_access_chains.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_project.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_project_index.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_public_api.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_real_world_false_positives.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_ambiguous_enum_member.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_argument_shape.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_argument_types.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_arrays.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_assignments.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_binary_operand_scalar.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_control_flow.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_division_by_zero.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_duplicates.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_expression_calls.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_expressions.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_invalid_as_type_names.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_is_operator_non_object.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_late_binding.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_lexical.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_module_kind.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_numeric_literals.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_object_state.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_parameter_defaults.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_property_setter_value_parameters.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_runtime_values.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_scalar_and_foreach.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_type_of_is.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_typeof_is_always_false.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_undeclared.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_runtime_tables.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_statement_token_derivation.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_stripped_lines.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_symbols.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_token_helpers.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_type_completion.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_type_names.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/generate_diagnostics_catalogue.py +0 -0
- {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/oracle/build_combining_mark_probe.py +0 -0
|
@@ -34,3 +34,6 @@ Thumbs.db
|
|
|
34
34
|
|
|
35
35
|
# Note: the vendored XLIDE data package under pyvbaanalysis/data/ is intentionally
|
|
36
36
|
# committed (it is the version-pinned contract surface), so it is NOT ignored here.
|
|
37
|
+
|
|
38
|
+
# A pinned XLIDE checkout is a build input, reproducible from its ref at any time.
|
|
39
|
+
artifacts/
|
|
@@ -5,6 +5,222 @@ All notable changes to pyVBAanalysis are recorded here. The format follows
|
|
|
5
5
|
follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html): a minor version
|
|
6
6
|
per milestone.
|
|
7
7
|
|
|
8
|
+
## 2.2.0 - 2026-09-22
|
|
9
|
+
|
|
10
|
+
Sync to XLIDE 10.6.0 (commit 5682c8f), from 6.2.0: twelve new diagnostics, early
|
|
11
|
+
binding checked against the libraries a project references, and member lookups
|
|
12
|
+
that follow the type library's own extensibility flags. The data is now vendored
|
|
13
|
+
from a pinned upstream commit, which the manifest records.
|
|
14
|
+
|
|
15
|
+
The sync also closes gaps earlier syncs left open. Replaying upstream's own test
|
|
16
|
+
suite through the port found checks that were never ported (member calls, typing
|
|
17
|
+
through the host model, constants from the host and the VBA library), fixes
|
|
18
|
+
older than 6.2.0 that were never taken, and false positives in 2.1.1 from that
|
|
19
|
+
drift. All of it is listed below.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
* `invalid-option-statement` (error): a malformed Option statement, such as
|
|
24
|
+
`Option Base 2`, `Option Explicit Foo` or a bare `Option Private`.
|
|
25
|
+
`Option Compare Database` is reported only when a host other than Access is
|
|
26
|
+
named: it is an Access directive, and a loose file names no host.
|
|
27
|
+
* `missing-library-reference` (error): a type or constant qualified with another
|
|
28
|
+
Office application's library the project does not reference, such as
|
|
29
|
+
`Dim doc As Word.Document` in a workbook with no reference to Word. The VBE
|
|
30
|
+
refuses it with "User-defined type not defined". Late binding through
|
|
31
|
+
`CreateObject` names nothing and stays silent. Reported once per library per
|
|
32
|
+
module, and only against a known reference list (see Changed).
|
|
33
|
+
* Four dead-code checks, all `information`: `unused-variable` (a local, or a
|
|
34
|
+
module-private variable or constant, that nothing uses), `variable-never-read`
|
|
35
|
+
(one that is only ever assigned), `unused-procedure` (a private procedure
|
|
36
|
+
nothing calls), and `unreachable-code` (statements after `Exit`, `End`, `GoTo`
|
|
37
|
+
or `Resume` that no label or `Case` arm reaches). A name in any module's
|
|
38
|
+
string literal counts as a use of a private procedure, because
|
|
39
|
+
`Application.Run "Poll"` reaches a private Sub. `unused-variable` and
|
|
40
|
+
`unreachable-code` findings carry the edit that removes the declaration or the
|
|
41
|
+
dead run.
|
|
42
|
+
* Six doc-comment checks, all `warning`: `doc-param-missing`,
|
|
43
|
+
`doc-param-unknown`, `doc-returns-missing`, `doc-returns-unexpected`,
|
|
44
|
+
`doc-tag-unclosed` and `doc-tag-duplicate` compare the XML tags of a `'''`
|
|
45
|
+
block with the declaration it documents, each with fixes that add, rename or
|
|
46
|
+
remove a tag. A `'''` block of plain prose is left alone.
|
|
47
|
+
* `referenced_hosts` on `analyze_project` and `analyze_module_options_for`: the
|
|
48
|
+
other Office libraries a project references, in declaration order. Their
|
|
49
|
+
types, constants and globals resolve against their own models, and the
|
|
50
|
+
project's own host wins a name two libraries share, as VBA resolves it.
|
|
51
|
+
`None`, the default, means the list is unknown; `[]` means it is known to name
|
|
52
|
+
nothing else.
|
|
53
|
+
* `read_office_project(path)` in `pyvbaanalysis.reader`, returning an
|
|
54
|
+
`OfficeProject`: a container's modules, the host its extension implies, and
|
|
55
|
+
the Office libraries its reference list names. `analyze_office_file` and the
|
|
56
|
+
CLI pass all three to the analysis.
|
|
57
|
+
* Member calls are checked for arity and argument types against the signature
|
|
58
|
+
the member resolves to, on host objects and project classes alike:
|
|
59
|
+
`Application.Calculate(1)`, a bare `Err.Raise`, `Workbooks.Open()`, and
|
|
60
|
+
`p.Save "bad"` on a class whose `Save` takes a Long. Earlier ports checked
|
|
61
|
+
calls to procedures only. A keyword before `:=` is a parameter name, so
|
|
62
|
+
`BreakLink Name:="x", Type:=xlLinkTypeExcelLinks` stays silent. A signature's
|
|
63
|
+
parameters end at their own closing parenthesis, so a member returning an
|
|
64
|
+
array, `Function Values() As Long()`, takes an empty argument list.
|
|
65
|
+
* Expressions are typed through the host model, the VBA runtime and the member
|
|
66
|
+
a chain resolves to, so `Set wb = ActiveSheet.Range("A1")` reports
|
|
67
|
+
`assignment-object-type-mismatch`, and a constant such as `vbFalse` or
|
|
68
|
+
`xlAbove` passed or assigned where an object is expected is reported.
|
|
69
|
+
* Constant expressions fold VBA and host constants: `1 / vbFalse` reports
|
|
70
|
+
`division-by-zero`, and `Left$(s, xlAbove - 1)` a negative length. A constant
|
|
71
|
+
qualified with a host (`Word.wdMainTextStory`) answers only in that host.
|
|
72
|
+
* A `vb6` host token and the VB6 object model: App, Screen, Printer, Form and
|
|
73
|
+
the intrinsic controls. It offers and describes, and never proves a member
|
|
74
|
+
absent.
|
|
75
|
+
* A UserForm's surface carries the MSForms UserForm members and the ones VBA
|
|
76
|
+
adds (Show, Hide, Name, ...). When the form's control list is authoritative,
|
|
77
|
+
supplied as `implicit_members` or spelled out by a `.frm` designer header, it
|
|
78
|
+
proves a member absent: `EntryForm.NoSuchControl` reports `member-not-found`
|
|
79
|
+
(XLIDE issue #26). A form nobody read the designer of proves nothing.
|
|
80
|
+
* The public pieces behind these: `classify_reference_kinds` in the new
|
|
81
|
+
`pyvbaanalysis.references`, the doc-comment grammar in `pyvbaanalysis.docs`,
|
|
82
|
+
`host_object_model_for_tokens`, `get_vb6_object_model` and the libid helpers
|
|
83
|
+
in `pyvbaanalysis.host`, the forms metadata in `pyvbaanalysis.host.msforms`,
|
|
84
|
+
`implicit_members`, `predeclared_id` and `designer_class` on `ModuleInput`
|
|
85
|
+
(with `ImplicitMember`), and the code-action payloads
|
|
86
|
+
`VbaAddLibraryReferenceData`, `VbaRemoveDeclarationData`,
|
|
87
|
+
`VbaRemoveUnreachableCodeData` and `VbaDocCommentFix`.
|
|
88
|
+
* `tools/vendor_data.py` vendors every data file from one pinned XLIDE commit,
|
|
89
|
+
after `tools/pin_analyzer.py` copies that commit out of the sibling checkout
|
|
90
|
+
(see CONTRIBUTING.md). The manifest gains `xlideCommit`.
|
|
91
|
+
* `tools/differential/harness.py` compares the port with the upstream analyzer
|
|
92
|
+
of the same pin. It records every `analyzeModule` call of upstream's own test
|
|
93
|
+
suite and replays each through the port, and it runs the oracle corpus, Office
|
|
94
|
+
files and folders of exported modules through both analyzers (see
|
|
95
|
+
CONTRIBUTING.md). It stays out of the published packages.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
* `member-not-found` reports an absent member only on a closed Excel interface.
|
|
100
|
+
Upstream now reads each interface's TYPEFLAGS from the type library, and
|
|
101
|
+
Application, Workbook and Range are extensible: VBA compiles a member they do
|
|
102
|
+
not list and resolves it at run time. `Application.Match` and the other
|
|
103
|
+
worksheet functions reached through Application were reported and are now
|
|
104
|
+
silent. In a workbook, `ThisWorkbook` is the project's own document class,
|
|
105
|
+
which the VBE closes, so a member it lacks is still reported. Analyzed with no
|
|
106
|
+
ThisWorkbook module, as the oracle corpus runs its cases, it falls back to the
|
|
107
|
+
library's open Workbook, and three cases the VBE rejects go unreported by both
|
|
108
|
+
analyzers. `Worksheets` stays closed: the type library returns the closed
|
|
109
|
+
`Sheets` from it, so `Worksheets.NoSuchMemberXyz` is still reported and
|
|
110
|
+
`Worksheets(1)` is still a Worksheet (XLIDE issue #79, found by this sync).
|
|
111
|
+
* The host models carry the members each type library marks hidden, which the
|
|
112
|
+
reference documentation leaves out: 405 more in Excel's model, 332 in Word's
|
|
113
|
+
and 200 in PowerPoint's, each with `hidden` set. They resolve like any other
|
|
114
|
+
member (see Fixed). Where a Global interface answers for bare names, as in
|
|
115
|
+
Excel, Word and PowerPoint, Application's hidden members stay out of bare
|
|
116
|
+
scope, so a bare `Save` in Excel is still `unknown-call`.
|
|
117
|
+
* The project's own types outrank the host library's, as they do in VBA: a class
|
|
118
|
+
named `Font` or `Point` resolves to its own members rather than Excel's
|
|
119
|
+
(XLIDE issue #11). A project Enum is a value type, never an object receiver.
|
|
120
|
+
* The rules that read a statement's structure also read the statements a
|
|
121
|
+
single-line `If` carries: `If ok Then K = 2` reports `const-assignment`, and
|
|
122
|
+
`If ok Then Helper 1, 2, 3` its arity (XLIDE issue #46).
|
|
123
|
+
* The arms of one `#If` chain are alternatives, and a repeat inside one arm is a
|
|
124
|
+
repeat: two `Case Else`, two `Option Explicit`, or a duplicated Enum member or
|
|
125
|
+
Type field in the same arm are reported, where every undecidable branch used
|
|
126
|
+
to be skipped. A call that no arm's declaration accepts reports
|
|
127
|
+
`argument-count`, where a name declared once per arm used to turn the check
|
|
128
|
+
off (XLIDE issue #58).
|
|
129
|
+
* A module's own `Type` shadows another module's `Type` of the same name, as it
|
|
130
|
+
does in the VBE. A class with a private `Type JsonTextBuilder` was resolved
|
|
131
|
+
against a public one elsewhere, and its fields reported missing (oracle case
|
|
132
|
+
`private_type_shadows_public_type_compile`).
|
|
133
|
+
* A procedure closer ends the open procedure even from inside a block left open
|
|
134
|
+
in it, as the VBE does and upstream's parser now does too (XLIDE issue #81,
|
|
135
|
+
found by this sync). After `If x Then` with no `End If`, an `End Function`
|
|
136
|
+
reports the If as missing its `End If` and closes the procedure. It used to
|
|
137
|
+
read as an unmatched closer and leave the procedure open.
|
|
138
|
+
* `analyze_workbook` returns exactly what `analyze_office_file` returns for the
|
|
139
|
+
same file. It now reads the workbook's reference list and names Excel as the
|
|
140
|
+
host, so it can report `missing-library-reference` and
|
|
141
|
+
`Option Compare Database`, which it could not before.
|
|
142
|
+
* `missing-library-reference` is reported only against a known reference list:
|
|
143
|
+
one read from a container, or passed as `referenced_hosts`. Upstream treats an
|
|
144
|
+
absent list as "nothing referenced"; a loose `.bas` file has no list, and a
|
|
145
|
+
missing reference cannot be proven there.
|
|
146
|
+
* The four dead-code checks report at `information`, and the CLI's default
|
|
147
|
+
`--fail-level information` fails on any diagnostic, so a workbook with one
|
|
148
|
+
unused variable now exits 1. Pass `--fail-level warning` to gate on warnings
|
|
149
|
+
and errors only. Each of 16 real workbooks reports at least one of these.
|
|
150
|
+
* The vendored data moves to 10.6.0: 443 oracle cases (from 418), 134 audited
|
|
151
|
+
codes (from 122) and 131 catalogue rules (from 119). Two data files join it,
|
|
152
|
+
both extracted from the same commit: the VB6 object model and the Microsoft
|
|
153
|
+
Forms members.
|
|
154
|
+
|
|
155
|
+
### Fixed
|
|
156
|
+
|
|
157
|
+
False positives 2.1.1 reported on code that compiles, each from a fix an earlier
|
|
158
|
+
sync did not carry over:
|
|
159
|
+
|
|
160
|
+
* `undeclared-variable` on a qualifier that names an enumeration or a VBA module
|
|
161
|
+
of constants: `XlDirection.xlUp`, `VbMsgBoxResult.vbYes`, `Strings.Left`,
|
|
162
|
+
`Constants.vbCrLf`.
|
|
163
|
+
* `undeclared-variable` on a UserForm's own controls in its code-behind, on a
|
|
164
|
+
bracketed name Excel evaluates (`[A1]`), on the field after `!` (`rs!Field`),
|
|
165
|
+
on `Line` in `Line Input #f, s`, and on a module name used as a qualifier
|
|
166
|
+
(`Module1.Limit`).
|
|
167
|
+
* `object-variable-not-set` on a variable declared `As New`, which VBA creates
|
|
168
|
+
on first use.
|
|
169
|
+
* `unallocated-dynamic-array-access` on an array read after a call that received
|
|
170
|
+
it, and may have allocated it: `If Fill(a) Then Debug.Print a(0)` (XLIDE issue
|
|
171
|
+
#70).
|
|
172
|
+
* `event-handler-module-scope` on each Document event handler in Word's
|
|
173
|
+
`ThisDocument`, such as `Document_Open`. The module was taken for a worksheet,
|
|
174
|
+
where upstream knows it as Word's document.
|
|
175
|
+
|
|
176
|
+
Three more, fixed upstream in 10.6.0:
|
|
177
|
+
|
|
178
|
+
* `readonly-member-assignment` on a comparison with a read-only property: in an
|
|
179
|
+
`ElseIf` or `Case` header, a single-line `If`'s condition, or a call given the
|
|
180
|
+
comparison, such as `Debug.Print w.Part = "a"`. The target of a member
|
|
181
|
+
assignment must be one receiver chain, which a keyword or a call before the
|
|
182
|
+
receiver breaks (XLIDE issue #78, found by this sync). An assignment that a
|
|
183
|
+
single-line `If` carries is still reported, named `w.Part` rather than
|
|
184
|
+
`If ok Then w.Part`.
|
|
185
|
+
* `member-not-found` on a member the type library hides, such as
|
|
186
|
+
`ThisWorkbook.Title` or `ws.OnEntry` on a Worksheet. Both compile, but the
|
|
187
|
+
models were built from the reference documentation, which leaves such members
|
|
188
|
+
out.
|
|
189
|
+
* `undeclared-variable` on a hidden global called bare, such as `Assistant` in
|
|
190
|
+
Word and PowerPoint, or PowerPoint's `Dialogs`.
|
|
191
|
+
|
|
192
|
+
### Verified
|
|
193
|
+
|
|
194
|
+
* Upstream's own test suite, recorded: every `analyzeModule` call its 10.6.0
|
|
195
|
+
tests make, with the options they pass and the modules of any project index
|
|
196
|
+
behind them, replayed through the port: 1055 standalone calls and 929 with
|
|
197
|
+
project context, every result identical in code, span and message. With two
|
|
198
|
+
of the 10.6.0 fixes undone in the port, 7 of them differ, so the replay sees
|
|
199
|
+
what those fixes change.
|
|
200
|
+
* The oracle corpus, standalone and with project context: all 1818 diagnostics
|
|
201
|
+
identical in code, span and message. That is with the reference list given as
|
|
202
|
+
known and empty to both analyzers. Left unknown, the port stays silent on the
|
|
203
|
+
one case the upstream analyzer reports, the reference-list gate above.
|
|
204
|
+
* The 116 modules of 16 real workbooks: identical diagnostics from both
|
|
205
|
+
analyzers.
|
|
206
|
+
* 693 further projects, 627 of them the VBA blocks of upstream's syntax corpus
|
|
207
|
+
and 66 folders of exported modules: identical diagnostics from both analyzers
|
|
208
|
+
across 948 modules. The seven VB6 projects among them are identical under the
|
|
209
|
+
`vb6` host too.
|
|
210
|
+
* 195 distinct Office files from the same repositories, from Excel, Word,
|
|
211
|
+
PowerPoint and Access: identical diagnostics across 965 modules, once the
|
|
212
|
+
`ThisDocument` fix above was in. That fix is what this comparison found.
|
|
213
|
+
* Each new rule compared case by case with upstream 10.5.0, fix payloads
|
|
214
|
+
included: option statements 23, library references 11, reference kinds 18,
|
|
215
|
+
dead code 33 plus 8 removal edits, doc comments 21 with 25 fixes.
|
|
216
|
+
* Against 2.1.1, in interleaved runs measuring CPU time: a real workbook's
|
|
217
|
+
analysis takes about 3 percent longer, and the largest module (26,721 lines)
|
|
218
|
+
about 15 percent. The 10.6.0 changes measure under 2 points of that.
|
|
219
|
+
* The differential harness behind the 2.1.0 and 2.1.1 figures read each module's
|
|
220
|
+
kind from the wrong corpus field, so class and document modules were compared
|
|
221
|
+
as standard modules. It is corrected, and the figures above come from the
|
|
222
|
+
corrected harness, now `tools/differential/`.
|
|
223
|
+
|
|
8
224
|
## 2.1.1 - 2026-09-05
|
|
9
225
|
|
|
10
226
|
Follows XLIDE 6.2.0. The vendored data is byte-identical to 6.1.2, so only the
|
|
@@ -14,8 +14,8 @@ pip install -e ".[dev]"
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
The `dev` extra adds the test, lint, and type tools. pyOpenVBA (the one runtime
|
|
17
|
-
dependency, used to read VBA out of
|
|
18
|
-
package, so the
|
|
17
|
+
dependency, used to read VBA out of Office files) is installed with the base
|
|
18
|
+
package, so the container reader is exercised by the test suite.
|
|
19
19
|
|
|
20
20
|
## Local checks
|
|
21
21
|
|
|
@@ -34,19 +34,73 @@ mypy pyvbaanalysis
|
|
|
34
34
|
This repository ports XLIDE's TypeScript analyzer. XLIDE owns the language and
|
|
35
35
|
host knowledge; pyVBAanalysis reproduces its behavior in Python.
|
|
36
36
|
|
|
37
|
-
* The XLIDE source is expected as a sibling checkout at `../xlide_vscode
|
|
38
|
-
|
|
37
|
+
* The XLIDE source is expected as a sibling checkout at `../xlide_vscode`, to read
|
|
38
|
+
while porting.
|
|
39
39
|
* XLIDE also owns the oracle: the Excel/VBE evidence corpus and the provenance
|
|
40
40
|
audit. pyVBAanalysis consumes the emitted evidence verbatim as both porting spec
|
|
41
41
|
and test fixtures. Do not reimplement the oracle here.
|
|
42
|
-
* The vendored data lives in `pyvbaanalysis/data/` (the host object
|
|
42
|
+
* The vendored data lives in `pyvbaanalysis/data/` (the host object models, the
|
|
43
43
|
runtime tables, the oracle cases, the rule metadata, and a manifest with
|
|
44
|
-
checksums). It is
|
|
45
|
-
|
|
44
|
+
checksums). It is never hand-edited. A sync regenerates all of it from one XLIDE
|
|
45
|
+
commit:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
python tools/vendor_data.py --ref vX.Y.Z
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The commit is pinned first. `tools/pin_analyzer.py` copies the sibling
|
|
52
|
+
repository's history into `artifacts/analyzer-pin/<commit>` (not in source
|
|
53
|
+
control) and checks that commit out, so neither uncommitted work in the sibling
|
|
54
|
+
checkout nor the branch it happens to be on reaches the data. The
|
|
55
|
+
`tools/extract_*.mjs` scripts then read the pin through `XLIDE_ROOT`, and stop
|
|
56
|
+
rather than fall back to the sibling when it does not name an XLIDE checkout. The
|
|
57
|
+
manifest records both the version label and the full commit (`xlideVersion`,
|
|
58
|
+
`xlideCommit`).
|
|
46
59
|
|
|
47
60
|
The build plan, parity inventory, and module-by-module port map are in
|
|
48
61
|
[agent.md](agent.md).
|
|
49
62
|
|
|
63
|
+
## Checking a sync against upstream
|
|
64
|
+
|
|
65
|
+
The port's own tests encode the behavior it had, so they stay green while upstream
|
|
66
|
+
widens a rule the port never took. A sync is checked by running both analyzers on
|
|
67
|
+
the same inputs, upstream from the pin of the vendored commit:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
python tools/differential/harness.py record
|
|
71
|
+
python tools/differential/harness.py replay
|
|
72
|
+
python tools/differential/harness.py corpus
|
|
73
|
+
python tools/differential/harness.py cases artifacts/differential/cases/mine.json PATH ...
|
|
74
|
+
python tools/differential/harness.py projects artifacts/differential/cases/mine.json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
* `record` runs upstream's own test suite with a recorder appended to its
|
|
78
|
+
`analyzeModule` and `ProjectIndex`, writing every call to
|
|
79
|
+
`artifacts/differential/<commit>/calls.jsonl`. `replay` runs each call through
|
|
80
|
+
the port, rebuilding the project index behind a call made with project context,
|
|
81
|
+
and compares the diagnostics by code, span and message. It finds the gaps
|
|
82
|
+
nothing else exercises: whole checks never ported, fixes older than the last
|
|
83
|
+
sync point.
|
|
84
|
+
* `corpus` runs the oracle corpus through both analyzers, each module standalone
|
|
85
|
+
and with its case's modules as a project.
|
|
86
|
+
* `cases` turns Office files, and folders searched for them and for exported
|
|
87
|
+
`.bas`/`.cls`/`.frm` modules, into project cases. `--markdown` adds every VBA
|
|
88
|
+
block of upstream's syntax corpus, and `--host` names a host for the cases no
|
|
89
|
+
file implies one for. `projects` runs a cases file through both analyzers.
|
|
90
|
+
|
|
91
|
+
`replay`, `corpus` and `projects` exit 1 when anything differs and print what only
|
|
92
|
+
one side reports. Where the port reports more, the port is wrong. Where upstream
|
|
93
|
+
reports more it may be an upstream false positive, so check before porting it.
|
|
94
|
+
|
|
95
|
+
The upstream halves (`tools/differential/upstream/*.mjs`) read the pin through
|
|
96
|
+
`tools/xlide_source.mjs`, as the extractors do, and need nothing installed. Only
|
|
97
|
+
`record` runs upstream's vitest suite, which needs the sibling checkout's
|
|
98
|
+
dependencies installed. The pin gets a `node_modules` folder of its own with one
|
|
99
|
+
link per package, so the caches Vite writes stay in the pin, and the run fails if
|
|
100
|
+
the sibling's folder changed. The recorder is removed with `git checkout` when the
|
|
101
|
+
run ends. `harness.py unpatch` restores a pin a run left patched, and
|
|
102
|
+
`tools/pin_analyzer.py` will not reuse a pin with local changes.
|
|
103
|
+
|
|
50
104
|
## Adding or changing a rule
|
|
51
105
|
|
|
52
106
|
* Port the rule from its XLIDE source; match the behavior, not just the shape.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pyvbaanalysis
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Pure-Python static analysis for Excel VBA
|
|
5
5
|
Project-URL: Homepage, https://github.com/WilliamSmithEdward/pyVBAanalysis
|
|
6
6
|
Project-URL: Repository, https://github.com/WilliamSmithEdward/pyVBAanalysis
|
|
@@ -22,9 +22,9 @@ Provides-Extra: build
|
|
|
22
22
|
Requires-Dist: build>=1.2; extra == 'build'
|
|
23
23
|
Requires-Dist: twine>=5; extra == 'build'
|
|
24
24
|
Provides-Extra: dev
|
|
25
|
-
Requires-Dist: mypy==2.3.
|
|
25
|
+
Requires-Dist: mypy==2.3.1; extra == 'dev'
|
|
26
26
|
Requires-Dist: pytest==9.1.1; extra == 'dev'
|
|
27
|
-
Requires-Dist: ruff==0.16.
|
|
27
|
+
Requires-Dist: ruff==0.16.8; extra == 'dev'
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
|
|
30
30
|
# pyVBAanalysis
|
|
@@ -46,8 +46,13 @@ It looks for more than a hundred kinds of problem, including:
|
|
|
46
46
|
- Undeclared variables and calls to procedures or members that do not exist.
|
|
47
47
|
- Code the VBA compiler rejects: duplicate declarations, malformed statements, or a `Declare` that lacks `PtrSafe` on 64-bit
|
|
48
48
|
Office.
|
|
49
|
+
- A type from another Office application's library the project does not
|
|
50
|
+
reference, such as `Dim doc As Word.Document` in a workbook with no reference to
|
|
51
|
+
Word.
|
|
49
52
|
- Likely run-time failures, such as dividing by a constant zero or a type mismatch
|
|
50
53
|
from a bad conversion.
|
|
54
|
+
- Dead code: variables nothing uses or nothing reads, private procedures nothing
|
|
55
|
+
calls, and statements no path reaches.
|
|
51
56
|
|
|
52
57
|
It only reports a problem when it can prove one, and stays quiet otherwise, so the
|
|
53
58
|
output does not bury you in false alarms.
|
|
@@ -122,6 +127,14 @@ a compressed record the reader does not open.
|
|
|
122
127
|
- [API reference](docs/api-reference.md)
|
|
123
128
|
- [Diagnostic catalogue](docs/diagnostics-catalogue.md)
|
|
124
129
|
|
|
130
|
+
## Built with this
|
|
131
|
+
|
|
132
|
+
[xlide-mcp](https://github.com/WilliamSmithEdward/xlide_mcp)
|
|
133
|
+
is an MCP server built on this. The diagnostics here are its build gate:
|
|
134
|
+
an agent that changes a macro runs them afterwards and treats an error
|
|
135
|
+
as a failure rather than a suggestion, which is most of what stops a
|
|
136
|
+
model shipping VBA that does not compile.
|
|
137
|
+
|
|
125
138
|
## License
|
|
126
139
|
|
|
127
140
|
MIT. See [LICENSE](LICENSE).
|
|
@@ -17,8 +17,13 @@ It looks for more than a hundred kinds of problem, including:
|
|
|
17
17
|
- Undeclared variables and calls to procedures or members that do not exist.
|
|
18
18
|
- Code the VBA compiler rejects: duplicate declarations, malformed statements, or a `Declare` that lacks `PtrSafe` on 64-bit
|
|
19
19
|
Office.
|
|
20
|
+
- A type from another Office application's library the project does not
|
|
21
|
+
reference, such as `Dim doc As Word.Document` in a workbook with no reference to
|
|
22
|
+
Word.
|
|
20
23
|
- Likely run-time failures, such as dividing by a constant zero or a type mismatch
|
|
21
24
|
from a bad conversion.
|
|
25
|
+
- Dead code: variables nothing uses or nothing reads, private procedures nothing
|
|
26
|
+
calls, and statements no path reaches.
|
|
22
27
|
|
|
23
28
|
It only reports a problem when it can prove one, and stays quiet otherwise, so the
|
|
24
29
|
output does not bury you in false alarms.
|
|
@@ -93,6 +98,14 @@ a compressed record the reader does not open.
|
|
|
93
98
|
- [API reference](docs/api-reference.md)
|
|
94
99
|
- [Diagnostic catalogue](docs/diagnostics-catalogue.md)
|
|
95
100
|
|
|
101
|
+
## Built with this
|
|
102
|
+
|
|
103
|
+
[xlide-mcp](https://github.com/WilliamSmithEdward/xlide_mcp)
|
|
104
|
+
is an MCP server built on this. The diagnostics here are its build gate:
|
|
105
|
+
an agent that changes a macro runs them afterwards and treats an error
|
|
106
|
+
as a failure rather than a suggestion, which is most of what stops a
|
|
107
|
+
model shipping VBA that does not compile.
|
|
108
|
+
|
|
96
109
|
## License
|
|
97
110
|
|
|
98
111
|
MIT. See [LICENSE](LICENSE).
|
|
@@ -11,18 +11,18 @@ These are re-exported at the package root for convenience:
|
|
|
11
11
|
| Symbol | Role |
|
|
12
12
|
| --- | --- |
|
|
13
13
|
| `analyze_module(source, opts=None)` | Analyze one module's source; returns `list[VbaDiagnostic]`. Never raises. |
|
|
14
|
-
| `analyze_project(modules, *, only=None, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True, host=None)` | Analyze a set of `ModuleInput`s with cross-module context; returns `dict[str, list[VbaDiagnostic]]`. `whole_project=False` for a partial set. `host` names the Office host (absent means Excel). |
|
|
14
|
+
| `analyze_project(modules, *, only=None, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True, host=None, referenced_hosts=None)` | Analyze a set of `ModuleInput`s with cross-module context; returns `dict[str, list[VbaDiagnostic]]`. `whole_project=False` for a partial set. `host` names the Office host (absent means Excel). `referenced_hosts` names the other Office libraries the project references, in declaration order; `None` means the reference list is unknown, `[]` that it is known to name nothing else. |
|
|
15
15
|
| `analyze_loose_file(path, *, severity_overrides=None, conditional_compilation=None, whole_project=False, inline_suppression=True)` | Analyze one `.bas`/`.cls`/`.frm` file (partial by default; the whole-project checks are skipped). |
|
|
16
16
|
| `analyze_loose_files(paths, *, only=None, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True)` | Analyze several loose files as one project. |
|
|
17
|
-
| `analyze_workbook(path, *, only=None, severity_overrides=None, conditional_compilation=None, inline_suppression=True)` |
|
|
18
|
-
| `analyze_office_file(path, *, only=None, severity_overrides=None, conditional_compilation=None, inline_suppression=True)` |
|
|
17
|
+
| `analyze_workbook(path, *, only=None, severity_overrides=None, conditional_compilation=None, inline_suppression=True)` | The Excel-only form of `analyze_office_file`: refuses any other extension, and otherwise returns exactly what it does. |
|
|
18
|
+
| `analyze_office_file(path, *, only=None, severity_overrides=None, conditional_compilation=None, inline_suppression=True)` | Analyze the VBA in any readable Office container (Excel, Word, PowerPoint, Access, via pyOpenVBA); the extension selects the host model, and the project's reference list is read with its modules. |
|
|
19
19
|
| `host_token_for_file_name(name)` | The host a container implies (`excel`, `word`, `powerpoint`, `access`), or `None`. |
|
|
20
|
-
| `host_object_model_for_token(host)` | The model a host token selects: `None` for Excel (the default), the host's own model, or the empty model when a named host has none. |
|
|
21
|
-
| `analyze_module_options_for(index, name, kind, *, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True, host=None)` | Build per-module `AnalyzeModuleOptions` from a populated `ProjectIndex`. |
|
|
20
|
+
| `host_object_model_for_token(host)` | The model a host token selects: `None` for Excel (the default), the host's own model (`word`, `powerpoint`, `access`, `vb6`), or the empty model when a named host has none. |
|
|
21
|
+
| `analyze_module_options_for(index, name, kind, *, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True, host=None, referenced_hosts=None)` | Build per-module `AnalyzeModuleOptions` from a populated `ProjectIndex`. |
|
|
22
22
|
| `build_project_index(modules)` | A `ProjectIndex` with every module registered. |
|
|
23
23
|
| `AnalyzeModuleOptions` | Inputs for `analyze_module` (name, kind, project context, overrides). |
|
|
24
24
|
| `VbaDiagnostic` | A single diagnostic (`code`, `message`, `severity`, `span`, `spec_reference`). |
|
|
25
|
-
| `ModuleInput` | One module fed into a project (`module_name`, `module_kind`, `source`). |
|
|
25
|
+
| `ModuleInput` | One module fed into a project (`module_name`, `module_kind`, `source`), plus what a caller that read the module's designer or attribute header knows: `implicit_members` (a UserForm's controls, as `ImplicitMember`s), `predeclared_id` and `designer_class`. Left `None`, the index reads what the source itself carries. |
|
|
26
26
|
| `ModuleSymbolKind` | `STANDARD`, `CLASS`, `DOCUMENT`, `USERFORM`. |
|
|
27
27
|
| `ProjectIndex` | The cross-module symbol/type index. |
|
|
28
28
|
| `__version__` | The package version string. |
|
|
@@ -34,6 +34,12 @@ These are re-exported at the package root for convenience:
|
|
|
34
34
|
* Result model: `VbaDiagnostic`, `VbaDiagnosticData`, `VbaEdit`, and the enums
|
|
35
35
|
`DiagnosticSeverity`, `DiagnosticCategory`, `DiagnosticEvidenceKind`,
|
|
36
36
|
`DiagnosticSuppressionScope`.
|
|
37
|
+
* Code-action payloads, carried on `VbaDiagnosticData`:
|
|
38
|
+
`VbaMissingRequiredArgumentPlaceholderData`, `VbaCreateProcedureStubData`,
|
|
39
|
+
`VbaAddLibraryReferenceData` (the library a `missing-library-reference` finding
|
|
40
|
+
needs), `VbaRemoveDeclarationData` and `VbaRemoveUnreachableCodeData` (the edit
|
|
41
|
+
that deletes an unused declaration or an unreachable run), and `VbaDocCommentFix`
|
|
42
|
+
(each way to bring a doc comment in line with its declaration).
|
|
37
43
|
* Registry and metadata: `DIAGNOSTIC_RULE_REGISTRY`, `DiagnosticRuleEntry`,
|
|
38
44
|
`STRUCTURAL_DIAGNOSTIC_RULES`, `DIAGNOSTIC_RULES`, `DiagnosticRuleMetadata`,
|
|
39
45
|
`diagnostic_metadata_for_code`, `rule_metadata_by_code`, `load_rule_metadata`,
|
|
@@ -42,15 +48,22 @@ These are re-exported at the package root for convenience:
|
|
|
42
48
|
## Readers (`pyvbaanalysis.reader`)
|
|
43
49
|
|
|
44
50
|
* High level: `analyze_loose_file`, `analyze_loose_files`, `analyze_workbook`,
|
|
45
|
-
`load_loose_module`, `read_workbook_modules
|
|
51
|
+
`analyze_office_file`, `load_loose_module`, `read_workbook_modules`,
|
|
52
|
+
`read_office_modules`, `read_office_project`.
|
|
53
|
+
* `read_office_project(path)` returns an `OfficeProject`: the container's
|
|
54
|
+
`modules`, the `host` its extension implies, and `referenced_hosts`, the other
|
|
55
|
+
Office libraries its project references (`None` when the reference list could
|
|
56
|
+
not be read).
|
|
46
57
|
* Building blocks: `LoadedModule`, `strip_export_header`, `classify_module_kind`,
|
|
47
58
|
`module_name_from_text`, `loaded_module_from_text`, `WorkbookReadError`,
|
|
48
|
-
`
|
|
59
|
+
`LooseFileReadError`, and the extension sets `LOOSE_EXTENSIONS`,
|
|
60
|
+
`EXCEL_EXTENSIONS`, `WORD_EXTENSIONS`, `POWERPOINT_EXTENSIONS`,
|
|
61
|
+
`ACCESS_EXTENSIONS`, `OFFICE_EXTENSIONS`.
|
|
49
62
|
|
|
50
63
|
## Project model (`pyvbaanalysis.symbols`)
|
|
51
64
|
|
|
52
|
-
* Index: `ProjectIndex`, `ProjectIndexOptions`, `ModuleInput`, `
|
|
53
|
-
`ShadowedSpan`.
|
|
65
|
+
* Index: `ProjectIndex`, `ProjectIndexOptions`, `ModuleInput`, `ImplicitMember`,
|
|
66
|
+
`ReferenceScope`, `ShadowedSpan`.
|
|
54
67
|
* Module symbols: `build_module_symbols`, `BuildModuleSymbolsOptions`,
|
|
55
68
|
`ModuleSymbols`, `ModuleSymbolKind`, `SymbolVisibility`, `VbaSymbol`,
|
|
56
69
|
`VbaSymbolKind`, `VbaSymbolAttribute`, `VbaProcedureSignature`,
|
|
@@ -72,7 +85,9 @@ them directly, but they are public and stable.
|
|
|
72
85
|
| `pyvbaanalysis.conditional` | Conditional-compilation indexing and activity (`index_conditional_compilation`, `evaluate_conditional_expression`, ...). |
|
|
73
86
|
| `pyvbaanalysis.types` | Type-name helpers: `normalize_type`, `is_known_scalar_type`, `is_numeric_type`, `numeric_literal_bounds`. |
|
|
74
87
|
| `pyvbaanalysis.completion` | Member-completion surface and project-type resolution (`resolve_member_surface_at`, `resolve_type_name`, ...). |
|
|
75
|
-
| `pyvbaanalysis.host` | The Excel, Word, PowerPoint and
|
|
88
|
+
| `pyvbaanalysis.host` | The Excel, Word, PowerPoint, Access and VB6 object models and the host registry (`get_excel_object_model`, `get_vb6_object_model`, `host_object_model_for_token`, `resolve_host_alias`, ...). `host_object_model_for_tokens` merges the models for a project and its references, the first token winning a shared name; `host_token_for_libid`, `host_tokens_for_project` and `referenced_host_tokens` map a project's reference libids to host tokens. `pyvbaanalysis.host.msforms` carries the Microsoft Forms members of a UserForm and its controls (`msforms_control_members`, `resolve_msforms_type_name`). |
|
|
89
|
+
| `pyvbaanalysis.references` | `classify_reference_kinds`: whether each mention of a name reads it, writes it, or modifies it in place. |
|
|
90
|
+
| `pyvbaanalysis.docs` | The `'''` doc-comment grammar: `leading_doc_lines`, `scan_doc_tags`, `attached_comments_start`. |
|
|
76
91
|
| `pyvbaanalysis.runtime` | VBA runtime functions, constants, and objects (`resolve_runtime_function`, ...). |
|
|
77
92
|
| `pyvbaanalysis.call` | Call-statement shape helpers. |
|
|
78
93
|
| `pyvbaanalysis.flow` | Procedure labels and unstructured-flow detection. |
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Diagnostic catalogue
|
|
2
2
|
|
|
3
|
-
The diagnostic codes pyVBAanalysis can emit, generated from the rule metadata (`tools/generate_diagnostics_catalogue.py`). This table lists the
|
|
3
|
+
The diagnostic codes pyVBAanalysis can emit, generated from the rule metadata (`tools/generate_diagnostics_catalogue.py`). This table lists the 131 rule-metadata codes across 6 categories. A further 3 structural block-balance codes (`mismatched-end-keyword`, `missing-block-closer`, `unmatched-block-closer`) are emitted by the parser pass and are not in the metadata table, for a full set of 134 codes.
|
|
4
4
|
|
|
5
5
|
Each code is reported only when it is provably correct; anything unknown or ambiguous stays quiet (the no-false-positive discipline). The **kind** column says what a code means: a *compile error* is rejected by the VBE compiler, a *runtime error* is a deterministic Run-time error, a *runtime risk* is a likely fault, and *style* is advisory.
|
|
6
6
|
|
|
7
7
|
Override a code's severity with `AnalyzeModuleOptions.severity_overrides` (or the `severity_overrides` argument of `analyze_project` / the reader functions), keyed by code. Use `"off"`, `"information"`, `"warning"`, or `"error"`; the allowed values per code are constrained by policy (some codes can be downgraded but not disabled). See [docs/usage.md](usage.md).
|
|
8
8
|
|
|
9
|
-
## Declaration (
|
|
9
|
+
## Declaration (42)
|
|
10
10
|
|
|
11
11
|
| Code | Title | Default | Kind | Spec reference |
|
|
12
12
|
| --- | --- | --- | --- | --- |
|
|
@@ -29,6 +29,7 @@ Override a code's severity with `AnalyzeModuleOptions.severity_overrides` (or th
|
|
|
29
29
|
| `invalid-identifier-character` | Invalid character in identifier | error | compile error | MS-VBAL 3.3.5 (identifier) / VBE compiler |
|
|
30
30
|
| `invalid-identifier-start` | Invalid identifier start | error | compile error | MS-VBAL 3.3.5 |
|
|
31
31
|
| `invalid-new-type-name` | Type cannot be created with New | error | compile error | MS-VBAL 5.2.3.1 / 5.6.9 |
|
|
32
|
+
| `invalid-option-statement` | Malformed Option statement | error | compile error | MS-VBAL 5.2.1 (module options) / VBE compiler |
|
|
32
33
|
| `invalid-proc-header` | Invalid procedure declaration | error | compile error | MS-VBAL 5.3.1 |
|
|
33
34
|
| `module-declaration-after-procedure` | Module-level declaration after procedure | error | compile error | MS-VBAL 5.2 / 5.3 |
|
|
34
35
|
| `module-declaration-in-procedure` | Module-level declaration inside procedure | error | compile error | MS-VBAL 5.2 / 5.3 |
|
|
@@ -57,7 +58,7 @@ Override a code's severity with `AnalyzeModuleOptions.severity_overrides` (or th
|
|
|
57
58
|
| Code | Title | Default | Kind | Spec reference |
|
|
58
59
|
| --- | --- | --- | --- | --- |
|
|
59
60
|
| `event-declaration-module-kind` | Event declaration is not valid in this module | error | compile error | MS-VBAL 5.2.5: Event declarations belong to object modules |
|
|
60
|
-
| `event-handler-module-scope` | Event handler is not wired in this module | information | style-policy |
|
|
61
|
+
| `event-handler-module-scope` | Event handler is not wired in this module | information | style-policy | Office document-module event binding |
|
|
61
62
|
| `friend-declaration` | Invalid Friend declaration | error | compile error | MS-VBAL Friend procedure visibility: object-module procedures only |
|
|
62
63
|
| `implements-statement-placement` | Invalid Implements statement | error | compile error | MS-VBAL Implements statement: module-level object-module declaration |
|
|
63
64
|
| `withevents-declaration` | Invalid WithEvents declaration | error | compile error | MS-VBAL 5.2.3: WithEvents object variable declarations |
|
|
@@ -69,7 +70,7 @@ Override a code's severity with `AnalyzeModuleOptions.severity_overrides` (or th
|
|
|
69
70
|
| `undeclared-variable` | Variable not defined | error | compile error | MS-VBAL 5.2.4.1.1 |
|
|
70
71
|
| `unknown-call` | Sub or Function not defined | error | compile error | MS-VBAL 5.4.2.1 |
|
|
71
72
|
|
|
72
|
-
## Semantic (
|
|
73
|
+
## Semantic (52)
|
|
73
74
|
|
|
74
75
|
| Code | Title | Default | Kind | Spec reference |
|
|
75
76
|
| --- | --- | --- | --- | --- |
|
|
@@ -105,6 +106,7 @@ Override a code's severity with `AnalyzeModuleOptions.severity_overrides` (or th
|
|
|
105
106
|
| `member-access-outside-with` | Leading member access outside With block | error | compile error | MS-VBAL 5.4.2.6 |
|
|
106
107
|
| `member-not-found` | Object member not found | error | compile error | VBE compiler: Method or data member not found |
|
|
107
108
|
| `mid-statement-literal-target` | Mid statement target must be a writable String variable | error | compile error | MS-VBAL 5.4.3.4 (Mid/MidB statement) |
|
|
109
|
+
| `missing-library-reference` | Type library not referenced | error | compile error | VBE compiler: User-defined type not defined |
|
|
108
110
|
| `missing-return-assignment` | Function has no return assignment | warning | runtime risk | VBA Function return variable semantics |
|
|
109
111
|
| `next-variable-mismatch` | Next variable does not match active For loop | error | compile error | MS-VBAL 5.4.2.5 |
|
|
110
112
|
| `non-callable-call` | Identifier is not callable | error | compile error | MS-VBAL 5.4.2.1 |
|
|
@@ -125,12 +127,22 @@ Override a code's severity with `AnalyzeModuleOptions.severity_overrides` (or th
|
|
|
125
127
|
| `unallocated-dynamic-array-access` | Dynamic array is not allocated | error | runtime error | VBE runtime error 9: Subscript out of range |
|
|
126
128
|
| `undefined-label` | Label not defined | error | compile error | MS-VBAL 5.4.1 / VBE compiler: Label not defined |
|
|
127
129
|
|
|
128
|
-
## Style (
|
|
130
|
+
## Style (13)
|
|
129
131
|
|
|
130
132
|
| Code | Title | Default | Kind | Spec reference |
|
|
131
133
|
| --- | --- | --- | --- | --- |
|
|
132
134
|
| `analysis-suppression-directive` | Invalid analysis suppression directive | warning | style-policy | Analysis suppression directive comment syntax |
|
|
135
|
+
| `doc-param-missing` | Doc comment does not describe a parameter | warning | style-policy | Doc comment syntax |
|
|
136
|
+
| `doc-param-unknown` | Doc comment describes a parameter the declaration does not have | warning | style-policy | Doc comment syntax |
|
|
137
|
+
| `doc-returns-missing` | Doc comment does not describe the return value | warning | style-policy | Doc comment syntax |
|
|
138
|
+
| `doc-returns-unexpected` | Doc comment describes a return value the declaration does not have | warning | style-policy | Doc comment syntax |
|
|
139
|
+
| `doc-tag-duplicate` | Doc comment repeats a tag | warning | style-policy | Doc comment syntax |
|
|
140
|
+
| `doc-tag-unclosed` | Doc comment tag is not closed | warning | style-policy | Doc comment syntax |
|
|
133
141
|
| `option-explicit-missing` | Option Explicit is not specified | warning | style-policy | MS-VBAL 5.2.4.1.1 |
|
|
142
|
+
| `unreachable-code` | Code is never reached | information | style-policy | MS-VBAL 5.4.1.3 (Exit), 5.4.1.4 (GoTo), 5.4.4 (Resume) plus dead-code policy |
|
|
143
|
+
| `unused-procedure` | Private procedure is never called | information | style-policy | MS-VBAL 5.3.1.1 (Private procedure visibility) plus dead-code policy |
|
|
144
|
+
| `unused-variable` | Variable or constant is never used | information | style-policy | MS-VBAL 5.2.3 / 5.4.3.1 (declaration scope) plus dead-code policy |
|
|
145
|
+
| `variable-never-read` | Variable is assigned but never read | information | style-policy | MS-VBAL 5.4.3 (assignment) plus dead-code policy |
|
|
134
146
|
| `vba-test-directive` | Invalid VBA test directive | warning | style-policy | VBA test directive comment syntax |
|
|
135
147
|
|
|
136
148
|
## Syntax (17)
|
|
@@ -162,7 +162,16 @@ and never against Excel's. Analyzing a Word module under Excel's model reports
|
|
|
162
162
|
members and constants that are perfectly legal in Word (`Selection.TypeText`,
|
|
163
163
|
`ActiveDocument`, `wdOrientPortrait`), which is the false positive this avoids.
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
The project's reference list is read with its modules. A workbook that references
|
|
166
|
+
the Word object library can declare `Dim doc As Word.Document` and use Word's
|
|
167
|
+
constants, and those are checked against Word's model. A workbook that names
|
|
168
|
+
`Word.Document` without the reference reports `missing-library-reference`: the VBE
|
|
169
|
+
refuses that declaration with "User-defined type not defined". To read a container
|
|
170
|
+
without analyzing it, `read_office_project(path)` in `pyvbaanalysis.reader` returns
|
|
171
|
+
its modules, its host, and the other Office libraries it references.
|
|
172
|
+
|
|
173
|
+
`analyze_workbook` is the Excel-only form of the same call: it refuses any other
|
|
174
|
+
extension and otherwise returns exactly what `analyze_office_file` does.
|
|
166
175
|
|
|
167
176
|
A path that is not a readable container, or a container with no readable VBA, raises
|
|
168
177
|
`WorkbookReadError`. Legacy `.ppt` is not readable: pyOpenVBA reads it as a plain
|
|
@@ -180,10 +189,29 @@ knowledge at all rather than falling back to Excel's.
|
|
|
180
189
|
from pyvbaanalysis import analyze_project
|
|
181
190
|
|
|
182
191
|
analyze_project(modules, host="word") # Word's object model
|
|
192
|
+
analyze_project(modules, host="vb6") # VB6: App, Screen, Printer, the intrinsic controls
|
|
183
193
|
analyze_project(modules, host="outlook") # no model yet: stays quiet, never Excel's
|
|
184
194
|
analyze_project(modules) # Excel, exactly as before
|
|
185
195
|
```
|
|
186
196
|
|
|
197
|
+
A VB6 project is no Office container, so nothing reads one from a file; pass its
|
|
198
|
+
modules with `host="vb6"`. The VB6 model offers and describes, and never proves a
|
|
199
|
+
member absent.
|
|
200
|
+
|
|
201
|
+
Name the other Office libraries the project references the same way, in the order
|
|
202
|
+
its References dialog lists them. The project's own host wins any name two
|
|
203
|
+
libraries share, as it does in VBA:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
analyze_project(modules, referenced_hosts=["word"]) # an Excel project referencing Word
|
|
207
|
+
analyze_project(modules, referenced_hosts=[]) # known to reference nothing else
|
|
208
|
+
analyze_project(modules) # reference list unknown
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`missing-library-reference` only reports against a known list. Left unset, the list
|
|
212
|
+
is unknown, as it is for loose `.bas` files, and the check stays silent rather than
|
|
213
|
+
guess that a reference is missing.
|
|
214
|
+
|
|
187
215
|
The reader loads the workbook and its VBA into memory and does not bound the input
|
|
188
216
|
size, so impose your own limit (for example a maximum file size) before pointing it
|
|
189
217
|
at untrusted files.
|
|
@@ -335,3 +363,7 @@ workbook. Tune the gate with the flags above: `--fail-level warning` to also fai
|
|
|
335
363
|
warnings, `--severity option-explicit-missing=off` or `--ignore <code>` to mute a
|
|
336
364
|
code, and `--partial-project` when the checked-in files are only a fragment of the
|
|
337
365
|
project. Use `--format json` if a later step needs to parse the results.
|
|
366
|
+
|
|
367
|
+
The dead-code checks (`unused-variable`, `variable-never-read`, `unused-procedure`,
|
|
368
|
+
`unreachable-code`) report at `information` level. Without `--fail-level`, the gate
|
|
369
|
+
fails on any diagnostic, so a single unused variable fails the run.
|
|
@@ -38,7 +38,7 @@ dependencies = ["pyOpenVBA>=3.4.0"]
|
|
|
38
38
|
# underneath main (ruff 0.16 broke a green tree with zero repo commits).
|
|
39
39
|
# Dependabot's weekly pip updates turn each tool upgrade into its own gated
|
|
40
40
|
# PR, where a red CI run blocks the bump instead of breaking main.
|
|
41
|
-
dev = ["pytest==9.1.1", "ruff==0.16.
|
|
41
|
+
dev = ["pytest==9.1.1", "ruff==0.16.8", "mypy==2.3.1"]
|
|
42
42
|
build = ["build>=1.2", "twine>=5"]
|
|
43
43
|
|
|
44
44
|
[project.scripts]
|
|
@@ -65,11 +65,13 @@ exclude = [
|
|
|
65
65
|
|
|
66
66
|
[tool.hatch.build.targets.sdist]
|
|
67
67
|
# Keep internal development notes out of the published sdist. The evidence corpus
|
|
68
|
-
# stays in (the test suite needs it); only the agent/working notes are excluded
|
|
68
|
+
# stays in (the test suite needs it); only the agent/working notes are excluded,
|
|
69
|
+
# with the differential harness, which runs only against an XLIDE checkout.
|
|
69
70
|
exclude = [
|
|
70
71
|
"agent.md",
|
|
71
72
|
"docs/agentic_ai_programming_best_practices.md",
|
|
72
73
|
"docs/AI-Smells-Agents-Avoid.md",
|
|
74
|
+
"tools/differential/",
|
|
73
75
|
]
|
|
74
76
|
|
|
75
77
|
[tool.pytest.ini_options]
|