Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/analyzer/code_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,29 @@ def _analyze_hot_paths(self, tree: ast.AST) -> None:
def _infer_expression_type(self, expr: ast.AST) -> str:
"""Backward compatibility method for tests."""
return self.type_analyzer._infer_expression_type(expr) or 'auto'

def _get_type_name(self, node: ast.AST) -> str:
"""Backward compatibility method for tests."""
return self.type_analyzer._annotation_to_cpp_type(node) or 'auto'

def _infer_variable_type(self, node: ast.Assign) -> None:
"""Backward compatibility method for tests."""
self.type_analyzer._infer_variable_type(node)
# Update local type_info from the analyzer
for var_name, var_type in self.type_analyzer.type_info.items():
if isinstance(var_type, str): # Only copy simple type strings
if not hasattr(self, 'type_info'):
self.type_info = {}
self.type_info[var_name] = var_type

def _infer_function_types(self, node: ast.FunctionDef) -> None:
"""Backward compatibility method for tests."""
self.type_analyzer._analyze_function_types(node)
# Update local type_info from the analyzer
for var_name, var_type in self.type_analyzer.type_info.items():
if not hasattr(self, 'type_info'):
self.type_info = {}
Comment on lines +131 to +143
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hasattr(self, 'type_info') check and dictionary initialization is performed inside the loop. This should be moved outside the loop to avoid repeated attribute checks and potential multiple initializations.

Suggested change
for var_name, var_type in self.type_analyzer.type_info.items():
if isinstance(var_type, str): # Only copy simple type strings
if not hasattr(self, 'type_info'):
self.type_info = {}
self.type_info[var_name] = var_type
def _infer_function_types(self, node: ast.FunctionDef) -> None:
"""Backward compatibility method for tests."""
self.type_analyzer._analyze_function_types(node)
# Update local type_info from the analyzer
for var_name, var_type in self.type_analyzer.type_info.items():
if not hasattr(self, 'type_info'):
self.type_info = {}
if not hasattr(self, 'type_info'):
self.type_info = {}
for var_name, var_type in self.type_analyzer.type_info.items():
if isinstance(var_type, str): # Only copy simple type strings
self.type_info[var_name] = var_type
def _infer_function_types(self, node: ast.FunctionDef) -> None:
"""Backward compatibility method for tests."""
self.type_analyzer._analyze_function_types(node)
# Update local type_info from the analyzer
if not hasattr(self, 'type_info'):
self.type_info = {}
for var_name, var_type in self.type_analyzer.type_info.items():

Copilot uses AI. Check for mistakes.
self.type_info[var_name] = var_type

def _find_containing_function_or_class(self, target_node: ast.AST, tree: ast.AST) -> Optional[str]:
"""Find the function or class containing a given node."""
Expand Down
30 changes: 23 additions & 7 deletions src/analyzer/performance_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,11 @@ def _analyze_loop_performance(self, node: ast.AST) -> None:
if isinstance(node, (ast.For, ast.While)):
# Check for nested loops
nested_loops = self._count_nested_loops(node)
if nested_loops > 2:
if nested_loops > 1: # Detect nested loops (2+ levels)
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says '2+ levels' but the condition checks for > 1, which means it triggers at exactly 2 levels. The comment should be '2+ levels' or the condition should be >= 2 to match the intended behavior.

Copilot uses AI. Check for mistakes.
line = getattr(node, 'lineno', 0)
self.performance_bottlenecks.append({
'type': 'nested_loops',
'description': f'Nested loop detected with {nested_loops} levels of nesting',
'nesting_level': nested_loops,
'line': line,
'suggestion': 'Consider algorithm optimization to reduce nesting'
Expand All @@ -87,12 +88,27 @@ def _analyze_loop_performance(self, node: ast.AST) -> None:
expensive_ops = self._find_expensive_operations_in_loop(node)
if expensive_ops:
line = getattr(node, 'lineno', 0)
self.performance_bottlenecks.append({
'type': 'expensive_loop_operations',
'operations': expensive_ops,
'line': line,
'suggestion': 'Move expensive operations outside the loop when possible'
})

# Check specifically for container modifications
container_ops = [op for op in expensive_ops if op in ['append', 'extend', 'insert']]
if container_ops:
self.performance_bottlenecks.append({
'type': 'container_modification',
'description': f'Container modification in loop: {", ".join(container_ops)}',
'operations': container_ops,
'line': line,
'suggestion': 'Consider pre-allocating containers or using list comprehensions'
})

# Check for other expensive operations
other_ops = [op for op in expensive_ops if op not in ['append', 'extend', 'insert']]
if other_ops:
self.performance_bottlenecks.append({
'type': 'expensive_loop_operations',
'operations': other_ops,
'line': line,
'suggestion': 'Move expensive operations outside the loop when possible'
})

def _analyze_comprehension_performance(self, node: ast.ListComp) -> None:
"""Analyze list comprehension performance."""
Expand Down
22 changes: 21 additions & 1 deletion src/analyzer/type_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ def _infer_expression_type(self, expr: ast.AST) -> Optional[str]:
result = 'double'
elif isinstance(expr.value, str):
result = 'std::string'
elif expr.value is None:
result = 'std::nullptr_t'
elif isinstance(expr, ast.List):
if expr.elts:
element_type = self._infer_expression_type(expr.elts[0])
Expand Down Expand Up @@ -190,6 +192,12 @@ def _infer_expression_type(self, expr: ast.AST) -> Optional[str]:
result = 'int'
else:
result = 'auto'
elif isinstance(expr, ast.Compare):
# Comparison operations always return bool
result = 'bool'
elif isinstance(expr, ast.BoolOp):
# Boolean operations (and, or) always return bool
result = 'bool'
elif isinstance(expr, ast.ListComp):
# List comprehension - infer from element type
element_type = self._infer_expression_type(expr.elt)
Expand Down Expand Up @@ -231,5 +239,17 @@ def _analyze_function_types(self, node: ast.FunctionDef) -> None:
return_type = self._annotation_to_cpp_type(node.returns)
if return_type:
func_info['return_type'] = return_type
else:
# Try to infer return type from return statements
inferred_return_type = self._infer_return_type_from_body(node.body)
if inferred_return_type:
func_info['return_type'] = inferred_return_type

self.type_info[node.name] = func_info
self.type_info[node.name] = func_info

def _infer_return_type_from_body(self, body: List[ast.stmt]) -> Optional[str]:
"""Infer return type by analyzing return statements in function body."""
for node in ast.walk(ast.Module(body=body, type_ignores=[])):
if isinstance(node, ast.Return) and node.value:
return self._infer_expression_type(node.value)
return None
Comment on lines +251 to +255
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function returns the type of the first return statement found, but functions may have multiple return statements with different types. This could lead to incorrect type inference when a function has multiple return paths with different types.

Suggested change
"""Infer return type by analyzing return statements in function body."""
for node in ast.walk(ast.Module(body=body, type_ignores=[])):
if isinstance(node, ast.Return) and node.value:
return self._infer_expression_type(node.value)
return None
"""Infer return type by analyzing all return statements in function body."""
return_types = set()
for node in ast.walk(ast.Module(body=body, type_ignores=[])):
if isinstance(node, ast.Return) and node.value:
ret_type = self._infer_expression_type(node.value)
if ret_type:
return_types.add(ret_type)
if not return_types:
return None
if len(return_types) == 1:
return return_types.pop()
# Multiple return types found; use 'auto' or a variant type
# Optionally, could return 'std::variant<...>' here if desired
return 'auto'

Copilot uses AI. Check for mistakes.