Skip to content

Commit 9de4012

Browse files
author
tkucar
committed
fix
1 parent c19a7a6 commit 9de4012

File tree

15 files changed

+1100
-26
lines changed

15 files changed

+1100
-26
lines changed

codegen-examples/examples/snapshot_event_handler/pr_tasks.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import logging
2-
from codegen.agents.code_agent import CodeAgent
32
from codegen.extensions.github.types.pull_request import PullRequestLabeledEvent
43

5-
from codegen.extensions.langchain.tools import GithubCreatePRCommentTool, GithubCreatePRReviewCommentTool, GithubViewPRTool
64
from codegen.sdk.core.codebase import Codebase
75

86
logging.basicConfig(level=logging.INFO, force=True)

src/codegen/sdk/core/expressions/name.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,36 @@ def rename_if_matching(self, old: str, new: str):
5050
if self.source == old:
5151
self.edit(new)
5252

53+
54+
def _resolve_conditionals(self,conditional_parent:ConditionalBlock,name:str,original_resolved):
55+
search_limit = conditional_parent.start_byte_for_condition_block
56+
if search_limit>=original_resolved.start_byte:
57+
search_limit=original_resolved.start_byte-1
58+
if not conditional_parent.is_true_conditional(original_resolved):
59+
#If it's a fake conditional we must skip any potential enveloping conditionals
60+
def get_top_of_fake_chain(conditional,resolved,search_limit=0):
61+
if skip_fake:= conditional.parent_of_type(ConditionalBlock):
62+
if skip_fake.is_true_conditional(resolved):
63+
return skip_fake.start_byte_for_condition_block
64+
search_limit=skip_fake.start_byte_for_condition_block
65+
return get_top_of_fake_chain(skip_fake,conditional,search_limit)
66+
return search_limit
67+
if search_limit:=get_top_of_fake_chain(conditional_parent,original_resolved):
68+
search_limit=search_limit
69+
else:
70+
return
71+
72+
original_conditional = conditional_parent
73+
while next_resolved:= next(conditional_parent.resolve_name(name,start_byte=search_limit,strict=False),None):
74+
yield next_resolved
75+
next_conditional = next_resolved.parent_of_type(ConditionalBlock)
76+
if not next_conditional or next_conditional == original_conditional:
77+
return
78+
search_limit = next_conditional.start_byte_for_condition_block
79+
if next_conditional and not next_conditional.is_true_conditional(original_resolved):
80+
pass
81+
if search_limit>=next_resolved.start_byte:
82+
search_limit=next_resolved.start_byte-1
5383
@noapidoc
5484
@reader
5585
def resolve_name(self, name: str, start_byte: int | None = None, strict: bool = True) -> Generator["Symbol | Import | WildcardImport"]:
@@ -60,14 +90,8 @@ def resolve_name(self, name: str, start_byte: int | None = None, strict: bool =
6090
return
6191

6292
if hasattr(resolved_name, "parent") and (conditional_parent := resolved_name.parent_of_type(ConditionalBlock)):
63-
top_of_conditional = conditional_parent.start_byte
6493
if self.parent_of_type(ConditionalBlock) == conditional_parent:
6594
# Use in the same block, should only depend on the inside of the block
6695
return
67-
for other_conditional in conditional_parent.other_possible_blocks:
68-
if cond_name := next(other_conditional.resolve_name(name, start_byte=other_conditional.end_byte_for_condition_block), None):
69-
if cond_name.start_byte >= other_conditional.start_byte:
70-
yield cond_name
71-
top_of_conditional = min(top_of_conditional, other_conditional.start_byte)
7296

73-
yield from self.resolve_name(name, top_of_conditional, strict=False)
97+
yield from self._resolve_conditionals(conditional_parent=conditional_parent,name=name,original_resolved=resolved_name)

src/codegen/sdk/core/interfaces/conditional_block.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from collections.abc import Sequence
33

44
from codegen.sdk.core.statements.statement import Statement
5+
from codegen.shared.decorators.docs import noapidoc
56

67

78
class ConditionalBlock(Statement, ABC):
@@ -15,3 +16,14 @@ def other_possible_blocks(self) -> Sequence["ConditionalBlock"]:
1516
@property
1617
def end_byte_for_condition_block(self) -> int:
1718
return self.end_byte
19+
20+
@property
21+
@noapidoc
22+
def start_byte_for_condition_block(self) -> int:
23+
"""Returns the start byte for the specific condition block"""
24+
return self.start_byte
25+
26+
@noapidoc
27+
def is_true_conditional(self,descendant) -> bool:
28+
"""Returns if this conditional is truly conditional, this is necessary as an override for things like finally statements that share a parent with try blocks"""
29+
return True

src/codegen/sdk/core/interfaces/editable.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,14 @@ def parent_of_types(self, types: set[type[T]]) -> T | None:
11061106
return self.parent.parent_of_types(types)
11071107
return None
11081108

1109+
def is_child_of(self, instance: Editable) -> bool:
1110+
if not self.parent:
1111+
return False
1112+
if self.parent is instance:
1113+
return True
1114+
else:
1115+
return self.parent.is_child_of(instance=instance)
1116+
11091117
@reader
11101118
def ancestors(self, type: type[T]) -> list[T]:
11111119
"""Find all ancestors of the node of the given type. Does not return itself"""

src/codegen/sdk/core/statements/if_block_statement.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,10 @@ def end_byte_for_condition_block(self) -> int:
297297
if self.is_if_statement:
298298
return self.consequence_block.end_byte
299299
return self.end_byte
300+
301+
@property
302+
@noapidoc
303+
def start_byte_for_condition_block(self) -> int:
304+
if self.is_if_statement:
305+
return self.consequence_block.start_byte
306+
return self.start_byte

src/codegen/sdk/core/statements/try_catch_statement.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from __future__ import annotations
22

33
from abc import ABC
4-
from typing import TYPE_CHECKING, Generic, TypeVar
4+
from typing import TYPE_CHECKING, Generic, TypeVar, override
55

66
from codegen.sdk.core.interfaces.conditional_block import ConditionalBlock
77
from codegen.sdk.core.interfaces.has_block import HasBlock
88
from codegen.sdk.core.statements.block_statement import BlockStatement
99
from codegen.sdk.core.statements.statement import StatementType
10-
from codegen.shared.decorators.docs import apidoc
10+
from codegen.shared.decorators.docs import apidoc, noapidoc
1111

1212
if TYPE_CHECKING:
1313
from codegen.sdk.core.detached_symbols.code_block import CodeBlock
@@ -27,3 +27,26 @@ class TryCatchStatement(ConditionalBlock, BlockStatement[Parent], HasBlock, ABC,
2727

2828
statement_type = StatementType.TRY_CATCH_STATEMENT
2929
finalizer: BlockStatement | None = None
30+
31+
@noapidoc
32+
@override
33+
def is_true_conditional(self,descendant) -> bool:
34+
if descendant.is_child_of(self.finalizer):
35+
return False
36+
return True
37+
38+
@property
39+
@noapidoc
40+
def end_byte_for_condition_block(self) -> int:
41+
if self.code_block:
42+
return self.code_block.end_byte
43+
else:
44+
return self.end_byte
45+
46+
@property
47+
@noapidoc
48+
def start_byte_for_condition_block(self) -> int:
49+
if self.code_block:
50+
return self.code_block.start_byte-1
51+
else:
52+
return self.start_byte

src/codegen/sdk/python/statements/catch_statement.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ def __init__(self, ts_node: PyNode, file_node_id: NodeId, ctx: CodebaseContext,
3131
@property
3232
def other_possible_blocks(self) -> list[ConditionalBlock]:
3333
return [clause for clause in self.parent.except_clauses if clause != self] + [self.parent]
34+

src/codegen/sdk/python/statements/try_catch_statement.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def _compute_dependencies(self, usage_type: UsageKind | None = None, dest: HasNa
6868
if self.finalizer:
6969
self.finalizer._compute_dependencies(usage_type, dest)
7070

71+
7172
@property
7273
@noapidoc
7374
def descendant_symbols(self) -> list[Importable]:
@@ -103,10 +104,3 @@ def nested_code_blocks(self) -> list[PyCodeBlock]:
103104
@property
104105
def other_possible_blocks(self) -> Sequence[ConditionalBlock]:
105106
return self.except_clauses
106-
107-
@property
108-
def end_byte_for_condition_block(self) -> int:
109-
if self.code_block:
110-
return self.code_block.end_byte
111-
else:
112-
return self.end_byte

src/codegen/sdk/typescript/statements/try_catch_statement.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class TSTryCatchStatement(TryCatchStatement["TSCodeBlock"], TSBlockStatement):
3636
def __init__(self, ts_node: TSNode, file_node_id: NodeId, ctx: CodebaseContext, parent: TSCodeBlock, pos: int | None = None) -> None:
3737
super().__init__(ts_node, file_node_id, ctx, parent, pos)
3838
if handler_node := self.ts_node.child_by_field_name("handler"):
39-
self.catch = TSCatchStatement(handler_node, file_node_id, ctx, self.code_block)
39+
self.catch = TSCatchStatement(handler_node, file_node_id, ctx, self)
4040
if finalizer_node := self.ts_node.child_by_field_name("finalizer"):
4141
self.finalizer = TSBlockStatement(finalizer_node, file_node_id, ctx, self.code_block)
4242

@@ -101,10 +101,3 @@ def other_possible_blocks(self) -> Sequence[ConditionalBlock]:
101101
return [self.catch]
102102
else:
103103
return []
104-
105-
@property
106-
def end_byte_for_condition_block(self) -> int:
107-
if self.code_block:
108-
return self.code_block.end_byte
109-
else:
110-
return self.end_byte

tests/unit/codegen/sdk/python/statements/if_block_statement/test_if_block_statement_properties.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,56 @@ def test_if_else_reassigment_handling_nested_usage(tmpdir) -> None:
266266
second = file.symbols[1]
267267
assert len(first.usages) == 0
268268
assert second.usages[0].match == pyspark_arg
269+
270+
271+
def test_if_else_reassigment_inside_func_with_external_element(tmpdir) -> None:
272+
content = """
273+
PYSPARK="0"
274+
def foo():
275+
if True:
276+
PYSPARK = True
277+
else:
278+
PYSPARK = False
279+
print(PYSPARK)
280+
281+
"""
282+
283+
with get_codebase_session(tmpdir=tmpdir, files={"test.py": content}) as codebase:
284+
file = codebase.get_file("test.py")
285+
funct_call = file.function_calls[0]
286+
pyspark_arg = funct_call.args.children[0]
287+
func = file.get_function("foo")
288+
for assign in func.valid_symbol_names[:-1]:
289+
assign.usages[0] == pyspark_arg
290+
291+
292+
293+
def test_if_else_reassigment_handling_double_nested(tmpdir) -> None:
294+
content = """
295+
if False:
296+
PYSPARK = "TEST1"
297+
elif True:
298+
PYSPARK = "TEST2"
299+
300+
if True:
301+
PYSPARK = True
302+
elif None:
303+
if True:
304+
PYSPARK = True
305+
elif None:
306+
if True:
307+
PYSPARK = True
308+
elif None:
309+
PYSPARK = False
310+
311+
print(PYSPARK)
312+
"""
313+
314+
with get_codebase_session(tmpdir=tmpdir, files={"test.py": content}) as codebase:
315+
file = codebase.get_file("test.py")
316+
symbo = file.get_symbol("PYSPARK")
317+
funct_call = file.function_calls[0]
318+
pyspark_arg = funct_call.args.children[0]
319+
for symb in file.symbols:
320+
usage = symb.usages[0]
321+
assert usage.match == pyspark_arg

0 commit comments

Comments
 (0)