codeboarding 0.14.1__tar.gz → 0.14.3__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.
- {codeboarding-0.14.1/codeboarding.egg-info → codeboarding-0.14.3}/PKG-INFO +1 -1
- {codeboarding-0.14.1 → codeboarding-0.14.3}/README.md +12 -4
- {codeboarding-0.14.1 → codeboarding-0.14.3/codeboarding.egg-info}/PKG-INFO +1 -1
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding.egg-info/SOURCES.txt +4 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/diagram_generator.py +3 -3
- {codeboarding-0.14.1 → codeboarding-0.14.3}/pyproject.toml +1 -1
- {codeboarding-0.14.1 → codeboarding-0.14.3}/repo_utils/__init__.py +3 -2
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/__init__.py +132 -46
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/analysis_cache.py +6 -1
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/names/__init__.py +1 -6
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/names/draft.py +334 -145
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/names/frontier.py +18 -48
- codeboarding-0.14.3/static_analyzer/clustering/names/inventory.py +139 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/names/replay.py +4 -5
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/names/spec.py +3 -13
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/names/tokens.py +0 -6
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/service.py +20 -13
- codeboarding-0.14.3/static_analyzer/dotnet_solution.py +29 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/csharp_adapter.py +68 -43
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/go_adapter.py +6 -13
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/java_adapter.py +9 -21
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/php_adapter.py +0 -10
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/rust_adapter.py +0 -6
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/typescript_adapter.py +6 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/call_graph_builder.py +69 -61
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/edge_build_context.py +5 -5
- codeboarding-0.14.3/static_analyzer/engine/edge_builder.py +612 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/language_adapter.py +32 -41
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/lsp_client.py +153 -123
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/lsp_constants.py +11 -15
- codeboarding-0.14.3/static_analyzer/engine/lsp_recycler.py +46 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/models.py +25 -0
- codeboarding-0.14.3/static_analyzer/engine/progress.py +59 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/protocols.py +0 -9
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/result_converter.py +8 -3
- codeboarding-0.14.3/static_analyzer/engine/source_inspector.py +1285 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/symbol_table.py +75 -78
- codeboarding-0.14.3/static_analyzer/exceptions.py +5 -0
- codeboarding-0.14.3/static_analyzer/external_calls.py +142 -0
- codeboarding-0.14.3/static_analyzer/graph_definitions.py +369 -0
- codeboarding-0.14.3/static_analyzer/incremental_orchestrator.py +284 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/internal_references.py +5 -0
- codeboarding-0.14.3/telemetry/__init__.py +11 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/telemetry/service.py +32 -18
- codeboarding-0.14.3/tests/test_telemetry_service.py +205 -0
- codeboarding-0.14.1/static_analyzer/clustering/names/inventory.py +0 -116
- codeboarding-0.14.1/static_analyzer/engine/edge_builder.py +0 -794
- codeboarding-0.14.1/static_analyzer/engine/lsp_recycler.py +0 -158
- codeboarding-0.14.1/static_analyzer/engine/progress.py +0 -83
- codeboarding-0.14.1/static_analyzer/engine/source_inspector.py +0 -765
- codeboarding-0.14.1/static_analyzer/incremental_orchestrator.py +0 -632
- codeboarding-0.14.1/telemetry/__init__.py +0 -10
- codeboarding-0.14.1/tests/test_telemetry_service.py +0 -99
- {codeboarding-0.14.1 → codeboarding-0.14.3}/LICENSE +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/PYPI.md +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/agent_responses.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/change_status.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/component_ownership.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/constants.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/content_hash.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/file_index_models.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/incremental_results.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/llm_config.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/llm_errors.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/llm_renderers/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/llm_renderers/call_graph.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/llm_renderers/scope.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/model_capabilities.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/planner_agent.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/prompts/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/prompts/profiles.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/prompts/shared.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/relation_edges.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/retry.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/scope_analysis_agent.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/scope_ids.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/tools/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/tools/base.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/tools/get_method_calls.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/tools/read_file.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/agents/tree_planner_agent.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/clustering_ids.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding.egg-info/dependency_links.txt +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding.egg-info/entry_points.txt +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding.egg-info/requires.txt +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding.egg-info/top_level.txt +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/bootstrap.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/commands/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/commands/full_analysis.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/commands/incremental_analysis.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/commands/partial_analysis.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/render.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_cli/view_instructions.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_workflows/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_workflows/analysis.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_workflows/orchestration.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_workflows/sources/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_workflows/sources/local.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/codeboarding_workflows/sources/remote.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/constants.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/core/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/core/plugin_loader.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/core/protocols.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/core/registry.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/analysis_json.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/exceptions.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/file_coverage.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/file_index.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/incremental_changes.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/incremental_update.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/io_utils.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/run_context.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/run_mode.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/scope_assembly.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/scope_plan.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/diagram_analysis/tree_shape.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/github_action.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/checks/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/checks/circular_deps.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/checks/function_size.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/checks/unused_code_diagnostics.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/config.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/models.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/health/runner.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/install.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/logging_config.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/main.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/monitoring/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/monitoring/callbacks.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/monitoring/context.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/monitoring/mixin.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/monitoring/paths.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/monitoring/stats.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/monitoring/writers.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/output_generators/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/output_generators/html.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/output_generators/html_template.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/output_generators/markdown.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/output_generators/mdx.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/output_generators/rendering.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/output_generators/sphinx.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/repo_utils/change_detector.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/repo_utils/errors.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/repo_utils/fingerprint_diff.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/repo_utils/git_ops.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/repo_utils/ignore.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/repo_utils/path_utils.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/setup.cfg +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/analysis_result.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/cfg/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/cfg/call_graph.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/cfg/edge.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/cfg/location_key.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/cluster_relations.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/exceptions.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/clustering/models.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/config.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/csharp_config_scanner.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/dotnet_sdk.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/adapters/python_adapter.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/hierarchy_builder.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/process_memory.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/engine/utils.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/java_config_scanner.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/java_utils.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/language_results.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/lsp_client/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/lsp_client/diagnostics.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/node.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/programming_language.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/reference_resolver.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/scanner.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/static_analyzer/typescript_config_scanner.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/telemetry/device_id.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/telemetry/events.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/telemetry/schemas.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_cli_parser.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_github_action.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_install.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_logging_config.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_main.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_persisted_analysis_artifacts.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_pyproject_packages.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_registry_coverage.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_telemetry_events.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_tool_registry.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_user_config.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_view_instructions.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_vscode_constants.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_windows_compatibility.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tests/test_windows_encoding.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tool_registry/__init__.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tool_registry/installers.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tool_registry/manifest.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tool_registry/paths.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/tool_registry/registry.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/user_config.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/utils.py +0 -0
- {codeboarding-0.14.1 → codeboarding-0.14.3}/vscode_constants.py +0 -0
|
@@ -147,6 +147,13 @@ On first run, CodeBoarding creates `~/.codeboarding/config.toml`. Set one provid
|
|
|
147
147
|
|
|
148
148
|
Shell environment variables such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`, and `OLLAMA_BASE_URL` take precedence over the config file. For private repositories, set `GITHUB_TOKEN` in your environment.
|
|
149
149
|
|
|
150
|
+
Two environment variables tune the static analysis itself:
|
|
151
|
+
|
|
152
|
+
| Variable | Effect |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `CODEBOARDING_LSP_REQUEST_TIMEOUT` | Seconds a language-server request may block *when it uses the per-language default* (120s for C#, 60s elsewhere). Not a hard cap on every request: the indexing and didOpen-drain probes pass their own scaled budget (60s plus 2s per file, capped at 1800s) and are unaffected. Applies to every language in the run. Unset or empty leaves the defaults alone; any other unusable value fails the run rather than falling back. |
|
|
155
|
+
| `CODEBOARDING_MAX_CONCURRENT_ENGINES` | How many language servers may be resident at once. `0` (the default) leaves the bound off. |
|
|
156
|
+
|
|
150
157
|
## Common commands
|
|
151
158
|
|
|
152
159
|
```bash
|
|
@@ -212,10 +219,11 @@ for the actual depth. Existing baseline loading behavior is unchanged: prefer
|
|
|
212
219
|
|
|
213
220
|
## Telemetry
|
|
214
221
|
|
|
215
|
-
CodeBoarding collects
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
222
|
+
CodeBoarding collects usage telemetry (which command ran, success/failure,
|
|
223
|
+
duration, token cost, repository size and languages, and the account the
|
|
224
|
+
repository belongs to) to help us improve the tool. It is on by default and
|
|
225
|
+
never collects source code, file names, repository names, paths, prompts, model
|
|
226
|
+
outputs, or API keys. Opt out anytime:
|
|
219
227
|
|
|
220
228
|
```bash
|
|
221
229
|
export CODEBOARDING_TELEMETRY=false # or: export DO_NOT_TRACK=1
|
|
@@ -112,6 +112,10 @@ static_analyzer/cluster_relations.py
|
|
|
112
112
|
static_analyzer/config.py
|
|
113
113
|
static_analyzer/csharp_config_scanner.py
|
|
114
114
|
static_analyzer/dotnet_sdk.py
|
|
115
|
+
static_analyzer/dotnet_solution.py
|
|
116
|
+
static_analyzer/exceptions.py
|
|
117
|
+
static_analyzer/external_calls.py
|
|
118
|
+
static_analyzer/graph_definitions.py
|
|
115
119
|
static_analyzer/incremental_orchestrator.py
|
|
116
120
|
static_analyzer/internal_references.py
|
|
117
121
|
static_analyzer/java_config_scanner.py
|
|
@@ -675,7 +675,7 @@ class DiagramGenerator:
|
|
|
675
675
|
self.tree_spec = self._stored_tree_spec()
|
|
676
676
|
self._incremental_preparation = self._prepare_incremental_clustering(root_analysis, sub_analyses, depth)
|
|
677
677
|
elif target_component is None:
|
|
678
|
-
service = ClusteringService(self._grouper())
|
|
678
|
+
service = ClusteringService(self._grouper(), self.repo_location)
|
|
679
679
|
self.clustering_hierarchy = service.build_full_hierarchy(static_analysis, depth)
|
|
680
680
|
self.tree_spec = service.spec
|
|
681
681
|
else:
|
|
@@ -1031,7 +1031,7 @@ class DiagramGenerator:
|
|
|
1031
1031
|
assert self.tree_spec is not None
|
|
1032
1032
|
persisted = {ROOT_SCOPE_ID: root_analysis, **sub_analyses}
|
|
1033
1033
|
# Scopes the specification never reached are drafted deterministically here.
|
|
1034
|
-
service = ClusteringService()
|
|
1034
|
+
service = ClusteringService(repo_dir=self.repo_location)
|
|
1035
1035
|
self.clustering_hierarchy = service.build_incremental_hierarchy(
|
|
1036
1036
|
self.static_analysis,
|
|
1037
1037
|
hierarchy_depth,
|
|
@@ -1252,7 +1252,7 @@ class DiagramGenerator:
|
|
|
1252
1252
|
raise ClusteringScopeUnavailableError(component.component_id, "no owned CFG nodes")
|
|
1253
1253
|
remaining_depth = max(1, hierarchy_depth - _component_depth(component.component_id))
|
|
1254
1254
|
assert self.tree_spec is not None
|
|
1255
|
-
service = ClusteringService(self._grouper())
|
|
1255
|
+
service = ClusteringService(self._grouper(), self.repo_location)
|
|
1256
1256
|
# The service replays the specification from the root down to this component, so the
|
|
1257
1257
|
# scope holds the units a full run placed in it, data-only files included.
|
|
1258
1258
|
scope = service.build_scope_hierarchy(graphs, remaining_depth, component.component_id, self.tree_spec)
|
|
@@ -66,6 +66,8 @@ def sanitize_repo_url(repo_url: str) -> str:
|
|
|
66
66
|
Normalizes Git URLs to ensure proper format for cloning.
|
|
67
67
|
Preserves HTTPS URLs for CI compatibility while supporting SSH URLs.
|
|
68
68
|
"""
|
|
69
|
+
repo_url = repo_url.rstrip("/") # else the suffix below yields ``.../repo/.git``
|
|
70
|
+
|
|
69
71
|
if repo_url.startswith("git@") or repo_url.startswith("ssh://"):
|
|
70
72
|
return repo_url # already in SSH format
|
|
71
73
|
elif repo_url.startswith("https://") or repo_url.startswith("http://"):
|
|
@@ -94,8 +96,7 @@ def remote_repo_exists(repo_url: str) -> bool:
|
|
|
94
96
|
|
|
95
97
|
|
|
96
98
|
def get_repo_name(repo_url: str):
|
|
97
|
-
|
|
98
|
-
base = repo_url.rstrip("/").split("/")[-1]
|
|
99
|
+
base = sanitize_repo_url(repo_url).split("/")[-1]
|
|
99
100
|
repo_name, _ = os.path.splitext(base)
|
|
100
101
|
return repo_name
|
|
101
102
|
|
|
@@ -12,15 +12,20 @@ from static_analyzer.analysis_cache import StaticAnalysisCache
|
|
|
12
12
|
from static_analyzer.analysis_result import StaticAnalysisResults
|
|
13
13
|
from static_analyzer.cfg import CallGraph
|
|
14
14
|
from static_analyzer.config import AdapterName, Language
|
|
15
|
-
from static_analyzer.csharp_config_scanner import CSharpConfigScanner
|
|
15
|
+
from static_analyzer.csharp_config_scanner import SOLUTION_GLOBS, CSharpConfigScanner, CSharpProjectConfig
|
|
16
|
+
from static_analyzer.dotnet_solution import solution_projects
|
|
16
17
|
from static_analyzer.engine.adapters import get_adapter
|
|
17
18
|
from static_analyzer.engine.call_graph_builder import CallGraphBuilder
|
|
18
19
|
from static_analyzer.engine.language_adapter import LanguageAdapter
|
|
19
20
|
from static_analyzer.engine.lsp_client import LSPClient
|
|
20
21
|
from static_analyzer.engine.lsp_recycler import default_memory_budget, per_engine_memory_budget
|
|
22
|
+
from static_analyzer.engine.models import ExternalCallSite
|
|
21
23
|
from static_analyzer.engine.result_converter import convert_to_codeboarding_format
|
|
22
24
|
from static_analyzer.engine.source_inspector import SourceInspector
|
|
23
25
|
from static_analyzer.engine.utils import uri_to_path
|
|
26
|
+
from static_analyzer.exceptions import StaticAnalysisFatalError
|
|
27
|
+
from static_analyzer.external_calls import link_external_call_sites, record_package_imports
|
|
28
|
+
from static_analyzer.graph_definitions import GraphIndex
|
|
24
29
|
from static_analyzer.incremental_orchestrator import update_cfg_for_changed_files
|
|
25
30
|
from static_analyzer.java_config_scanner import JavaConfigScanner
|
|
26
31
|
from static_analyzer.lsp_client.diagnostics import FileDiagnosticsMap
|
|
@@ -39,20 +44,21 @@ class EngineConfig:
|
|
|
39
44
|
"""One adapter + project root the engine should run.
|
|
40
45
|
|
|
41
46
|
``source_files`` is non-empty only when a scanner has authoritatively
|
|
42
|
-
resolved file membership (
|
|
43
|
-
otherwise the adapter walks ``project_path``
|
|
47
|
+
resolved file membership (TypeScript via ``tsc --showConfig``, C# by what
|
|
48
|
+
each root's solution lists); otherwise the adapter walks ``project_path``
|
|
49
|
+
itself in ``_run_full_analysis``. A config whose membership resolved to no
|
|
50
|
+
file is not created at all.
|
|
44
51
|
"""
|
|
45
52
|
|
|
46
53
|
adapter: LanguageAdapter
|
|
47
54
|
project_path: Path
|
|
48
55
|
source_files: list[Path] = field(default_factory=list)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class StaticAnalysisFatalError(RuntimeError):
|
|
52
|
-
"""Raised when continuing would produce misleading cached analysis."""
|
|
56
|
+
# Retain discovery exclusions for incremental edits, including deleted files.
|
|
57
|
+
excluded_roots: list[Path] = field(default_factory=list)
|
|
53
58
|
|
|
54
59
|
|
|
55
60
|
MAX_CONCURRENT_ENGINES_ENV_VAR = "CODEBOARDING_MAX_CONCURRENT_ENGINES"
|
|
61
|
+
LSP_REQUEST_TIMEOUT_ENV_VAR = "CODEBOARDING_LSP_REQUEST_TIMEOUT"
|
|
56
62
|
|
|
57
63
|
|
|
58
64
|
# An engine costs ~3 cores: the server's own peak (~1.9, measured on csharp-ls),
|
|
@@ -84,6 +90,24 @@ def max_concurrent_engines() -> int:
|
|
|
84
90
|
return value
|
|
85
91
|
|
|
86
92
|
|
|
93
|
+
def lsp_request_timeout_override() -> int | None:
|
|
94
|
+
"""Seconds from ``CODEBOARDING_LSP_REQUEST_TIMEOUT``, or None when it is unset.
|
|
95
|
+
|
|
96
|
+
Why it raises rather than falling back: the fallback is the adapter ceiling the
|
|
97
|
+
operator set the variable to escape, so the run would time out as if ignored.
|
|
98
|
+
"""
|
|
99
|
+
raw = os.environ.get(LSP_REQUEST_TIMEOUT_ENV_VAR, "").strip()
|
|
100
|
+
if not raw:
|
|
101
|
+
return None
|
|
102
|
+
try:
|
|
103
|
+
seconds = int(raw)
|
|
104
|
+
except ValueError:
|
|
105
|
+
raise ValueError(f"{LSP_REQUEST_TIMEOUT_ENV_VAR} must be a whole number of seconds, got {raw!r}") from None
|
|
106
|
+
if seconds <= 0:
|
|
107
|
+
raise ValueError(f"{LSP_REQUEST_TIMEOUT_ENV_VAR} must be a positive number of seconds, got {raw!r}")
|
|
108
|
+
return seconds
|
|
109
|
+
|
|
110
|
+
|
|
87
111
|
def recommended_engine_concurrency(engine_count: int) -> int:
|
|
88
112
|
"""Engine concurrency bounded by available work, cores, and memory.
|
|
89
113
|
|
|
@@ -121,6 +145,15 @@ def _adapter_names_for(programming_languages: list[ProgrammingLanguage]) -> list
|
|
|
121
145
|
return names
|
|
122
146
|
|
|
123
147
|
|
|
148
|
+
def _csharp_solution_members(csharp_projects: list[CSharpProjectConfig]) -> dict[Path, list[Path]]:
|
|
149
|
+
"""Per C# root, the project files its solution files list."""
|
|
150
|
+
members: dict[Path, list[Path]] = {}
|
|
151
|
+
for config in csharp_projects:
|
|
152
|
+
solutions = [path for pattern in SOLUTION_GLOBS for path in config.root.glob(pattern)]
|
|
153
|
+
members[config.root] = [project for solution in solutions for project in solution_projects(solution)]
|
|
154
|
+
return members
|
|
155
|
+
|
|
156
|
+
|
|
124
157
|
def _create_engine_configs(
|
|
125
158
|
programming_languages: list[ProgrammingLanguage],
|
|
126
159
|
repository_path: Path,
|
|
@@ -198,12 +231,32 @@ def _create_engine_configs(
|
|
|
198
231
|
csharp_projects = csharp_scanner.scan()
|
|
199
232
|
|
|
200
233
|
if csharp_projects:
|
|
234
|
+
members = _csharp_solution_members(csharp_projects)
|
|
201
235
|
for csharp_config in csharp_projects:
|
|
202
236
|
logger.info(
|
|
203
237
|
f"Creating engine config for CSharp ({csharp_config.project_type}) at: "
|
|
204
238
|
f"{csharp_config.root.relative_to(repository_path)}"
|
|
205
239
|
)
|
|
206
|
-
|
|
240
|
+
# A project a nested root's solution lists, and this root's solutions do not,
|
|
241
|
+
# is that engine's; naming it here as well would put it in the graph twice.
|
|
242
|
+
elsewhere = [
|
|
243
|
+
project.parent
|
|
244
|
+
for root, projects in members.items()
|
|
245
|
+
if root != csharp_config.root and root.is_relative_to(csharp_config.root)
|
|
246
|
+
for project in projects
|
|
247
|
+
if project not in members[csharp_config.root]
|
|
248
|
+
]
|
|
249
|
+
source_files = adapter.discover_source_files(csharp_config.root, ignore_manager, elsewhere)
|
|
250
|
+
if not source_files:
|
|
251
|
+
logger.info(
|
|
252
|
+
f"Every C# file under {csharp_config.root} belongs to a nested solution; skipping"
|
|
253
|
+
)
|
|
254
|
+
continue
|
|
255
|
+
configs.append(
|
|
256
|
+
EngineConfig(
|
|
257
|
+
adapter, csharp_config.root, source_files=source_files, excluded_roots=elsewhere
|
|
258
|
+
)
|
|
259
|
+
)
|
|
207
260
|
else:
|
|
208
261
|
logger.info("No C# projects detected")
|
|
209
262
|
|
|
@@ -254,6 +307,11 @@ class StaticAnalyzer:
|
|
|
254
307
|
# e.g. the incremental fingerprint diff. ``None`` means "detect via git"
|
|
255
308
|
# (the legacy CLI-on-a-real-checkout path); an empty set re-LSPs nothing.
|
|
256
309
|
self.changed_files = changed_files
|
|
310
|
+
# Resolved here so an unusable value fails before any engine starts, where
|
|
311
|
+
# the per-language handlers would turn it into "skip this language".
|
|
312
|
+
self._request_timeout_override = lsp_request_timeout_override()
|
|
313
|
+
if self._request_timeout_override is not None:
|
|
314
|
+
logger.info("Per-request LSP timeout overridden to %ds", self._request_timeout_override)
|
|
257
315
|
|
|
258
316
|
def __enter__(self) -> "StaticAnalyzer":
|
|
259
317
|
self.start_clients()
|
|
@@ -402,7 +460,7 @@ class StaticAnalyzer:
|
|
|
402
460
|
command=command,
|
|
403
461
|
project_root=project_path,
|
|
404
462
|
init_options=init_options,
|
|
405
|
-
default_timeout=adapter.get_lsp_default_timeout(),
|
|
463
|
+
default_timeout=self._request_timeout_override or adapter.get_lsp_default_timeout(),
|
|
406
464
|
collect_diagnostics=True,
|
|
407
465
|
extra_env=extra_env,
|
|
408
466
|
workspace_settings=adapter.get_workspace_settings(),
|
|
@@ -580,7 +638,7 @@ class StaticAnalyzer:
|
|
|
580
638
|
|
|
581
639
|
Returns:
|
|
582
640
|
Deduplicated list of absolute file paths that the file depends on.
|
|
583
|
-
Returns an empty list if no
|
|
641
|
+
Returns an empty list if no client serves the file; a failed query raises.
|
|
584
642
|
"""
|
|
585
643
|
suffix = file_path.suffix
|
|
586
644
|
client = next(
|
|
@@ -594,34 +652,30 @@ class StaticAnalyzer:
|
|
|
594
652
|
if client is None:
|
|
595
653
|
return []
|
|
596
654
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
if not call_sites:
|
|
600
|
-
return []
|
|
601
|
-
|
|
602
|
-
queries = [(file_path, site.lsp_line, site.lsp_column) for site in call_sites]
|
|
603
|
-
results, _ = client.send_definition_batch(queries)
|
|
604
|
-
|
|
605
|
-
resolved = file_path.resolve()
|
|
606
|
-
unique_paths: set[str] = set()
|
|
607
|
-
for definitions in results:
|
|
608
|
-
for defn in definitions:
|
|
609
|
-
uri = defn.get("targetUri", defn.get("uri", ""))
|
|
610
|
-
if not uri.startswith("file://"):
|
|
611
|
-
continue
|
|
612
|
-
dep_path_obj = uri_to_path(uri)
|
|
613
|
-
if dep_path_obj is None:
|
|
614
|
-
continue
|
|
615
|
-
dep_path = str(dep_path_obj)
|
|
616
|
-
if dep_path != str(resolved):
|
|
617
|
-
unique_paths.add(dep_path)
|
|
618
|
-
|
|
619
|
-
logger.debug(f"Discovered {len(unique_paths)} dependencies for {file_path}")
|
|
620
|
-
return list(unique_paths)
|
|
621
|
-
except Exception:
|
|
622
|
-
logger.warning(f"Failed to discover dependencies for {file_path}", exc_info=True)
|
|
655
|
+
call_sites = SourceInspector().find_call_sites(file_path)
|
|
656
|
+
if not call_sites:
|
|
623
657
|
return []
|
|
624
658
|
|
|
659
|
+
queries = [(file_path, site.lsp_line, site.lsp_column) for site in call_sites]
|
|
660
|
+
results = client.send_definition_batch(queries)
|
|
661
|
+
|
|
662
|
+
resolved = file_path.resolve()
|
|
663
|
+
unique_paths: set[str] = set()
|
|
664
|
+
for definitions in results:
|
|
665
|
+
for defn in definitions:
|
|
666
|
+
uri = defn.get("targetUri", defn.get("uri", ""))
|
|
667
|
+
if not uri.startswith("file://"):
|
|
668
|
+
continue
|
|
669
|
+
dep_path_obj = uri_to_path(uri)
|
|
670
|
+
if dep_path_obj is None:
|
|
671
|
+
continue
|
|
672
|
+
dep_path = str(dep_path_obj)
|
|
673
|
+
if dep_path != str(resolved):
|
|
674
|
+
unique_paths.add(dep_path)
|
|
675
|
+
|
|
676
|
+
logger.debug(f"Discovered {len(unique_paths)} dependencies for {file_path}")
|
|
677
|
+
return list(unique_paths)
|
|
678
|
+
|
|
625
679
|
def analyze(
|
|
626
680
|
self,
|
|
627
681
|
cache_dir: Path,
|
|
@@ -702,7 +756,7 @@ class StaticAnalyzer:
|
|
|
702
756
|
# order. The merges replace on key collision, and overlapping configs
|
|
703
757
|
# (nested solution roots) do collide, so completion order would let two
|
|
704
758
|
# identical runs keep different nodes and produce different component IDs.
|
|
705
|
-
completed: dict[int, tuple[
|
|
759
|
+
completed: dict[int, tuple[LanguageAdapter, dict]] = {}
|
|
706
760
|
|
|
707
761
|
def run_one(engine_config: EngineConfig, engine_client: LSPClient | None, order: int = 0) -> None:
|
|
708
762
|
"""Analyze one engine. Owns the client's lifetime when given none."""
|
|
@@ -726,7 +780,7 @@ class StaticAnalyzer:
|
|
|
726
780
|
duration_ms = round((time.monotonic() - t_lang_start) * 1000)
|
|
727
781
|
logger.info(f"Engine analysis for {adapter.language} completed in {duration_ms / 1000:.1f}s")
|
|
728
782
|
with absorb_lock:
|
|
729
|
-
completed[order] = (
|
|
783
|
+
completed[order] = (adapter, analysis)
|
|
730
784
|
self._collect_diagnostics_for(adapter, engine_client, analysis)
|
|
731
785
|
track_lsp_result(
|
|
732
786
|
language=adapter.language_enum.value,
|
|
@@ -783,9 +837,7 @@ class StaticAnalyzer:
|
|
|
783
837
|
f"(attempted: {', '.join(cfg.adapter.language for cfg in pending)}){details}"
|
|
784
838
|
)
|
|
785
839
|
|
|
786
|
-
for order in sorted(completed)
|
|
787
|
-
language, analysis = completed[order]
|
|
788
|
-
self._absorb_into_results(results, language, analysis)
|
|
840
|
+
self._absorb_and_link(results, [completed[order] for order in sorted(completed)])
|
|
789
841
|
|
|
790
842
|
summaries = []
|
|
791
843
|
for language in results.get_languages():
|
|
@@ -829,6 +881,8 @@ class StaticAnalyzer:
|
|
|
829
881
|
# so a config that took its own copy of the cache would hand back the nodes another
|
|
830
882
|
# config had just invalidated, and the merge would resurrect deleted files.
|
|
831
883
|
carried: dict[Language, dict] = {}
|
|
884
|
+
carried_adapters: dict[Language, LanguageAdapter] = {}
|
|
885
|
+
rebuilt: list[tuple[LanguageAdapter, dict]] = []
|
|
832
886
|
for engine_config, engine_client in self._live_clients("warm-start"):
|
|
833
887
|
adapter, project_path = engine_config.adapter, engine_config.project_path
|
|
834
888
|
language = adapter.results_language
|
|
@@ -837,14 +891,26 @@ class StaticAnalyzer:
|
|
|
837
891
|
|
|
838
892
|
if changed_files is None:
|
|
839
893
|
analysis = self._run_full_analysis(engine_config, engine_client)
|
|
840
|
-
|
|
894
|
+
rebuilt.append((adapter, analysis))
|
|
841
895
|
else:
|
|
896
|
+
changed_files = {
|
|
897
|
+
path
|
|
898
|
+
for path in changed_files
|
|
899
|
+
if not any(path.is_relative_to(root) for root in engine_config.excluded_roots)
|
|
900
|
+
}
|
|
842
901
|
logger.info(f"warmstart {adapter.language}: re-LSPing {len(changed_files)} changed file(s)")
|
|
843
902
|
cached_lang_dict = carried.get(language) or self._extract_language_dict(cached_results, language)
|
|
844
903
|
analysis = update_cfg_for_changed_files(
|
|
845
|
-
cached_lang_dict,
|
|
904
|
+
cached_lang_dict,
|
|
905
|
+
changed_files,
|
|
906
|
+
adapter,
|
|
907
|
+
project_path,
|
|
908
|
+
self.repository_path,
|
|
909
|
+
engine_client,
|
|
910
|
+
self.ignore_manager,
|
|
846
911
|
)
|
|
847
912
|
carried[language] = analysis
|
|
913
|
+
carried_adapters[language] = adapter
|
|
848
914
|
|
|
849
915
|
self._collect_diagnostics_for(adapter, engine_client, analysis)
|
|
850
916
|
track_lsp_result(
|
|
@@ -855,8 +921,9 @@ class StaticAnalyzer:
|
|
|
855
921
|
analysis=analysis,
|
|
856
922
|
diagnostics=self.collected_diagnostics.get(adapter.results_language, {}),
|
|
857
923
|
)
|
|
858
|
-
|
|
859
|
-
|
|
924
|
+
self._absorb_and_link(
|
|
925
|
+
results, rebuilt + [(carried_adapters[language], analysis) for language, analysis in carried.items()]
|
|
926
|
+
)
|
|
860
927
|
results.incremental_base_results = cached_results
|
|
861
928
|
return results
|
|
862
929
|
|
|
@@ -905,6 +972,25 @@ class StaticAnalyzer:
|
|
|
905
972
|
"diagnostics": cached_results.diagnostics.get(language, {}),
|
|
906
973
|
}
|
|
907
974
|
|
|
975
|
+
def _absorb_and_link(self, results: StaticAnalysisResults, analyses: list[tuple[LanguageAdapter, dict]]) -> None:
|
|
976
|
+
"""Absorb every engine's analysis, then finish the calls whose definitions lie in another engine's files.
|
|
977
|
+
|
|
978
|
+
Why after all of them: only the merged graph holds every engine's nodes, so a call into
|
|
979
|
+
another solution's project can find its target, whichever engine ran first.
|
|
980
|
+
"""
|
|
981
|
+
for adapter, analysis in analyses:
|
|
982
|
+
self._absorb_into_results(results, adapter.results_language, analysis)
|
|
983
|
+
inspector = SourceInspector()
|
|
984
|
+
for adapter, analysis in analyses:
|
|
985
|
+
sites: list[ExternalCallSite] = analysis.get("external_call_sites", [])
|
|
986
|
+
if not sites:
|
|
987
|
+
continue
|
|
988
|
+
language = adapter.results_language
|
|
989
|
+
analysed_files = {str(path) for path in analysis.get("source_files", [])}
|
|
990
|
+
index = GraphIndex(results.get_cfg(language))
|
|
991
|
+
linked = link_external_call_sites(index, sites, adapter, inspector, analysed_files)
|
|
992
|
+
record_package_imports(results.get_package_dependencies(language), adapter, linked.edges)
|
|
993
|
+
|
|
908
994
|
def _absorb_into_results(self, results: StaticAnalysisResults, language: Language, analysis: dict) -> None:
|
|
909
995
|
"""Stuff one language's analysis-dict into the shared ``StaticAnalysisResults``."""
|
|
910
996
|
results.add_references(language, analysis.get("references", []))
|
|
@@ -988,7 +1074,7 @@ class StaticAnalyzer:
|
|
|
988
1074
|
engine_client,
|
|
989
1075
|
adapter,
|
|
990
1076
|
project_path,
|
|
991
|
-
|
|
1077
|
+
self.repository_path,
|
|
992
1078
|
)
|
|
993
1079
|
engine_result = builder.build(source_files)
|
|
994
1080
|
logger.info(f"CallGraphBuilder.build() for {adapter.language}: {time.monotonic() - t_build_start:.1f}s")
|
|
@@ -67,8 +67,13 @@ _LEGACY_CACHE_SUBDIR = "cache"
|
|
|
67
67
|
# named after.
|
|
68
68
|
# v7: the pickle no longer carries cluster lineage; components come from the tree
|
|
69
69
|
# specification in analysis.json, replayed over the graph.
|
|
70
|
+
# v8: a C# file compiled into several projects has symbols and callers, and a
|
|
71
|
+
# nested solution's files are named by its own engine only.
|
|
72
|
+
# v9: a call into a project of another solution root is an edge.
|
|
73
|
+
# v10: every name is spelled from the repository root; C# keeps ``src`` and Java its source root.
|
|
74
|
+
# v11: every language builds its call edges from definitions at the call site.
|
|
70
75
|
# Older pickles are treated as cache misses and re-run.
|
|
71
|
-
_TAG_VERSION = "
|
|
76
|
+
_TAG_VERSION = "v11"
|
|
72
77
|
|
|
73
78
|
|
|
74
79
|
class StaticAnalysisCache:
|
|
@@ -17,17 +17,14 @@ from static_analyzer.clustering.names.frontier import Candidate, Frontier, walk
|
|
|
17
17
|
from static_analyzer.clustering.names.inventory import (
|
|
18
18
|
Trie,
|
|
19
19
|
Unit,
|
|
20
|
-
unit_key,
|
|
21
|
-
unit_position,
|
|
22
20
|
units_from_graph,
|
|
23
21
|
units_from_graphs,
|
|
24
22
|
)
|
|
25
23
|
from static_analyzer.clustering.names.replay import Partition, replay
|
|
26
24
|
from static_analyzer.clustering.names.spec import ComponentRule, ScopeSpec, TreeSpec
|
|
27
|
-
from static_analyzer.clustering.names.tokens import
|
|
25
|
+
from static_analyzer.clustering.names.tokens import ROLE_WORDS, stem, tokenize
|
|
28
26
|
|
|
29
27
|
__all__ = [
|
|
30
|
-
"LAYOUT_WORDS",
|
|
31
28
|
"ROLE_WORDS",
|
|
32
29
|
"AffinityGrouper",
|
|
33
30
|
"Candidate",
|
|
@@ -48,8 +45,6 @@ __all__ = [
|
|
|
48
45
|
"role_words_for",
|
|
49
46
|
"stem",
|
|
50
47
|
"tokenize",
|
|
51
|
-
"unit_key",
|
|
52
|
-
"unit_position",
|
|
53
48
|
"units_from_graph",
|
|
54
49
|
"units_from_graphs",
|
|
55
50
|
"walk",
|