aboutsummaryrefslogtreecommitdiff
path: root/Scripts/normalize-zig-issues.pl
diff options
context:
space:
mode:
Diffstat (limited to 'Scripts/normalize-zig-issues.pl')
-rw-r--r--Scripts/normalize-zig-issues.pl93
1 files changed, 93 insertions, 0 deletions
diff --git a/Scripts/normalize-zig-issues.pl b/Scripts/normalize-zig-issues.pl
new file mode 100644
index 0000000..b6ff328
--- /dev/null
+++ b/Scripts/normalize-zig-issues.pl
@@ -0,0 +1,93 @@
1use strict;
2use warnings;
3$| = 1;
4
5my $base = $ENV{NOVA_ZIG_TASK_CWD} || $ENV{PWD} || "";
6my %file_cache = ();
7
8sub normalize_path {
9 my ($path) = @_;
10 return $path if $path =~ m{^/} || $path =~ m{^[A-Za-z]:[\/\\]};
11
12 # The Zig compiler occasionally emits paths without a leading slash (e.g.
13 # "Users/..." instead of "/Users/...") when traversing relative directories.
14 # Detect known top-level directory names and restore the leading slash.
15 if ($path =~ m{^(?:Users|private|opt|Library|System|usr|var|tmp|etc|home)/}) {
16 return "/$path";
17 }
18
19 return $base eq "" ? $path : "$base/$path";
20}
21
22sub source_line_for_path {
23 my ($path, $line_number) = @_;
24 return undef if $line_number < 1;
25
26 if (!exists $file_cache{$path}) {
27 if (open my $fh, "<", $path) {
28 my @lines = <$fh>;
29 close $fh;
30 $file_cache{$path} = \@lines;
31 } else {
32 $file_cache{$path} = undef;
33 }
34 }
35
36 my $lines = $file_cache{$path};
37 return undef if !defined $lines;
38 return undef if $line_number > scalar(@$lines);
39
40 my $line = $lines->[$line_number - 1];
41 $line =~ s/\r?\n$//;
42 return $line;
43}
44
45# Zig reports argument-count errors at the column of the opening parenthesis,
46# which causes Nova to underline the entire argument list. For method-call
47# expressions (receiver.method(...)), shift the column back to the start of
48# the callee identifier so only the call site itself is highlighted.
49sub adjusted_call_column {
50 my ($source_line, $column) = @_;
51 return $column if !defined $source_line || $column < 1;
52
53 my $column_index = $column - 1;
54 my $open_paren = index($source_line, "(", $column_index);
55 return $column if $open_paren < 0;
56
57 my $prefix = substr($source_line, 0, $open_paren);
58 return $column if $prefix !~ /([A-Za-z_][A-Za-z0-9_]*)\s*$/;
59
60 my $callee = $1;
61 my $callee_index = rindex($prefix, $callee);
62 return $column if $callee_index < 0;
63
64 my $target_column = $callee_index + 1;
65 return $column if $target_column <= $column;
66
67 my $between = substr($source_line, $column_index, $target_column - $column);
68 return $column if $between !~ /\./;
69
70 return $target_column;
71}
72
73while (my $line = <STDIN>) {
74 my $newline = $line =~ s/\r?\n$// ? "\n" : "";
75
76 if ($line =~ m{^([^:\n]+\.zig):(\d+):(\d+):\s*(error|warning|note):\s*(.*)$}) {
77 my ($path, $line_number, $column, $severity, $message) = ($1, $2, $3, $4, $5);
78 my $normalized = normalize_path($path);
79
80 if ($message =~ /\bexpected\b.*argument\(s\).*\bfound\b/i) {
81 my $source_line = source_line_for_path($normalized, $line_number);
82 $column = adjusted_call_column($source_line, $column);
83 }
84
85 $line = "$normalized:$line_number:$column: $severity: $message";
86 } elsif ($line =~ m{^([^:\n]+\.zig):(\d+):(\d+):}) {
87 my ($path, $line_number, $column) = ($1, $2, $3);
88 my $normalized = normalize_path($path);
89 $line =~ s{^[^:\n]+\.zig:\d+:\d+:}{$normalized:$line_number:$column:};
90 }
91
92 print $line, $newline;
93}