Add TypeScript, Go, and Rust analyzers
Some checks failed
CI / test (push) Failing after 14s
CI / build (push) Has been skipped

This commit is contained in:
2026-02-03 06:59:00 +00:00
parent 034bb54949
commit c029e1b0b4

View File

@@ -0,0 +1,187 @@
"""Rust analyzer for VibeGuard."""
import re
from pathlib import Path
from typing import Any
from vibeguard.analyzers.base import BaseAnalyzer
class RustAnalyzer(BaseAnalyzer):
"""Analyzer for Rust code."""
LANGUAGE_NAME = "rust"
FILE_EXTENSIONS = [".rs"]
def parse_file(self, path: Path) -> str | None:
"""Parse a Rust file and return the content."""
try:
with open(path, "r", encoding="utf-8") as f:
return f.read()
except Exception:
return None
def analyze(self, content: str, path: Path) -> list[dict[str, Any]]:
"""Analyze Rust content for anti-patterns."""
issues: list[dict[str, Any]] = []
lines = content.split("\n")
for i, line in enumerate(lines, 1):
issues.extend(self._check_clone_on_copy(line, i, path))
issues.extend(self._check_unused_imports(line, i, path))
issues.extend(self._check_expect_usage(line, i, path))
issues.extend(self._check_magic_strings(line, i, path))
issues.extend(self._check_hardcoded_values(line, i, path))
issues.extend(self._check_unnecessary_boxing(content, path))
issues.extend(self._check_into_iter_consumed(content, path))
return issues
def _check_clone_on_copy(
self, line: str, line_num: int, path: Path
) -> list[dict[str, Any]]:
"""Check for unnecessary .clone() on Copy types."""
issues: list[dict[str, Any]] = []
if re.search(r"\.clone\(\)", line):
issues.append(
{
"pattern": "UNNECESSARY_CLONE",
"severity": "warning",
"file": str(path),
"line": line_num,
"message": "Unnecessary .clone() - type implements Copy trait",
"suggestion": "Remove .clone() as the type will be automatically copied",
"language": self.LANGUAGE_NAME,
}
)
return issues
def _check_unused_imports(
self, line: str, line_num: int, path: Path
) -> list[dict[str, Any]]:
"""Check for unused imports."""
issues: list[dict[str, Any]] = []
if re.search(r"#\[allow\(unused\)\]", line):
issues.append(
{
"pattern": "ALLOW_UNUSED",
"severity": "info",
"file": str(path),
"line": line_num,
"message": "#[allow(unused)] - remove unused code instead",
"suggestion": "Remove the unused imports or code instead of suppressing warnings",
"language": self.LANGUAGE_NAME,
}
)
return issues
def _check_expect_usage(
self, line: str, line_num: int, path: Path
) -> list[dict[str, Any]]:
"""Check for .expect() usage which can panic."""
issues: list[dict[str, Any]] = []
if re.search(r"\.expect\(", line):
issues.append(
{
"pattern": "EXPECT_PANIC",
"severity": "warning",
"file": str(path),
"line": line_num,
"message": ".expect() can panic - consider proper error handling",
"suggestion": "Use ? operator or proper error handling instead of expect",
"language": self.LANGUAGE_NAME,
}
)
return issues
def _check_magic_strings(
self, line: str, line_num: int, path: Path
) -> list[dict[str, Any]]:
"""Check for magic strings."""
issues: list[dict[str, Any]] = []
if re.search(r'"[^"]{30,}"', line):
issues.append(
{
"pattern": "MAGIC_STRING",
"severity": "warning",
"file": str(path),
"line": line_num,
"message": "Long magic string detected - consider using constants",
"suggestion": "Extract to a named constant",
"language": self.LANGUAGE_NAME,
}
)
return issues
def _check_hardcoded_values(
self, line: str, line_num: int, path: Path
) -> list[dict[str, Any]]:
"""Check for hardcoded values."""
issues: list[dict[str, Any]] = []
if re.search(r"[^0-9a-zA-Z](?:1[0-9]{3}|[2-9][0-9]{3,})(?![0-9])", line):
issues.append(
{
"pattern": "HARDCODED_VALUE",
"severity": "warning",
"file": str(path),
"line": line_num,
"message": "Large hardcoded numeric value detected",
"suggestion": "Extract to a named constant with descriptive name",
"language": self.LANGUAGE_NAME,
}
)
return issues
def _check_unnecessary_boxing(self, content: str, path: Path) -> list[dict[str, Any]]:
"""Check for unnecessary Box<T> usage."""
issues: list[dict[str, Any]] = []
pattern = re.compile(r"Box::new\([^)]+\)")
matches = pattern.findall(content)
for match in matches:
issues.append(
{
"pattern": "UNNECESSARY_BOXING",
"severity": "info",
"file": str(path),
"line": 0,
"message": "Unnecessary Box::new() - consider if Box is needed",
"suggestion": "Only use Box for recursive types, trait objects, or large stacks",
"language": self.LANGUAGE_NAME,
}
)
return issues
def _check_into_iter_consumed(self, content: str, path: Path) -> list[dict[str, Any]]:
"""Check for into_iter() which consumes the collection."""
issues: list[dict[str, Any]] = []
pattern = re.compile(r"\.into_iter\(\)")
matches = pattern.findall(content)
for match in matches:
issues.append(
{
"pattern": "INTO_ITER_CONSUMPTION",
"severity": "info",
"file": str(path),
"line": 0,
"message": "into_iter() consumes the collection - consider iter() or iter_mut()",
"suggestion": "Use .iter() for borrowing, .iter_mut() for mutable borrowing",
"language": self.LANGUAGE_NAME,
}
)
return issues