From c029e1b0b4c08bcfb9d69a6d397a379d4db69027 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Tue, 3 Feb 2026 06:59:00 +0000 Subject: [PATCH] Add TypeScript, Go, and Rust analyzers --- vibeguard/analyzers/languages/rust.py | 187 ++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 vibeguard/analyzers/languages/rust.py diff --git a/vibeguard/analyzers/languages/rust.py b/vibeguard/analyzers/languages/rust.py new file mode 100644 index 0000000..b9d89be --- /dev/null +++ b/vibeguard/analyzers/languages/rust.py @@ -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 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