gabion 0.1.0__py3-none-any.whl → 0.1.5__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.
- gabion/__init__.py +1 -1
- gabion/analysis/dataflow_audit.py +315 -88
- gabion/analysis/visitors.py +80 -0
- gabion/cli.py +367 -144
- gabion/config.py +8 -0
- gabion/lsp_client.py +3 -2
- gabion/refactor/engine.py +214 -23
- gabion/refactor/model.py +1 -0
- gabion/schema.py +2 -0
- gabion/server.py +10 -7
- gabion/synthesis/merge.py +0 -2
- gabion/synthesis/model.py +1 -0
- {gabion-0.1.0.dist-info → gabion-0.1.5.dist-info}/METADATA +21 -4
- gabion-0.1.5.dist-info/RECORD +26 -0
- gabion-0.1.0.dist-info/RECORD +0 -26
- {gabion-0.1.0.dist-info → gabion-0.1.5.dist-info}/WHEEL +0 -0
- {gabion-0.1.0.dist-info → gabion-0.1.5.dist-info}/entry_points.txt +0 -0
- {gabion-0.1.0.dist-info → gabion-0.1.5.dist-info}/licenses/LICENSE +0 -0
gabion/analysis/visitors.py
CHANGED
|
@@ -68,6 +68,7 @@ class UseVisitor(ast.NodeVisitor):
|
|
|
68
68
|
callee_name: Callable[[ast.Call], str],
|
|
69
69
|
call_args_factory: Callable[..., CallArgs],
|
|
70
70
|
call_context: Callable[[ast.AST, dict[ast.AST, ast.AST]], tuple[ast.Call | None, bool]],
|
|
71
|
+
return_aliases: dict[str, tuple[list[str], list[str]]] | None = None,
|
|
71
72
|
) -> None:
|
|
72
73
|
# dataflow-bundle: alias_to_param, call_args, call_args_factory, call_context, callee_name, const_repr, is_test, parents, strictness, use_map
|
|
73
74
|
self.parents = parents
|
|
@@ -80,6 +81,7 @@ class UseVisitor(ast.NodeVisitor):
|
|
|
80
81
|
self.callee_name = callee_name
|
|
81
82
|
self.call_args_factory = call_args_factory
|
|
82
83
|
self.call_context = call_context
|
|
84
|
+
self.return_aliases = return_aliases or {}
|
|
83
85
|
self._suspend_non_forward: set[str] = set()
|
|
84
86
|
self._attr_alias_to_param: dict[tuple[str, str], str] = {}
|
|
85
87
|
self._key_alias_to_param: dict[tuple[str, str], str] = {}
|
|
@@ -196,7 +198,76 @@ class UseVisitor(ast.NodeVisitor):
|
|
|
196
198
|
return sources
|
|
197
199
|
return set()
|
|
198
200
|
|
|
201
|
+
def _alias_from_call(self, call: ast.Call) -> list[str] | None:
|
|
202
|
+
if not self.return_aliases:
|
|
203
|
+
return None
|
|
204
|
+
callee = self.callee_name(call)
|
|
205
|
+
info = self.return_aliases.get(callee)
|
|
206
|
+
if info is None:
|
|
207
|
+
return None
|
|
208
|
+
params, aliases = info
|
|
209
|
+
if not aliases:
|
|
210
|
+
return None
|
|
211
|
+
mapping: dict[str, str | None] = {}
|
|
212
|
+
for idx, arg in enumerate(call.args):
|
|
213
|
+
if isinstance(arg, ast.Starred):
|
|
214
|
+
return None
|
|
215
|
+
if idx >= len(params):
|
|
216
|
+
return None
|
|
217
|
+
if isinstance(arg, ast.Name) and arg.id in self.alias_to_param:
|
|
218
|
+
mapping[params[idx]] = self.alias_to_param[arg.id]
|
|
219
|
+
else:
|
|
220
|
+
mapping[params[idx]] = None
|
|
221
|
+
for kw in call.keywords:
|
|
222
|
+
if kw.arg is None:
|
|
223
|
+
return None
|
|
224
|
+
if kw.arg not in params:
|
|
225
|
+
continue
|
|
226
|
+
if isinstance(kw.value, ast.Name) and kw.value.id in self.alias_to_param:
|
|
227
|
+
mapping[kw.arg] = self.alias_to_param[kw.value.id]
|
|
228
|
+
else:
|
|
229
|
+
mapping[kw.arg] = None
|
|
230
|
+
resolved: list[str] = []
|
|
231
|
+
for param in aliases:
|
|
232
|
+
mapped = mapping.get(param)
|
|
233
|
+
if not mapped:
|
|
234
|
+
return None
|
|
235
|
+
resolved.append(mapped)
|
|
236
|
+
return resolved
|
|
237
|
+
|
|
238
|
+
def _bind_return_alias(
|
|
239
|
+
self, targets: list[ast.AST], aliases: list[str]
|
|
240
|
+
) -> bool:
|
|
241
|
+
if len(targets) != 1:
|
|
242
|
+
return False
|
|
243
|
+
target = targets[0]
|
|
244
|
+
if isinstance(target, ast.Name):
|
|
245
|
+
if len(aliases) != 1:
|
|
246
|
+
return False
|
|
247
|
+
param = aliases[0]
|
|
248
|
+
self.alias_to_param[target.id] = param
|
|
249
|
+
if param in self.use_map:
|
|
250
|
+
self.use_map[param].current_aliases.add(target.id)
|
|
251
|
+
return True
|
|
252
|
+
if isinstance(target, (ast.Tuple, ast.List)):
|
|
253
|
+
if len(target.elts) != len(aliases):
|
|
254
|
+
return False
|
|
255
|
+
if not all(isinstance(elt, ast.Name) for elt in target.elts):
|
|
256
|
+
return False
|
|
257
|
+
for elt, param in zip(target.elts, aliases):
|
|
258
|
+
if isinstance(elt, ast.Name):
|
|
259
|
+
self.alias_to_param[elt.id] = param
|
|
260
|
+
if param in self.use_map:
|
|
261
|
+
self.use_map[param].current_aliases.add(elt.id)
|
|
262
|
+
return True
|
|
263
|
+
return False
|
|
264
|
+
|
|
199
265
|
def visit_Assign(self, node: ast.Assign) -> None:
|
|
266
|
+
if isinstance(node.value, ast.Call):
|
|
267
|
+
aliases = self._alias_from_call(node.value)
|
|
268
|
+
if aliases and self._bind_return_alias(node.targets, aliases):
|
|
269
|
+
self.visit(node.value)
|
|
270
|
+
return
|
|
200
271
|
rhs_param = None
|
|
201
272
|
if isinstance(node.value, ast.Name) and node.value.id in self.alias_to_param:
|
|
202
273
|
rhs_param = self.alias_to_param[node.value.id]
|
|
@@ -238,6 +309,15 @@ class UseVisitor(ast.NodeVisitor):
|
|
|
238
309
|
def visit_AnnAssign(self, node: ast.AnnAssign) -> None:
|
|
239
310
|
if node.value is None:
|
|
240
311
|
return
|
|
312
|
+
if isinstance(node.value, ast.Call) and isinstance(node.target, ast.Name):
|
|
313
|
+
aliases = self._alias_from_call(node.value)
|
|
314
|
+
if aliases and len(aliases) == 1:
|
|
315
|
+
param = aliases[0]
|
|
316
|
+
self.alias_to_param[node.target.id] = param
|
|
317
|
+
if param in self.use_map:
|
|
318
|
+
self.use_map[param].current_aliases.add(node.target.id)
|
|
319
|
+
self.visit(node.value)
|
|
320
|
+
return
|
|
241
321
|
rhs_param = None
|
|
242
322
|
if isinstance(node.value, ast.Name) and node.value.id in self.alias_to_param:
|
|
243
323
|
rhs_param = self.alias_to_param[node.value.id]
|