Skip to main content

garbage_code_hunter/
utils.rs

1use syn::spanned::Spanned;
2
3/// Get line number from syn AST node using proc_macro2 span-locations
4pub fn get_line_number<T: Spanned>(node: &T) -> usize {
5    node.span().start().line
6}
7
8/// Get column number from syn AST node using proc_macro2 span-locations
9pub fn get_column_number<T: Spanned>(node: &T) -> usize {
10    node.span().start().column + 1 // Convert 0-based to 1-based
11}
12
13/// Get position info (line, column) from syn AST node
14pub fn get_position<T: Spanned>(node: &T) -> (usize, usize) {
15    (get_line_number(node), get_column_number(node))
16}
17
18/// Check if a line is a comment
19fn is_comment_line(trimmed: &str) -> bool {
20    trimmed.starts_with("///")
21        || trimmed.starts_with("//!")
22        || trimmed.starts_with("//")
23        || trimmed.starts_with("/*")
24        || trimmed.starts_with("*")
25}
26
27/// Find the line number of a string literal in source content (skipping comments)
28pub fn find_line_of_str(content: &str, target: &str) -> usize {
29    for (i, line) in content.lines().enumerate() {
30        let trimmed = line.trim();
31        if is_comment_line(trimmed) {
32            continue;
33        }
34        if line.contains(target) {
35            return i + 1;
36        }
37    }
38    1
39}
40
41/// Find the line number of a string literal, skipping comments and import statements
42pub fn find_line_of_str_non_import(content: &str, target: &str) -> usize {
43    for (i, line) in content.lines().enumerate() {
44        let trimmed = line.trim();
45        if is_comment_line(trimmed) || trimmed.starts_with("use ") {
46            continue;
47        }
48        if line.contains(target) {
49            return i + 1;
50        }
51    }
52    1
53}
54
55/// Count non-comment occurrences of a pattern in source content
56pub fn count_non_comment_matches(content: &str, target: &str) -> usize {
57    let mut count = 0;
58    for line in content.lines() {
59        let trimmed = line.trim();
60        if is_comment_line(trimmed) {
61            continue;
62        }
63        count += line.matches(target).count();
64    }
65    count
66}
67
68/// Count non-comment, non-import occurrences of a pattern in source content
69pub fn count_non_import_matches(content: &str, target: &str) -> usize {
70    let mut count = 0;
71    for line in content.lines() {
72        let trimmed = line.trim();
73        if is_comment_line(trimmed) || trimmed.starts_with("use ") {
74            continue;
75        }
76        count += line.matches(target).count();
77    }
78    count
79}