codegraph-ir 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- cgir/__init__.py +1 -1
- cgir/analyses/cfg.py +15 -1
- cgir/languages/base.py +8 -0
- cgir/languages/go.py +4 -1
- cgir/languages/python.py +29 -1
- cgir/languages/typescript.py +13 -1
- {codegraph_ir-0.2.0.dist-info → codegraph_ir-0.2.1.dist-info}/METADATA +1 -1
- {codegraph_ir-0.2.0.dist-info → codegraph_ir-0.2.1.dist-info}/RECORD +11 -11
- {codegraph_ir-0.2.0.dist-info → codegraph_ir-0.2.1.dist-info}/WHEEL +0 -0
- {codegraph_ir-0.2.0.dist-info → codegraph_ir-0.2.1.dist-info}/entry_points.txt +0 -0
- {codegraph_ir-0.2.0.dist-info → codegraph_ir-0.2.1.dist-info}/licenses/LICENSE +0 -0
cgir/__init__.py
CHANGED
cgir/analyses/cfg.py
CHANGED
|
@@ -79,7 +79,13 @@ def build(graph: RepoGraph, repo_path: Path, adapter: LanguageAdapter | None = N
|
|
|
79
79
|
body = file_adapter.function_body(func_ts)
|
|
80
80
|
if body is None:
|
|
81
81
|
continue
|
|
82
|
-
builder = _CFGBuilder(
|
|
82
|
+
builder = _CFGBuilder(
|
|
83
|
+
graph=graph,
|
|
84
|
+
owner=func,
|
|
85
|
+
source=source,
|
|
86
|
+
adapter=file_adapter,
|
|
87
|
+
global_names=file_adapter.global_declared_names(func_ts, source),
|
|
88
|
+
)
|
|
83
89
|
builder.build_block(body, predecessors=[func.id], controller=None)
|
|
84
90
|
|
|
85
91
|
|
|
@@ -89,6 +95,9 @@ class _CFGBuilder:
|
|
|
89
95
|
owner: Node
|
|
90
96
|
source: bytes
|
|
91
97
|
adapter: LanguageAdapter
|
|
98
|
+
# names declared global/nonlocal in this function: writes to them mutate
|
|
99
|
+
# outer state and are recorded as `mutates`, not local `writes`.
|
|
100
|
+
global_names: set[str] = field(default_factory=set)
|
|
92
101
|
_counter: int = field(default=0, init=False)
|
|
93
102
|
|
|
94
103
|
def build_block(
|
|
@@ -102,6 +111,11 @@ class _CFGBuilder:
|
|
|
102
111
|
|
|
103
112
|
def build_stmt(self, ts_node: TSNode, preds: list[str], controller: str | None) -> list[str]:
|
|
104
113
|
desc = self.adapter.describe_statement(ts_node, self.source)
|
|
114
|
+
if isinstance(desc, AssignDesc) and self.global_names:
|
|
115
|
+
outer = [w for w in desc.writes if w in self.global_names]
|
|
116
|
+
if outer:
|
|
117
|
+
desc.writes = [w for w in desc.writes if w not in self.global_names]
|
|
118
|
+
desc.mutates = list(desc.mutates) + outer
|
|
105
119
|
if isinstance(desc, BranchDesc):
|
|
106
120
|
return self._build_branch(ts_node, desc, preds, controller)
|
|
107
121
|
if isinstance(desc, LoopDesc):
|
cgir/languages/base.py
CHANGED
|
@@ -264,6 +264,14 @@ class LanguageAdapter(ABC):
|
|
|
264
264
|
def describe_statement(self, node: TSNode, source: bytes) -> StatementDesc:
|
|
265
265
|
"""Classify one statement and extract its parts (see descriptors)."""
|
|
266
266
|
|
|
267
|
+
def global_declared_names(self, func_node: TSNode, source: bytes) -> set[str]:
|
|
268
|
+
"""Names this function declares as outer-scope (`global`/`nonlocal`).
|
|
269
|
+
|
|
270
|
+
Assignments to these names mutate state *outside* the function, so
|
|
271
|
+
the CFG builder records them as ``mutates`` rather than local
|
|
272
|
+
``writes``. Default: none (TS/Go have no such declaration form)."""
|
|
273
|
+
return set()
|
|
274
|
+
|
|
267
275
|
# --- phase 3: ingest extraction ------------------------------------------
|
|
268
276
|
|
|
269
277
|
@abstractmethod
|
cgir/languages/go.py
CHANGED
|
@@ -295,8 +295,11 @@ class GoAdapter(LanguageAdapter):
|
|
|
295
295
|
first_decl = next(
|
|
296
296
|
(c for c in root.named_children if c.type not in {"comment", "package_clause"}), None
|
|
297
297
|
)
|
|
298
|
+
pinnable = {"function_declaration", "method_declaration", "type_declaration"}
|
|
298
299
|
module_pins = pin_index.module_pins(
|
|
299
|
-
first_decl.start_point[0]
|
|
300
|
+
first_decl.start_point[0]
|
|
301
|
+
if first_decl is not None and first_decl.type in pinnable
|
|
302
|
+
else None
|
|
300
303
|
)
|
|
301
304
|
if module_pins:
|
|
302
305
|
for decl in decls:
|
cgir/languages/python.py
CHANGED
|
@@ -205,6 +205,28 @@ class PythonAdapter(LanguageAdapter):
|
|
|
205
205
|
def function_body(self, func_node: TSNode) -> TSNode | None:
|
|
206
206
|
return func_node.child_by_field_name("body")
|
|
207
207
|
|
|
208
|
+
def global_declared_names(self, func_node: TSNode, source: bytes) -> set[str]:
|
|
209
|
+
"""Names bound by `global`/`nonlocal` in *this* function's own body.
|
|
210
|
+
|
|
211
|
+
Nested function bodies are skipped — their declarations apply to
|
|
212
|
+
their own CFG walk, not this one."""
|
|
213
|
+
names: set[str] = set()
|
|
214
|
+
body = func_node.child_by_field_name("body")
|
|
215
|
+
if body is None:
|
|
216
|
+
return names
|
|
217
|
+
stack: list[TSNode] = [body]
|
|
218
|
+
while stack:
|
|
219
|
+
node = stack.pop()
|
|
220
|
+
if node.type in {"function_definition", "class_definition"}:
|
|
221
|
+
continue # a nested scope's declarations are not ours
|
|
222
|
+
if node.type in {"global_statement", "nonlocal_statement"}:
|
|
223
|
+
for child in node.named_children:
|
|
224
|
+
if child.type == "identifier":
|
|
225
|
+
names.add(_text(child, source))
|
|
226
|
+
continue
|
|
227
|
+
stack.extend(node.named_children)
|
|
228
|
+
return names
|
|
229
|
+
|
|
208
230
|
def block_statements(self, block: TSNode) -> list[TSNode]:
|
|
209
231
|
return [c for c in block.named_children if c.type != "comment"]
|
|
210
232
|
|
|
@@ -335,8 +357,14 @@ class PythonAdapter(LanguageAdapter):
|
|
|
335
357
|
for child in root.children:
|
|
336
358
|
decls.extend(self._top_level_decl(child, source, module_name, pin_index))
|
|
337
359
|
first_decl = next((c for c in root.children if c.type != "comment"), None)
|
|
360
|
+
# A header block only belongs to the first statement when that
|
|
361
|
+
# statement is *pinnable* (a definition) — touching an import keeps
|
|
362
|
+
# the pins module-level.
|
|
363
|
+
pinnable = {"function_definition", "class_definition", "decorated_definition"}
|
|
338
364
|
module_pins = pin_index.module_pins(
|
|
339
|
-
first_decl.start_point[0]
|
|
365
|
+
first_decl.start_point[0]
|
|
366
|
+
if first_decl is not None and first_decl.type in pinnable
|
|
367
|
+
else None
|
|
340
368
|
)
|
|
341
369
|
if module_pins:
|
|
342
370
|
for decl in decls:
|
cgir/languages/typescript.py
CHANGED
|
@@ -391,8 +391,20 @@ class TypeScriptAdapter(LanguageAdapter):
|
|
|
391
391
|
for child in root.children:
|
|
392
392
|
decls.extend(self._top_level(child, source, rel_path, pin_index))
|
|
393
393
|
first_decl = next((c for c in root.children if c.type != "comment"), None)
|
|
394
|
+
# Only a pinnable definition claims an adjacent header block; an
|
|
395
|
+
# import keeps the pins module-level.
|
|
396
|
+
pinnable = {
|
|
397
|
+
"function_declaration",
|
|
398
|
+
"class_declaration",
|
|
399
|
+
"abstract_class_declaration",
|
|
400
|
+
"export_statement",
|
|
401
|
+
"lexical_declaration",
|
|
402
|
+
"variable_declaration",
|
|
403
|
+
}
|
|
394
404
|
module_pins = pin_index.module_pins(
|
|
395
|
-
first_decl.start_point[0]
|
|
405
|
+
first_decl.start_point[0]
|
|
406
|
+
if first_decl is not None and first_decl.type in pinnable
|
|
407
|
+
else None
|
|
396
408
|
)
|
|
397
409
|
if module_pins:
|
|
398
410
|
for decl in decls:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codegraph-ir
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: The deterministic contract layer for AI-modified codebases — effects, purity, contracts, and blast radius, with zero LLM calls.
|
|
5
5
|
Project-URL: Homepage, https://github.com/asonkiya/llm-semantic-compilers
|
|
6
6
|
Project-URL: Repository, https://github.com/asonkiya/llm-semantic-compilers
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
cgir/__init__.py,sha256=
|
|
1
|
+
cgir/__init__.py,sha256=P6fJ6w2O8KkY-PZHk_scyugcQ4VC0s3lzSZfng_Yi4M,153
|
|
2
2
|
cgir/cli.py,sha256=HOz6lY7kOz0uJKh_x_alCylOFkUNv6RL-hEDEB5pvJc,29609
|
|
3
3
|
cgir/config.py,sha256=-PV5vhm_cKdRu5eYZ88GLW1e8FazgczbZ1CWal9rHSk,630
|
|
4
4
|
cgir/hooks.py,sha256=Pg1KQvLmU01aLy0yhWYKt7vLn6k7TxyV1v3KKlMwYoE,7059
|
|
@@ -9,7 +9,7 @@ cgir/verify.py,sha256=ks0apBRShE5a0XXoxq6F_X10uygxPRyfEkc9Lg5PzBU,6314
|
|
|
9
9
|
cgir/watch.py,sha256=yNrVltZ9GMlkRnxH_OAVz21o4Wy8Q55QfYIG5te1ryI,5867
|
|
10
10
|
cgir/analyses/__init__.py,sha256=zXyy1sTQ1_vr6ngVp-wHXQ_tvfPMMoqo6Y8VDUzaPJs,298
|
|
11
11
|
cgir/analyses/call_graph.py,sha256=lT_hiaAnNomtkzWcxiXubHLqbhVKzVIwi7LTpgaXNyI,4432
|
|
12
|
-
cgir/analyses/cfg.py,sha256=
|
|
12
|
+
cgir/analyses/cfg.py,sha256=zoHl1aek0hpBRrAvoG2HAVVrlq5DLrKPAwzTQJWuM2w,13504
|
|
13
13
|
cgir/analyses/effects.py,sha256=0wjkoK4z3vTEAU1YQg7Du54lo7qbL8M4gDe7GGiMmBg,4051
|
|
14
14
|
cgir/analyses/entrypoints.py,sha256=ZDAbfXpmu1fBwWj7moBEgo9UeEH6NzQJUwAR_I51YkI,2203
|
|
15
15
|
cgir/analyses/param_flow.py,sha256=CGLmylORfT_GG_xk8eNx9RvH8TGVSQ3scSGJlf25a5k,2623
|
|
@@ -32,12 +32,12 @@ cgir/ir/edges.py,sha256=pDIFgpg4UVx9lcTi8Y7aoAxGYT5yEU6aEqywq-KNa4I,700
|
|
|
32
32
|
cgir/ir/graph.py,sha256=T18-WS_wi_nDfjd7P7_xjZylkUPrR0JTtpwpJqXBnKs,4592
|
|
33
33
|
cgir/ir/nodes.py,sha256=P5dZ4GqQZwsxANg5e_jYc5uN3R6hkUYqjP7O6n-XDsY,858
|
|
34
34
|
cgir/languages/__init__.py,sha256=4CQavFpRbmfdw9MjIh8nKOv0o3md8E8YC-ECiuUGXdY,779
|
|
35
|
-
cgir/languages/base.py,sha256=
|
|
35
|
+
cgir/languages/base.py,sha256=IaiKOGeucf_HziaSw5q8-ojYOBe47N6Dl2U1Z3FsEc8,10087
|
|
36
36
|
cgir/languages/cache.py,sha256=_wcNLb5OmVBSuIXEIxEvVOT6GA5FzhXxWKOsC1sGCm0,2878
|
|
37
|
-
cgir/languages/go.py,sha256=
|
|
38
|
-
cgir/languages/python.py,sha256=
|
|
37
|
+
cgir/languages/go.py,sha256=U6n03hK_seaR5847xP-R1rCPCbJhGxUgcAYQBRuM6cQ,19960
|
|
38
|
+
cgir/languages/python.py,sha256=tzgdCB_BQm5jbEMnfcoU4URyt6Ul-sUakd6Y-cDqJTU,44688
|
|
39
39
|
cgir/languages/registry.py,sha256=N0ViSe5O3tP-n-FljrdP-TxwSAtdz6N-S5k2SgF628U,895
|
|
40
|
-
cgir/languages/typescript.py,sha256=
|
|
40
|
+
cgir/languages/typescript.py,sha256=MhtqQ4wsGzjjVT1FBYU6B-CWxbTgRLhNMitpKQJajmk,35713
|
|
41
41
|
cgir/regenerate/__init__.py,sha256=tES3u6yn28zcxOaKUGli5iqCc0j5W501SS-zxvsy_a8,227
|
|
42
42
|
cgir/regenerate/prompt_pack.py,sha256=wJs9x5Jn7ap09HHF4ULJ2yHiZ56YYhLaQ6uXZEjkDHc,584
|
|
43
43
|
cgir/regenerate/regenerator.py,sha256=DBpufeJItrhBkxt4v45Ltnp8BnV1gAUshxwKa-U8fzA,3517
|
|
@@ -58,8 +58,8 @@ cgir/sources/joern_source.py,sha256=TeI5Uu7E3vDLLnCDVuHu1U_k1RW7lpdKAwZGzb5OuEc,
|
|
|
58
58
|
cgir/sources/tree_sitter_source.py,sha256=LEgPihpMdwLJ4j3cB4Jsx3SXJfutTftUx1Ewzdbme8Q,9574
|
|
59
59
|
cgir/trace/__init__.py,sha256=vMwb47f70-zpsupyVCC_cq6lEIe2k2Kn2W8Z87-30Hg,153
|
|
60
60
|
cgir/trace/trace_map.py,sha256=x5k46_5CZYPe7PxXmFSKZrbhlg1rXK0_OBHsawE5xWM,2536
|
|
61
|
-
codegraph_ir-0.2.
|
|
62
|
-
codegraph_ir-0.2.
|
|
63
|
-
codegraph_ir-0.2.
|
|
64
|
-
codegraph_ir-0.2.
|
|
65
|
-
codegraph_ir-0.2.
|
|
61
|
+
codegraph_ir-0.2.1.dist-info/METADATA,sha256=Xn_FrYrThQuo2Q5CnpofPEkvcL8Pp3ADKu64ifGAwac,6707
|
|
62
|
+
codegraph_ir-0.2.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
63
|
+
codegraph_ir-0.2.1.dist-info/entry_points.txt,sha256=-y9moAY3BkNj-4tRQW8JM_xLjioEIsgQFKRECvVZpj0,38
|
|
64
|
+
codegraph_ir-0.2.1.dist-info/licenses/LICENSE,sha256=ZKZDuzSRXDx9ssBTaEKsx97f7j7w5L3LIvns0fVbMLo,1072
|
|
65
|
+
codegraph_ir-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|