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.
Files changed (211) hide show
  1. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.gitignore +3 -0
  2. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/CHANGELOG.md +216 -0
  3. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/CONTRIBUTING.md +61 -7
  4. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/PKG-INFO +16 -3
  5. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/README.md +13 -0
  6. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/docs/api-reference.md +26 -11
  7. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/docs/diagnostics-catalogue.md +17 -5
  8. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/docs/usage.md +33 -1
  9. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyproject.toml +4 -2
  10. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/__init__.py +1 -1
  11. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/cli.py +5 -4
  12. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/event_handlers.py +14 -8
  13. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/member_access.py +408 -99
  14. pyvbaanalysis-2.2.0/pyvbaanalysis/data/access_host_model.json +1 -0
  15. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/diagnostic_influence_audit.json +159 -2
  16. pyvbaanalysis-2.2.0/pyvbaanalysis/data/excel_closed_types.json +31 -0
  17. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/excel_host_model.json +1 -1
  18. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/manifest.json +35 -10
  19. pyvbaanalysis-2.2.0/pyvbaanalysis/data/msforms_members.json +1 -0
  20. pyvbaanalysis-2.2.0/pyvbaanalysis/data/powerpoint_host_model.json +1 -0
  21. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/rule_metadata.json +139 -1
  22. pyvbaanalysis-2.2.0/pyvbaanalysis/data/vb6_host_model.json +1 -0
  23. pyvbaanalysis-2.2.0/pyvbaanalysis/data/vba_runtime_tables.json +1 -0
  24. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/vbe_oracle_cases.json +286 -0
  25. pyvbaanalysis-2.2.0/pyvbaanalysis/data/word_host_model.json +1 -0
  26. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/__init__.py +8 -0
  27. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/analyze_module.py +36 -8
  28. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/argument_inference.py +289 -14
  29. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/call_extraction.py +9 -5
  30. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/callable_signatures.py +255 -15
  31. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/const_expr.py +62 -4
  32. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/context.py +23 -0
  33. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/dataflow.py +53 -18
  34. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/model.py +36 -0
  35. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/registry.py +74 -7
  36. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rule_metadata.py +3 -1
  37. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/argument_types.py +19 -4
  38. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/arrays.py +32 -5
  39. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/assignments.py +50 -15
  40. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/call_arity.py +77 -8
  41. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/control_flow.py +33 -22
  42. pyvbaanalysis-2.2.0/pyvbaanalysis/diagnostics/rules/dead_code.py +562 -0
  43. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/declarations.py +139 -30
  44. pyvbaanalysis-2.2.0/pyvbaanalysis/diagnostics/rules/doc_comments.py +372 -0
  45. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/duplicates.py +55 -33
  46. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/expressions.py +5 -7
  47. pyvbaanalysis-2.2.0/pyvbaanalysis/diagnostics/rules/missing_reference.py +136 -0
  48. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/module_kind.py +5 -3
  49. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/object_state.py +44 -19
  50. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/parameter_defaults.py +8 -7
  51. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/runtime_values.py +7 -8
  52. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/shared.py +153 -12
  53. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/type_of_is.py +15 -64
  54. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/undeclared.py +95 -1
  55. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/walker.py +1 -1
  56. pyvbaanalysis-2.2.0/pyvbaanalysis/docs/__init__.py +19 -0
  57. pyvbaanalysis-2.2.0/pyvbaanalysis/docs/doc_comment.py +231 -0
  58. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/host/__init__.py +8 -0
  59. pyvbaanalysis-2.2.0/pyvbaanalysis/host/host_libraries.py +92 -0
  60. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/host/host_model.py +88 -3
  61. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/host/host_registry.py +76 -2
  62. pyvbaanalysis-2.2.0/pyvbaanalysis/host/msforms.py +91 -0
  63. pyvbaanalysis-2.2.0/pyvbaanalysis/host/type_extensibility.py +74 -0
  64. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/token_helpers.py +43 -2
  65. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/parse_module.py +7 -1
  66. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/project.py +18 -3
  67. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/__init__.py +4 -0
  68. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/workbook.py +103 -37
  69. pyvbaanalysis-2.2.0/pyvbaanalysis/references/__init__.py +10 -0
  70. pyvbaanalysis-2.2.0/pyvbaanalysis/references/reference_kinds.py +365 -0
  71. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/runtime/__init__.py +4 -0
  72. pyvbaanalysis-2.2.0/pyvbaanalysis/runtime/vba_runtime.py +190 -0
  73. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/__init__.py +2 -0
  74. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/build_module_symbols.py +2 -0
  75. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/project_index.py +241 -4
  76. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/symbol_model.py +30 -1
  77. pyvbaanalysis-2.2.0/pyvbaanalysis/symbols/user_form_controls.py +145 -0
  78. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/types/__init__.py +1 -1
  79. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/types/type_inference.py +2 -1
  80. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/types/type_names.py +3 -18
  81. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/oracle_support.py +11 -17
  82. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_cli.py +4 -1
  83. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_conditional_arms.py +3 -1
  84. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_dataflow.py +21 -14
  85. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_evidence.py +2 -2
  86. pyvbaanalysis-2.2.0/tests/test_host_libraries.py +176 -0
  87. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_host_seam.py +38 -10
  88. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_parser.py +19 -8
  89. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_reader.py +34 -2
  90. pyvbaanalysis-2.2.0/tests/test_reference_kinds.py +175 -0
  91. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_registry_parity.py +9 -2
  92. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rule_metadata.py +15 -5
  93. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_assignments_types.py +68 -4
  94. pyvbaanalysis-2.2.0/tests/test_rules_call_arity.py +102 -0
  95. pyvbaanalysis-2.2.0/tests/test_rules_dead_code.py +347 -0
  96. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_declarations.py +40 -0
  97. pyvbaanalysis-2.2.0/tests/test_rules_doc_comments.py +197 -0
  98. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_event_handler_module_scope.py +29 -1
  99. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_member_not_found.py +68 -43
  100. pyvbaanalysis-2.2.0/tests/test_rules_missing_reference.py +152 -0
  101. pyvbaanalysis-2.2.0/tests/test_upstream_sync_10_5_0.py +278 -0
  102. pyvbaanalysis-2.2.0/tests/test_upstream_sync_10_6_0.py +246 -0
  103. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_upstream_sync_6_1_2.py +3 -1
  104. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/extract_event_definitions.mjs +9 -7
  105. pyvbaanalysis-2.2.0/tools/extract_host_model.mjs +64 -0
  106. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/extract_rule_metadata.mjs +6 -3
  107. pyvbaanalysis-2.2.0/tools/extract_runtime_tables.mjs +20 -0
  108. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/generate_manifest.py +16 -6
  109. pyvbaanalysis-2.2.0/tools/pin_analyzer.py +127 -0
  110. pyvbaanalysis-2.2.0/tools/vendor_data.py +106 -0
  111. pyvbaanalysis-2.2.0/tools/xlide_source.mjs +52 -0
  112. pyvbaanalysis-2.1.1/pyvbaanalysis/data/access_host_model.json +0 -1
  113. pyvbaanalysis-2.1.1/pyvbaanalysis/data/powerpoint_host_model.json +0 -1
  114. pyvbaanalysis-2.1.1/pyvbaanalysis/data/vba_runtime_tables.json +0 -1
  115. pyvbaanalysis-2.1.1/pyvbaanalysis/data/word_host_model.json +0 -1
  116. pyvbaanalysis-2.1.1/pyvbaanalysis/runtime/vba_runtime.py +0 -329
  117. pyvbaanalysis-2.1.1/tests/test_rules_call_arity.py +0 -60
  118. pyvbaanalysis-2.1.1/tools/extract_host_model.mjs +0 -31
  119. pyvbaanalysis-2.1.1/tools/extract_runtime_tables.mjs +0 -10
  120. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.gitattributes +0 -0
  121. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.github/dependabot.yml +0 -0
  122. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.github/workflows/ci.yml +0 -0
  123. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/.github/workflows/publish.yml +0 -0
  124. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/LICENSE +0 -0
  125. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/__main__.py +0 -0
  126. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/call/__init__.py +0 -0
  127. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/call/call_context.py +0 -0
  128. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/__init__.py +0 -0
  129. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/cursor_context.py +0 -0
  130. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/completion/type_completion.py +0 -0
  131. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/conditional/__init__.py +0 -0
  132. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/conditional/conditional_compilation.py +0 -0
  133. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/constants/__init__.py +0 -0
  134. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/constants/integer_constant_expression.py +0 -0
  135. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/data/event_definitions.json +0 -0
  136. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/exprwalk.py +0 -0
  137. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/inline_suppression.py +0 -0
  138. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/__init__.py +0 -0
  139. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/argument_shape.py +0 -0
  140. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/binary_operand_scalar.py +0 -0
  141. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/late_binding.py +0 -0
  142. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/lexical.py +0 -0
  143. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/diagnostics/rules/numeric_literals.py +0 -0
  144. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/evidence.py +0 -0
  145. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/flow/__init__.py +0 -0
  146. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/flow/procedure_labels.py +0 -0
  147. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/flow/procedure_unstructured.py +0 -0
  148. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/identity_cache.py +0 -0
  149. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/__init__.py +0 -0
  150. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/keyword_table.py +0 -0
  151. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/stripped_lines.py +0 -0
  152. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/token_kinds.py +0 -0
  153. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/tokenize.py +0 -0
  154. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/lexer/trivia.py +0 -0
  155. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/__init__.py +0 -0
  156. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/fixed_length_string.py +0 -0
  157. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/nodes.py +0 -0
  158. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/parse_expression.py +0 -0
  159. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/parser_state.py +0 -0
  160. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/parser/type_declaration_suffix.py +0 -0
  161. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/py.typed +0 -0
  162. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/loose_file.py +0 -0
  163. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/reader/vbe_module.py +0 -0
  164. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/pyvbaanalysis/symbols/name_resolution.py +0 -0
  165. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/conftest.py +0 -0
  166. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_conditional_compilation.py +0 -0
  167. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_diagnostics_engine.py +0 -0
  168. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_host_model.py +0 -0
  169. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_inline_suppression.py +0 -0
  170. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_integer_constant_expression.py +0 -0
  171. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_language_matrix.py +0 -0
  172. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_lexer.py +0 -0
  173. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_member_access_chains.py +0 -0
  174. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_project.py +0 -0
  175. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_project_index.py +0 -0
  176. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_public_api.py +0 -0
  177. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_real_world_false_positives.py +0 -0
  178. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_ambiguous_enum_member.py +0 -0
  179. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_argument_shape.py +0 -0
  180. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_argument_types.py +0 -0
  181. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_arrays.py +0 -0
  182. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_assignments.py +0 -0
  183. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_binary_operand_scalar.py +0 -0
  184. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_control_flow.py +0 -0
  185. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_division_by_zero.py +0 -0
  186. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_duplicates.py +0 -0
  187. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_expression_calls.py +0 -0
  188. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_expressions.py +0 -0
  189. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_invalid_as_type_names.py +0 -0
  190. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_is_operator_non_object.py +0 -0
  191. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_late_binding.py +0 -0
  192. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_lexical.py +0 -0
  193. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_module_kind.py +0 -0
  194. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_numeric_literals.py +0 -0
  195. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_object_state.py +0 -0
  196. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_parameter_defaults.py +0 -0
  197. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_property_setter_value_parameters.py +0 -0
  198. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_runtime_values.py +0 -0
  199. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_scalar_and_foreach.py +0 -0
  200. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_type_of_is.py +0 -0
  201. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_typeof_is_always_false.py +0 -0
  202. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_rules_undeclared.py +0 -0
  203. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_runtime_tables.py +0 -0
  204. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_statement_token_derivation.py +0 -0
  205. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_stripped_lines.py +0 -0
  206. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_symbols.py +0 -0
  207. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_token_helpers.py +0 -0
  208. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_type_completion.py +0 -0
  209. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tests/test_type_names.py +0 -0
  210. {pyvbaanalysis-2.1.1 → pyvbaanalysis-2.2.0}/tools/generate_diagnostics_catalogue.py +0 -0
  211. {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 Excel workbooks) is installed with the base
18
- package, so the workbook reader is exercised by the test suite.
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`. The
38
- data-extraction tools reference it through that relative path.
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 model, the
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 regenerated by the `tools/extract_*.mjs` scripts (run with
45
- `npx tsx`) against the sibling XLIDE checkout, never hand-edited.
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.1.1
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.0; extra == 'dev'
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.2; extra == 'dev'
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)` | Analyze the VBA in an Excel workbook (via pyOpenVBA). |
18
- | `analyze_office_file(path, *, only=None, severity_overrides=None, conditional_compilation=None, inline_suppression=True)` | The same for any readable Office container (Excel, Word, PowerPoint, Access); the extension selects the host model. |
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
- `LOOSE_EXTENSIONS`, `EXCEL_EXTENSIONS`.
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`, `ReferenceScope`,
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 Access host object models and the host registry (`get_excel_object_model`, `host_object_model_for_token`, `resolve_host_alias`, ...). |
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 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.
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 (41)
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 | Excel document-module event binding |
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 (51)
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 (3)
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
- `analyze_workbook` remains the Excel-only entry point and is unchanged.
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.2", "mypy==2.3.0"]
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]
@@ -41,7 +41,7 @@ from .reader import (
41
41
  )
42
42
  from .symbols import ModuleInput, ModuleSymbolKind, ProjectIndex, ProjectIndexOptions
43
43
 
44
- __version__ = "2.1.1"
44
+ __version__ = "2.2.0"
45
45
 
46
46
  __all__ = [
47
47
  "AnalyzeModuleOptions",