COGENBAI / cogenbai /review /analyzer.py
algoscienceacademy's picture
cogenbai
bd91486
Raw
History Blame Contribute Delete
3.31 kB
from typing import List, Dict, Any
import ast
import re
class CodeReviewAnalyzer:
def __init__(self):
self.metrics = {
'complexity': self._analyze_complexity,
'naming': self._analyze_naming,
'documentation': self._analyze_documentation,
'security': self._analyze_security
}
def review_code(self, code: str, language: str) -> Dict[str, Any]:
results = {}
for metric_name, analyzer in self.metrics.items():
results[metric_name] = analyzer(code, language)
return results
def _analyze_complexity(self, code: str, language: str) -> Dict[str, Any]:
if language == 'python':
tree = ast.parse(code)
return {
'cyclomatic_complexity': self._count_branches(tree),
'cognitive_complexity': self._analyze_cognitive_complexity(tree)
}
return {}
def _analyze_naming(self, code: str, language: str) -> Dict[str, List[str]]:
issues = []
if language == 'python':
tree = ast.parse(code)
for node in ast.walk(tree):
if isinstance(node, ast.Name):
if not self._is_valid_name(node.id):
issues.append(f"Invalid name: {node.id}")
return {'issues': issues}
def _analyze_documentation(self, code: str, language: str) -> Dict[str, Any]:
doc_ratio = len(re.findall(r'"""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\'', code)) / max(1, len(code.splitlines()))
return {
'documentation_ratio': doc_ratio,
'has_module_docstring': code.lstrip().startswith('"""') or code.lstrip().startswith("'''")
}
def _analyze_security(self, code: str, language: str) -> Dict[str, List[str]]:
vulnerabilities = []
dangerous_patterns = {
'python': [
(r'eval\(', 'Dangerous eval() usage'),
(r'exec\(', 'Dangerous exec() usage'),
(r'os\.system\(', 'Unsafe system command execution')
]
}
for pattern, message in dangerous_patterns.get(language, []):
if re.search(pattern, code):
vulnerabilities.append(message)
return {'vulnerabilities': vulnerabilities}
def _count_branches(self, tree: ast.AST) -> int:
count = 0
for node in ast.walk(tree):
if isinstance(node, (ast.If, ast.For, ast.While, ast.Try)):
count += 1
return count
def _analyze_cognitive_complexity(self, tree: ast.AST) -> int:
complexity = 0
for node in ast.walk(tree):
if isinstance(node, (ast.If, ast.While, ast.For)):
complexity += 1
# Add nesting penalty
complexity += self._get_nesting_level(node) * 0.5
return int(complexity)
def _get_nesting_level(self, node: ast.AST, level: int = 0) -> int:
parent = getattr(node, 'parent', None)
if parent is None:
return level
return self._get_nesting_level(parent, level + 1)
def _is_valid_name(self, name: str) -> bool:
if len(name) < 2:
return False
if not name.isidentifier():
return False
return True