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 CHANGED
@@ -3,4 +3,4 @@
3
3
  See ``Code-IR.md`` at the repo root for the product specification.
4
4
  """
5
5
 
6
- __version__ = "0.2.0"
6
+ __version__ = "0.2.1"
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(graph=graph, owner=func, source=source, adapter=file_adapter)
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] if first_decl is not None else None
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] if first_decl is not None else None
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:
@@ -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] if first_decl is not None else None
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.0
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=V7neyGEmb34avZRvMxCGk1Cedjlxo-0OVTTeRevz6eA,153
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=22qXPTIxR_gfRe7P0SNivfs6haXdPb_vbaiSN-WkkMw,12866
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=mNR-aMM57D9PFaABVUvE9l5EFKq6QZ13yvQuAXeAo-w,9682
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=SOWOIMpkoLIsGpzMIn_IgwMhS51Ke6cxl-HPv5fhQ4Y,19818
38
- cgir/languages/python.py,sha256=tyjzbNtMuz5BiR4uObCxEIguDu64G9ys_I2VX-4LbUw,43392
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=R6xH_engTOBevT2pkPqyh6-7Kkn8VSxbdZq9g2EAHWg,35293
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.0.dist-info/METADATA,sha256=g-5IH6JpjDC3uG5w6Jbm_bdrOuUL-Iw3PLUV23qsYrM,6707
62
- codegraph_ir-0.2.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
63
- codegraph_ir-0.2.0.dist-info/entry_points.txt,sha256=-y9moAY3BkNj-4tRQW8JM_xLjioEIsgQFKRECvVZpj0,38
64
- codegraph_ir-0.2.0.dist-info/licenses/LICENSE,sha256=ZKZDuzSRXDx9ssBTaEKsx97f7j7w5L3LIvns0fVbMLo,1072
65
- codegraph_ir-0.2.0.dist-info/RECORD,,
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,,