import ast from typing import List, Dict class CodeSmellVisitor(ast.NodeVisitor): def __init__(self): self.issues = [] def visit_FunctionDef(self, node): """Check for functions with too many arguments (Code Smell)""" if len(node.args.args) > 5: self.issues.append({ "line": node.lineno, "type": "Complexity", "message": f"Function '{node.name}' has too many arguments ({len(node.args.args)}). Max is 5." }) # Check for mutable default arguments (e.g., def foo(l=[])) # This is a classic Python 'gotcha' interview question for default in node.args.defaults: if isinstance(default, (ast.List, ast.Dict, ast.Set)): self.issues.append({ "line": node.lineno, "type": "Bug Risk", "message": f"Function '{node.name}' uses a mutable default argument. This persists state across calls!" }) # Continue walking through the children of this node self.generic_visit(node) def visit_Call(self, node): """Check for dangerous function calls like eval()""" if isinstance(node.func, ast.Name) and node.func.id == 'eval': self.issues.append({ "line": node.lineno, "type": "Security", "message": "Use of 'eval()' detected. This is a major security risk." }) self.generic_visit(node) def analyze_code(code_content: str) -> List[Dict]: try: tree = ast.parse(code_content) visitor = CodeSmellVisitor() visitor.visit(tree) return visitor.issues except SyntaxError as e: return [{"line": e.lineno, "type": "Syntax Error", "message": str(e)}]