* [PATCH] checkpatch: add --json output mode
@ 2026-04-06 17:00 Sasha Levin
2026-04-06 19:00 ` Konstantin Ryabitsev
2026-04-06 20:41 ` Joe Perches
0 siblings, 2 replies; 6+ messages in thread
From: Sasha Levin @ 2026-04-06 17:00 UTC (permalink / raw)
To: dwaipayanray1, lukas.bulwahn
Cc: joe, corbet, skhan, apw, workflows, linux-doc, linux-kernel,
Sasha Levin
Add a --json flag to checkpatch.pl that emits structured JSON output,
making results machine-parseable for CI systems, IDE integrations, and
AI-assisted code review tools.
The JSON output includes per-file totals (errors, warnings, checks,
lines) and an array of individual issues with structured fields for
level, type, message, file path, and line number.
The --json flag is mutually exclusive with --terse and --emacs.
Normal text output behavior is completely unchanged when --json is
not specified.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Documentation/dev-tools/checkpatch.rst | 7 +++
scripts/checkpatch.pl | 86 ++++++++++++++++++++++++--
2 files changed, 87 insertions(+), 6 deletions(-)
diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst
index dccede68698ca..17e5744d3dee6 100644
--- a/Documentation/dev-tools/checkpatch.rst
+++ b/Documentation/dev-tools/checkpatch.rst
@@ -64,6 +64,13 @@ Available options:
Output only one line per report.
+ - --json
+
+ Output results as a JSON object. The object includes total error, warning,
+ and check counts, plus an array of individual issues with structured fields
+ for level, type, message, file, and line number. Cannot be used with
+ --terse or --emacs.
+
- --showfile
Show the diffed file position instead of the input file position.
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index e56374662ff79..ed70753ba1afc 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -33,6 +33,7 @@ my $chk_patch = 1;
my $tst_only;
my $emacs = 0;
my $terse = 0;
+my $json = 0;
my $showfile = 0;
my $file = 0;
my $git = 0;
@@ -93,6 +94,7 @@ Options:
--patch treat FILE as patchfile (default)
--emacs emacs compile window format
--terse one line per report
+ --json output results as JSON
--showfile emit diffed file position, not input file position
-g, --git treat FILE as a single commit or git revision range
single git commit with:
@@ -320,6 +322,7 @@ GetOptions(
'patch!' => \$chk_patch,
'emacs!' => \$emacs,
'terse!' => \$terse,
+ 'json!' => \$json,
'showfile!' => \$showfile,
'f|file!' => \$file,
'g|git!' => \$git,
@@ -379,6 +382,7 @@ help($help - 1) if ($help);
die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse);
+die "$P: --json cannot be used with --terse or --emacs\n" if ($json && ($terse || $emacs));
if ($color =~ /^[01]$/) {
$color = !$color;
@@ -1351,7 +1355,7 @@ for my $filename (@ARGV) {
}
close($FILE);
- if ($#ARGV > 0 && $quiet == 0) {
+ if (!$json && $#ARGV > 0 && $quiet == 0) {
print '-' x length($vname) . "\n";
print "$vname\n";
print '-' x length($vname) . "\n";
@@ -1372,7 +1376,7 @@ for my $filename (@ARGV) {
$file = $oldfile if ($is_git_file);
}
-if (!$quiet) {
+if (!$quiet && !$json) {
hash_show_words(\%use_type, "Used");
hash_show_words(\%ignore_type, "Ignored");
@@ -2395,6 +2399,18 @@ sub report {
push(our @report, $output);
+ if ($json) {
+ our ($realfile, $realline);
+ my %issue = (
+ level => $level,
+ type => $type,
+ message => $msg,
+ );
+ $issue{file} = $realfile if (defined $realfile && $realfile ne '');
+ $issue{line} = $realline + 0 if (defined $realline && $realline);
+ push(our @json_issues, \%issue);
+ }
+
return 1;
}
@@ -2402,6 +2418,34 @@ sub report_dump {
our @report;
}
+sub json_escape {
+ my ($str) = @_;
+ $str =~ s/\\/\\\\/g;
+ $str =~ s/"/\\"/g;
+ $str =~ s/\n/\\n/g;
+ $str =~ s/\r/\\r/g;
+ $str =~ s/\t/\\t/g;
+ $str =~ s/\x08/\\b/g;
+ $str =~ s/\x0c/\\f/g;
+ $str =~ s/([\x00-\x07\x0b\x0e-\x1f])/sprintf("\\u%04x", ord($1))/ge;
+ return $str;
+}
+
+sub json_encode_issue {
+ my ($issue) = @_;
+ my @fields;
+ push(@fields, '"level":"' . json_escape($issue->{level}) . '"');
+ push(@fields, '"type":"' . json_escape($issue->{type}) . '"');
+ push(@fields, '"message":"' . json_escape($issue->{message}) . '"');
+ if (defined $issue->{file}) {
+ push(@fields, '"file":"' . json_escape($issue->{file}) . '"');
+ }
+ if (defined $issue->{line}) {
+ push(@fields, '"line":' . ($issue->{line} + 0));
+ }
+ return '{' . join(',', @fields) . '}';
+}
+
sub fixup_current_range {
my ($lineRef, $offset, $length) = @_;
@@ -2690,14 +2734,15 @@ sub process {
my $last_coalesced_string_linenr = -1;
our @report = ();
+ our @json_issues = ();
our $cnt_lines = 0;
our $cnt_error = 0;
our $cnt_warn = 0;
our $cnt_chk = 0;
# Trace the real file/line as we go.
- my $realfile = '';
- my $realline = 0;
+ our $realfile = '';
+ our $realline = 0;
my $realcnt = 0;
my $here = '';
my $context_function; #undef'd unless there's a known function
@@ -7791,18 +7836,33 @@ sub process {
# If we have no input at all, then there is nothing to report on
# so just keep quiet.
if ($#rawlines == -1) {
+ if ($json) {
+ print '{"filename":"' . json_escape($filename) .
+ '","total_errors":0,"total_warnings":0,' .
+ '"total_checks":0,"total_lines":0,"issues":[]}' . "\n";
+ }
exit(0);
}
# In mailback mode only produce a report in the negative, for
# things that appear to be patches.
if ($mailback && ($clean == 1 || !$is_patch)) {
+ if ($json) {
+ print '{"filename":"' . json_escape($filename) .
+ '","total_errors":0,"total_warnings":0,' .
+ '"total_checks":0,"total_lines":0,"issues":[]}' . "\n";
+ }
exit(0);
}
# This is not a patch, and we are in 'no-patch' mode so
# just keep quiet.
if (!$chk_patch && !$is_patch) {
+ if ($json) {
+ print '{"filename":"' . json_escape($filename) .
+ '","total_errors":0,"total_warnings":0,' .
+ '"total_checks":0,"total_lines":0,"issues":[]}' . "\n";
+ }
exit(0);
}
@@ -7850,6 +7910,19 @@ sub process {
}
}
+ if ($json) {
+ my @issue_strings;
+ foreach my $issue (@json_issues) {
+ push(@issue_strings, json_encode_issue($issue));
+ }
+ print '{"filename":"' . json_escape($filename) . '",' .
+ '"total_errors":' . ($cnt_error + 0) . ',' .
+ '"total_warnings":' . ($cnt_warn + 0) . ',' .
+ '"total_checks":' . ($cnt_chk + 0) . ',' .
+ '"total_lines":' . ($cnt_lines + 0) . ',' .
+ '"issues":[' . join(',', @issue_strings) . ']' .
+ '}' . "\n";
+ } else {
print report_dump();
if ($summary && !($clean == 1 && $quiet == 1)) {
print "$filename " if ($summary_file);
@@ -7878,8 +7951,9 @@ NOTE: Whitespace errors detected.
EOM
}
}
+ } # end !$json
- if ($clean == 0 && $fix &&
+ if (!$json && $clean == 0 && $fix &&
("@rawlines" ne "@fixed" ||
$#fixed_inserted >= 0 || $#fixed_deleted >= 0)) {
my $newfile = $filename;
@@ -7918,7 +7992,7 @@ EOM
}
}
- if ($quiet == 0) {
+ if (!$json && $quiet == 0) {
print "\n";
if ($clean == 1) {
print "$vname has no obvious style problems and is ready for submission.\n";
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] checkpatch: add --json output mode
2026-04-06 17:00 [PATCH] checkpatch: add --json output mode Sasha Levin
@ 2026-04-06 19:00 ` Konstantin Ryabitsev
2026-04-06 19:13 ` Sasha Levin
2026-04-06 20:41 ` Joe Perches
1 sibling, 1 reply; 6+ messages in thread
From: Konstantin Ryabitsev @ 2026-04-06 19:00 UTC (permalink / raw)
To: Sasha Levin
Cc: dwaipayanray1, lukas.bulwahn, joe, corbet, skhan, apw, workflows,
linux-doc, linux-kernel
On Mon, Apr 06, 2026 at 01:00:39PM -0400, Sasha Levin wrote:
> Add a --json flag to checkpatch.pl that emits structured JSON output,
> making results machine-parseable for CI systems, IDE integrations, and
> AI-assisted code review tools.
>
> The JSON output includes per-file totals (errors, warnings, checks,
> lines) and an array of individual issues with structured fields for
> level, type, message, file path, and line number.
>
> The --json flag is mutually exclusive with --terse and --emacs.
> Normal text output behavior is completely unchanged when --json is
> not specified.
I see that it's writing json out manually, implementing its own escaping.
While there are upsides to not requiring a perl json library, I think it's
fair to expect that people who would want to get json output can probably make
sure that JSON::XS is installed.
Not a strong object, but seems cleaner that way.
-K
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] checkpatch: add --json output mode
2026-04-06 19:00 ` Konstantin Ryabitsev
@ 2026-04-06 19:13 ` Sasha Levin
2026-04-06 19:22 ` Konstantin Ryabitsev
0 siblings, 1 reply; 6+ messages in thread
From: Sasha Levin @ 2026-04-06 19:13 UTC (permalink / raw)
To: Konstantin Ryabitsev
Cc: dwaipayanray1, lukas.bulwahn, joe, corbet, skhan, apw, workflows,
linux-doc, linux-kernel
On Mon, Apr 06, 2026 at 03:00:25PM -0400, Konstantin Ryabitsev wrote:
>On Mon, Apr 06, 2026 at 01:00:39PM -0400, Sasha Levin wrote:
>> Add a --json flag to checkpatch.pl that emits structured JSON output,
>> making results machine-parseable for CI systems, IDE integrations, and
>> AI-assisted code review tools.
>>
>> The JSON output includes per-file totals (errors, warnings, checks,
>> lines) and an array of individual issues with structured fields for
>> level, type, message, file path, and line number.
>>
>> The --json flag is mutually exclusive with --terse and --emacs.
>> Normal text output behavior is completely unchanged when --json is
>> not specified.
>
>I see that it's writing json out manually, implementing its own escaping.
>While there are upsides to not requiring a perl json library, I think it's
>fair to expect that people who would want to get json output can probably make
>sure that JSON::XS is installed.
>
>Not a strong object, but seems cleaner that way.
No objection here, but from what I saw the checkpatch code only uses core perl
packages so I wanted to keep it that way.
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] checkpatch: add --json output mode
2026-04-06 19:13 ` Sasha Levin
@ 2026-04-06 19:22 ` Konstantin Ryabitsev
2026-04-06 20:34 ` Joe Perches
0 siblings, 1 reply; 6+ messages in thread
From: Konstantin Ryabitsev @ 2026-04-06 19:22 UTC (permalink / raw)
To: Sasha Levin
Cc: dwaipayanray1, lukas.bulwahn, joe, corbet, skhan, apw, workflows,
linux-doc, linux-kernel
On Mon, Apr 06, 2026 at 03:13:52PM -0400, Sasha Levin wrote:
> > I see that it's writing json out manually, implementing its own escaping.
> > While there are upsides to not requiring a perl json library, I think it's
> > fair to expect that people who would want to get json output can probably make
> > sure that JSON::XS is installed.
> >
> > Not a strong object, but seems cleaner that way.
>
> No objection here, but from what I saw the checkpatch code only uses core perl
> packages so I wanted to keep it that way.
I saw that, too, but I think that stems from the expectation that we need to
make it easy to run checkpatch by any random person submitting patches, which
is why, by default, we'll output human-readable results.
JSON output, on the other hand, is mostly useful for specific setups that have
a lot more control over their environment and we don't have to stick to the
"pure perl only" guideline here.
Generating correct json is an exercise in corner cases, which is why I'd
rather this is done with a library that has addressed most of them already.
Regards,
--
KR
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] checkpatch: add --json output mode
2026-04-06 19:22 ` Konstantin Ryabitsev
@ 2026-04-06 20:34 ` Joe Perches
0 siblings, 0 replies; 6+ messages in thread
From: Joe Perches @ 2026-04-06 20:34 UTC (permalink / raw)
To: Konstantin Ryabitsev, Sasha Levin
Cc: dwaipayanray1, lukas.bulwahn, corbet, skhan, apw, workflows,
linux-doc, linux-kernel
On Mon, 2026-04-06 at 15:22 -0400, Konstantin Ryabitsev wrote:
> On Mon, Apr 06, 2026 at 03:13:52PM -0400, Sasha Levin wrote:
> I see that it's writing json out manually, implementing its own escaping.
> > > While there are upsides to not requiring a perl json library, I think it's
> > > fair to expect that people who would want to get json output can probably make
> > > sure that JSON::XS is installed.
> > >
> > > Not a strong object, but seems cleaner that way.
To me too.
JSON:PP is standard since 5.14, and that's 15 years old.
I'd rather just require 5.14 as a minimum and remove
a bunch of other checks too.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] checkpatch: add --json output mode
2026-04-06 17:00 [PATCH] checkpatch: add --json output mode Sasha Levin
2026-04-06 19:00 ` Konstantin Ryabitsev
@ 2026-04-06 20:41 ` Joe Perches
1 sibling, 0 replies; 6+ messages in thread
From: Joe Perches @ 2026-04-06 20:41 UTC (permalink / raw)
To: Sasha Levin, dwaipayanray1, lukas.bulwahn
Cc: corbet, skhan, apw, workflows, linux-doc, linux-kernel
On Mon, 2026-04-06 at 13:00 -0400, Sasha Levin wrote:
> Add a --json flag to checkpatch.pl that emits structured JSON output,
> making results machine-parseable for CI systems, IDE integrations, and
> AI-assisted code review tools.
Seems a reasonable idea but perhaps can be improved
> @@ -1372,7 +1376,7 @@ for my $filename (@ARGV) {
> $file = $oldfile if ($is_git_file);
> }
>
> -if (!$quiet) {
> +if (!$quiet && !$json) {
> hash_show_words(\%use_type, "Used");
> hash_show_words(\%ignore_type, "Ignored");
Maybe keep but update?
> @@ -7791,18 +7836,33 @@ sub process {
> # If we have no input at all, then there is nothing to report on
> # so just keep quiet.
> if ($#rawlines == -1) {
> + if ($json) {
> + print '{"filename":"' . json_escape($filename) .
> + '","total_errors":0,"total_warnings":0,' .
poor formatting for that trailing ". please separate by content blocks.
> + '"total_checks":0,"total_lines":0,"issues":[]}' . "\n";
> + }
I'd prefer to keep the print() style used elsewhere
and perhaps the JSON:PP module should be used here.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-06 20:41 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-06 17:00 [PATCH] checkpatch: add --json output mode Sasha Levin
2026-04-06 19:00 ` Konstantin Ryabitsev
2026-04-06 19:13 ` Sasha Levin
2026-04-06 19:22 ` Konstantin Ryabitsev
2026-04-06 20:34 ` Joe Perches
2026-04-06 20:41 ` Joe Perches
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox