graphlint 0.3.3__tar.gz → 0.3.4__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.
- {graphlint-0.3.3 → graphlint-0.3.4}/CHANGELOG.md +7 -0
- {graphlint-0.3.3/graphlint.egg-info → graphlint-0.3.4}/PKG-INFO +1 -1
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/__init__.py +1 -1
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/graph.py +26 -7
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/incremental/_db_ops.py +75 -3
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/incremental/indexer.py +6 -1
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/storage/schema.py +13 -0
- {graphlint-0.3.3 → graphlint-0.3.4/graphlint.egg-info}/PKG-INFO +1 -1
- {graphlint-0.3.3 → graphlint-0.3.4}/pyproject.toml +1 -1
- {graphlint-0.3.3 → graphlint-0.3.4}/CONTRIBUTING.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/LICENSE +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/MANIFEST.in +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/README.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/README_PYPI.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/api/build.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/api/configure.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/api/exceptions.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/api/query.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/architecture/overview.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/cli/usage.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/guide/agent-integration.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/guide/configuration.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/guide/entry-detection.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/guide/getting-started.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/guide/warnings.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/en/index.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/README.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/api/build.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/api/configure.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/api/exceptions.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/api/query.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/architecture/overview.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/cli/usage.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/guide/agent-integration.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/guide/configuration.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/guide/entry-detection.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/guide/getting-started.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/guide/warnings.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/docs/zh/index.md +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/agent_tools.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/_graph_algo.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/_types.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/base.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/python/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/python/constants.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/python/decorators.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/python/entry.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/python/imports.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/python/parser.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/python/visitor.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/registry.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/rust/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/rust/constants.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/rust/entry.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/rust/imports.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/rust/parser.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/language/rust/visitor.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/analyzer/warnings.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/api.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/cli.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/config/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/config/defaults.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/config/manager.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/exceptions.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/i18n/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/i18n/en.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/i18n/zh_CN.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/incremental/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/params.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/query/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/query/engine.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/query/formatter.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/query/volume.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/storage/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/storage/db.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint/storage/hashing.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint.egg-info/SOURCES.txt +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint.egg-info/dependency_links.txt +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint.egg-info/entry_points.txt +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint.egg-info/requires.txt +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/graphlint.egg-info/top_level.txt +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/setup.cfg +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/test_api.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/test_cli.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/test_data_transfer.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/test_dead_code_query.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/test_full_pipeline.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/test_incremental.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/integration/test_json_output.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/performance/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/performance/test_large_codebase.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/__init__.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_auto_build.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_config.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_db.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_db_ops.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_decorators.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_engine.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_entry_detect.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_exceptions.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_formatter.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_graph.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_graph_algo.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_hashing.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_i18n.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_imports.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_mock_boundary.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_params.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_parser.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_schema.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_volume.py +0 -0
- {graphlint-0.3.3 → graphlint-0.3.4}/tests/unit/test_warnings.py +0 -0
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.3.4] - 2026-07-27
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Incremental entry detection: entry point results are now persisted to DB
|
|
9
|
+
and only re-scanned for changed files in incremental builds, reducing
|
|
10
|
+
redundant computation when most files are unchanged
|
|
11
|
+
|
|
5
12
|
## [0.3.3] - 2026-07-25
|
|
6
13
|
|
|
7
14
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphlint
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A static analysis tool for identifying dead code in a codebase. It provides Python API and CLI for use by agents.
|
|
5
5
|
Author-email: Yutong Zou <yutong.zou.24@alumni.ucl.ac.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -259,6 +259,7 @@ class GraphBuilder:
|
|
|
259
259
|
parse_results: dict[str, ParseResult],
|
|
260
260
|
changed_files: Optional[set[str]] = None,
|
|
261
261
|
prebuilt_edges: Optional[list[EdgeInfo]] = None,
|
|
262
|
+
prebuilt_entries: Optional[list[EntryInfo]] = None,
|
|
262
263
|
old_changed_node_ids: dict[int, tuple[str, str]] | None = None,
|
|
263
264
|
) -> GraphBuildResult:
|
|
264
265
|
"""Build the complete dependency graph from parse results.
|
|
@@ -267,6 +268,9 @@ class GraphBuilder:
|
|
|
267
268
|
old_changed_node_ids: Maps old global node ID → (qualified_name, file_path)
|
|
268
269
|
for nodes in changed files. Used to remap parent_node_id when a
|
|
269
270
|
child in an unchanged file references a parent in a changed file.
|
|
271
|
+
prebuilt_entries: Pre-loaded EntryInfo from DB for unchanged files
|
|
272
|
+
(incremental mode). When provided, entry detection only scans
|
|
273
|
+
changed files and merges these prebuilt entries.
|
|
270
274
|
"""
|
|
271
275
|
fid_map: dict[str, int] = {}
|
|
272
276
|
fid_cnt = 1
|
|
@@ -332,15 +336,30 @@ class GraphBuilder:
|
|
|
332
336
|
if fid and fid in file_nodes_by_fid:
|
|
333
337
|
fnodes_map[fp] = {n.qualified_name: n.id for n in file_nodes_by_fid[fid]}
|
|
334
338
|
|
|
335
|
-
# Detect entries via language adapters
|
|
339
|
+
# Detect entries via language adapters.
|
|
340
|
+
# In incremental mode, only scan changed files and merge prebuilt
|
|
341
|
+
# entries loaded from DB for unchanged files.
|
|
336
342
|
entries: list[EntryInfo] = []
|
|
337
|
-
if
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
343
|
+
if prebuilt_entries is not None and changed_files and len(changed_files) < len(parse_results):
|
|
344
|
+
changed_pr = {
|
|
345
|
+
fp: pr for fp, pr in parse_results.items() if fp in changed_files
|
|
346
|
+
}
|
|
347
|
+
if self.registry:
|
|
348
|
+
for adapter in self.registry.all_adapters():
|
|
349
|
+
entries.extend(
|
|
350
|
+
adapter.detect_entries(
|
|
351
|
+
changed_pr, self._nodes, self._node_id_map, self.config
|
|
352
|
+
)
|
|
353
|
+
)
|
|
354
|
+
entries.extend(prebuilt_entries)
|
|
355
|
+
else:
|
|
356
|
+
if self.registry:
|
|
357
|
+
for adapter in self.registry.all_adapters():
|
|
358
|
+
entries.extend(
|
|
359
|
+
adapter.detect_entries(
|
|
360
|
+
parse_results, self._nodes, self._node_id_map, self.config
|
|
361
|
+
)
|
|
342
362
|
)
|
|
343
|
-
)
|
|
344
363
|
for e in entries:
|
|
345
364
|
if e.node_id and e.node_id in self._node_id_map:
|
|
346
365
|
self._node_id_map[e.node_id].is_entry = True
|
|
@@ -9,7 +9,7 @@ import json
|
|
|
9
9
|
import os
|
|
10
10
|
from typing import Any, Optional
|
|
11
11
|
|
|
12
|
-
from graphlint.analyzer._types import EdgeInfo, NodeInfo, GraphBuildResult
|
|
12
|
+
from graphlint.analyzer._types import EdgeInfo, EntryInfo, NodeInfo, GraphBuildResult
|
|
13
13
|
from graphlint.storage.db import Database
|
|
14
14
|
from graphlint.storage.hashing import compute_file_hash, is_test_file
|
|
15
15
|
|
|
@@ -96,13 +96,14 @@ def update_db(
|
|
|
96
96
|
else:
|
|
97
97
|
# Full build: unconditionally clear all data tables (keep files table)
|
|
98
98
|
# files table is updated by subsequent _upsert_files INSERT OR REPLACE
|
|
99
|
-
for tbl in ("edges", "nodes", "imports", "warnings", "graph_snapshots"):
|
|
99
|
+
for tbl in ("edges", "nodes", "imports", "warnings", "graph_snapshots", "entries"):
|
|
100
100
|
db.execute(f"DELETE FROM {tbl}")
|
|
101
101
|
_upsert_files(db, build_result, root_dir, test_patterns, changed)
|
|
102
102
|
fid_map = _load_fid_map(db)
|
|
103
103
|
_insert_nodes(db, build_result, fid_map, changed_files=changed_set)
|
|
104
104
|
_do_insert_edges(db, build_result, fid_map, changed_files=changed_set)
|
|
105
105
|
_insert_warnings(db, build_result, fid_map, changed_files=changed_set)
|
|
106
|
+
_insert_entries(db, build_result, fid_map, changed_files=changed_set)
|
|
106
107
|
if incremental:
|
|
107
108
|
update_snapshots(db, build_result)
|
|
108
109
|
else:
|
|
@@ -115,7 +116,7 @@ def _delete_old(db: Database, removed: list[str], changed: list[str]) -> None:
|
|
|
115
116
|
if not paths:
|
|
116
117
|
continue
|
|
117
118
|
ph = ",".join("?" for _ in paths)
|
|
118
|
-
for tbl in ("edges", "nodes", "imports", "warnings"):
|
|
119
|
+
for tbl in ("edges", "nodes", "imports", "warnings", "entries"):
|
|
119
120
|
db.execute(
|
|
120
121
|
f"DELETE FROM {tbl} WHERE file_id IN "
|
|
121
122
|
f"(SELECT id FROM files WHERE path IN ({ph}))",
|
|
@@ -302,6 +303,77 @@ def _insert_warnings(
|
|
|
302
303
|
)
|
|
303
304
|
|
|
304
305
|
|
|
306
|
+
def _insert_entries(
|
|
307
|
+
db: Database,
|
|
308
|
+
build_result: GraphBuildResult,
|
|
309
|
+
fid_map: dict[str, int],
|
|
310
|
+
changed_files: Optional[set[str]] = None,
|
|
311
|
+
) -> None:
|
|
312
|
+
"""Insert entry point detection results."""
|
|
313
|
+
batch: list[tuple[Any, ...]] = []
|
|
314
|
+
for entry in build_result.entry_info_list:
|
|
315
|
+
fp = entry.file_path
|
|
316
|
+
if changed_files is not None and fp not in changed_files:
|
|
317
|
+
continue
|
|
318
|
+
fid = fid_map.get(fp, 0)
|
|
319
|
+
if not fid:
|
|
320
|
+
continue
|
|
321
|
+
batch.append(
|
|
322
|
+
(
|
|
323
|
+
fid,
|
|
324
|
+
entry.node_id or 0,
|
|
325
|
+
entry.rule_name,
|
|
326
|
+
entry.line,
|
|
327
|
+
entry.description or "",
|
|
328
|
+
1 if entry.no_propagate else 0,
|
|
329
|
+
)
|
|
330
|
+
)
|
|
331
|
+
if len(batch) >= 5000:
|
|
332
|
+
db.executemany(
|
|
333
|
+
"INSERT INTO entries (file_id, node_id, rule_name, "
|
|
334
|
+
"line, description, no_propagate) VALUES (?,?,?,?,?,?)",
|
|
335
|
+
batch,
|
|
336
|
+
)
|
|
337
|
+
batch.clear()
|
|
338
|
+
if batch:
|
|
339
|
+
db.executemany(
|
|
340
|
+
"INSERT INTO entries (file_id, node_id, rule_name, "
|
|
341
|
+
"line, description, no_propagate) VALUES (?,?,?,?,?,?)",
|
|
342
|
+
batch,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def load_unchanged_entries(
|
|
347
|
+
db: Database,
|
|
348
|
+
unchanged_files: set[str],
|
|
349
|
+
) -> list[EntryInfo]:
|
|
350
|
+
"""Load entry points for unchanged files from DB (incremental build)."""
|
|
351
|
+
if not unchanged_files:
|
|
352
|
+
return []
|
|
353
|
+
ph = ",".join("?" for _ in unchanged_files)
|
|
354
|
+
rows = db.fetchall(
|
|
355
|
+
f"SELECT e.*, f.path FROM entries e "
|
|
356
|
+
f"JOIN files f ON e.file_id = f.id "
|
|
357
|
+
f"WHERE f.path IN ({ph})",
|
|
358
|
+
tuple(unchanged_files),
|
|
359
|
+
)
|
|
360
|
+
entries: list[EntryInfo] = []
|
|
361
|
+
for r in rows:
|
|
362
|
+
file_path = r["path"]
|
|
363
|
+
node_id = r["node_id"] or 0
|
|
364
|
+
entries.append(
|
|
365
|
+
EntryInfo(
|
|
366
|
+
rule_name=r["rule_name"],
|
|
367
|
+
file_path=file_path,
|
|
368
|
+
line=r["line"],
|
|
369
|
+
node_id=node_id,
|
|
370
|
+
description=r["description"] or "",
|
|
371
|
+
no_propagate=bool(r["no_propagate"]),
|
|
372
|
+
)
|
|
373
|
+
)
|
|
374
|
+
return entries
|
|
375
|
+
|
|
376
|
+
|
|
305
377
|
def _precompute_edge_counts(
|
|
306
378
|
component_map: dict[int, int],
|
|
307
379
|
edges: list[EdgeInfo],
|
|
@@ -20,6 +20,7 @@ from graphlint.incremental._db_ops import (
|
|
|
20
20
|
build_snapshots,
|
|
21
21
|
load_old_changed_node_ids,
|
|
22
22
|
load_prebuilt_edges,
|
|
23
|
+
load_unchanged_entries,
|
|
23
24
|
persist_unchanged_parent_node_ids,
|
|
24
25
|
update_db,
|
|
25
26
|
update_snapshots,
|
|
@@ -140,7 +141,7 @@ class IncrementalIndexer:
|
|
|
140
141
|
|
|
141
142
|
if needs_full:
|
|
142
143
|
with self.db.transaction():
|
|
143
|
-
for t in ("edges", "nodes", "imports", "warnings", "graph_snapshots", "files"):
|
|
144
|
+
for t in ("edges", "nodes", "imports", "warnings", "graph_snapshots", "entries", "files"):
|
|
144
145
|
self.db.execute(f"DELETE FROM {t}")
|
|
145
146
|
all_results = self._parse_batch(disk_files)
|
|
146
147
|
for fp, pr in all_results:
|
|
@@ -186,11 +187,15 @@ class IncrementalIndexer:
|
|
|
186
187
|
prebuilt = load_prebuilt_edges(self.db, unchanged, sql_to_mem)
|
|
187
188
|
|
|
188
189
|
# ------ Phase 4: Rebuild graph (upstream + downstream + analysis) --
|
|
190
|
+
prebuilt_entries: Optional[list[Any]] = None
|
|
191
|
+
if unchanged:
|
|
192
|
+
prebuilt_entries = load_unchanged_entries(self.db, unchanged)
|
|
189
193
|
builder = self._create_builder(wc)
|
|
190
194
|
br = builder.build(
|
|
191
195
|
pr_map,
|
|
192
196
|
changed_files=set(changed),
|
|
193
197
|
prebuilt_edges=prebuilt,
|
|
198
|
+
prebuilt_entries=prebuilt_entries,
|
|
194
199
|
old_changed_node_ids=old_ids if old_ids else None,
|
|
195
200
|
)
|
|
196
201
|
|
|
@@ -117,6 +117,19 @@ CREATE TABLE IF NOT EXISTS graph_snapshots (
|
|
|
117
117
|
|
|
118
118
|
CREATE INDEX IF NOT EXISTS idx_snapshots_time ON graph_snapshots(snapshot_time);
|
|
119
119
|
|
|
120
|
+
-- Entry points: persisted detection results for incremental rebuild reuse
|
|
121
|
+
CREATE TABLE IF NOT EXISTS entries (
|
|
122
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
123
|
+
file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
|
|
124
|
+
node_id INTEGER DEFAULT 0,
|
|
125
|
+
rule_name TEXT NOT NULL,
|
|
126
|
+
line INTEGER NOT NULL DEFAULT 0,
|
|
127
|
+
description TEXT NOT NULL DEFAULT '',
|
|
128
|
+
no_propagate INTEGER NOT NULL DEFAULT 0
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
CREATE INDEX IF NOT EXISTS idx_entries_file ON entries(file_id);
|
|
132
|
+
|
|
120
133
|
-- Component members: maps node_id to component_id for incremental connectivity analysis
|
|
121
134
|
CREATE TABLE IF NOT EXISTS component_members (
|
|
122
135
|
component_id INTEGER NOT NULL,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphlint
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A static analysis tool for identifying dead code in a codebase. It provides Python API and CLI for use by agents.
|
|
5
5
|
Author-email: Yutong Zou <yutong.zou.24@alumni.ucl.ac.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "graphlint"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.4"
|
|
8
8
|
description = "A static analysis tool for identifying dead code in a codebase. It provides Python API and CLI for use by agents."
|
|
9
9
|
readme = "README_PYPI.md"
|
|
10
10
|
license = "MIT"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|