]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - scripts/checkpatch.pl
kbuild: kill output in silent mode of mkcompile_h
[linux-2.6.git] / scripts / checkpatch.pl
index b2b0648ee14a48f43a0172767c14f8340b6ff3e0..f88bb3e21cda9c9a29470004f9e964907a1a17bb 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-# (c) 2001, Dave Jones. <davej@codemonkey.org.uk> (the file handling bit)
+# (c) 2001, Dave Jones. <davej@redhat.com> (the file handling bit)
 # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
 # (c) 2007, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite, etc)
 # Licensed under the terms of the GNU GPL License version 2
@@ -9,7 +9,7 @@ use strict;
 my $P = $0;
 $P =~ s@.*/@@g;
 
-my $V = '0.20';
+my $V = '0.24';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -17,7 +17,6 @@ my $quiet = 0;
 my $tree = 1;
 my $chk_signoff = 1;
 my $chk_patch = 1;
-my $tst_type = 0;
 my $tst_only;
 my $emacs = 0;
 my $terse = 0;
@@ -44,7 +43,6 @@ GetOptions(
        'summary-file!' => \$summary_file,
 
        'debug=s'       => \%debug,
-       'test-type!'    => \$tst_type,
        'test-only=s'   => \$tst_only,
 ) or exit;
 
@@ -67,6 +65,8 @@ if ($#ARGV < 0) {
 
 my $dbg_values = 0;
 my $dbg_possible = 0;
+my $dbg_type = 0;
+my $dbg_attr = 0;
 for my $key (keys %debug) {
        eval "\${dbg_$key} = '$debug{$key}';"
 }
@@ -113,7 +113,10 @@ our $Attribute     = qr{
                        const|
                        __read_mostly|
                        __kprobes|
-                       __(?:mem|cpu|dev|)(?:initdata|init)
+                       __(?:mem|cpu|dev|)(?:initdata|init)|
+                       ____cacheline_aligned|
+                       ____cacheline_aligned_in_smp|
+                       ____cacheline_internodealigned_in_smp
                  }x;
 our $Modifier;
 our $Inline    = qr{inline|__always_inline|noinline};
@@ -143,6 +146,11 @@ our $UTF8  = qr {
        |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
 }x;
 
+our $typeTypedefs = qr{(?x:
+       (?:__)?(?:u|s|be|le)(?:\d|\d\d)|
+       atomic_t
+)};
+
 our @typeList = (
        qr{void},
        qr{(?:unsigned\s+)?char},
@@ -156,7 +164,6 @@ our @typeList = (
        qr{float},
        qr{double},
        qr{bool},
-       qr{(?:__)?(?:u|s|be|le)(?:8|16|32|64)},
        qr{struct\s+$Ident},
        qr{union\s+$Ident},
        qr{enum\s+$Ident},
@@ -169,14 +176,14 @@ our @modifierList = (
 );
 
 sub build_types {
-       my $mods = "(?:  \n" . join("|\n  ", @modifierList) . "\n)";
-       my $all = "(?:  \n" . join("|\n  ", @typeList) . "\n)";
+       my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
+       my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
        $Modifier       = qr{(?:$Attribute|$Sparse|$mods)};
        $NonptrType     = qr{
-                       (?:const\s+)?
-                       (?:$mods\s+)?
+                       (?:$Modifier\s+|const\s+)*
                        (?:
                                (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+                               (?:$typeTypedefs\b)|
                                (?:${all}\b)
                        )
                        (?:\s+$Modifier|\s+const)*
@@ -333,7 +340,7 @@ sub sanitise_line {
                        $off++;
                        next;
                }
-               if (substr($line, $off, 2) eq '*/') {
+               if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
                        $sanitise_quote = '';
                        substr($res, $off, 2, "$;$;");
                        $off++;
@@ -406,6 +413,7 @@ sub ctx_statement_block {
                # context.
                if ($off >= $len) {
                        for (; $remain > 0; $line++) {
+                               last if (!defined $lines[$line]);
                                next if ($lines[$line] =~ /^-/);
                                $remain--;
                                $loff = $len;
@@ -470,7 +478,9 @@ sub ctx_statement_block {
                }
                $off++;
        }
+       # We are truly at the end, so shuffle to the next line.
        if ($off == $len) {
+               $loff = $len + 1;
                $line++;
                $remain--;
        }
@@ -669,6 +679,22 @@ sub ctx_has_comment {
        return ($cmt ne '');
 }
 
+sub raw_line {
+       my ($linenr, $cnt) = @_;
+
+       my $offset = $linenr - 1;
+       $cnt++;
+
+       my $line;
+       while ($cnt) {
+               $line = $rawlines[$offset++];
+               next if (defined($line) && $line =~ /^-/);
+               $cnt--;
+       }
+
+       return $line;
+}
+
 sub cat_vet {
        my ($vet) = @_;
        my ($res, $coded);
@@ -689,17 +715,20 @@ sub cat_vet {
 my $av_preprocessor = 0;
 my $av_pending;
 my @av_paren_type;
+my $av_pend_colon;
 
 sub annotate_reset {
        $av_preprocessor = 0;
        $av_pending = '_';
        @av_paren_type = ('E');
+       $av_pend_colon = 'O';
 }
 
 sub annotate_values {
        my ($stream, $type) = @_;
 
        my $res;
+       my $var = '_' x length($stream);
        my $cur = $stream;
 
        print "$stream\n" if ($dbg_values > 1);
@@ -715,10 +744,14 @@ sub annotate_values {
                                $av_preprocessor = 0;
                        }
 
-               } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\))/) {
+               } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) {
                        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;
@@ -775,12 +808,17 @@ sub annotate_values {
                        }
                        $type = 'N';
 
-               } elsif ($cur =~ /^(if|while|typeof|__typeof__|for)\b/o) {
+               } elsif ($cur =~ /^(if|while|for)\b/o) {
                        print "COND($1)\n" if ($dbg_values > 1);
-                       $av_pending = 'N';
+                       $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|case|else|goto)/o) {
+               } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
                        print "KEYWORD($1)\n" if ($dbg_values > 1);
                        $type = 'N';
 
@@ -805,6 +843,15 @@ sub annotate_values {
                        $type = 'V';
                        $av_pending = 'V';
 
+               } elsif ($cur =~ /^($Ident\s*):/) {
+                       if ($type eq 'E') {
+                               $av_pend_colon = 'L';
+                       } elsif ($type eq 'T') {
+                               $av_pend_colon = 'B';
+                       }
+                       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';
@@ -816,11 +863,40 @@ sub annotate_values {
                } elsif ($cur =~/^(;|{|})/) {
                        print "END($1)\n" if ($dbg_values > 1);
                        $type = 'E';
+                       $av_pend_colon = 'O';
 
-               } elsif ($cur =~ /^(;|\?|:|\[)/o) {
+               } 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 '--') {
@@ -836,18 +912,28 @@ sub annotate_values {
                }
        }
 
-       return $res;
+       return ($res, $var);
 }
 
 sub possible {
        my ($possible, $line) = @_;
 
-       print "CHECK<$possible> ($line)\n" if ($dbg_possible > 1);
-       if ($possible !~ /^(?:$Storage|$Type|DEFINE_\S+)$/ &&
-           $possible ne 'goto' && $possible ne 'return' &&
-           $possible ne 'case' && $possible ne 'else' &&
-           $possible ne 'asm' && $possible ne '__asm__' &&
-           $possible !~ /^(typedef|struct|enum)\b/) {
+       print "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+       if ($possible !~ /(?:
+               ^(?:
+                       $Modifier|
+                       $Storage|
+                       $Type|
+                       DEFINE_\S+|
+                       goto|
+                       return|
+                       case|
+                       else|
+                       asm|__asm__|
+                       do
+               )$|
+               ^(?:typedef|struct|enum)\b
+           )/x) {
                # Check for modifiers.
                $possible =~ s/\s*$Storage\s*//g;
                $possible =~ s/\s*$Sparse\s*//g;
@@ -855,14 +941,18 @@ sub possible {
 
                } elsif ($possible =~ /\s/) {
                        $possible =~ s/\s*$Type\s*//g;
-                       warn "MODIFIER: $possible ($line)\n" if ($dbg_possible);
-                       push(@modifierList, $possible);
+                       for my $modifier (split(' ', $possible)) {
+                               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);
        }
 }
 
@@ -902,6 +992,33 @@ sub CHK {
        }
 }
 
+sub check_absolute_file {
+       my ($absolute, $herecurr) = @_;
+       my $file = $absolute;
+
+       ##print "absolute<$absolute>\n";
+
+       # See if any suffix of this path is a path within the tree.
+       while ($file =~ s@^[^/]*/@@) {
+               if (-f "$root/$file") {
+                       ##print "file<$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<$prefix>\n";
+       if ($prefix ne ".../") {
+               WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+       }
+}
+
 sub process {
        my $filename = shift;
 
@@ -939,6 +1056,7 @@ sub process {
 
        # suppression flags
        my %suppress_ifbraces;
+       my %suppress_whiletrailers;
 
        # Pre-scan the patch sanitizing the lines.
        # Pre-scan the patch looking for any __setup documentation.
@@ -973,9 +1091,14 @@ sub process {
                        # edge is a close comment then we must be in a comment
                        # at context start.
                        my $edge;
-                       for (my $ln = $linenr + 1; $ln < ($linenr + $realcnt); $ln++) {
-                               next if ($line =~ /^-/);
-                               ($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@);
+                       my $cnt = $realcnt;
+                       for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+                               next if (defined $rawlines[$ln - 1] &&
+                                        $rawlines[$ln - 1] =~ /^-/);
+                               $cnt--;
+                               #print "RAW<$rawlines[$ln - 1]>\n";
+                               ($edge) = (defined $rawlines[$ln - 1] &&
+                                       $rawlines[$ln - 1] =~ m@(/\*|\*/)@);
                                last if (defined $edge);
                        }
                        if (defined $edge && $edge eq '*/') {
@@ -1023,6 +1146,7 @@ sub process {
                $linenr++;
 
                my $rawline = $rawlines[$linenr - 1];
+               my $hunk_line = ($realcnt != 0);
 
 #extract the line range in the file after the patch is applied
                if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
@@ -1038,6 +1162,7 @@ sub process {
                        $prev_values = 'E';
 
                        %suppress_ifbraces = ();
+                       %suppress_whiletrailers = ();
                        next;
 
 # track the line number as we move through the hunk, note that
@@ -1073,7 +1198,7 @@ sub process {
                        $realfile = $1;
                        $realfile =~ s@^[^/]*/@@;
 
-                       if ($realfile =~ m@include/asm/@) {
+                       if ($realfile =~ m@^include/asm/@) {
                                ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
                        }
                        next;
@@ -1107,6 +1232,20 @@ sub process {
                                $herecurr) if (!$emitted_corrupt++);
                }
 
+# Check for absolute kernel paths.
+               if ($tree) {
+                       while ($line =~ m{(?:^|\s)(/\S*)}g) {
+                               my $file = $1;
+
+                               if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+                                   check_absolute_file($1, $herecurr)) {
+                                       #
+                               } else {
+                                       check_absolute_file($file, $herecurr);
+                               }
+                       }
+               }
+
 # UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
                if (($realfile =~ /^$/ || $line =~ /^\+/) &&
                    $rawline !~ m/^$UTF8*$/) {
@@ -1119,11 +1258,8 @@ sub process {
                        ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
                }
 
-#ignore lines being removed
-               if ($line=~/^-/) {next;}
-
-# check we are in a valid source file if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+# ignore non-hunk lines and lines being removed
+               next if (!$hunk_line || $line =~ /^-/);
 
 #trailing whitespace
                if ($line =~ /^\+.*\015/) {
@@ -1134,9 +1270,15 @@ sub process {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        ERROR("trailing whitespace\n" . $herevet);
                }
+
+# check we are in a valid source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
 #80 column limit
                if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
-                   $rawline !~ /^.\s*\*\s*\@$Ident\s/ && $length > 80)
+                   $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
+                   $line !~ /^\+\s*printk\s*\(\s*(?:KERN_\S+\s*)?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ &&
+                   $length > 80)
                {
                        WARN("line over 80 characters\n" . $herecurr);
                }
@@ -1146,8 +1288,8 @@ sub process {
                        WARN("adding a line without newline at end of file\n" . $herecurr);
                }
 
-# check we are in a valid source file *.[hc] if not then ignore this hunk
-               next if ($realfile !~ /\.[hc]$/);
+# check we are in a valid source file C or perl if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|pl)$/);
 
 # at the beginning of a line any tabs must come first and anything
 # more than 8 must use tabs.
@@ -1157,16 +1299,19 @@ sub process {
                        ERROR("code indent should use tabs where possible\n" . $herevet);
                }
 
+# check we are in a valid C source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c)$/);
+
 # check for RCS/CVS revision markers
                if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
                        WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
                }
 
 # Check for potential 'bare' types
-               my ($stat, $cond);
+               my ($stat, $cond, $line_nr_next, $remain_next, $off_next);
                if ($realcnt && $line =~ /.\s*\S/) {
-                       ($stat, $cond) = ctx_statement_block($linenr,
-                                                               $realcnt, 0);
+                       ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+                               ctx_statement_block($linenr, $realcnt, 0);
                        $stat =~ s/\n./\n /g;
                        $cond =~ s/\n./\n /g;
 
@@ -1180,13 +1325,13 @@ sub process {
                        } elsif ($s =~ /^.\s*$Ident\s*\(/s) {
 
                        # declarations always start with types
-                       } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))\s*(?:;|=|,|\()/s) {
+                       } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) {
                                my $type = $1;
                                $type =~ s/\s+/ /g;
                                possible($type, "A:" . $s);
 
                        # definitions in global scope can only start with types
-                       } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/s) {
+                       } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
                                possible($1, "B:" . $s);
                        }
 
@@ -1247,17 +1392,22 @@ sub process {
                        my $pre_ctx = "$1$2";
 
                        my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
-                       my $ctx_ln = $linenr + $#ctx + 1;
                        my $ctx_cnt = $realcnt - $#ctx - 1;
                        my $ctx = join("\n", @ctx);
 
-                       ##warn "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+                       my $ctx_ln = $linenr;
+                       my $ctx_skip = $realcnt;
 
-                       # Skip over any removed lines in the context following statement.
-                       while (defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^-/) {
+                       while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&
+                                       defined $lines[$ctx_ln - 1] &&
+                                       $lines[$ctx_ln - 1] =~ /^-/)) {
+                               ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
+                               $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);
                                $ctx_ln++;
                        }
-                       ##warn "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
+
+                       #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+                       #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
 
                        if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
                                ERROR("that open brace { should be on the previous line\n" .
@@ -1275,14 +1425,101 @@ sub process {
                        }
                }
 
+# Check relative indent for conditionals and blocks.
+               if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+                       my ($s, $c) = ($stat, $cond);
+
+                       substr($s, 0, length($c), '');
+
+                       # Make sure we remove the line prefixes as we have
+                       # none on the first line, and are going to readd them
+                       # where necessary.
+                       $s =~ s/\n./\n/gs;
+
+                       # Find out how long the conditional actually is.
+                       my @newlines = ($c =~ /\n/gs);
+                       my $cond_lines = 1 + $#newlines;
+
+                       # We want to check the first line inside the block
+                       # starting at the end of the conditional, so remove:
+                       #  1) any blank line termination
+                       #  2) any opening brace { on end of the line
+                       #  3) any do (...) {
+                       my $continuation = 0;
+                       my $check = 0;
+                       $s =~ s/^.*\bdo\b//;
+                       $s =~ s/^\s*{//;
+                       if ($s =~ s/^\s*\\//) {
+                               $continuation = 1;
+                       }
+                       if ($s =~ s/^\s*?\n//) {
+                               $check = 1;
+                               $cond_lines++;
+                       }
+
+                       # Also ignore a loop construct at the end of a
+                       # preprocessor statement.
+                       if (($prevline =~ /^.\s*#\s*define\s/ ||
+                           $prevline =~ /\\\s*$/) && $continuation == 0) {
+                               $check = 0;
+                       }
+
+                       my $cond_ptr = -1;
+                       $continuation = 0;
+                       while ($cond_ptr != $cond_lines) {
+                               $cond_ptr = $cond_lines;
+
+                               # If we see an #else/#elif then the code
+                               # is not linear.
+                               if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+                                       $check = 0;
+                               }
+
+                               # Ignore:
+                               #  1) blank lines, they should be at 0,
+                               #  2) preprocessor lines, and
+                               #  3) labels.
+                               if ($continuation ||
+                                   $s =~ /^\s*?\n/ ||
+                                   $s =~ /^\s*#\s*?/ ||
+                                   $s =~ /^\s*$Ident\s*:/) {
+                                       $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+                                       $s =~ s/^.*?\n//;
+                                       $cond_lines++;
+                               }
+                       }
+
+                       my (undef, $sindent) = line_stats("+" . $s);
+                       my $stat_real = raw_line($linenr, $cond_lines);
+
+                       # Check if either of these lines are modified, else
+                       # this is not this patch's fault.
+                       if (!defined($stat_real) ||
+                           $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+                               $check = 0;
+                       }
+                       if (defined($stat_real) && $cond_lines > 1) {
+                               $stat_real = "[...]\n$stat_real";
+                       }
+
+                       #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+                       if ($check && (($sindent % 8) != 0 ||
+                           ($sindent <= $indent && $s ne ''))) {
+                               WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+                       }
+               }
+
                # Track the 'values' across context and added lines.
                my $opline = $line; $opline =~ s/^./ /;
-               my $curr_values = annotate_values($opline . "\n", $prev_values);
+               my ($curr_values, $curr_vars) =
+                               annotate_values($opline . "\n", $prev_values);
                $curr_values = $prev_values . $curr_values;
                if ($dbg_values) {
                        my $outline = $opline; $outline =~ s/\t/ /g;
                        print "$linenr > .$outline\n";
                        print "$linenr > $curr_values\n";
+                       print "$linenr >  $curr_vars\n";
                }
                $prev_values = substr($curr_values, -1);
 
@@ -1290,8 +1527,21 @@ sub process {
                if ($line=~/^[^\+]/) {next;}
 
 # TEST: allow direct testing of the type matcher.
-               if ($tst_type && $line =~ /^.$Declare$/) {
-                       ERROR("TEST: is type $Declare\n" . $herecurr);
+               if ($dbg_type) {
+                       if ($line =~ /^.\s*$Declare\s*$/) {
+                               ERROR("TEST: is type\n" . $herecurr);
+                       } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
+                               ERROR("TEST: is not type ($1 is)\n". $herecurr);
+                       }
+                       next;
+               }
+# TEST: allow direct testing of the attribute matcher.
+               if ($dbg_attr) {
+                       if ($line =~ /^.\s*$Attribute\s*$/) {
+                               ERROR("TEST: is attr\n" . $herecurr);
+                       } elsif ($dbg_attr > 1 && $line =~ /^.+($Attribute)/) {
+                               ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+                       }
                        next;
                }
 
@@ -1326,13 +1576,14 @@ sub process {
                if (($line =~ /EXPORT_SYMBOL.*\((.*)\)/) ||
                    ($line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
                        my $name = $1;
-                       if (($prevline !~ /^}/) &&
-                          ($prevline !~ /^\+}/) &&
-                          ($prevline !~ /^ }/) &&
-                          ($prevline !~ /^.DECLARE_$Ident\(\Q$name\E\)/) &&
-                          ($prevline !~ /^.LIST_HEAD\(\Q$name\E\)/) &&
-                          ($prevline !~ /^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(/) &&
-                          ($prevline !~ /\b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)/)) {
+                       if ($prevline !~ /(?:
+                               ^.}|
+                               ^.DEFINE_$Ident\(\Q$name\E\)|
+                               ^.DECLARE_$Ident\(\Q$name\E\)|
+                               ^.LIST_HEAD\(\Q$name\E\)|
+                               ^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+                               \b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)
+                           )/x) {
                                WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
                        }
                }
@@ -1353,6 +1604,7 @@ sub process {
                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("do not add new typedefs\n" . $herecurr);
                }
@@ -1366,11 +1618,11 @@ sub process {
                        ERROR("\"(foo $1 )\" should be \"(foo $1)\"\n" .
                                $herecurr);
 
-               } elsif ($line =~ m{$NonptrType(\*+)(?:\s+(?:$Attribute|$Sparse))?\s+[A-Za-z\d_]+}) {
+               } elsif ($line =~ m{\b$NonptrType(\*+)(?:\s+(?:$Attribute|$Sparse))?\s+[A-Za-z\d_]+}) {
                        ERROR("\"foo$1 bar\" should be \"foo $1bar\"\n" .
                                $herecurr);
 
-               } elsif ($line =~ m{$NonptrType\s+(\*+)(?!\s+(?:$Attribute|$Sparse))\s+[A-Za-z\d_]+}) {
+               } elsif ($line =~ m{\b$NonptrType\s+(\*+)(?!\s+(?:$Attribute|$Sparse))\s+[A-Za-z\d_]+}) {
                        ERROR("\"foo $1 bar\" should be \"foo $1bar\"\n" .
                                $herecurr);
                }
@@ -1422,6 +1674,19 @@ sub process {
                        ERROR("open brace '{' following $1 go on the same line\n" . $hereprev);
                }
 
+# check for spacing round square brackets; allowed:
+#  1. with a type on the left -- int [] a;
+#  2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+#  3. inside a curly brace -- = { [0...10] = 5 }
+               while ($line =~ /(.*?\s)\[/g) {
+                       my ($where, $prefix) = ($-[1], $1);
+                       if ($prefix !~ /$Type\s+$/ &&
+                           ($where != 0 || $prefix !~ /^.\s+$/) &&
+                           $prefix !~ /{\s+$/) {
+                               ERROR("space prohibited before open square bracket '['\n" . $herecurr);
+                       }
+               }
+
 # check for spaces between functions and their parentheses.
                while ($line =~ /($Ident)\s+\(/g) {
                        my $name = $1;
@@ -1458,7 +1723,8 @@ sub process {
                                <<=|>>=|<=|>=|==|!=|
                                \+=|-=|\*=|\/=|%=|\^=|\|=|&=|
                                =>|->|<<|>>|<|>|=|!|~|
-                               &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+                               &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
+                               \?|:
                        }x;
                        my @elements = split(/($ops|;)/, $opline);
                        my $off = 0;
@@ -1505,22 +1771,11 @@ sub process {
                                my $ptr = substr($blank, 0, $off) . "^";
                                my $hereptr = "$hereline$ptr\n";
 
-                               # Classify operators into binary, unary, or
-                               # definitions (* only) where they have more
-                               # than one mode.
+                               # Pull out the value of this operator.
                                my $op_type = substr($curr_values, $off + 1, 1);
-                               my $op_left = substr($curr_values, $off, 1);
-                               my $is_unary;
-                               if ($op_type eq 'T') {
-                                       $is_unary = 2;
-                               } elsif ($op_left eq 'V') {
-                                       $is_unary = 0;
-                               } else {
-                                       $is_unary = 1;
-                               }
-                               #if ($op eq '-' || $op eq '&' || $op eq '*') {
-                               #       print "UNARY: <$op_left$op_type $is_unary $a:$op:$c> <$ca:$op:$cc> <$unary_ctx>\n";
-                               #}
+
+                               # Get the full operator variant.
+                               my $opv = $op . substr($curr_vars, $off, 1);
 
                                # Ignore operators passed as parameters.
                                if ($op_type ne 'V' &&
@@ -1539,8 +1794,10 @@ sub process {
                                # // is a comment
                                } elsif ($op eq '//') {
 
-                               # -> should have no spaces
-                               } elsif ($op eq '->') {
+                               # No spaces for:
+                               #   ->
+                               #   :   when part of a bitfield
+                               } elsif ($op eq '->' || $opv eq ':B') {
                                        if ($ctx =~ /Wx.|.xW/) {
                                                ERROR("spaces prohibited around that '$op' $at\n" . $hereptr);
                                        }
@@ -1552,18 +1809,19 @@ sub process {
                                        }
 
                                # '*' as part of a type definition -- reported already.
-                               } elsif ($op eq '*' && $is_unary == 2) {
+                               } 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 '~' ||
-                                        ($is_unary && ($op eq '*' || $op eq '-' || $op eq '&'))) {
+                                        $opv eq '*U' || $opv eq '-U' ||
+                                        $opv eq '&U' || $opv eq '&&U') {
                                        if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
                                                ERROR("space required before that '$op' $at\n" . $hereptr);
                                        }
-                                       if ($op  eq '*' && $cc =~/\s*const\b/) {
+                                       if ($op eq '*' && $cc =~/\s*const\b/) {
                                                # A unary '*' may be const
 
                                        } elsif ($ctx =~ /.xW/) {
@@ -1596,11 +1854,33 @@ sub process {
                                                        $hereptr);
                                        }
 
+                               # 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./) {
+                                               ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+                                       }
+
                                # All the others need spaces both sides.
                                } elsif ($ctx !~ /[EWC]x[CWE]/) {
+                                       my $ok = 0;
+
                                        # Ignore email addresses <foo@bar>
-                                       if (!($op eq '<' && $cb =~ /$;\S+\@\S+>/) &&
-                                           !($op eq '>' && $cb =~ /<\S+\@\S+$;/)) {
+                                       if (($op eq '<' &&
+                                            $cc =~ /^\S+\@\S+>/) ||
+                                           ($op eq '>' &&
+                                            $ca =~ /<\S+\@\S+$/))
+                                       {
+                                               $ok = 1;
+                                       }
+
+                                       # Ignore ?:
+                                       if (($opv eq ':O' && $ca =~ /\?$/) ||
+                                           ($op eq '?' && $cc =~ /^:/)) {
+                                               $ok = 1;
+                                       }
+
+                                       if ($ok == 0) {
                                                ERROR("spaces required around that '$op' $at\n" . $hereptr);
                                        }
                                }
@@ -1688,8 +1968,28 @@ sub process {
                        ERROR("space required before the open parenthesis '('\n" . $herecurr);
                }
 
-# Check for illegal assignment in if conditional.
-               if ($line =~ /\bif\s*\(/) {
+# Check for illegal assignment in if conditional -- and check for trailing
+# statements after the conditional.
+               if ($line =~ /do\s*(?!{)/) {
+                       my ($stat_next) = ctx_statement_block($line_nr_next,
+                                               $remain_next, $off_next);
+                       $stat_next =~ s/\n./\n /g;
+                       ##print "stat<$stat> stat_next<$stat_next>\n";
+
+                       if ($stat_next =~ /^\s*while\b/) {
+                               # If the statement carries leading newlines,
+                               # then count those as offsets.
+                               my ($whitespace) =
+                                       ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+                               my $offset =
+                                       statement_rawlines($whitespace) - 1;
+
+                               $suppress_whiletrailers{$line_nr_next +
+                                                               $offset} = 1;
+                       }
+               }
+               if (!defined $suppress_whiletrailers{$linenr} &&
+                   $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
                        my ($s, $c) = ($stat, $cond);
 
                        if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/) {
@@ -1701,10 +2001,19 @@ sub process {
                        substr($s, 0, length($c), '');
                        $s =~ s/\n.*//g;
                        $s =~ s/$;//g;  # Remove any comments
-                       if (length($c) && $s !~ /^\s*({|;|)\s*\\*\s*$/ &&
-                           $c !~ /^.\s*\#\s*if/)
+                       if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
+                           $c !~ /}\s*while\s*/)
                        {
-                               ERROR("trailing statements should be on next line\n" . $herecurr);
+                               # Find out how long the conditional actually is.
+                               my @newlines = ($c =~ /\n/gs);
+                               my $cond_lines = 1 + $#newlines;
+
+                               my $stat_real = raw_line($linenr, $cond_lines);
+                               if (defined($stat_real) && $cond_lines > 1) {
+                                       $stat_real = "[...]\n$stat_real";
+                               }
+
+                               ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real);
                        }
                }
 
@@ -1731,6 +2040,15 @@ sub process {
                                ERROR("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 should be on next line\n" . $herecurr);
+               }
 
                # Check for }<nl>else {, these must be at the same
                # indent level to be relevant to each other.
@@ -1767,19 +2085,25 @@ sub process {
 
 #warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
                if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
-                       my $checkfile = "include/linux/$1.h";
-                       if (-f "$root/$checkfile" && $realfile ne $checkfile &&
+                       my $file = "$1.h";
+                       my $checkfile = "include/linux/$file";
+                       if (-f "$root/$checkfile" &&
+                           $realfile ne $checkfile &&
                            $1 ne 'irq')
                        {
-                               WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
-                                       $herecurr);
+                               if ($realfile =~ m{^arch/}) {
+                                       CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+                               } else {
+                                       WARN("Use #include <linux/$file> instead of <asm/$file>\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 ($line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
+               if ($realfile !~ m@/vmlinux.lds.h$@ &&
+                   $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
                        my $ln = $linenr;
                        my $cnt = $realcnt;
                        my ($off, $dstat, $dcond, $rest);
@@ -1793,30 +2117,26 @@ sub process {
                                $lines[$ln - 1] =~ /^(?:-|..*\\$)/)
                        {
                                $ctx .= $rawlines[$ln - 1] . "\n";
+                               $cnt-- if ($lines[$ln - 1] !~ /^-/);
                                $ln++;
-                               $cnt--;
                        }
                        $ctx .= $rawlines[$ln - 1];
 
                        ($dstat, $dcond, $ln, $cnt, $off) =
                                ctx_statement_block($linenr, $ln - $linenr + 1, 0);
                        #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
-                       #print "LINE<$lines[$ln]> len<" . length($lines[$ln]) . "\n";
+                       #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
 
                        # Extract the remainder of the define (if any) and
                        # rip off surrounding spaces, and trailing \'s.
                        $rest = '';
-                       if (defined $lines[$ln - 1] &&
-                           $off > length($lines[$ln - 1]))
-                       {
+                       while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
+                               #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
+                               if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
+                                       $rest .= substr($lines[$ln - 1], $off) . "\n";
+                                       $cnt--;
+                               }
                                $ln++;
-                               $cnt--;
-                               $off = 0;
-                       }
-                       while ($cnt > 0) {
-                               $rest .= substr($lines[$ln - 1], $off) . "\n";
-                               $ln++;
-                               $cnt--;
                                $off = 0;
                        }
                        $rest =~ s/\\\n.//g;
@@ -1829,14 +2149,16 @@ sub process {
                        } else {
                                $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//;
                        }
+                       $dstat =~ s/$;//g;
                        $dstat =~ s/\\\n.//g;
                        $dstat =~ s/^\s*//s;
                        $dstat =~ s/\s*$//s;
 
                        # Flatten any parentheses and braces
-                       while ($dstat =~ s/\([^\(\)]*\)/1/) {
-                       }
-                       while ($dstat =~ s/\{[^\{\}]*\}/1/) {
+                       while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+                              $dstat =~ s/\{[^\{\}]*\}/1/ ||
+                              $dstat =~ s/\[[^\{\}]*\]/1/)
+                       {
                        }
 
                        my $exceptions = qr{
@@ -1847,6 +2169,7 @@ sub process {
                                DEFINE_PER_CPU|
                                __typeof__\(
                        }x;
+                       #print "REST<$rest>\n";
                        if ($rest ne '') {
                                if ($rest !~ /while\s*\(/ &&
                                    $dstat !~ /$exceptions/)
@@ -1858,6 +2181,7 @@ sub process {
                                if ($dstat ne '' &&
                                    $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
                                    $dstat !~ /$exceptions/ &&
+                                   $dstat !~ /^\.$Ident\s*=/ &&
                                    $dstat =~ /$Operators/)
                                {
                                        ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
@@ -1958,10 +2282,10 @@ sub process {
                        }
                        if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
                                my $herectx = $here . "\n";;
-                               my $end = $linenr + statement_rawlines($block) - 1;
+                               my $cnt = statement_rawlines($block);
 
-                               for (my $ln = $linenr - 1; $ln < $end; $ln++) {
-                                       $herectx .= $rawlines[$ln] . "\n";;
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";;
                                }
 
                                WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
@@ -2003,7 +2327,14 @@ sub process {
                if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
                        my $expr = $1;
                        if ($line =~ /\bkfree\(\Q$expr\E\);/) {
-                               WARN("kfree(NULL) is safe this check is probabally not required\n" . $hereprev);
+                               WARN("kfree(NULL) is safe this check is probably not required\n" . $hereprev);
+                       }
+               }
+# check for needless usb_free_urb() checks
+               if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+                       my $expr = $1;
+                       if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) {
+                               WARN("usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev);
                        }
                }
 
@@ -2129,6 +2460,7 @@ sub process {
                my $string;
                while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
                        $string = substr($rawline, $-[1], $+[1] - $-[1]);
+                       $string =~ s/%%/__/g;
                        if ($string =~ /(?<!%)%L[udi]/) {
                                WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
                                last;