pyvbaanalysis 2.0.0__tar.gz → 2.1.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.0.0 → pyvbaanalysis-2.1.0}/CHANGELOG.md +63 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/PKG-INFO +1 -1
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/docs/diagnostics-catalogue.md +3 -2
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/__init__.py +1 -1
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/conditional/conditional_compilation.py +80 -3
- pyvbaanalysis-2.1.0/pyvbaanalysis/data/access_host_model.json +1 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/data/diagnostic_influence_audit.json +14 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/data/event_definitions.json +1 -1
- pyvbaanalysis-2.1.0/pyvbaanalysis/data/excel_host_model.json +1 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/data/manifest.json +12 -10
- pyvbaanalysis-2.1.0/pyvbaanalysis/data/powerpoint_host_model.json +1 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/data/rule_metadata.json +11 -0
- pyvbaanalysis-2.1.0/pyvbaanalysis/data/vba_runtime_tables.json +1 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/data/vbe_oracle_cases.json +64 -0
- pyvbaanalysis-2.1.0/pyvbaanalysis/data/word_host_model.json +1 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/context.py +4 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/registry.py +16 -4
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/assignments.py +91 -15
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/control_flow.py +54 -20
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/declarations.py +28 -6
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/duplicates.py +186 -56
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/module_kind.py +10 -3
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/walker.py +18 -1
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/parser/nodes.py +6 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/parser/parse_module.py +25 -1
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/project.py +1 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/symbols/project_index.py +11 -0
- pyvbaanalysis-2.1.0/tests/test_conditional_arms.py +212 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_evidence.py +2 -2
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rule_metadata.py +5 -5
- pyvbaanalysis-2.1.0/tests/test_upstream_sync_6_1_2.py +169 -0
- pyvbaanalysis-2.0.0/pyvbaanalysis/data/access_host_model.json +0 -1
- pyvbaanalysis-2.0.0/pyvbaanalysis/data/excel_host_model.json +0 -1
- pyvbaanalysis-2.0.0/pyvbaanalysis/data/powerpoint_host_model.json +0 -1
- pyvbaanalysis-2.0.0/pyvbaanalysis/data/vba_runtime_tables.json +0 -1
- pyvbaanalysis-2.0.0/pyvbaanalysis/data/word_host_model.json +0 -1
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/.gitattributes +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/.github/dependabot.yml +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/.github/workflows/ci.yml +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/.github/workflows/publish.yml +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/.gitignore +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/CONTRIBUTING.md +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/LICENSE +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/README.md +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/docs/api-reference.md +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/docs/usage.md +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyproject.toml +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/__main__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/call/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/call/call_context.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/cli.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/completion/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/completion/cursor_context.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/completion/event_handlers.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/completion/member_access.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/completion/type_completion.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/conditional/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/constants/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/constants/integer_constant_expression.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/analyze_module.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/argument_inference.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/call_extraction.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/callable_signatures.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/const_expr.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/dataflow.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/exprwalk.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/inline_suppression.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/model.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rule_metadata.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/argument_shape.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/argument_types.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/arrays.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/binary_operand_scalar.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/call_arity.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/expressions.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/late_binding.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/lexical.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/numeric_literals.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/object_state.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/parameter_defaults.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/runtime_values.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/shared.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/type_of_is.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/diagnostics/rules/undeclared.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/evidence.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/flow/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/flow/procedure_labels.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/flow/procedure_unstructured.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/host/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/host/host_model.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/host/host_registry.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/identity_cache.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/lexer/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/lexer/keyword_table.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/lexer/stripped_lines.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/lexer/token_helpers.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/lexer/token_kinds.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/lexer/tokenize.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/lexer/trivia.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/parser/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/parser/fixed_length_string.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/parser/parse_expression.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/parser/parser_state.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/parser/type_declaration_suffix.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/py.typed +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/reader/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/reader/loose_file.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/reader/vbe_module.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/reader/workbook.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/runtime/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/runtime/vba_runtime.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/symbols/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/symbols/build_module_symbols.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/symbols/name_resolution.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/symbols/symbol_model.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/types/__init__.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/types/type_inference.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/types/type_names.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/conftest.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/oracle_support.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_cli.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_conditional_compilation.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_dataflow.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_diagnostics_engine.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_host_model.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_host_seam.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_inline_suppression.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_integer_constant_expression.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_language_matrix.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_lexer.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_member_access_chains.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_parser.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_project.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_project_index.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_public_api.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_reader.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_real_world_false_positives.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_registry_parity.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_ambiguous_enum_member.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_argument_shape.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_argument_types.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_arrays.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_assignments.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_assignments_types.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_binary_operand_scalar.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_call_arity.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_control_flow.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_declarations.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_division_by_zero.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_duplicates.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_event_handler_module_scope.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_expression_calls.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_expressions.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_invalid_as_type_names.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_is_operator_non_object.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_late_binding.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_lexical.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_member_not_found.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_module_kind.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_numeric_literals.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_object_state.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_parameter_defaults.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_property_setter_value_parameters.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_runtime_values.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_scalar_and_foreach.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_type_of_is.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_typeof_is_always_false.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_rules_undeclared.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_runtime_tables.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_statement_token_derivation.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_stripped_lines.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_symbols.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_token_helpers.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_type_completion.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tests/test_type_names.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tools/extract_event_definitions.mjs +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tools/extract_host_model.mjs +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tools/extract_rule_metadata.mjs +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tools/extract_runtime_tables.mjs +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tools/generate_diagnostics_catalogue.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tools/generate_manifest.py +0 -0
- {pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/tools/oracle/build_combining_mark_probe.py +0 -0
|
@@ -5,6 +5,69 @@ 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.1.0 - 2026-09-05
|
|
9
|
+
|
|
10
|
+
Sync to XLIDE 6.1.2, the analyzer's first re-pin since 3.1.4. Verified by a
|
|
11
|
+
differential against the upstream analyzer over the whole oracle corpus: 418 of
|
|
12
|
+
418 cases identical, in both directions.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
* `ambiguousProjectProcedure`: VBA is content for two modules to export the same
|
|
17
|
+
public procedure name, but it refuses to compile an UNQUALIFIED call to that
|
|
18
|
+
name from a module declaring neither. The finding sits at the call site, not
|
|
19
|
+
the declarations, because a project that exports a name twice and always
|
|
20
|
+
qualifies its calls is legal VBA and common. Silent when the call is
|
|
21
|
+
qualified, when the calling module declares the name itself, when a local or
|
|
22
|
+
parameter shadows it, or when only one module exports it.
|
|
23
|
+
* `ConditionalActivityTracker.mutually_exclusive` and `in_same_branch`, the
|
|
24
|
+
primitive the arm-aware rules below need, plus
|
|
25
|
+
`ProjectIndex.implemented_interface_names()` and the
|
|
26
|
+
`AnalyzeModuleOptions.implemented_interfaces` option it feeds.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
* Rules no longer pair declarations from mutually exclusive `#If` arms. Only one
|
|
31
|
+
arm of a chain is ever built, so two declarations in different arms are
|
|
32
|
+
alternatives rather than duplicates. With a compiler constant the analyzer
|
|
33
|
+
cannot evaluate, the ordinary `#If VBA7 / #Else` idiom reported
|
|
34
|
+
`duplicate-procedure` and `duplicate-module-variable` on legal code. The same
|
|
35
|
+
reasoning now covers duplicate declarations and labels, undefined labels,
|
|
36
|
+
`For`/`Next` pairing, `Else` branch order, `Option` placement, and `Implements`
|
|
37
|
+
placement (XLIDE issue #58).
|
|
38
|
+
* A `#Const` directive may precede `Option Explicit`. A conditional-compilation
|
|
39
|
+
directive is not a declaration, and the live VBE compiles it there
|
|
40
|
+
(oracle case `const_directive_before_option_explicit_compile`).
|
|
41
|
+
* Three gaps in return-assignment detection, each of which the widened rule below
|
|
42
|
+
would otherwise have turned into a false positive:
|
|
43
|
+
assigning a field of the returned value (`MsToSystemTime.wYear = ...`) is a
|
|
44
|
+
return assignment; so is an assignment inside a single-line `If`, whose
|
|
45
|
+
branches the statement walk never entered; and a name that SPELLS a keyword is
|
|
46
|
+
still an assignment target, so `Function Read()` assigning `Read = True` was
|
|
47
|
+
read as never assigning its return. Measured on one real workbook these three
|
|
48
|
+
accounted for nine false findings.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
* `missingReturnAssignment` now covers every Function and Property Get, not only
|
|
53
|
+
untyped ones, so a typed Function that never assigns its return reports. An
|
|
54
|
+
empty member of a module some other module declares with `Implements` stays
|
|
55
|
+
silent: that is a contract for an implementer to fill in, not unfinished code.
|
|
56
|
+
A body whose work is to raise stays silent too. **This reports on code that was
|
|
57
|
+
previously quiet**; the rule is warning severity and can be turned off through
|
|
58
|
+
`severity_overrides`.
|
|
59
|
+
* The vendored host models grew with upstream's move to the whole documented
|
|
60
|
+
object model: Excel 229 to 651 types, Word 364 to 627, PowerPoint 201 to 464,
|
|
61
|
+
Access 188 to 451. The wheel grows from 0.94 MB to 1.84 MB; the models still
|
|
62
|
+
load lazily, so import cost is unchanged.
|
|
63
|
+
* Data re-pinned to XLIDE 6.1.2: 418 oracle cases (was 415), 122 audited codes
|
|
64
|
+
(was 121), 119 rules (was 118).
|
|
65
|
+
|
|
66
|
+
### Known limits
|
|
67
|
+
|
|
68
|
+
* Upstream's form-control member work is not ported, and the oracle corpus has no
|
|
69
|
+
UserForm designer cases, so that area is untested here rather than verified.
|
|
70
|
+
|
|
8
71
|
## 2.0.0 - 2026-08-19
|
|
9
72
|
|
|
10
73
|
Multi-host analysis: VBA is now measured against the object model of the Office
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pyvbaanalysis
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.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
|
|
@@ -1,6 +1,6 @@
|
|
|
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 119 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 122 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
|
|
|
@@ -69,11 +69,12 @@ Override a code's severity with `AnalyzeModuleOptions.severity_overrides` (or th
|
|
|
69
69
|
| `undeclared-variable` | Variable not defined | error | compile error | MS-VBAL 5.2.4.1.1 |
|
|
70
70
|
| `unknown-call` | Sub or Function not defined | error | compile error | MS-VBAL 5.4.2.1 |
|
|
71
71
|
|
|
72
|
-
## Semantic (
|
|
72
|
+
## Semantic (51)
|
|
73
73
|
|
|
74
74
|
| Code | Title | Default | Kind | Spec reference |
|
|
75
75
|
| --- | --- | --- | --- | --- |
|
|
76
76
|
| `ambiguous-enum-member` | Ambiguous Enum member reference | error | compile error | VBE compiler: Ambiguous name detected |
|
|
77
|
+
| `ambiguous-project-procedure` | Ambiguous unqualified call to a name two modules export | error | compile error | VBE compiler: Ambiguous name detected |
|
|
77
78
|
| `argument-count` | Wrong number of arguments | error | compile error | MS-VBAL 5.4.2.1 |
|
|
78
79
|
| `argument-object-type-mismatch` | Object argument type mismatch | error | compile error | MS-VBAL 5.3.1 |
|
|
79
80
|
| `argument-shape-mismatch` | Argument shape (array/Type vs scalar) mismatch | error | compile error | MS-VBAL 5.3.1 (argument passing) / VBE compiler: ByRef argument type mismatch; array or user-defined type expected |
|
{pyvbaanalysis-2.0.0 → pyvbaanalysis-2.1.0}/pyvbaanalysis/conditional/conditional_compilation.py
RENAMED
|
@@ -114,10 +114,42 @@ class _ConditionalFrame:
|
|
|
114
114
|
seen_unknown: bool
|
|
115
115
|
|
|
116
116
|
|
|
117
|
+
@dataclass(frozen=True, slots=True)
|
|
118
|
+
class _ConditionalArm:
|
|
119
|
+
"""One arm of one `#If` chain, as a persistent stack.
|
|
120
|
+
|
|
121
|
+
``parent`` is the enclosing chain's arm. Immutable, so an event can keep the
|
|
122
|
+
arm that was in effect when it was recorded without copying the stack, and
|
|
123
|
+
one arm is one object, which makes identity the comparison for
|
|
124
|
+
``in_same_branch``.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
chain: int
|
|
128
|
+
#: 0 for the `#If`, then one per `#ElseIf` / `#Else`.
|
|
129
|
+
index: int
|
|
130
|
+
parent: "_ConditionalArm | None"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _arms_diverge(a: _ConditionalArm | None, b: _ConditionalArm | None) -> bool:
|
|
134
|
+
"""Whether two arm stacks disagree about which arm of a shared chain they are
|
|
135
|
+
in. The branches then exclude each other whatever the constants are worth.
|
|
136
|
+
Stacks are as deep as the source nests directives, so the walk is short."""
|
|
137
|
+
outer = a
|
|
138
|
+
while outer is not None:
|
|
139
|
+
inner = b
|
|
140
|
+
while inner is not None:
|
|
141
|
+
if outer.chain == inner.chain:
|
|
142
|
+
return outer.index != inner.index
|
|
143
|
+
inner = inner.parent
|
|
144
|
+
outer = outer.parent
|
|
145
|
+
return False
|
|
146
|
+
|
|
147
|
+
|
|
117
148
|
@dataclass(slots=True)
|
|
118
149
|
class _ConditionalActivityEvent:
|
|
119
150
|
start: int
|
|
120
151
|
activity: ConditionalActivity
|
|
152
|
+
branch: _ConditionalArm | None = None
|
|
121
153
|
|
|
122
154
|
|
|
123
155
|
class ConditionalActivityTracker:
|
|
@@ -128,7 +160,7 @@ class ConditionalActivityTracker:
|
|
|
128
160
|
def __init__(self, events: list[_ConditionalActivityEvent]) -> None:
|
|
129
161
|
self._events = events
|
|
130
162
|
|
|
131
|
-
def
|
|
163
|
+
def _event_for_span(self, span: Span) -> _ConditionalActivityEvent | None:
|
|
132
164
|
# Directives starting at or after the queried offset are not applied.
|
|
133
165
|
lo = -1
|
|
134
166
|
hi = len(self._events) - 1
|
|
@@ -138,11 +170,41 @@ class ConditionalActivityTracker:
|
|
|
138
170
|
lo = mid
|
|
139
171
|
else:
|
|
140
172
|
hi = mid - 1
|
|
141
|
-
return self._events[lo]
|
|
173
|
+
return self._events[lo] if lo >= 0 else None
|
|
174
|
+
|
|
175
|
+
def activity_for_span(self, span: Span) -> ConditionalActivity:
|
|
176
|
+
event = self._event_for_span(span)
|
|
177
|
+
return event.activity if event is not None else ConditionalActivity.ACTIVE
|
|
142
178
|
|
|
143
179
|
def is_inactive(self, span: Span) -> bool:
|
|
144
180
|
return self.activity_for_span(span) is ConditionalActivity.INACTIVE
|
|
145
181
|
|
|
182
|
+
def mutually_exclusive(self, a: Span, b: Span) -> bool:
|
|
183
|
+
"""Whether the two spans sit in different arms of one `#If` chain, and so
|
|
184
|
+
are never compiled together however the constants evaluate."""
|
|
185
|
+
left = self._event_for_span(a)
|
|
186
|
+
right = self._event_for_span(b)
|
|
187
|
+
return _arms_diverge(
|
|
188
|
+
left.branch if left is not None else None,
|
|
189
|
+
right.branch if right is not None else None,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def in_same_branch(self, a: Span, b: Span) -> bool:
|
|
193
|
+
"""Whether the two spans sit under exactly the same arms, so every build
|
|
194
|
+
either compiles both or neither.
|
|
195
|
+
|
|
196
|
+
Stricter than "not mutually exclusive": spans in two SEPARATE chains are
|
|
197
|
+
neither exclusive nor in the same branch, because a build may take one and
|
|
198
|
+
not the other. Rules that pair two pieces of one construct need this, since
|
|
199
|
+
a pairing made across different chains is a guess about a build that may
|
|
200
|
+
never exist.
|
|
201
|
+
"""
|
|
202
|
+
left = self._event_for_span(a)
|
|
203
|
+
right = self._event_for_span(b)
|
|
204
|
+
return (left.branch if left is not None else None) is (
|
|
205
|
+
right.branch if right is not None else None
|
|
206
|
+
)
|
|
207
|
+
|
|
146
208
|
|
|
147
209
|
def create_conditional_activity_tracker(
|
|
148
210
|
module: ModuleNode, env: ConditionalCompilationEnvironment | None = None
|
|
@@ -162,10 +224,25 @@ def _collect_conditional_activity_events(
|
|
|
162
224
|
project_constants = _lowercased(effective_env.project_constants)
|
|
163
225
|
stack: list[_ConditionalFrame] = []
|
|
164
226
|
current = ConditionalActivity.ACTIVE
|
|
227
|
+
branch: _ConditionalArm | None = None
|
|
228
|
+
chains = 0
|
|
165
229
|
events: list[_ConditionalActivityEvent] = []
|
|
166
230
|
for occ in directives:
|
|
167
231
|
current = _apply_conditional_directive(occ.directive, effective_env, project_constants, stack, current)
|
|
168
|
-
|
|
232
|
+
kind = occ.directive.directive_kind
|
|
233
|
+
if kind is ConditionalDirectiveKind.IF:
|
|
234
|
+
branch = _ConditionalArm(chain=chains, index=0, parent=branch)
|
|
235
|
+
chains += 1
|
|
236
|
+
elif kind in (ConditionalDirectiveKind.ELSE_IF, ConditionalDirectiveKind.ELSE):
|
|
237
|
+
# An `#ElseIf` with no open `#If` is a parse-level error; leave the
|
|
238
|
+
# stack alone rather than inventing an arm for it.
|
|
239
|
+
if branch is not None:
|
|
240
|
+
branch = _ConditionalArm(chain=branch.chain, index=branch.index + 1, parent=branch.parent)
|
|
241
|
+
elif kind is ConditionalDirectiveKind.END_IF:
|
|
242
|
+
branch = branch.parent if branch is not None else None
|
|
243
|
+
events.append(
|
|
244
|
+
_ConditionalActivityEvent(start=occ.directive.span.start, activity=current, branch=branch)
|
|
245
|
+
)
|
|
169
246
|
return events
|
|
170
247
|
|
|
171
248
|
|