#!/usr/bin/perl -w
# (c) 2001, Dave Jones. (the file handling bit)
# (c) 2005, Joel Schopp (the ugly bit)
# (c) 2007,2008, Andy Whitcroft (new conditions, test suite)
# (c) 2008-2010 Andy Whitcroft
# Licensed under the terms of the GNU GPL License version 2
use strict;
use POSIX;
my $P = $0;
$P =~ s@.*/@@g;
my $V = '0.32';
use Getopt::Long qw(:config no_auto_abbrev);
my $quiet = 0;
my $tree = 1;
my $chk_signoff = 1;
my $chk_patch = 1;
my $tst_only;
my $emacs = 0;
my $terse = 0;
my $file = 0;
my $check = 0;
my $summary = 1;
my $mailback = 0;
my $summary_file = 0;
my $show_types = 0;
my $fix = 0;
my $root;
my %debug;
my %ignore_type = ();
my %camelcase = ();
my @ignore = ();
my $help = 0;
my $configuration_file = ".checkpatch.conf";
my $max_line_length = 80;
sub help {
my ($exitcode) = @_;
print \$quiet,
'tree!' => \$tree,
'signoff!' => \$chk_signoff,
'patch!' => \$chk_patch,
'emacs!' => \$emacs,
'terse!' => \$terse,
'f|file!' => \$file,
'subjective!' => \$check,
'strict!' => \$check,
'ignore=s' => \@ignore,
'show-types!' => \$show_types,
'max-line-length=i' => \$max_line_length,
'root=s' => \$root,
'summary!' => \$summary,
'mailback!' => \$mailback,
'summary-file!' => \$summary_file,
'fix!' => \$fix,
'debug=s' => \%debug,
'test-only=s' => \$tst_only,
'h|help' => \$help,
'version' => \$help
) or help(1);
help(0) if ($help);
my $exit = 0;
if ($#ARGV < 0) {
print "$P: no input files\n";
exit(1);
}
@ignore = split(/,/, join(',',@ignore));
foreach my $word (@ignore) {
$word =~ s/\s*\n?$//g;
$word =~ s/^\s*//g;
$word =~ s/\s+/ /g;
$word =~ tr/[a-z]/[A-Z]/;
next if ($word =~ m/^\s*#/);
next if ($word =~ m/^\s*$/);
$ignore_type{$word}++;
}
my $dbg_values = 0;
my $dbg_possible = 0;
my $dbg_type = 0;
my $dbg_attr = 0;
for my $key (keys %debug) {
## no critic
eval "\${dbg_$key} = '$debug{$key}';";
die "$@" if ($@);
}
my $rpt_cleaners = 0;
if ($terse) {
$emacs = 1;
$quiet++;
}
if ($tree) {
if (defined $root) {
if (!top_of_kernel_tree($root)) {
die "$P: $root: --root does not point at a valid tree\n";
}
} else {
if (top_of_kernel_tree('.')) {
$root = '.';
} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
top_of_kernel_tree($1)) {
$root = $1;
}
}
if (!defined $root) {
print "Must be run from the top-level dir. of a kernel tree\n";
exit(2);
}
}
my $emitted_corrupt = 0;
our $Ident = qr{
[A-Za-z_][A-Za-z\d_]*
(?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
}x;
our $Storage = qr{extern|static|asmlinkage};
our $Sparse = qr{
__user|
__kernel|
__force|
__iomem|
__must_check|
__init_refok|
__kprobes|
__ref|
__rcu
}x;
# Notes to $Attribute:
# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
our $Attribute = qr{
const|
__percpu|
__nocast|
__safe|
__bitwise__|
__packed__|
__packed2__|
__naked|
__maybe_unused|
__always_unused|
__noreturn|
__used|
__cold|
__noclone|
__deprecated|
__read_mostly|
__kprobes|
__(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
____cacheline_aligned|
____cacheline_aligned_in_smp|
____cacheline_internodealigned_in_smp|
__weak
}x;
our $Modifier;
our $Inline = qr{inline|__always_inline|noinline};
our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]};
our $Lval = qr{$Ident(?:$Member)*};
our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u};
our $Binary = qr{(?i)0b[01]+$Int_type?};
our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?};
our $Int = qr{[0-9]+$Int_type?};
our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
our $Float = qr{$Float_hex|$Float_dec|$Float_int};
our $Constant = qr{$Float|$Binary|$Hex|$Int};
our $Assignment = qr{\*\=|/=|%=|\+=|-=|=|&=|\^=|\|=|=};
our $Compare = qr{=|==|!=|};
our $Arithmetic = qr{\+|-|\*|\/|%};
our $Operators = qr{
=|==|!=|
=>|->|||!|~|
&&|\|\||,|\^|\+\+|--|&|\||$Arithmetic
}x;
our $NonptrType;
our $Type;
our $Declare;
our $NON_ASCII_UTF8 = qr{
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
}x;
our $UTF8 = qr{
[\x09\x0A\x0D\x20-\x7E] # ASCII
| $NON_ASCII_UTF8
}x;
our $typeTypedefs = qr{(?x:
(?:__)?(?:u|s|be|le)(?:8|16|32|64)|
atomic_t
)};
our $logFunctions = qr{(?x:
printk(?:_ratelimited|_once|)|
(?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
WARN(?:_RATELIMIT|_ONCE|)|
panic|
MODULE_[A-Z_]+
)};
our $signature_tags = qr{(?xi:
Signed-off-by:|
Acked-by:|
Tested-by:|
Reviewed-by:|
Reported-by:|
Suggested-by:|
To:|
Cc:
)};
our @typeList = (
qr{void},
qr{(?:unsigned\s+)?char},
qr{(?:unsigned\s+)?short},
qr{(?:unsigned\s+)?int},
qr{(?:unsigned\s+)?long},
qr{(?:unsigned\s+)?long\s+int},
qr{(?:unsigned\s+)?long\s+long},
qr{(?:unsigned\s+)?long\s+long\s+int},
qr{unsigned},
qr{float},
qr{double},
qr{bool},
qr{struct\s+$Ident},
qr{union\s+$Ident},
qr{enum\s+$Ident},
qr{${Ident}_t},
qr{${Ident}_handler},
qr{${Ident}_handler_fn},
);
our @modifierList = (
qr{fastcall},
);
our $allowed_asm_includes = qr{(?x:
irq|
memory
)};
# memory.h: ARM has a custom one
sub build_types {
my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)";
my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)";
$Modifier = qr{(?:$Attribute|$Sparse|$mods)};
$NonptrType = qr{
(?:$Modifier\s+|const\s+)*
(?:
(?:typeof|__typeof__)\s*\([^\)]*\)|
(?:$typeTypedefs\b)|
(?:${all}\b)
)
(?:\s+$Modifier|\s+const)*
}x;
$Type = qr{
$NonptrType
(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
(?:\s+$Inline|\s+$Modifier)*
}x;
$Declare = qr{(?:$Storage\s+)?$Type};
}
build_types();
our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
# Using $balanced_parens, $LvalOrFunc, or $FuncArg
# requires at least perl version v5.10.0
# Any use must be runtime checked with $^V
our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
our $LvalOrFunc = qr{($Lval)\s*($balanced_parens{0,1})\s*};
our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
sub deparenthesize {
my ($string) = @_;
return "" if (!defined($string));
$string =~ s@^\s*\(\s*@@g;
$string =~ s@\s*\)\s*$@@g;
$string =~ s@\s+@ @g;
return $string;
}
sub seed_camelcase_file {
my ($file) = @_;
return if (!(-f $file));
local $/;
open(my $include_file, '', "$camelcase_cache")
or warn "$P: Can't write '$camelcase_cache' $!\n";
foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) {
print $camelcase_file ("$_\n");
}
close($camelcase_file);
}
}
$chk_signoff = 0 if ($file);
my @rawlines = ();
my @lines = ();
my @fixed = ();
my $vname;
for my $filename (@ARGV) {
my $FILE;
if ($file) {
open($FILE, '-|', "diff -u /dev/null $filename") ||
die "$P: $filename: diff failed - $!\n";
} elsif ($filename eq '-') {
open($FILE, ''.
if ($res =~ /^.\s*\#\s*include\s+\/) {
my $clean = 'X' x length($1);
$res =~ s@\@@;
# The whole of a #error is a string.
} elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
my $clean = 'X' x length($1);
$res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
}
return $res;
}
sub get_quoted_string {
my ($line, $rawline) = @_;
return "" if ($line !~ m/(\"[X]+\")/g);
return substr($rawline, $-[0], $+[0] - $-[0]);
}
sub ctx_statement_block {
my ($linenr, $remain, $off) = @_;
my $line = $linenr - 1;
my $blk = '';
my $soff = $off;
my $coff = $off - 1;
my $coff_set = 0;
my $loff = 0;
my $type = '';
my $level = 0;
my @stack = ();
my $p;
my $c;
my $len = 0;
my $remainder;
while (1) {
@stack = (['', 0]) if ($#stack == -1);
#warn "CSB: blk remain\n";
# If we are about to drop off the end, pull in more
# context.
if ($off >= $len) {
for (; $remain > 0; $line++) {
last if (!defined $lines[$line]);
next if ($lines[$line] =~ /^-/);
$remain--;
$loff = $len;
$blk .= $lines[$line] . "\n";
$len = length($blk);
$line++;
last;
}
# Bail if there is no further context.
#warn "CSB: blk off len\n";
if ($off >= $len) {
last;
}
if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) {
$level++;
$type = '#';
}
}
$p = $c;
$c = substr($blk, $off, 1);
$remainder = substr($blk, $off);
#warn "CSB: c type level remainder coff_set\n";
# Handle nested #if/#else.
if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
push(@stack, [ $type, $level ]);
} elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
($type, $level) = @{$stack[$#stack - 1]};
} elsif ($remainder =~ /^#\s*endif\b/) {
($type, $level) = @{pop(@stack)};
}
# Statement ends at the ';' or a close '}' at the
# outermost level.
if ($level == 0 && $c eq ';') {
last;
}
# An else is really a conditional as long as its not else if
if ($level == 0 && $coff_set == 0 &&
(!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
$remainder =~ /^(else)(?:\s|{)/ &&
$remainder !~ /^else\s+if\b/) {
$coff = $off + length($1) - 1;
$coff_set = 1;
#warn "CSB: mark coff soff 1\n";
#warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
}
if (($type eq '' || $type eq '(') && $c eq '(') {
$level++;
$type = '(';
}
if ($type eq '(' && $c eq ')') {
$level--;
$type = ($level != 0)? '(' : '';
if ($level == 0 && $coff < $soff) {
$coff = $off;
$coff_set = 1;
#warn "CSB: mark coff\n";
}
}
if (($type eq '' || $type eq '{') && $c eq '{') {
$level++;
$type = '{';
}
if ($type eq '{' && $c eq '}') {
$level--;
$type = ($level != 0)? '{' : '';
if ($level == 0) {
if (substr($blk, $off + 1, 1) eq ';') {
$off++;
}
last;
}
}
# Preprocessor commands end at the newline unless escaped.
if ($type eq '#' && $c eq "\n" && $p ne "\\") {
$level--;
$type = '';
$off++;
last;
}
$off++;
}
# We are truly at the end, so shuffle to the next line.
if ($off == $len) {
$loff = $len + 1;
$line++;
$remain--;
}
my $statement = substr($blk, $soff, $off - $soff + 1);
my $condition = substr($blk, $soff, $coff - $soff + 1);
#warn "STATEMENT\n";
#warn "CONDITION\n";
#print "coff soff loff\n";
return ($statement, $condition,
$line, $remain + 1, $off - $loff + 1, $level);
}
sub statement_lines {
my ($stmt) = @_;
# Strip the diff line prefixes and rip blank lines at start and end.
$stmt =~ s/(^|\n)./$1/g;
$stmt =~ s/^\s*//;
$stmt =~ s/\s*$//;
my @stmt_lines = ($stmt =~ /\n/g);
return $#stmt_lines + 2;
}
sub statement_rawlines {
my ($stmt) = @_;
my @stmt_lines = ($stmt =~ /\n/g);
return $#stmt_lines + 2;
}
sub statement_block_size {
my ($stmt) = @_;
$stmt =~ s/(^|\n)./$1/g;
$stmt =~ s/^\s*{//;
$stmt =~ s/}\s*$//;
$stmt =~ s/^\s*//;
$stmt =~ s/\s*$//;
my @stmt_lines = ($stmt =~ /\n/g);
my @stmt_statements = ($stmt =~ /;/g);
my $stmt_lines = $#stmt_lines + 2;
my $stmt_statements = $#stmt_statements + 1;
if ($stmt_lines > $stmt_statements) {
return $stmt_lines;
} else {
return $stmt_statements;
}
}
sub ctx_statement_full {
my ($linenr, $remain, $off) = @_;
my ($statement, $condition, $level);
my (@chunks);
# Grab the first conditional/block pair.
($statement, $condition, $linenr, $remain, $off, $level) =
ctx_statement_block($linenr, $remain, $off);
#print "F: c s remain\n";
push(@chunks, [ $condition, $statement ]);
if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
return ($level, $linenr, @chunks);
}
# Pull in the following conditional/block pairs and see if they
# could continue the statement.
for (;;) {
($statement, $condition, $linenr, $remain, $off, $level) =
ctx_statement_block($linenr, $remain, $off);
#print "C: c s remain\n";
last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
#print "C: push\n";
push(@chunks, [ $condition, $statement ]);
}
return ($level, $linenr, @chunks);
}
sub ctx_block_get {
my ($linenr, $remain, $outer, $open, $close, $off) = @_;
my $line;
my $start = $linenr - 1;
my $blk = '';
my @o;
my @c;
my @res = ();
my $level = 0;
my @stack = ($level);
for ($line = $start; $remain > 0; $line++) {
next if ($rawlines[$line] =~ /^-/);
$remain--;
$blk .= $rawlines[$line];
# Handle nested #if/#else.
if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
push(@stack, $level);
} elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
$level = $stack[$#stack - 1];
} elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
$level = pop(@stack);
}
foreach my $c (split(//, $lines[$line])) {
##print "CLO\n";
if ($off > 0) {
$off--;
next;
}
if ($c eq $close && $level > 0) {
$level--;
last if ($level == 0);
} elsif ($c eq $open) {
$level++;
}
}
if (!$outer || $level 1);
while (length($cur)) {
@av_paren_type = ('E') if ($#av_paren_type < 0);
print " " if ($dbg_values > 1);
if ($cur =~ /^(\s+)/o) {
print "WS($1)\n" if ($dbg_values > 1);
if ($1 =~ /\n/ && $av_preprocessor) {
$type = pop(@av_paren_type);
$av_preprocessor = 0;
}
} elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') {
print "CAST($1)\n" if ($dbg_values > 1);
push(@av_paren_type, $type);
$type = 'c';
} elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
print "DECLARE($1)\n" if ($dbg_values > 1);
$type = 'T';
} elsif ($cur =~ /^($Modifier)\s*/) {
print "MODIFIER($1)\n" if ($dbg_values > 1);
$type = 'T';
} elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
print "DEFINE($1,$2)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
push(@av_paren_type, $type);
if ($2 ne '') {
$av_pending = 'N';
}
$type = 'E';
} elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
print "UNDEF($1)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
push(@av_paren_type, $type);
} elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
print "PRE_START($1)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
push(@av_paren_type, $type);
push(@av_paren_type, $type);
$type = 'E';
} elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
print "PRE_RESTART($1)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
push(@av_paren_type, $av_paren_type[$#av_paren_type]);
$type = 'E';
} elsif ($cur =~ /^(\#\s*(?:endif))/o) {
print "PRE_END($1)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
# Assume all arms of the conditional end as this
# one does, and continue as if the #endif was not here.
pop(@av_paren_type);
push(@av_paren_type, $type);
$type = 'E';
} elsif ($cur =~ /^(\\\n)/o) {
print "PRECONT($1)\n" if ($dbg_values > 1);
} elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
print "ATTR($1)\n" if ($dbg_values > 1);
$av_pending = $type;
$type = 'N';
} elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
print "SIZEOF($1)\n" if ($dbg_values > 1);
if (defined $2) {
$av_pending = 'V';
}
$type = 'N';
} elsif ($cur =~ /^(if|while|for)\b/o) {
print "COND($1)\n" if ($dbg_values > 1);
$av_pending = 'E';
$type = 'N';
} elsif ($cur =~/^(case)/o) {
print "CASE($1)\n" if ($dbg_values > 1);
$av_pend_colon = 'C';
$type = 'N';
} elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
print "KEYWORD($1)\n" if ($dbg_values > 1);
$type = 'N';
} elsif ($cur =~ /^(\()/o) {
print "PAREN('$1')\n" if ($dbg_values > 1);
push(@av_paren_type, $av_pending);
$av_pending = '_';
$type = 'N';
} elsif ($cur =~ /^(\))/o) {
my $new_type = pop(@av_paren_type);
if ($new_type ne '_') {
$type = $new_type;
print "PAREN('$1') -> $type\n"
if ($dbg_values > 1);
} else {
print "PAREN('$1')\n" if ($dbg_values > 1);
}
} elsif ($cur =~ /^($Ident)\s*\(/o) {
print "FUNC($1)\n" if ($dbg_values > 1);
$type = 'V';
$av_pending = 'V';
} elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
if (defined $2 && $type eq 'C' || $type eq 'T') {
$av_pend_colon = 'B';
} elsif ($type eq 'E') {
$av_pend_colon = 'L';
}
print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
$type = 'V';
} elsif ($cur =~ /^($Ident|$Constant)/o) {
print "IDENT($1)\n" if ($dbg_values > 1);
$type = 'V';
} elsif ($cur =~ /^($Assignment)/o) {
print "ASSIGN($1)\n" if ($dbg_values > 1);
$type = 'N';
} elsif ($cur =~/^(;|{|})/) {
print "END($1)\n" if ($dbg_values > 1);
$type = 'E';
$av_pend_colon = 'O';
} elsif ($cur =~/^(,)/) {
print "COMMA($1)\n" if ($dbg_values > 1);
$type = 'C';
} elsif ($cur =~ /^(\?)/o) {
print "QUESTION($1)\n" if ($dbg_values > 1);
$type = 'N';
} elsif ($cur =~ /^(:)/o) {
print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
substr($var, length($res), 1, $av_pend_colon);
if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
$type = 'E';
} else {
$type = 'N';
}
$av_pend_colon = 'O';
} elsif ($cur =~ /^(\[)/o) {
print "CLOSE($1)\n" if ($dbg_values > 1);
$type = 'N';
} elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
my $variant;
print "OPV($1)\n" if ($dbg_values > 1);
if ($type eq 'V') {
$variant = 'B';
} else {
$variant = 'U';
}
substr($var, length($res), 1, $variant);
$type = 'N';
} elsif ($cur =~ /^($Operators)/o) {
print "OP($1)\n" if ($dbg_values > 1);
if ($1 ne '++' && $1 ne '--') {
$type = 'N';
}
} elsif ($cur =~ /(^.)/o) {
print "C($1)\n" if ($dbg_values > 1);
}
if (defined $1) {
$cur = substr($cur, length($1));
$res .= $type x length($1);
}
}
return ($res, $var);
}
sub possible {
my ($possible, $line) = @_;
my $notPermitted = qr{(?:
^(?:
$Modifier|
$Storage|
$Type|
DEFINE_\S+
)$|
^(?:
goto|
return|
case|
else|
asm|__asm__|
do|
\#|
\#\#|
)(?:\s|$)|
^(?:typedef|struct|enum)\b
)}x;
warn "CHECK ($line)\n" if ($dbg_possible > 2);
if ($possible !~ $notPermitted) {
# Check for modifiers.
$possible =~ s/\s*$Storage\s*//g;
$possible =~ s/\s*$Sparse\s*//g;
if ($possible =~ /^\s*$/) {
} elsif ($possible =~ /\s/) {
$possible =~ s/\s*$Type\s*//g;
for my $modifier (split(' ', $possible)) {
if ($modifier !~ $notPermitted) {
warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
push(@modifierList, $modifier);
}
}
} else {
warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
push(@typeList, $possible);
}
build_types();
} else {
warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
}
}
my $prefix = '';
sub show_type {
return !defined $ignore_type{$_[0]};
}
sub report {
if (!show_type($_[1]) ||
(defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) {
return 0;
}
my $line;
if ($show_types) {
$line = "$prefix$_[0]:$_[1]: $_[2]\n";
} else {
$line = "$prefix$_[0]: $_[2]\n";
}
$line = (split('\n', $line))[0] . "\n" if ($terse);
push(our @report, $line);
return 1;
}
sub report_dump {
our @report;
}
sub ERROR {
if (report("ERROR", $_[0], $_[1])) {
our $clean = 0;
our $cnt_error++;
return 1;
}
return 0;
}
sub WARN {
if (report("WARNING", $_[0], $_[1])) {
our $clean = 0;
our $cnt_warn++;
return 1;
}
return 0;
}
sub CHK {
if ($check && report("CHECK", $_[0], $_[1])) {
our $clean = 0;
our $cnt_chk++;
return 1;
}
return 0;
}
sub check_absolute_file {
my ($absolute, $herecurr) = @_;
my $file = $absolute;
##print "absolute\n";
# See if any suffix of this path is a path within the tree.
while ($file =~ s@^[^/]*/@@) {
if (-f "$root/$file") {
##print "file\n";
last;
}
}
if (! -f _) {
return 0;
}
# It is, so see if the prefix is acceptable.
my $prefix = $absolute;
substr($prefix, -length($file)) = '';
##print "prefix\n";
if ($prefix ne ".../") {
WARN("USE_RELATIVE_PATH",
"use relative pathname instead of absolute in changelog text\n" . $herecurr);
}
}
sub trim {
my ($string) = @_;
$string =~ s/(^\s+|\s+$)//g;
return $string;
}
sub tabify {
my ($leading) = @_;
my $source_indent = 8;
my $max_spaces_before_tab = $source_indent - 1;
my $spaces_to_tab = " " x $source_indent;
#convert leading spaces to tabs
1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g;
#Remove spaces before a tab
1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g;
return "$leading";
}
sub pos_last_openparen {
my ($line) = @_;
my $pos = 0;
my $opens = $line =~ tr/\(/\(/;
my $closes = $line =~ tr/\)/\)/;
my $last_openparen = 0;
if (($opens == 0) || ($closes >= $opens)) {
return -1;
}
my $len = length($line);
for ($pos = 0; $pos < $len; $pos++) {
my $string = substr($line, $pos);
if ($string =~ /^($FuncArg|$balanced_parens)/) {
$pos += length($1) - 1;
} elsif (substr($line, $pos, 1) eq '(') {
$last_openparen = $pos;
} elsif (index($string, '(') == -1) {
last;
}
}
return $last_openparen + 1;
}
sub process {
my $filename = shift;
my $linenr=0;
my $prevline="";
my $prevrawline="";
my $stashline="";
my $stashrawline="";
my $length;
my $indent;
my $previndent=0;
my $stashindent=0;
our $clean = 1;
my $signoff = 0;
my $is_patch = 0;
my $in_header_lines = 1;
my $in_commit_log = 0; #Scanning lines before patch
my $non_utf8_charset = 0;
our @report = ();
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;
my $realcnt = 0;
my $here = '';
my $in_comment = 0;
my $comment_edge = 0;
my $first_line = 0;
my $p1_prefix = '';
my $prev_values = 'E';
# suppression flags
my %suppress_ifbraces;
my %suppress_whiletrailers;
my %suppress_export;
my $suppress_statement = 0;
# Pre-scan the patch sanitizing the lines.
# Pre-scan the patch looking for any __setup documentation.
#
my @setup_docs = ();
my $setup_docs = 0;
sanitise_line_reset();
my $line;
foreach my $rawline (@rawlines) {
$linenr++;
$line = $rawline;
push(@fixed, $rawline) if ($fix);
if ($rawline=~/^\+\+\+\s+(\S+)/) {
$setup_docs = 0;
if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
$setup_docs = 1;
}
#next;
}
if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
$realline=$1-1;
if (defined $2) {
$realcnt=$3+1;
} else {
$realcnt=1+1;
}
$in_comment = 0;
# Guestimate if this is a continuing comment. Run
# the context looking for a comment "edge". If this
# edge is a close comment then we must be in a comment
# at context start.
my $edge;
my $cnt = $realcnt;
for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
next if (defined $rawlines[$ln - 1] &&
$rawlines[$ln - 1] =~ /^-/);
$cnt--;
#print "RAW\n";
last if (!defined $rawlines[$ln - 1]);
if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
$rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
($edge) = $1;
last;
}
}
if (defined $edge && $edge eq '*/') {
$in_comment = 1;
}
# Guestimate if this is a continuing comment. If this
# is the start of a diff block and this line starts
# ' *' then it is very likely a comment.
if (!defined $edge &&
$rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
{
$in_comment = 1;
}
##print "COMMENT:$in_comment edge $rawline\n";
sanitise_line_reset($in_comment);
} elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
# Standardise the strings and chars within the input to
# simplify matching -- only bother with positive lines.
$line = sanitise_line($rawline);
}
push(@lines, $line);
if ($realcnt > 1) {
$realcnt-- if ($line =~ /^(?:\+| |$)/);
} else {
$realcnt = 0;
}
#print "==>$rawline\n";
#print "-->$line\n";
if ($setup_docs && $line =~ /^\+/) {
push(@setup_docs, $line);
}
}
$prefix = '';
$realcnt = 0;
$linenr = 0;
foreach my $line (@lines) {
$linenr++;
my $rawline = $rawlines[$linenr - 1];
#extract the line range in the file after the patch is applied
if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
$is_patch = 1;
$first_line = $linenr + 1;
$realline=$1-1;
if (defined $2) {
$realcnt=$3+1;
} else {
$realcnt=1+1;
}
annotate_reset();
$prev_values = 'E';
%suppress_ifbraces = ();
%suppress_whiletrailers = ();
%suppress_export = ();
$suppress_statement = 0;
next;
# track the line number as we move through the hunk, note that
# new versions of GNU diff omit the leading space on completely
# blank context lines so we need to count that too.
} elsif ($line =~ /^( |\+|$)/) {
$realline++;
$realcnt-- if ($realcnt != 0);
# Measure the line length and indent.
($length, $indent) = line_stats($rawline);
# Track the previous line.
($prevline, $stashline) = ($stashline, $line);
($previndent, $stashindent) = ($stashindent, $indent);
($prevrawline, $stashrawline) = ($stashrawline, $rawline);
#warn "line\n";
} elsif ($realcnt == 1) {
$realcnt--;
}
my $hunk_line = ($realcnt != 0);
#make up the handle for any error we report on this line
$prefix = "$filename:$realline: " if ($emacs && $file);
$prefix = "$filename:$linenr: " if ($emacs && !$file);
$here = "#$linenr: " if (!$file);
$here = "#$realline: " if ($file);
# extract the filename as it passes
if ($line =~ /^diff --git.*?(\S+)$/) {
$realfile = $1;
$realfile =~ s@^([^/]*)/@@;
$in_commit_log = 0;
} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
$realfile = $1;
$realfile =~ s@^([^/]*)/@@;
$in_commit_log = 0;
$p1_prefix = $1;
if (!$file && $tree && $p1_prefix ne '' &&
-e "$root/$p1_prefix") {
WARN("PATCH_PREFIX",
"patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
}
if ($realfile =~ m@^include/asm/@) {
ERROR("MODIFIED_INCLUDE_ASM",
"do not modify files in include/asm, change architecture specific files in include/asm-\n" . "$here$rawline\n");
}
next;
}
$here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
my $hereline = "$here\n$rawline\n";
my $herecurr = "$here\n$rawline\n";
my $hereprev = "$here\n$prevrawline\n$rawline\n";
$cnt_lines++ if ($realcnt != 0);
# Check for incorrect file permissions
if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
my $permhere = $here . "FILE: $realfile\n";
if ($realfile !~ m@scripts/@ &&
$realfile !~ /\.(py|pl|awk|sh)$/) {
ERROR("EXECUTE_PERMISSIONS",
"do not set execute permissions for source files\n" . $permhere);
}
}
# Check the patch for a signoff:
if ($line =~ /^\s*signed-off-by:/i) {
$signoff++;
$in_commit_log = 0;
}
# Check signature styles
if (!$in_header_lines &&
$line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) {
my $space_before = $1;
my $sign_off = $2;
my $space_after = $3;
my $email = $4;
my $ucfirst_sign_off = ucfirst(lc($sign_off));
if ($sign_off !~ /$signature_tags/) {
WARN("BAD_SIGN_OFF",
"Non-standard signature: $sign_off\n" . $herecurr);
}
if (defined $space_before && $space_before ne "") {
if (WARN("BAD_SIGN_OFF",
"Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) &&
$fix) {
$fixed[$linenr - 1] =
"$ucfirst_sign_off $email";
}
}
if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) {
if (WARN("BAD_SIGN_OFF",
"'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) &&
$fix) {
$fixed[$linenr - 1] =
"$ucfirst_sign_off $email";
}
}
if (!defined $space_after || $space_after ne " ") {
if (WARN("BAD_SIGN_OFF",
"Use a single space after $ucfirst_sign_off\n" . $herecurr) &&
$fix) {
$fixed[$linenr - 1] =
"$ucfirst_sign_off $email";
}
}
my ($email_name, $email_address, $comment) = parse_email($email);
my $suggested_email = format_email(($email_name, $email_address));
if ($suggested_email eq "") {
ERROR("BAD_SIGN_OFF",
"Unrecognized email address: '$email'\n" . $herecurr);
} else {
my $dequoted = $suggested_email;
$dequoted =~ s/^"//;
$dequoted =~ s/" .$outline\n";
print "$linenr > $curr_values\n";
print "$linenr > $curr_vars\n";
}
$prev_values = substr($curr_values, -1);
#ignore lines not being added
next if ($line =~ /^[^\+]/);
# TEST: allow direct testing of the type matcher.
if ($dbg_type) {
if ($line =~ /^.\s*$Declare\s*$/) {
ERROR("TEST_TYPE",
"TEST: is type\n" . $herecurr);
} elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
ERROR("TEST_NOT_TYPE",
"TEST: is not type ($1 is)\n". $herecurr);
}
next;
}
# TEST: allow direct testing of the attribute matcher.
if ($dbg_attr) {
if ($line =~ /^.\s*$Modifier\s*$/) {
ERROR("TEST_ATTR",
"TEST: is attr\n" . $herecurr);
} elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
ERROR("TEST_NOT_ATTR",
"TEST: is not attr ($1 is)\n". $herecurr);
}
next;
}
# check for initialisation to aggregates open brace on the next line
if ($line =~ /^.\s*{/ &&
$prevline =~ /(?:^|[^=])=\s*$/) {
ERROR("OPEN_BRACE",
"that open brace { should be on the previous line\n" . $hereprev);
}
#
# Checks which are anchored on the added line.
#
# check for malformed paths in #include statements (uses RAW line)
if ($rawline =~ m{^.\s*\#\s*include\s+[]}) {
my $path = $1;
if ($path =~ m{//}) {
ERROR("MALFORMED_INCLUDE",
"malformed #include filename\n" . $herecurr);
}
if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) {
ERROR("UAPI_INCLUDE",
"No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr);
}
}
# no C99 // comments
if ($line =~ m{//}) {
if (ERROR("C99_COMMENTS",
"do not use C99 // comments\n" . $herecurr) &&
$fix) {
my $line = $fixed[$linenr - 1];
if ($line =~ /\/\/(.*)$/) {
my $comment = trim($1);
$fixed[$linenr - 1] =~ s@\/\/(.*)$@/\* $comment \*/@;
}
}
}
# Remove C99 comments.
$line =~ s@//.*@@;
$opline =~ s@//.*@@;
# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
# the whole statement.
#print "APW \n";
if (defined $realline_next &&
exists $lines[$realline_next - 1] &&
!defined $suppress_export{$realline_next} &&
($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
$lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
# Handle definitions which produce identifiers with
# a prefix:
# XXX(foo);
# EXPORT_SYMBOL(something_foo);
my $name = $1;
if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
$name =~ /^${Ident}_$2/) {
#print "FOO C name\n";
$suppress_export{$realline_next} = 1;
} elsif ($stat !~ /(?:
\n.}\s*$|
^.DEFINE_$Ident\(\Q$name\E\)|
^.DECLARE_$Ident\(\Q$name\E\)|
^.LIST_HEAD\(\Q$name\E\)|
^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
\b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
)/x) {
#print "FOO A stat name\n";
$suppress_export{$realline_next} = 2;
} else {
$suppress_export{$realline_next} = 1;
}
}
if (!defined $suppress_export{$linenr} &&
$prevline =~ /^.\s*$/ &&
($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
$line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
#print "FOO B \n";
$suppress_export{$linenr} = 2;
}
if (defined $suppress_export{$linenr} &&
$suppress_export{$linenr} == 2) {
WARN("EXPORT_SYMBOL",
"EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
}
# check for global initialisers.
if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
ERROR("GLOBAL_INITIALISERS",
"do not initialise globals to 0 or NULL\n" .
$herecurr);
}
# check for static initialisers.
if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
ERROR("INITIALISED_STATIC",
"do not initialise statics to 0 or NULL\n" .
$herecurr);
}
# check for static const char * arrays.
if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
WARN("STATIC_CONST_CHAR_ARRAY",
"static const char * array should probably be static const char * const\n" .
$herecurr);
}
# check for static char foo[] = "bar" declarations.
if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) {
WARN("STATIC_CONST_CHAR_ARRAY",
"static char array declaration should probably be static const char\n" .
$herecurr);
}
# check for declarations of struct pci_device_id
if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) {
WARN("DEFINE_PCI_DEVICE_TABLE",
"Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr);
}
# check for new typedefs, only function parameters and sparse annotations
# make sense.
if ($line =~ /\btypedef\s/ &&
$line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
$line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
$line !~ /\b$typeTypedefs\b/ &&
$line !~ /\b__bitwise(?:__|)\b/) {
WARN("NEW_TYPEDEFS",
"do not add new typedefs\n" . $herecurr);
}
# * goes on variable not on type
# (char*[ const])
while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) {
#print "AA\n";
my ($ident, $from, $to) = ($1, $2, $2);
# Should start with a space.
$to =~ s/^(\S)/ $1/;
# Should not end with a space.
$to =~ s/\s+$//;
# '*'s should not have spaces between.
while ($to =~ s/\*\s+\*/\*\*/) {
}
## print "1: from to ident\n";
if ($from ne $to) {
if (ERROR("POINTER_LOCATION",
"\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr) &&
$fix) {
my $sub_from = $ident;
my $sub_to = $ident;
$sub_to =~ s/\Q$from\E/$to/;
$fixed[$linenr - 1] =~
s@\Q$sub_from\E@$sub_to@;
}
}
}
while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) {
#print "BB\n";
my ($match, $from, $to, $ident) = ($1, $2, $2, $3);
# Should start with a space.
$to =~ s/^(\S)/ $1/;
# Should not end with a space.
$to =~ s/\s+$//;
# '*'s should not have spaces between.
while ($to =~ s/\*\s+\*/\*\*/) {
}
# Modifiers should have spaces.
$to =~ s/(\b$Modifier$)/$1 /;
## print "2: from to ident\n";
if ($from ne $to && $ident !~ /^$Modifier$/) {
if (ERROR("POINTER_LOCATION",
"\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr) &&
$fix) {
my $sub_from = $match;
my $sub_to = $match;
$sub_to =~ s/\Q$from\E/$to/;
$fixed[$linenr - 1] =~
s@\Q$sub_from\E@$sub_to@;
}
}
}
# # no BUG() or BUG_ON()
# if ($line =~ /\b(BUG|BUG_ON)\b/) {
# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n";
# print "$herecurr";
# $clean = 0;
# }
if ($line =~ /\bLINUX_VERSION_CODE\b/) {
WARN("LINUX_VERSION_CODE",
"LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
}
# check for uses of printk_ratelimit
if ($line =~ /\bprintk_ratelimit\s*\(/) {
WARN("PRINTK_RATELIMITED",
"Prefer printk_ratelimited or pr__ratelimited to printk_ratelimit\n" . $herecurr);
}
# printk should use KERN_* levels. Note that follow on printk's on the
# same line do not need a level, so we use the current block context
# to try and find and validate the current printk. In summary the current
# printk includes all preceding printk's which have no newline on the end.
# we assume the first bad printk is the one to report.
if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
my $ok = 0;
for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
#print "CHECK' || $opv eq ':B') {
if ($ctx =~ /Wx.|.xW/) {
if (ERROR("SPACING",
"spaces prohibited around that '$op' $at\n" . $hereptr)) {
$good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
$line_fixed = 1;
if (defined $fix_elements[$n + 2]) {
$fix_elements[$n + 2] =~ s/^\s+//;
}
}
}
# , must have a space on the right.
} elsif ($op eq ',') {
if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
if (ERROR("SPACING",
"space required after that '$op' $at\n" . $hereptr)) {
$good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]) . " ";
$line_fixed = 1;
}
}
# '*' as part of a type definition -- reported already.
} elsif ($opv eq '*_') {
#warn "'*' is part of type\n";
# unary operators should have a space before and
# none after. May be left adjacent to another
# unary operator, or a cast
} elsif ($op eq '!' || $op eq '~' ||
$opv eq '*U' || $opv eq '-U' ||
$opv eq '&U' || $opv eq '&&U') {
if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
if (ERROR("SPACING",
"space required before that '$op' $at\n" . $hereptr)) {
$good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]);
$line_fixed = 1;
}
}
if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
# A unary '*' may be const
} elsif ($ctx =~ /.xW/) {
if (ERROR("SPACING",
"space prohibited after that '$op' $at\n" . $hereptr)) {
$fixed_line =~ s/\s+$//;
$good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
$line_fixed = 1;
if (defined $fix_elements[$n + 2]) {
$fix_elements[$n + 2] =~ s/^\s+//;
}
}
}
# unary ++ and unary -- are allowed no space on one side.
} elsif ($op eq '++' or $op eq '--') {
if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
if (ERROR("SPACING",
"space required one side of that '$op' $at\n" . $hereptr)) {
$fixed_line =~ s/\s+$//;
$good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]) . " ";
$line_fixed = 1;
}
}
if ($ctx =~ /Wx[BE]/ ||
($ctx =~ /Wx./ && $cc =~ /^;/)) {
if (ERROR("SPACING",
"space prohibited before that '$op' $at\n" . $hereptr)) {
$fixed_line =~ s/\s+$//;
$good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
$line_fixed = 1;
}
}
if ($ctx =~ /ExW/) {
if (ERROR("SPACING",
"space prohibited after that '$op' $at\n" . $hereptr)) {
$fixed_line =~ s/\s+$//;
$good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
$line_fixed = 1;
if (defined $fix_elements[$n + 2]) {
$fix_elements[$n + 2] =~ s/^\s+//;
}
}
}
# > may either have or not have spaces both sides
} elsif ($op eq '' or
$op eq '&' or $op eq '^' or $op eq '|' or
$op eq '+' or $op eq '-' or
$op eq '*' or $op eq '/' or
$op eq '%')
{
if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
if (ERROR("SPACING",
"need consistent spacing around '$op' $at\n" . $hereptr)) {
$fixed_line =~ s/\s+$//;
$good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
$line_fixed = 1;
}
}
# A colon needs no spaces before when it is
# terminating a case value or a label.
} elsif ($opv eq ':C' || $opv eq ':L') {
if ($ctx =~ /Wx./) {
if (ERROR("SPACING",
"space prohibited before that '$op' $at\n" . $hereptr)) {
$good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
$line_fixed = 1;
}
}
# All the others need spaces both sides.
} elsif ($ctx !~ /[EWC]x[CWE]/) {
my $ok = 0;
# Ignore email addresses
if (($op eq '' &&
$ca =~ / 1) {
$stat_real = "[...]\n$stat_real";
}
ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" . $herecurr . $stat_real);
}
}
# Check for bitwise tests written as boolean
if ($line =~ /
(?:
(?:\[|\(|\&\&|\|\|)
\s*0[xX][0-9]+\s*
(?:\&\&|\|\|)
|
(?:\&\&|\|\|)
\s*0[xX][0-9]+\s*
(?:\&\&|\|\||\)|\])
)/x)
{
WARN("HEXADECIMAL_BOOLEAN_TEST",
"boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
}
# if and else should not have general statements after it
if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
my $s = $1;
$s =~ s/$;//g; # Remove any comments
if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" . $herecurr);
}
}
# if should not continue a brace
if ($line =~ /}\s*if\b/) {
ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" .
$herecurr);
}
# case and default should not have general statements after them
if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
$line !~ /\G(?:
(?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
\s*return\s+
)/xg)
{
ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" . $herecurr);
}
# Check for }else {, these must be at the same
# indent level to be relevant to each other.
if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
$previndent == $indent) {
ERROR("ELSE_AFTER_BRACE",
"else should follow close brace '}'\n" . $hereprev);
}
if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
$previndent == $indent) {
my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
# Find out what is on the end of the line after the
# conditional.
substr($s, 0, length($c), '');
$s =~ s/\n.*//g;
if ($s =~ /^\s*;/) {
ERROR("WHILE_AFTER_BRACE",
"while should follow close brace '}'\n" . $hereprev);
}
}
#Specific variable tests
while ($line =~ m{($Constant|$Lval)}g) {
my $var = $1;
#gcc binary extension
if ($var =~ /^$Binary$/) {
WARN("GCC_BINARY_CONSTANT",
"Avoid gcc v4.3+ binary constant extension: \n" . $herecurr);
}
#CamelCase
if ($var !~ /^$Constant$/ &&
$var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
#Ignore Page variants
$var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show)
$var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/) {
seed_camelcase_includes() if ($check);
if (!defined $camelcase{$var}) {
$camelcase{$var} = 1;
CHK("CAMELCASE",
"Avoid CamelCase: \n" . $herecurr);
}
}
}
#no spaces allowed after \ in define
if ($line=~/\#\s*define.*\\\s$/) {
WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
"Whitepspace after \\ makes next lines useless\n" . $herecurr);
}
#warn if is #included and is available (uses RAW line)
if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\}) {
my $file = "$1.h";
my $checkfile = "include/linux/$file";
if (-f "$root/$checkfile" &&
$realfile ne $checkfile &&
$1 !~ /$allowed_asm_includes/)
{
if ($realfile =~ m{^arch/}) {
CHK("ARCH_INCLUDE_LINUX",
"Consider using #include instead of \n" . $herecurr);
} else {
WARN("INCLUDE_LINUX",
"Use #include instead of \n" . $herecurr);
}
}
}
# multi-statement macros should be enclosed in a do while loop, grab the
# first statement and ensure its the whole macro if its not enclosed
# in a known good container
if ($realfile !~ m@/vmlinux.lds.h$@ &&
$line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
my $ln = $linenr;
my $cnt = $realcnt;
my ($off, $dstat, $dcond, $rest);
my $ctx = '';
($dstat, $dcond, $ln, $cnt, $off) =
ctx_statement_block($linenr, $realcnt, 0);
$ctx = $dstat;
#print "dstat dcond cnt off\n";
#print "LINE len $max) {
WARN("USLEEP_RANGE",
"usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
}
}
# check for new externs in .c files.
if ($realfile =~ /\.c$/ && defined $stat &&
$stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
{
my $function_name = $1;
my $paren_space = $2;
my $s = $stat;
if (defined $cond) {
substr($s, 0, length($cond), '');
}
if ($s =~ /^\s*;/ &&
$function_name ne 'uninitialized_var')
{
WARN("AVOID_EXTERNS",
"externs should be avoided in .c files\n" . $herecurr);
}
if ($paren_space =~ /\n/) {
WARN("FUNCTION_ARGUMENTS",
"arguments for function declarations should follow identifier\n" . $herecurr);
}
} elsif ($realfile =~ /\.c$/ && defined $stat &&
$stat =~ /^.\s*extern\s+/)
{
WARN("AVOID_EXTERNS",
"externs should be avoided in .c files\n" . $herecurr);
}
# checks for new __setup's
if ($rawline =~ /\b__setup\("([^"]*)"/) {
my $name = $1;
if (!grep(/$name/, @setup_docs)) {
CHK("UNDOCUMENTED_SETUP",
"__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
}
}
# check for pointless casting of kmalloc return
if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) {
WARN("UNNECESSARY_CASTS",
"unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
}
# alloc style
# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
if ($^V && $^V ge 5.10.0 &&
$line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
CHK("ALLOC_SIZEOF_STRUCT",
"Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
}
# check for krealloc arg reuse
if ($^V && $^V ge 5.10.0 &&
$line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) {
WARN("KREALLOC_ARG_REUSE",
"Reusing the krealloc arg is almost always a bug\n" . $herecurr);
}
# check for alloc argument mismatch
if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) {
WARN("ALLOC_ARRAY_ARGS",
"$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
}
# check for multiple semicolons
if ($line =~ /;\s*;\s*$/) {
WARN("ONE_SEMICOLON",
"Statements terminations use 1 semicolon\n" . $herecurr);
}
# check for switch/default statements without a break;
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) {
my $ctx = '';
my $herectx = $here . "\n";
my $cnt = statement_rawlines($stat);
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
WARN("DEFAULT_NO_BREAK",
"switch default: should use break\n" . $herectx);
}
# check for gcc specific __FUNCTION__
if ($line =~ /__FUNCTION__/) {
WARN("USE_FUNC",
"__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr);
}
# check for use of yield()
if ($line =~ /\byield\s*\(\s*\)/) {
WARN("YIELD",
"Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr);
}
# check for comparisons against true and false
if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) {
my $lead = $1;
my $arg = $2;
my $test = $3;
my $otype = $4;
my $trail = $5;
my $op = "!";
($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i);
my $type = lc($otype);
if ($type =~ /^(?:true|false)$/) {
if (("$test" eq "==" && "$type" eq "true") ||
("$test" eq "!=" && "$type" eq "false")) {
$op = "";
}
CHK("BOOL_COMPARISON",
"Using comparison to $otype is error prone\n" . $herecurr);
## maybe suggesting a correct construct would better
## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr);
}
}
# check for semaphores initialized locked
if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
WARN("CONSIDER_COMPLETION",
"consider using a completion\n" . $herecurr);
}
# recommend kstrto* over simple_strto* and strict_strto*
if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) {
WARN("CONSIDER_KSTRTO",
"$1 is obsolete, use k$3 instead\n" . $herecurr);
}
# check for __initcall(), use device_initcall() explicitly please
if ($line =~ /^.\s*__initcall\s*\(/) {
WARN("USE_DEVICE_INITCALL",
"please use device_initcall() instead of __initcall()\n" . $herecurr);
}
# check for various ops structs, ensure they are const.
my $struct_ops = qr{acpi_dock_ops|
address_space_operations|
backlight_ops|
block_device_operations|
dentry_operations|
dev_pm_ops|
dma_map_ops|
extent_io_ops|
file_lock_operations|
file_operations|
hv_ops|
ide_dma_ops|
intel_dvo_dev_ops|
item_operations|
iwl_ops|
kgdb_arch|
kgdb_io|
kset_uevent_ops|
lock_manager_operations|
microcode_ops|
mtrr_ops|
neigh_ops|
nlmsvc_binding|
pci_raw_ops|
pipe_buf_operations|
platform_hibernation_ops|
platform_suspend_ops|
proto_ops|
rpc_pipe_ops|
seq_operations|
snd_ac97_build_ops|
soc_pcmcia_socket_ops|
stacktrace_ops|
sysfs_ops|
tty_operations|
usb_mon_operations|
wd_ops}x;
if ($line !~ /\bconst\b/ &&
$line =~ /\bstruct\s+($struct_ops)\b/) {
WARN("CONST_STRUCT",
"struct $1 should normally be const\n" .
$herecurr);
}
# use of NR_CPUS is usually wrong
# ignore definitions of NR_CPUS and usage to define arrays as likely right
if ($line =~ /\bNR_CPUS\b/ &&
$line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
$line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
$line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
$line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
$line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
{
WARN("NR_CPUS",
"usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
}
# check for %L{u,d,i} in strings
my $string;
while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
$string = substr($rawline, $-[1], $+[1] - $-[1]);
$string =~ s/%%/__/g;
if ($string =~ /(? 3) {
$fixed_line =~ s/^\+//;
print $f $fixed_line. "\n";
}
} else {
print $f $fixed_line . "\n";
}
}
close($f);
if (!$quiet) {
print