qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] Update QEMU checkpatch.pl to current linux version


From: Mike Day
Subject: [Qemu-devel] [PATCH] Update QEMU checkpatch.pl to current linux version
Date: Tue, 6 May 2014 14:16:37 -0400

This updates scripts/checkpatch.pl to version 0.32. Also,
forward-ported the QEMU checks for no tabs and correct capitalization
of "QEMU." Finally, make --no-tree the default option since this will
be used with Qemu.

Signed-off-by: Mike Day <address@hidden>
---

Notes: This is a huge patch and I needed to include white space
changes to get it applying cleanly.

I've tested this so far with some random patches off the mailing list
and some others that I've got around. I also tested for some intentional
errors.

 scripts/checkpatch.pl | 2544 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 2120 insertions(+), 424 deletions(-)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 9d46e5a..b5587f7 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -6,16 +6,17 @@
 # Licensed under the terms of the GNU GPL License version 2
 
 use strict;
+use POSIX;
 
 my $P = $0;
 $P =~ address@hidden/@@g;
 
-my $V = '0.31';
+my $V = '0.32';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
 my $quiet = 0;
-my $tree = 1;
+my $tree = 0;
 my $chk_signoff = 1;
 my $chk_patch = 1;
 my $tst_only;
@@ -26,9 +27,21 @@ my $check = 0;
 my $summary = 1;
 my $mailback = 0;
 my $summary_file = 0;
+my $show_types = 0;
+my $fix = 0;
+my $fix_inplace = 0;
 my $root;
 my %debug;
+my %camelcase = ();
+my %use_type = ();
+my @use = ();
+my %ignore_type = ();
+my @ignore = ();
 my $help = 0;
+my $configuration_file = ".checkpatch.conf";
+my $max_line_length = 80;
+my $ignore_perl_version = 0;
+my $minimum_perl_version = 5.10.0;
 
 sub help {
        my ($exitcode) = @_;
@@ -46,6 +59,10 @@ Options:
   --terse                    one line per report
   -f, --file                 treat FILE as regular source file
   --subjective, --strict     enable more subjective tests
+  --types TYPE(,TYPE2...)    show only these comma separated message types
+  --ignore TYPE(,TYPE2...)   ignore various comma separated message types
+  --max-line-length=n        set the maximum line length, if exceeded, warn
+  --show-types               show the message "types" in the output
   --root=PATH                PATH to the kernel tree root
   --no-summary               suppress the per-file summary
   --mailback                 only produce a report in case of warnings/errors
@@ -55,6 +72,16 @@ Options:
                              is all off)
   --test-only=WORD           report only warnings/errors containing WORD
                              literally
+  --fix                      EXPERIMENTAL - may create horrible results
+                             If correctable single-line errors exist, create
+                             "<inputfile>.EXPERIMENTAL-checkpatch-fixes"
+                             with potential errors corrected to the preferred
+                             checkpatch style
+  --fix-inplace              EXPERIMENTAL - may create horrible results
+                             Is the same as --fix, but overwrites the input
+                             file.  It's your fault if there's no backup or git
+  --ignore-perl-version      override checking of perl version.  expect
+                             runtime errors.
   -h, --help, --version      display this help and exit
 
 When FILE is - read standard input.
@@ -63,6 +90,32 @@ EOM
        exit($exitcode);
 }
 
+my $conf = which_conf($configuration_file);
+if (-f $conf) {
+       my @conf_args;
+       open(my $conffile, '<', "$conf")
+           or warn "$P: Can't find a readable $configuration_file file $!\n";
+
+       while (<$conffile>) {
+               my $line = $_;
+
+               $line =~ s/\s*\n?$//g;
+               $line =~ s/^\s*//g;
+               $line =~ s/\s+/ /g;
+
+               next if ($line =~ m/^\s*#/);
+               next if ($line =~ m/^\s*$/);
+
+               my @words = split(" ", $line);
+               foreach my $word (@words) {
+                       last if ($word =~ m/^#/);
+                       push (@conf_args, $word);
+               }
+       }
+       close($conffile);
+       unshift(@ARGV, @conf_args) if @conf_args;
+}
+
 GetOptions(
        'q|quiet+'      => \$quiet,
        'tree!'         => \$tree,
@@ -73,11 +126,17 @@ GetOptions(
        'f|file!'       => \$file,
        'subjective!'   => \$check,
        'strict!'       => \$check,
+       'ignore=s'      => address@hidden,
+       'types=s'       => address@hidden,
+       'show-types!'   => \$show_types,
+       'max-line-length=i' => \$max_line_length,
        'root=s'        => \$root,
        'summary!'      => \$summary,
        'mailback!'     => \$mailback,
        'summary-file!' => \$summary_file,
-
+       'fix!'          => \$fix,
+       'fix-inplace!'  => \$fix_inplace,
+       'ignore-perl-version!' => \$ignore_perl_version,
        'debug=s'       => \%debug,
        'test-only=s'   => \$tst_only,
        'h|help'        => \$help,
@@ -86,28 +145,64 @@ GetOptions(
 
 help(0) if ($help);
 
+$fix = 1 if ($fix_inplace);
+
 my $exit = 0;
 
+if ($^V && $^V lt $minimum_perl_version) {
+       printf "$P: requires at least perl version %vd\n", 
$minimum_perl_version;
+       if (!$ignore_perl_version) {
+               exit(1);
+       }
+}
+
 if ($#ARGV < 0) {
        print "$P: no input files\n";
        exit(1);
 }
 
+sub hash_save_array_words {
+       my ($hashRef, $arrayRef) = @_;
+
+       my @array = split(/,/, join(',', @$arrayRef));
+       foreach my $word (@array) {
+               $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*$/);
+
+               $hashRef->{$word}++;
+       }
+}
+
+sub hash_show_words {
+       my ($hashRef, $prefix) = @_;
+
+       if ($quiet == 0 && keys %$hashRef) {
+               print "NOTE: $prefix message types:";
+               foreach my $word (sort keys %$hashRef) {
+                       print " $word";
+               }
+               print "\n\n";
+       }
+}
+
+hash_save_array_words(\%ignore_type, address@hidden);
+hash_save_array_words(\%use_type, address@hidden);
+
 my $dbg_values = 0;
 my $dbg_possible = 0;
 my $dbg_type = 0;
 my $dbg_attr = 0;
-my $dbg_adv_dcs = 0;
-my $dbg_adv_checking = 0;
-my $dbg_adv_apw = 0;
 for my $key (keys %debug) {
        ## no critic
        eval "\${dbg_$key} = '$debug{$key}';";
        die "$@" if ($@);
 }
 
-my $rpt_cleaners = 0;
-
 if ($terse) {
        $emacs = 1;
        $quiet++;
@@ -148,8 +243,14 @@ our $Sparse        = qr{
                        __must_check|
                        __init_refok|
                        __kprobes|
-                       __ref
+                       __ref|
+                       __rcu
                }x;
+our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)};
+our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)};
+our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)};
+our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)};
+our $InitAttribute = 
qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit};
 
 # Notes to $Attribute:
 # We need \b after 'init' otherwise 'initconst' will cause a false positive in 
a check
@@ -171,33 +272,45 @@ our $Attribute    = qr{
                        __deprecated|
                        __read_mostly|
                        __kprobes|
-                       __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+                       $InitAttribute|
                        ____cacheline_aligned|
                        ____cacheline_aligned_in_smp|
                        ____cacheline_internodealigned_in_smp|
                        __weak
                  }x;
 our $Modifier;
-our $Inline    = qr{inline|__always_inline|noinline};
+our $Inline    = qr{inline|__always_inline|noinline|__inline|__inline__};
 our $Member    = qr{->$Ident|\.$Ident|\[[^]]*\]};
 our $Lval      = qr{$Ident(?:$Member)*};
 
-our $Constant  = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};
-our $Assignment        = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
-our $Compare    = qr{<=|>=|==|!=|<|>};
+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 $Octal     = qr{0[0-7]+$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|$Octal|$Hex|$Int};
+our $Assignment        = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
+our $Compare    = qr{<=|>=|==|!=|<|(?<!-)>};
+our $Arithmetic = qr{\+|-|\*|\/|%};
 our $Operators = qr{
                        <=|>=|==|!=|
                        =>|->|<<|>>|<|>|!|~|
-                       &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+                       &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic
                  }x;
 
+our $c90_Keywords = 
qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x;
+
 our $NonptrType;
+our $NonptrTypeWithAttr;
 our $Type;
 our $Declare;
 
-our $UTF8      = qr {
-       [\x09\x0A\x0D\x20-\x7E]              # ASCII
-       | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
+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
@@ -206,17 +319,34 @@ our $UTF8 = qr {
        |  \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|
-       pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)|
-       
(dev|netdev|netif)_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)|
-       WARN|
-       panic
+       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_]+|
+       seq_vprintf|seq_printf|seq_puts
+)};
+
+our $signature_tags = qr{(?xi:
+       Signed-off-by:|
+       Acked-by:|
+       Tested-by:|
+       Reviewed-by:|
+       Reported-by:|
+       Suggested-by:|
+       To:|
+       Cc:
 )};
 
 our @typeList = (
@@ -239,10 +369,32 @@ our @typeList = (
        qr{${Ident}_handler},
        qr{${Ident}_handler_fn},
 );
+our @typeListWithAttr = (
+       @typeList,
+       qr{struct\s+$InitAttribute\s+$Ident},
+       qr{union\s+$InitAttribute\s+$Ident},
+);
+
 our @modifierList = (
        qr{fastcall},
 );
 
+our @mode_permission_funcs = (
+       ["module_param", 3],
+       ["module_param_(?:array|named|string)", 4],
+       ["module_param_array_named", 5],
+       
["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)",
 2],
+       ["proc_create(?:_data|)", 2],
+       ["(?:CLASS|DEVICE|SENSOR)_ATTR", 2],
+);
+
+#Create a search pattern for all these functions to speed up a loop below
+our $mode_perms_search = "";
+foreach my $entry (@mode_permission_funcs) {
+       $mode_perms_search .= '|' if ($mode_perms_search ne "");
+       $mode_perms_search .= $entry->[0];
+}
+
 our $allowed_asm_includes = qr{(?x:
        irq|
        memory
@@ -252,50 +404,148 @@ our $allowed_asm_includes = qr{(?x:
 sub build_types {
        my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
        my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
+       my $allWithAttr = "(?x:  \n" . join("|\n  ", @typeListWithAttr) . "\n)";
        $Modifier       = qr{(?:$Attribute|$Sparse|$mods)};
        $NonptrType     = qr{
                        (?:$Modifier\s+|const\s+)*
                        (?:
-                               (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+                               (?:typeof|__typeof__)\s*\([^\)]*\)|
                                (?:$typeTypedefs\b)|
                                (?:${all}\b)
                        )
                        (?:\s+$Modifier|\s+const)*
                  }x;
+       $NonptrTypeWithAttr     = qr{
+                       (?:$Modifier\s+|const\s+)*
+                       (?:
+                               (?:typeof|__typeof__)\s*\([^\)]*\)|
+                               (?:$typeTypedefs\b)|
+                               (?:${allWithAttr}\b)
+                       )
+                       (?:\s+$Modifier|\s+const)*
+                 }x;
        $Type   = qr{
                        $NonptrType
-                       (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)?
+                       
(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
                        (?:\s+$Inline|\s+$Modifier)*
                  }x;
-       $Declare        = qr{(?:$Storage\s+)?$Type};
+       $Declare        = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type};
 }
 build_types();
 
-$chk_signoff = 0 if ($file);
+our $Typecast  = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
 
-my @dep_includes = ();
-my @dep_functions = ();
-my $removal = "Documentation/feature-removal-schedule.txt";
-if ($tree && -f "$root/$removal") {
-       open(my $REMOVE, '<', "$root/$removal") ||
-                               die "$P: $removal: open failed - $!\n";
-       while (<$REMOVE>) {
-               if (/^Check:\s+(.*\S)/) {
-                       for my $entry (split(/[, ]+/, $1)) {
-                               if ($entry =~ address@hidden/(.*)@) {
-                                       push(@dep_includes, $1);
-
-                               } elsif ($entry !~ m@/@) {
-                                       push(@dep_functions, $entry);
-                               }
-                       }
+# 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{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*};
+our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
+
+sub deparenthesize {
+       my ($string) = @_;
+       return "" if (!defined($string));
+
+       while ($string =~ /^\s*\(.*\)\s*$/) {
+               $string =~ address@hidden(\s*@@;
+               $string =~ address@hidden)\s*$@@;
+       }
+
+       $string =~ address@hidden@ @g;
+
+       return $string;
+}
+
+sub seed_camelcase_file {
+       my ($file) = @_;
+
+       return if (!(-f $file));
+
+       local $/;
+
+       open(my $include_file, '<', "$file")
+           or warn "$P: Can't read '$file' $!\n";
+       my $text = <$include_file>;
+       close($include_file);
+
+       my @lines = split('\n', $text);
+
+       foreach my $line (@lines) {
+               next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/);
+               if ($line =~ /^[ \t]*(?:#[ 
\t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) {
+                       $camelcase{$1} = 1;
+               } elsif ($line =~ 
/^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) {
+                       $camelcase{$1} = 1;
+               } elsif ($line =~ 
/^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) {
+                       $camelcase{$1} = 1;
+               }
+       }
+}
+
+my $camelcase_seeded = 0;
+sub seed_camelcase_includes {
+       return if ($camelcase_seeded);
+
+       my $files;
+       my $camelcase_cache = "";
+       my @include_files = ();
+
+       $camelcase_seeded = 1;
+
+       if (-e ".git") {
+               my $git_last_include_commit = `git log --no-merges 
--pretty=format:"%h%n" -1 -- include`;
+               chomp $git_last_include_commit;
+               $camelcase_cache = 
".checkpatch-camelcase.git.$git_last_include_commit";
+       } else {
+               my $last_mod_date = 0;
+               $files = `find $root/include -name "*.h"`;
+               @include_files = split('\n', $files);
+               foreach my $file (@include_files) {
+                       my $date = POSIX::strftime("%Y%m%d%H%M",
+                                                  localtime((stat $file)[9]));
+                       $last_mod_date = $date if ($last_mod_date < $date);
+               }
+               $camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date";
+       }
+
+       if ($camelcase_cache ne "" && -f $camelcase_cache) {
+               open(my $camelcase_file, '<', "$camelcase_cache")
+                   or warn "$P: Can't read '$camelcase_cache' $!\n";
+               while (<$camelcase_file>) {
+                       chomp;
+                       $camelcase{$_} = 1;
+               }
+               close($camelcase_file);
+
+               return;
+       }
+
+       if (-e ".git") {
+               $files = `git ls-files "include/*.h"`;
+               @include_files = split('\n', $files);
+       }
+
+       foreach my $file (@include_files) {
+               seed_camelcase_file($file);
+       }
+
+       if ($camelcase_cache ne "") {
+               unlink glob ".checkpatch-camelcase.*";
+               open(my $camelcase_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);
        }
-       close($REMOVE);
 }
 
+$chk_signoff = 0 if ($file);
+
 my @rawlines = ();
 my @lines = ();
+my @fixed = ();
 my $vname;
 for my $filename (@ARGV) {
        my $FILE;
@@ -323,6 +573,7 @@ for my $filename (@ARGV) {
        }
        @rawlines = ();
        @lines = ();
+       @fixed = ();
 }
 
 exit($exit);
@@ -331,9 +582,9 @@ sub top_of_kernel_tree {
        my ($root) = @_;
 
        my @tree_check = (
-               "COPYING", "MAINTAINERS", "Makefile",
-               "README", "docs", "VERSION",
-               "vl.c"
+               "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile",
+               "README", "Documentation", "arch", "include", "drivers",
+               "fs", "init", "ipc", "kernel", "lib", "scripts",
        );
 
        foreach my $check (@tree_check) {
@@ -344,6 +595,88 @@ sub top_of_kernel_tree {
        return 1;
 }
 
+sub parse_email {
+       my ($formatted_email) = @_;
+
+       my $name = "";
+       my $address = "";
+       my $comment = "";
+
+       if ($formatted_email =~ /^(.*)<(address@hidden)>(.*)$/) {
+               $name = $1;
+               $address = $2;
+               $comment = $3 if defined $3;
+       } elsif ($formatted_email =~ /^\s*<(address@hidden)>(.*)$/) {
+               $address = $1;
+               $comment = $2 if defined $2;
+       } elsif ($formatted_email =~ /(address@hidden)(.*)$/) {
+               $address = $1;
+               $comment = $2 if defined $2;
+               $formatted_email =~ s/$address.*$//;
+               $name = $formatted_email;
+               $name = trim($name);
+               $name =~ s/^\"|\"$//g;
+               # If there's a name left after stripping spaces and
+               # leading quotes, and the address doesn't have both
+               # leading and trailing angle brackets, the address
+               # is invalid. ie:
+               #   "joe smith address@hidden" bad
+               #   "joe smith <address@hidden" bad
+               if ($name ne "" && $address !~ /^<[^>]+>$/) {
+                       $name = "";
+                       $address = "";
+                       $comment = "";
+               }
+       }
+
+       $name = trim($name);
+       $name =~ s/^\"|\"$//g;
+       $address = trim($address);
+       $address =~ s/^\<|\>$//g;
+
+       if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
+               $name =~ s/(?<!\\)"/\\"/g; ##escape quotes
+               $name = "\"$name\"";
+       }
+
+       return ($name, $address, $comment);
+}
+
+sub format_email {
+       my ($name, $address) = @_;
+
+       my $formatted_email;
+
+       $name = trim($name);
+       $name =~ s/^\"|\"$//g;
+       $address = trim($address);
+
+       if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
+               $name =~ s/(?<!\\)"/\\"/g; ##escape quotes
+               $name = "\"$name\"";
+       }
+
+       if ("$name" eq "") {
+               $formatted_email = "$address";
+       } else {
+               $formatted_email = "$name <$address>";
+       }
+
+       return $formatted_email;
+}
+
+sub which_conf {
+       my ($conf) = @_;
+
+       foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+               if (-e "$path/$conf") {
+                       return "$path/$conf";
+               }
+       }
+
+       return "";
+}
+
 sub expand_tabs {
        my ($str) = @_;
 
@@ -481,6 +814,13 @@ sub sanitise_line {
        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;
@@ -521,6 +861,10 @@ sub ctx_statement_block {
                        if ($off >= $len) {
                                last;
                        }
+                       if ($level == 0 && substr($blk, $off) =~ 
/^.\s*#\s*define/) {
+                               $level++;
+                               $type = '#';
+                       }
                }
                $p = $c;
                $c = substr($blk, $off, 1);
@@ -583,6 +927,13 @@ sub ctx_statement_block {
                                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.
@@ -865,7 +1216,7 @@ sub annotate_values {
                } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') {
                        print "CAST($1)\n" if ($dbg_values > 1);
                        push(@av_paren_type, $type);
-                       $type = 'C';
+                       $type = 'c';
 
                } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
                        print "DECLARE($1)\n" if ($dbg_values > 1);
@@ -1057,7 +1408,9 @@ sub possible {
                        case|
                        else|
                        asm|__asm__|
-                       do
+                       do|
+                       \#|
+                       \#\#|
                )(?:\s|$)|
                ^(?:typedef|struct|enum)\b
            )}x;
@@ -1089,38 +1442,67 @@ sub possible {
 
 my $prefix = '';
 
+sub show_type {
+       my ($type) = @_;
+
+       return defined $use_type{$type} if (scalar keys %use_type > 0);
+
+       return !defined $ignore_type{$type};
+}
+
 sub report {
-       if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+       my ($level, $type, $msg) = @_;
+
+       if (!show_type($type) ||
+           (defined $tst_only && $msg !~ /\Q$tst_only\E/)) {
                return 0;
        }
-       my $line = $prefix . $_[0];
-
+       my $line;
+       if ($show_types) {
+               $line = "$prefix$level:$type: $msg\n";
+       } else {
+               $line = "$prefix$level: $msg\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]\n")) {
+       my ($type, $msg) = @_;
+
+       if (report("ERROR", $type, $msg)) {
                our $clean = 0;
                our $cnt_error++;
+               return 1;
        }
+       return 0;
 }
 sub WARN {
-       if (report("WARNING: $_[0]\n")) {
+       my ($type, $msg) = @_;
+
+       if (report("WARNING", $type, $msg)) {
                our $clean = 0;
                our $cnt_warn++;
+               return 1;
        }
+       return 0;
 }
 sub CHK {
-       if ($check && report("CHECK: $_[0]\n")) {
+       my ($type, $msg) = @_;
+
+       if ($check && report("CHECK", $type, $msg)) {
                our $clean = 0;
                our $cnt_chk++;
+               return 1;
        }
+       return 0;
 }
 
 sub check_absolute_file {
@@ -1146,8 +1528,86 @@ sub check_absolute_file {
 
        ##print "prefix<$prefix>\n";
        if ($prefix ne ".../") {
-               WARN("use relative pathname instead of absolute in changelog 
text\n" . $herecurr);
+               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 ltrim {
+       my ($string) = @_;
+
+       $string =~ s/^\s+//;
+
+       return $string;
+}
+
+sub rtrim {
+       my ($string) = @_;
+
+       $string =~ s/\s+$//;
+
+       return $string;
+}
+
+sub string_find_replace {
+       my ($string, $find, $replace) = @_;
+
+       $string =~ s/$find/$replace/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 =~ address@hidden([\t]*)address@hidden@g;
+       #Remove spaces before a tab
+       1 while $leading =~ address@hidden([\t]*)( 
{1,$max_spaces_before_tab})address@hidden@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 length(expand_tabs(substr($line, 0, $last_openparen))) + 1;
 }
 
 sub process {
@@ -1168,6 +1628,11 @@ sub process {
        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;
@@ -1190,6 +1655,9 @@ sub process {
        my %suppress_ifbraces;
        my %suppress_whiletrailers;
        my %suppress_export;
+       my $suppress_statement = 0;
+
+       my %signatures = ();
 
        # Pre-scan the patch sanitizing the lines.
        # Pre-scan the patch looking for any __setup documentation.
@@ -1197,12 +1665,16 @@ sub process {
        my @setup_docs = ();
        my $setup_docs = 0;
 
+       my $camelcase_file_seeded = 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 =~ address@hidden/kernel-parameters.txt$@) {
@@ -1280,6 +1752,8 @@ sub process {
        $linenr = 0;
        foreach my $line (@lines) {
                $linenr++;
+               my $sline = $line;      #copy of $line
+               $sline =~ s/$;/ /g;     #with comments as spaces
 
                my $rawline = $rawlines[$linenr - 1];
 
@@ -1299,6 +1773,7 @@ sub process {
                        %suppress_ifbraces = ();
                        %suppress_whiletrailers = ();
                        %suppress_export = ();
+                       $suppress_statement = 0;
                        next;
 
 # track the line number as we move through the hunk, note that
@@ -1334,20 +1809,23 @@ sub process {
                # extract the filename as it passes
                if ($line =~ /^diff --git.*?(\S+)$/) {
                        $realfile = $1;
-                       $realfile =~ address@hidden([^/]*)/@@;
-
+                       $realfile =~ address@hidden([^/]*)/@@ if (!$file);
+                       $in_commit_log = 0;
                } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
                        $realfile = $1;
-                       $realfile =~ address@hidden([^/]*)/@@;
+                       $realfile =~ address@hidden([^/]*)/@@ if (!$file);
+                       $in_commit_log = 0;
 
                        $p1_prefix = $1;
                        if (!$file && $tree && $p1_prefix ne '' &&
                            -e "$root/$p1_prefix") {
-                               WARN("patch prefix '$p1_prefix' exists, appears 
to be a -p0 patch\n");
+                               WARN("PATCH_PREFIX",
+                                    "patch prefix '$p1_prefix' exists, appears 
to be a -p0 patch\n");
                        }
 
                        if ($realfile =~ address@hidden/asm/@) {
-                               ERROR("do not modify files in include/asm, 
change architecture specific files in include/asm-<architecture>\n" . 
"$here$rawline\n");
+                               ERROR("MODIFIED_INCLUDE_ASM",
+                                     "do not modify files in include/asm, 
change architecture specific files in include/asm-<architecture>\n" . 
"$here$rawline\n");
                        }
                        next;
                }
@@ -1363,28 +1841,99 @@ sub process {
 # Check for incorrect file permissions
                if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
                        my $permhere = $here . "FILE: $realfile\n";
-                       if ($realfile =~ 
/(Makefile|Kconfig|\.c|\.cpp|\.h|\.S|\.tmpl)$/) {
-                               ERROR("do not set execute permissions for 
source files\n" . $permhere);
+                       if ($realfile !~ address@hidden/@ &&
+                           $realfile !~ /\.(py|pl|awk|sh)$/) {
+                               ERROR("EXECUTE_PERMISSIONS",
+                                     "do not set execute permissions for 
source files\n" . $permhere);
                        }
                }
 
-#check the patch for a signoff:
+# Check the patch for a signoff:
                if ($line =~ /^\s*signed-off-by:/i) {
-                       # This is a signoff, if ugly, so do not double report.
                        $signoff++;
-                       if (!($line =~ /^\s*Signed-off-by:/)) {
-                               WARN("Signed-off-by: is the preferred form\n" .
-                                       $herecurr);
+                       $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 ($line =~ /^\s*signed-off-by:\S/i) {
-                               WARN("space required after Signed-off-by:\n" .
-                                       $herecurr);
+                       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/" </ </;
+                               # Don't force email to have quotes
+                               # Allow just an angle bracketed address
+                               if ("$dequoted$comment" ne $email &&
+                                   "<$email_address>$comment" ne $email &&
+                                   "$suggested_email$comment" ne $email) {
+                                       WARN("BAD_SIGN_OFF",
+                                            "email address '$email' might be 
better as '$suggested_email$comment'\n" . $herecurr);
+                               }
                        }
+
+# Check for duplicate signatures
+                       my $sig_nospace = $line;
+                       $sig_nospace =~ s/\s//g;
+                       $sig_nospace = lc($sig_nospace);
+                       if (defined $signatures{$sig_nospace}) {
+                               WARN("BAD_SIGN_OFF",
+                                    "Duplicate signature\n" . $herecurr);
+                       } else {
+                               $signatures{$sig_nospace} = 1;
+                       }
+               }
+
+# Check for unwanted Gerrit info
+               if ($in_commit_log && $line =~ /^\s*change-id:/i) {
+                       ERROR("GERRIT_CHANGE_ID",
+                             "Remove Gerrit Change-Id's before submitting 
upstream.\n" . $herecurr);
                }
 
 # Check for wrappage within a valid hunk of the file
                if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
-                       ERROR("patch seems to be corrupt (line wrapped?)\n" .
+                       ERROR("CORRUPTED_PATCH",
+                             "patch seems to be corrupt (line wrapped?)\n" .
                                $herecurr) if (!$emitted_corrupt++);
                }
 
@@ -1411,7 +1960,30 @@ sub process {
                        my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
                        my $hereptr = "$hereline$ptr\n";
 
-                       ERROR("Invalid UTF-8, patch and commit message should 
be encoded in UTF-8\n" . $hereptr);
+                       CHK("INVALID_UTF8",
+                           "Invalid UTF-8, patch and commit message should be 
encoded in UTF-8\n" . $hereptr);
+               }
+
+# Check if it's the start of a commit log
+# (not a header line and we haven't seen the patch filename)
+               if ($in_header_lines && $realfile =~ /^$/ &&
+                   $rawline !~ /^(commit\b|from\b|[\w-]+:).+$/i) {
+                       $in_header_lines = 0;
+                       $in_commit_log = 1;
+               }
+
+# Check if there is UTF-8 in a commit log when a mail header has explicitly
+# declined it, i.e defined some charset where it is missing.
+               if ($in_header_lines &&
+                   $rawline =~ /^Content-Type:.+charset="(.+)".*$/ &&
+                   $1 !~ /utf-8/i) {
+                       $non_utf8_charset = 1;
+               }
+
+               if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ &&
+                   $rawline =~ /$NON_ASCII_UTF8/) {
+                       WARN("UTF8_BEFORE_PATCH",
+                           "8-bit UTF-8 used in possible commit log\n" . 
$herecurr);
                }
 
 # ignore non-hunk lines and lines being removed
@@ -1420,31 +1992,55 @@ sub process {
 #trailing whitespace
                if ($line =~ /^\+.*\015/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       ERROR("DOS line endings\n" . $herevet);
-
+                       if (ERROR("DOS_LINE_ENDINGS",
+                                 "DOS line endings\n" . $herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/[\s\015]+$//;
+                       }
                } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       ERROR("trailing whitespace\n" . $herevet);
-                       $rpt_cleaners = 1;
+                       if (ERROR("TRAILING_WHITESPACE",
+                                 "trailing whitespace\n" . $herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\s+$//;
+                       }
+               }
+
+# Check for FSF mailing addresses.
+               if ($rawline =~ /\bwrite to the Free/i ||
+                   $rawline =~ /\b59\s+Temple\s+Pl/i ||
+                   $rawline =~ /\b51\s+Franklin\s+St/i) {
+                       my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+                       my $msg_type = \&ERROR;
+                       $msg_type = \&CHK if ($file);
+                       &{$msg_type}("FSF_MAILING_ADDRESS",
+                                    "Do not include the paragraph about 
writing to the Free Software Foundation's mailing address from the sample GPL 
notice. The FSF has changed addresses in the past, and may do so again. Linux 
already includes a copy of the GPL.\n" . $herevet)
                }
 
 # check for Kconfig help text having a real description
 # Only applies when adding the entry originally, after that we do not have
 # sufficient context to determine whether it is indeed long enough.
                if ($realfile =~ /Kconfig/ &&
-                   $line =~ /\+\s*(?:---)?help(?:---)?$/) {
+                   $line =~ /.\s*config\s+/) {
                        my $length = 0;
                        my $cnt = $realcnt;
                        my $ln = $linenr + 1;
                        my $f;
+                       my $is_start = 0;
                        my $is_end = 0;
-                       while ($cnt > 0 && defined $lines[$ln - 1]) {
+                       for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) {
                                $f = $lines[$ln - 1];
                                $cnt-- if ($lines[$ln - 1] !~ /^-/);
                                $is_end = $lines[$ln - 1] =~ /^\+/;
-                               $ln++;
 
                                next if ($f =~ /^-/);
+
+                               if ($lines[$ln - 1] =~ 
/.\s*(?:bool|tristate)\s*\"/) {
+                                       $is_start = 1;
+                               } elsif ($lines[$ln - 1] =~ 
/.\s*(?:---)?help(?:---)?$/) {
+                                       $length = -1;
+                               }
+
                                $f =~ s/^.//;
                                $f =~ s/#.*//;
                                $f =~ s/^\s+//;
@@ -1455,82 +2051,275 @@ sub process {
                                }
                                $length++;
                        }
-                       WARN("please write a paragraph that describes the 
config symbol fully\n" . $herecurr) if ($is_end && $length < 4);
-                       #print "is_end<$is_end> length<$length>\n";
+                       WARN("CONFIG_DESCRIPTION",
+                            "please write a paragraph that describes the 
config symbol fully\n" . $herecurr) if ($is_start && $is_end && $length < 4);
+                       #print "is_start<$is_start> is_end<$is_end> 
length<$length>\n";
+               }
+
+# discourage the addition of CONFIG_EXPERIMENTAL in Kconfig.
+               if ($realfile =~ /Kconfig/ &&
+                   $line =~ /.\s*depends on\s+.*\bEXPERIMENTAL\b/) {
+                       WARN("CONFIG_EXPERIMENTAL",
+                            "Use of CONFIG_EXPERIMENTAL is deprecated. For 
alternatives, see https://lkml.org/lkml/2012/10/23/580\n";);
+               }
+
+               if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) &&
+                   ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) {
+                       my $flag = $1;
+                       my $replacement = {
+                               'EXTRA_AFLAGS' =>   'asflags-y',
+                               'EXTRA_CFLAGS' =>   'ccflags-y',
+                               'EXTRA_CPPFLAGS' => 'cppflags-y',
+                               'EXTRA_LDFLAGS' =>  'ldflags-y',
+                       };
+
+                       WARN("DEPRECATED_VARIABLE",
+                            "Use of $flag is deprecated, please use 
\`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag});
+               }
+
+# check for DT compatible documentation
+               if (defined $root &&
+                       (($realfile =~ /\.dtsi?$/ && $line =~ 
/^\+\s*compatible\s*=\s*\"/) ||
+                        ($realfile =~ /\.[ch]$/ && $line =~ 
/^\+.*\.compatible\s*=\s*\"/))) {
+
+                       my @compats = $rawline =~ 
/\"([a-zA-Z0-9\-\,\.\+_]+)\"/g;
+
+                       my $dt_path = $root . 
"/Documentation/devicetree/bindings/";
+                       my $vp_file = $dt_path . "vendor-prefixes.txt";
+
+                       foreach my $compat (@compats) {
+                               my $compat2 = $compat;
+                               $compat2 =~ s/\,[a-z]*\-/\,<\.\*>\-/;
+                               `grep -Erq "$compat|$compat2" $dt_path`;
+                               if ( $? >> 8 ) {
+                                       WARN("UNDOCUMENTED_DT_STRING",
+                                            "DT compatible string \"$compat\" 
appears un-documented -- check $dt_path\n" . $herecurr);
+                               }
+
+                               next if $compat !~ /^([a-zA-Z0-9\-]+)\,/;
+                               my $vendor = $1;
+                               `grep -Eq "^$vendor\\b" $vp_file`;
+                               if ( $? >> 8 ) {
+                                       WARN("UNDOCUMENTED_DT_STRING",
+                                            "DT compatible string vendor 
\"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr);
+                               }
+                       }
                }
 
 # check we are in a valid source file if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|cpp|s|S|pl|sh)$/);
+               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
 
-#80 column limit
+#line length limit
                if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
                    $rawline !~ /address@hidden/ &&
-                   !($line =~ 
/^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:,|\)\s*;)\s*$/
 ||
+                   !($line =~ 
/^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/
 ||
                    $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
-                   $length > 80)
+                   $length > $max_line_length)
                {
-                       WARN("line over 80 characters\n" . $herecurr);
+                       WARN("LONG_LINE",
+                            "line over $max_line_length characters\n" . 
$herecurr);
+               }
+
+# Check for user-visible strings broken across lines, which breaks the ability
+# to grep for the string.  Make exceptions when the previous string ends in a
+# newline (multiple lines in one string constant) or '\t', '\r', ';', or '{'
+# (common in inline assembly) or is a octal \123 or hexadecimal \xaf value
+               if ($line =~ /^\+\s*"/ &&
+                   $prevline =~ /"\s*$/ &&
+                   $prevrawline !~ 
/(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) {
+                       WARN("SPLIT_STRING",
+                            "quoted string split across lines\n" . $hereprev);
                }
 
 # check for spaces before a quoted newline
                if ($rawline =~ /^.*\".*\s\\n/) {
-                       WARN("unnecessary whitespace before a quoted newline\n" 
. $herecurr);
+                       if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
+                                "unnecessary whitespace before a quoted 
newline\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/^(\+.*\".*)\s+\\n/$1\\n/;
+                       }
+
                }
 
 # check for adding lines without a newline.
                if ($line =~ /^\+/ && defined $lines[$linenr] && 
$lines[$linenr] =~ /^\\ No newline at end of file/) {
-                       WARN("adding a line without newline at end of file\n" . 
$herecurr);
+                       WARN("MISSING_EOF_NEWLINE",
+                            "adding a line without newline at end of file\n" . 
$herecurr);
                }
 
 # Blackfin: use hi/lo macros
                if ($realfile =~ address@hidden/blackfin/.*\.S$@) {
                        if ($line =~ 
/\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
                                my $herevet = "$here\n" . cat_vet($line) . "\n";
-                               ERROR("use the LO() macro, not (... & 
0xFFFF)\n" . $herevet);
+                               ERROR("LO_MACRO",
+                                     "use the LO() macro, not (... & 
0xFFFF)\n" . $herevet);
                        }
                        if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
                                my $herevet = "$here\n" . cat_vet($line) . "\n";
-                               ERROR("use the HI() macro, not (... >> 16)\n" . 
$herevet);
+                               ERROR("HI_MACRO",
+                                     "use the HI() macro, not (... >> 16)\n" . 
$herevet);
                        }
                }
 
 # check we are in a valid source file C or perl if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|cpp|pl)$/);
+               next if ($realfile !~ /\.(h|c|pl)$/);
+
 
 # in QEMU, no tabs are allowed
-               if ($rawline =~ /^\+.*\t/) {
+               if ($rawline =~ /^\+.*\t/ ||
+                   $rawline =~ /^\+/ && $rawline =~ / \t/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       ERROR("code indent should never use tabs\n" . $herevet);
-                       $rpt_cleaners = 1;
+                       if (ERROR("CODE_INDENT",
+                                 "code indent should never use tabs\n" . 
$herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/^\+([ \t]+)/"\+" . 
tabify($1)/e;
+                       }
+               }
+
+# QEMU specific tests
+               if ($rawline =~ /\b(?:Qemu|QEmu)\b/) {
+                   WARN("CAPS", "use QEMU instead of Qemu or QEmu\n" . 
$herecurr);
+               }
+# check for && or || at the start of a line
+               if ($rawline =~ /^\+\s*(&&|\|\|)/) {
+                       CHK("LOGICAL_CONTINUATIONS",
+                           "Logical continuations should be on the previous 
line\n" . $hereprev);
+               }
+
+# check multi-line statement indentation matches previous line
+               if ($^V && $^V ge 5.10.0 &&
+                   $prevline =~ /^\+([ 
\t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/)
 {
+                       $prevline =~ /^\+(\t*)(.*)$/;
+                       my $oldindent = $1;
+                       my $rest = $2;
+
+                       my $pos = pos_last_openparen($rest);
+                       if ($pos >= 0) {
+                               $line =~ /^(\+| )([ \t]*)/;
+                               my $newindent = $2;
+
+                               my $goodtabindent = $oldindent .
+                                       "\t" x ($pos / 8) .
+                                       " "  x ($pos % 8);
+                               my $goodspaceindent = $oldindent . " "  x $pos;
+
+                               if ($newindent ne $goodtabindent &&
+                                   $newindent ne $goodspaceindent) {
+
+                                       if (CHK("PARENTHESIS_ALIGNMENT",
+                                               "Alignment should match open 
parenthesis\n" . $hereprev) &&
+                                           $fix && $line =~ /^\+/) {
+                                               $fixed[$linenr - 1] =~
+                                                   s/^\+[ 
\t]*/\+$goodtabindent/;
+                                       }
+                               }
+                       }
+               }
+
+               if ($line =~ /^\+.*\*[ \t]*\)[ 
\t]+(?!$Assignment|$Arithmetic)/) {
+                       if (CHK("SPACING",
+                               "No space is necessary after a cast\n" . 
$hereprev) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(\+.*\*[ \t]*\))[ \t]+/$1/;
+                       }
+               }
+
+               if ($realfile =~ address@hidden(drivers/net/|net/)@ &&
+                   $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
+                   $rawline =~ /^\+[ \t]*\*/ &&
+                   $realline > 2) {
+                       WARN("NETWORKING_BLOCK_COMMENT_STYLE",
+                            "networking block comments don't use an empty /* 
line, use /* Comment...\n" . $hereprev);
+               }
+
+               if ($realfile =~ address@hidden(drivers/net/|net/)@ &&
+                   $prevrawline =~ /^\+[ \t]*\/\*/ &&          #starting /*
+                   $prevrawline !~ /\*\/[ \t]*$/ &&            #no trailing */
+                   $rawline =~ /^\+/ &&                        #line is new
+                   $rawline !~ /^\+[ \t]*\*/) {                #no leading *
+                       WARN("NETWORKING_BLOCK_COMMENT_STYLE",
+                            "networking block comments start with * on 
subsequent lines\n" . $hereprev);
+               }
+
+               if ($realfile =~ address@hidden(drivers/net/|net/)@ &&
+                   $rawline !~ address@hidden \t]*\*/[ \t]*$@ &&       
#trailing */
+                   $rawline !~ address@hidden/\*.*\*/[ \t]*$@ &&       #inline 
/*...*/
+                   $rawline !~ address@hidden,}/[ \t]*$@ &&    #trailing **/
+                   $rawline =~ address@hidden \t]*.+\*\/[ \t]*$@) {    #non 
blank */
+                       WARN("NETWORKING_BLOCK_COMMENT_STYLE",
+                            "networking block comments put the trailing */ on 
a separate line\n" . $herecurr);
+               }
+
+# check for missing blank lines after declarations
+               if ($realfile =~ address@hidden(drivers/net/|net/)@ &&
+                   $prevline =~ /^\+\s+$Declare\s+$Ident/ &&
+                   !($prevline =~ /(?:$Compare|$Assignment|$Operators)\s*$/ ||
+                     $prevline =~ /(?:\{\s*|\\)$/) &&          #extended lines
+                   $sline =~ /^\+\s+/ &&                       #Not at char 1
+                   !($sline =~ /^\+\s+$Declare/ ||
+                     $sline =~ /^\+\s+$Ident\s+$Ident/ ||      #eg: typedef foo
+                     $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ ||
+                     $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(])/ ||
+                     $sline =~ 
/^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/)) {
+                       WARN("SPACING",
+                            "networking uses a blank line after 
declarations\n" . $hereprev);
                }
 
 # check we are in a valid C source file if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|cpp)$/);
+               next if ($realfile !~ /\.(h|c)$/);
+
+# discourage the addition of CONFIG_EXPERIMENTAL in #if(def).
+               if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) {
+                       WARN("CONFIG_EXPERIMENTAL",
+                            "Use of CONFIG_EXPERIMENTAL is deprecated. For 
alternatives, see https://lkml.org/lkml/2012/10/23/580\n";);
+               }
 
 # check for RCS/CVS revision markers
                if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
-                       WARN("CVS style keyword markers, these will _not_ be 
updated\n". $herecurr);
+                       WARN("CVS_KEYWORD",
+                            "CVS style keyword markers, these will _not_ be 
updated\n". $herecurr);
                }
 
 # Blackfin: don't use __builtin_bfin_[cs]sync
                if ($line =~ /__builtin_bfin_csync/) {
                        my $herevet = "$here\n" . cat_vet($line) . "\n";
-                       ERROR("use the CSYNC() macro in asm/blackfin.h\n" . 
$herevet);
+                       ERROR("CSYNC",
+                             "use the CSYNC() macro in asm/blackfin.h\n" . 
$herevet);
                }
                if ($line =~ /__builtin_bfin_ssync/) {
                        my $herevet = "$here\n" . cat_vet($line) . "\n";
-                       ERROR("use the SSYNC() macro in asm/blackfin.h\n" . 
$herevet);
+                       ERROR("SSYNC",
+                             "use the SSYNC() macro in asm/blackfin.h\n" . 
$herevet);
+               }
+
+# check for old HOTPLUG __dev<foo> section markings
+               if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) {
+                       WARN("HOTPLUG_SECTION",
+                            "Using $1 is unnecessary\n" . $herecurr);
                }
 
 # Check for potential 'bare' types
                my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
                    $realline_next);
-               if ($realcnt && $line =~ /.\s*\S/) {
+#print "LINE<$line>\n";
+               if ($linenr >= $suppress_statement &&
+                   $realcnt && $sline =~ /.\s*\S/) {
                        ($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;
 
+#print "linenr<$linenr> <$stat>\n";
+                       # If this statement has no statement boundaries within
+                       # it there is no point in retrying a statement scan
+                       # until we hit end of it.
+                       my $frag = $stat; $frag =~ s/;+\s*$//;
+                       if ($frag !~ /(?:{|;)/) {
+#print "skip<$line_nr_next>\n";
+                               $suppress_statement = $line_nr_next;
+                       }
+
                        # Find the real next line.
                        $realline_next = $line_nr_next;
                        if (defined $realline_next &&
@@ -1608,7 +2397,8 @@ sub process {
                                }
                        }
                        if ($err ne '') {
-                               ERROR("switch and case should be at the same 
indent\n$hereline$err");
+                               ERROR("SWITCH_CASE_INDENT_LEVEL",
+                                     "switch and case should be at the same 
indent\n$hereline$err");
                        }
                }
 
@@ -1618,6 +2408,12 @@ sub process {
                        my $pre_ctx = "$1$2";
 
                        my ($level, @ctx) = ctx_statement_level($linenr, 
$realcnt, 0);
+
+                       if ($line =~ /^\+\t{6,}/) {
+                               WARN("DEEP_INDENTATION",
+                                    "Too many leading tabs - consider code 
refactoring\n" . $herecurr);
+                       }
+
                        my $ctx_cnt = $realcnt - $#ctx - 1;
                        my $ctx = join("\n", @ctx);
 
@@ -1636,7 +2432,8 @@ sub process {
                        #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" .
+                               ERROR("OPEN_BRACE",
+                                     "that open brace { should be on the 
previous line\n" .
                                        "$here\n$ctx\n$rawlines[$ctx_ln - 
1]\n");
                        }
                        if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
@@ -1645,7 +2442,8 @@ sub process {
                        {
                                my ($nlength, $nindent) = 
line_stats($lines[$ctx_ln - 1]);
                                if ($nindent > $indent) {
-                                       WARN("trailing semicolon indicates no 
statements, indent implies otherwise\n" .
+                                       WARN("TRAILING_SEMICOLON",
+                                            "trailing semicolon indicates no 
statements, indent implies otherwise\n" .
                                                "$here\n$ctx\n$rawlines[$ctx_ln 
- 1]\n");
                                }
                        }
@@ -1653,6 +2451,9 @@ sub process {
 
 # Check relative indent for conditionals and blocks.
                if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ 
/^.\s*#/ && $line !~ /\}\s*while\s*/) {
+                       ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+                               ctx_statement_block($linenr, $realcnt, 0)
+                                       if (!defined $stat);
                        my ($s, $c) = ($stat, $cond);
 
                        substr($s, 0, length($c), '');
@@ -1731,9 +2532,10 @@ sub process {
 
                        #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 % 4) != 0 ||
+                       if ($check && (($sindent % 8) != 0 ||
                            ($sindent <= $indent && $s ne ''))) {
-                               WARN("suspect code indent for conditional 
statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+                               WARN("SUSPECT_CODE_INDENT",
+                                    "suspect code indent for conditional 
statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
                        }
                }
 
@@ -1751,23 +2553,27 @@ sub process {
                $prev_values = substr($curr_values, -1);
 
 #ignore lines not being added
-               if ($line=~/^[^\+]/) {next;}
+               next if ($line =~ /^[^\+]/);
 
 # TEST: allow direct testing of the type matcher.
                if ($dbg_type) {
                        if ($line =~ /^.\s*$Declare\s*$/) {
-                               ERROR("TEST: is type\n" . $herecurr);
+                               ERROR("TEST_TYPE",
+                                     "TEST: is type\n" . $herecurr);
                        } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
-                               ERROR("TEST: is not type ($1 is)\n". $herecurr);
+                               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: is attr\n" . $herecurr);
+                               ERROR("TEST_ATTR",
+                                     "TEST: is attr\n" . $herecurr);
                        } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
-                               ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+                               ERROR("TEST_NOT_ATTR",
+                                     "TEST: is not attr ($1 is)\n". $herecurr);
                        }
                        next;
                }
@@ -1775,7 +2581,8 @@ sub process {
 # check for initialisation to aggregates open brace on the next line
                if ($line =~ /^.\s*{/ &&
                    $prevline =~ /(?:^|[^=])=\s*$/) {
-                       ERROR("that open brace { should be on the previous 
line\n" . $hereprev);
+                       ERROR("OPEN_BRACE",
+                             "that open brace { should be on the previous 
line\n" . $hereprev);
                }
 
 #
@@ -1786,14 +2593,26 @@ sub process {
                if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
                        my $path = $1;
                        if ($path =~ m{//}) {
-                               ERROR("malformed #include filename\n" .
-                                       $herecurr);
+                               ERROR("MALFORMED_INCLUDE",
+                                     "malformed #include filename\n" . 
$herecurr);
+                       }
+                       if ($path =~ "^uapi/" && $realfile =~ 
address@hidden/uapi/@) {
+                               ERROR("UAPI_INCLUDE",
+                                     "No #include in ...include/uapi/... 
should use a uapi/ path prefix\n" . $herecurr);
                        }
                }
 
 # no C99 // comments
                if ($line =~ m{//}) {
-                       ERROR("do not use C99 // comments\n" . $herecurr);
+                       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] =~ 
address@hidden/\/(.*)$@/\* $comment \*/@;
+                               }
+                       }
                }
                # Remove C99 comments.
                $line =~ s@//.*@@;
@@ -1812,7 +2631,7 @@ sub process {
                        #   XXX(foo);
                        #   EXPORT_SYMBOL(something_foo);
                        my $name = $1;
-                       if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ &&
+                       if ($stat =~ 
/^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
                            $name =~ /^${Ident}_$2/) {
 #print "FOO C name<$name>\n";
                                $suppress_export{$realline_next} = 1;
@@ -1840,26 +2659,86 @@ sub process {
                }
                if (defined $suppress_export{$linenr} &&
                    $suppress_export{$linenr} == 2) {
-                       WARN("EXPORT_SYMBOL(foo); should immediately follow its 
function/variable\n" . $herecurr);
+                       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("do not initialise globals to 0 or NULL\n" .
-                               $herecurr);
+               if ($line =~ 
/^\+(\s*$Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/) {
+                       if (ERROR("GLOBAL_INITIALISERS",
+                                 "do not initialise globals to 0 or NULL\n" .
+                                     $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/($Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/$1;/;
+                       }
                }
 # check for static initialisers.
-               if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
-                       ERROR("do not initialise statics to 0 or NULL\n" .
-                               $herecurr);
+               if ($line =~ /^\+.*\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+                       if (ERROR("INITIALISED_STATIC",
+                                 "do not initialise statics to 0 or NULL\n" .
+                                     $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/(\bstatic\s.*?)\s*=\s*(0|NULL|false)\s*;/$1;/;
+                       }
                }
 
-# * goes on variable not on type
-               # (char*[ const])
-               if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) {
-                       my ($from, $to) = ($1, $1);
+# 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);
+               }
 
-                       # Should start with a space.
+# 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 non-global char *foo[] = {"bar", ...} declarations.
+               if ($line =~ 
/^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) {
+                       WARN("STATIC_CONST_CHAR_ARRAY",
+                            "char * array declaration might be better as 
static const\n" .
+                               $herecurr);
+               }
+
+# check for function declarations without arguments like "int foo()"
+               if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) {
+                       if (ERROR("FUNCTION_WITHOUT_ARGS",
+                                 "Bad function definition - $1() should 
probably be $1(void)\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/;
+                       }
+               }
+
+# check for uses of DEFINE_PCI_DEVICE_TABLE
+               if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) 
{
+                       if (WARN("DEFINE_PCI_DEVICE_TABLE",
+                                "Prefer struct pci_device_id over deprecated 
DEFINE_PCI_DEVICE_TABLE\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\b(?:static\s+|)DEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=\s*/static const 
struct pci_device_id $1\[\] = /;
+                       }
+               }
+
+# 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<$1>\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+$//;
@@ -1867,12 +2746,22 @@ sub process {
                        while ($to =~ s/\*\s+\*/\*\*/) {
                        }
 
-                       #print "from<$from> to<$to>\n";
+##                     print "1: from<$from> to<$to> ident<$ident>\n";
                        if ($from ne $to) {
-                               ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" 
.  $herecurr);
+                               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] =~
+                                           address@hidden@$sub_to@;
+                               }
                        }
-               } elsif ($line =~ 
m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) {
-                       my ($from, $to, $ident) = ($1, $1, $2);
+               }
+               while ($line =~ 
m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) {
+                       #print "BB<$1>\n";
+                       my ($match, $from, $to, $ident) = ($1, $2, $2, $3);
 
                        # Should start with a space.
                        $to =~ s/^(\S)/ $1/;
@@ -1884,9 +2773,18 @@ sub process {
                        # Modifiers should have spaces.
                        $to =~ s/(\b$Modifier$)/$1 /;
 
-                       #print "from<$from> to<$to> ident<$ident>\n";
+##                     print "2: from<$from> to<$to> ident<$ident>\n";
                        if ($from ne $to && $ident !~ /^$Modifier$/) {
-                               ERROR("\"foo${from}bar\" should be 
\"foo${to}bar\"\n" .  $herecurr);
+                               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] =~
+                                           address@hidden@$sub_to@;
+                               }
                        }
                }
 
@@ -1898,7 +2796,14 @@ sub process {
 #              }
 
                if ($line =~ /\bLINUX_VERSION_CODE\b/) {
-                       WARN("LINUX_VERSION_CODE should be avoided, code should 
be for the version to which it is merged\n" . $herecurr);
+                       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_<level>_ratelimited to printk_ratelimit\n" . 
$herecurr);
                }
 
 # printk should use KERN_* levels.  Note that follow on printk's on the
@@ -1920,26 +2825,132 @@ sub process {
                                }
                        }
                        if ($ok == 0) {
-                               WARN("printk() should include KERN_ facility 
level\n" . $herecurr);
+                               WARN("PRINTK_WITHOUT_KERN_LEVEL",
+                                    "printk() should include KERN_ facility 
level\n" . $herecurr);
+                       }
+               }
+
+               if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) {
+                       my $orig = $1;
+                       my $level = lc($orig);
+                       $level = "warn" if ($level eq "warning");
+                       my $level2 = $level;
+                       $level2 = "dbg" if ($level eq "debug");
+                       WARN("PREFER_PR_LEVEL",
+                            "Prefer [subsystem eg: 
netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then 
pr_$level(...  to printk(KERN_$orig ...\n" . $herecurr);
+               }
+
+               if ($line =~ /\bpr_warning\s*\(/) {
+                       if (WARN("PREFER_PR_LEVEL",
+                                "Prefer pr_warn(... to pr_warning(...\n" . 
$herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\bpr_warning\b/pr_warn/;
                        }
                }
 
+               if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) {
+                       my $orig = $1;
+                       my $level = lc($orig);
+                       $level = "warn" if ($level eq "warning");
+                       $level = "dbg" if ($level eq "debug");
+                       WARN("PREFER_DEV_LEVEL",
+                            "Prefer dev_$level(... to dev_printk(KERN_$orig, 
...\n" . $herecurr);
+               }
+
 # function brace can't be on same line, except for #defines of do while,
 # or if closed on same line
                if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and
                    !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) {
-                       ERROR("open brace '{' following function declarations 
go on the next line\n" . $herecurr);
+                       ERROR("OPEN_BRACE",
+                             "open brace '{' following function declarations 
go on the next line\n" . $herecurr);
                }
 
 # open braces for enum, union and struct go on the same line.
                if ($line =~ /^.\s*{/ &&
                    $prevline =~ 
/^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
-                       ERROR("open brace '{' following $1 go on the same 
line\n" . $hereprev);
+                       ERROR("OPEN_BRACE",
+                             "open brace '{' following $1 go on the same 
line\n" . $hereprev);
                }
 
 # missing space after union, struct or enum definition
-               if ($line =~ 
/^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
-                   WARN("missing space after $1 definition\n" . $herecurr);
+               if ($line =~ 
/^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/) {
+                       if (WARN("SPACING",
+                                "missing space after $1 definition\n" . 
$herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   
s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/;
+                       }
+               }
+
+# Function pointer declarations
+# check spacing between type, funcptr, and args
+# canonical declaration is "type (*funcptr)(args...)"
+               if ($line =~ 
/^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/) {
+                       my $declare = $1;
+                       my $pre_pointer_space = $2;
+                       my $post_pointer_space = $3;
+                       my $funcname = $4;
+                       my $post_funcname_space = $5;
+                       my $pre_args_space = $6;
+
+# the $Declare variable will capture all spaces after the type
+# so check it for a missing trailing missing space but pointer return types
+# don't need a space so don't warn for those.
+                       my $post_declare_space = "";
+                       if ($declare =~ /(\s+)$/) {
+                               $post_declare_space = $1;
+                               $declare = rtrim($declare);
+                       }
+                       if ($declare !~ /\*$/ && $post_declare_space =~ /^$/) {
+                               WARN("SPACING",
+                                    "missing space after return type\n" . 
$herecurr);
+                               $post_declare_space = " ";
+                       }
+
+# unnecessary space "type  (*funcptr)(args...)"
+# This test is not currently implemented because these declarations are
+# equivalent to
+#      int  foo(int bar, ...)
+# and this is form shouldn't/doesn't generate a checkpatch warning.
+#
+#                      elsif ($declare =~ /\s{2,}$/) {
+#                              WARN("SPACING",
+#                                   "Multiple spaces after return type\n" . 
$herecurr);
+#                      }
+
+# unnecessary space "type ( *funcptr)(args...)"
+                       if (defined $pre_pointer_space &&
+                           $pre_pointer_space =~ /^\s/) {
+                               WARN("SPACING",
+                                    "Unnecessary space after function pointer 
open parenthesis\n" . $herecurr);
+                       }
+
+# unnecessary space "type (* funcptr)(args...)"
+                       if (defined $post_pointer_space &&
+                           $post_pointer_space =~ /^\s/) {
+                               WARN("SPACING",
+                                    "Unnecessary space before function pointer 
name\n" . $herecurr);
+                       }
+
+# unnecessary space "type (*funcptr )(args...)"
+                       if (defined $post_funcname_space &&
+                           $post_funcname_space =~ /^\s/) {
+                               WARN("SPACING",
+                                    "Unnecessary space after function pointer 
name\n" . $herecurr);
+                       }
+
+# unnecessary space "type (*funcptr) (args...)"
+                       if (defined $pre_args_space &&
+                           $pre_args_space =~ /^\s/) {
+                               WARN("SPACING",
+                                    "Unnecessary space before function pointer 
arguments\n" . $herecurr);
+                       }
+
+                       if (show_type("SPACING") && $fix) {
+                               $fixed[$linenr - 1] =~
+                                   
s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . 
$post_declare_space . '(*' . $funcname . ')('/ex;
+                       }
                }
 
 # check for spacing round square brackets; allowed:
@@ -1950,8 +2961,13 @@ sub process {
                        my ($where, $prefix) = ($-[1], $1);
                        if ($prefix !~ /$Type\s+$/ &&
                            ($where != 0 || $prefix !~ /^.\s+$/) &&
-                           $prefix !~ /{\s+$/) {
-                               ERROR("space prohibited before open square 
bracket '['\n" . $herecurr);
+                           $prefix !~ /[{,]\s+$/) {
+                               if (ERROR("BRACKET_SPACE",
+                                         "space prohibited before open square 
bracket '['\n" . $herecurr) &&
+                                   $fix) {
+                                   $fixed[$linenr - 1] =~
+                                       s/^(\+.*?)\s+\[/$1\[/;
+                               }
                        }
                }
 
@@ -1968,10 +2984,6 @@ sub process {
                                __attribute__|format|__extension__|
                                asm|__asm__)$/x)
                        {
-
-                       # Ignore 'catch (...)' in C++
-                       } elsif ($name =~ /^catch$/ && $realfile =~ 
/(\.cpp|\.h)$/) {
-
                        # cpp #define statements have non-optional spaces, ie
                        # if there is a space between the name and the open
                        # parenthesis it is simply not a parameter group.
@@ -1985,24 +2997,53 @@ sub process {
                        } elsif ($ctx =~ /$Type$/) {
 
                        } else {
-                               WARN("space prohibited between function name 
and open parenthesis '('\n" . $herecurr);
+                               if (WARN("SPACING",
+                                        "space prohibited between function 
name and open parenthesis '('\n" . $herecurr) &&
+                                            $fix) {
+                                       $fixed[$linenr - 1] =~
+                                           s/\b$name\s+\(/$name\(/;
+                               }
                        }
                }
+
 # Check operator spacing.
                if (!($line=~/\#\s*include/)) {
+                       my $fixed_line = "";
+                       my $line_fixed = 0;
+
                        my $ops = qr{
                                <<=|>>=|<=|>=|==|!=|
                                \+=|-=|\*=|\/=|%=|\^=|\|=|&=|
                                =>|->|<<|>>|<|>|=|!|~|
                                &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
-                               \?|::|:
+                               \?:|\?|:
                        }x;
                        my @elements = split(/($ops|;)/, $opline);
+
+##                     print("element count: <" . $#elements . ">\n");
+##                     foreach my $el (@elements) {
+##                             print("el: <$el>\n");
+##                     }
+
+                       my @fix_elements = ();
                        my $off = 0;
 
+                       foreach my $el (@elements) {
+                               push(@fix_elements, substr($rawline, $off, 
length($el)));
+                               $off += length($el);
+                       }
+
+                       $off = 0;
+
                        my $blank = copy_spacing($opline);
+                       my $last_after = -1;
 
                        for (my $n = 0; $n < $#elements; $n += 2) {
+
+                               my $good = $fix_elements[$n] . $fix_elements[$n 
+ 1];
+
+##                             print("n: <$n> good: <$good>\n");
+
                                $off += length($elements[$n]);
 
                                # Pick up the preceding and succeeding 
characters.
@@ -2059,30 +3100,43 @@ sub process {
                                } elsif ($op eq ';') {
                                        if ($ctx !~ /.x[WEBC]/ &&
                                            $cc !~ /^\\/ && $cc !~ /^;/) {
-                                               ERROR("space required after 
that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space required after 
that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
$fix_elements[$n] . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
                                # // is a comment
                                } elsif ($op eq '//') {
 
-                               # Ignore : used in class declaration in C++
-                               } elsif ($opv eq ':B' && $ctx =~ /Wx[WE]/ &&
-                                                $line =~ /class/ && $realfile 
=~ /(\.cpp|\.h)$/) {
+                               #   :   when part of a bitfield
+                               } elsif ($opv eq ':B') {
+                                       # skip the bitfield test for now
 
                                # No spaces for:
                                #   ->
-                               #   :   when part of a bitfield
-                               } elsif ($op eq '->' || $opv eq ':B') {
+                               } elsif ($op eq '->') {
                                        if ($ctx =~ /Wx.|.xW/) {
-                                               ERROR("spaces prohibited around 
that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "spaces prohibited 
around that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       if (defined 
$fix_elements[$n + 2]) {
+                                                               
$fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
                                # , must have a space on the right.
-                                # not required when having a single },{ on one 
line
                                } elsif ($op eq ',') {
-                                       if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/ &&
-                                            ($elements[$n] . $elements[$n + 
2]) !~ " *}{") {
-                                               ERROR("space required after 
that '$op' $at\n" . $hereptr);
+                                       if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+                                               if (ERROR("SPACING",
+                                                         "space required after 
that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
$fix_elements[$n] . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                                       $last_after = $n;
+                                               }
                                        }
 
                                # '*' as part of a type definition -- reported 
already.
@@ -2095,33 +3149,57 @@ sub process {
                                } elsif ($op eq '!' || $op eq '~' ||
                                         $opv eq '*U' || $opv eq '-U' ||
                                         $opv eq '&U' || $opv eq '&&U') {
-                                       if ($op eq '~' && $ca =~ /::$/ && 
$realfile =~ /(\.cpp|\.h)$/) {
-                                               # '~' used as a name of 
Destructor
-
-                                       } elsif ($ctx !~ /[WEBC]x./ && $ca !~ 
/(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
-                                               ERROR("space required before 
that '$op' $at\n" . $hereptr);
+                                       if ($ctx !~ /[WEBC]x./ && $ca !~ 
/(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+                                               if (ERROR("SPACING",
+                                                         "space required 
before that '$op' $at\n" . $hereptr)) {
+                                                       if ($n != $last_after + 
2) {
+                                                               $good = 
$fix_elements[$n] . " " . ltrim($fix_elements[$n + 1]);
+                                                               $line_fixed = 1;
+                                                       }
+                                               }
                                        }
                                        if ($op eq '*' && $cc 
=~/\s*$Modifier\b/) {
                                                # A unary '*' may be const
 
                                        } elsif ($ctx =~ /.xW/) {
-                                               ERROR("space prohibited after 
that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited 
after that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
$fix_elements[$n] . rtrim($fix_elements[$n + 1]);
+                                                       if (defined 
$fix_elements[$n + 2]) {
+                                                               
$fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
                                # 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]/) {
-                                               ERROR("space required one side 
of that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space required one 
side of that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
$fix_elements[$n] . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                               }
                                        }
                                        if ($ctx =~ /Wx[BE]/ ||
                                            ($ctx =~ /Wx./ && $cc =~ /^;/)) {
-                                               ERROR("space prohibited before 
that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited 
before that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $line_fixed = 1;
+                                               }
                                        }
                                        if ($ctx =~ /ExW/) {
-                                               ERROR("space prohibited after 
that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited 
after that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
$fix_elements[$n] . trim($fix_elements[$n + 1]);
+                                                       if (defined 
$fix_elements[$n + 2]) {
+                                                               
$fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
-
                                # << and >> 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
@@ -2130,59 +3208,87 @@ sub process {
                                         $op eq '%')
                                {
                                        if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
-                                               ERROR("need consistent spacing 
around '$op' $at\n" .
-                                                       $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "need consistent 
spacing around '$op' $at\n" . $hereptr)) {
+                                                       $good = 
rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       if (defined 
$fix_elements[$n + 2]) {
+                                                               
$fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                                       $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./) {
-                                               ERROR("space prohibited before 
that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited 
before that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
rtrim($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;
 
-                                       if ($realfile =~ /\.cpp|\.h$/) {
-                                               # Ignore template arguments 
<...> in C++
-                                               if (($op eq '<' || $op eq '>') 
&& $line =~ /<.*>/) {
-                                                       $ok = 1;
-                                               }
-
-                                               # Ignore :: in C++
-                                               if ($op eq '::') {
-                                                       $ok = 1;
-                                               }
-                                       }
-
                                        # Ignore email addresses 
<address@hidden>
                                        if (($op eq '<' &&
                                             $cc =~ /address@hidden>/) ||
                                            ($op eq '>' &&
                                             $ca =~ /<address@hidden/))
                                        {
-                                               $ok = 1;
-                                       }
-
-                                       # Ignore ?:
-                                       if (($opv eq ':O' && $ca =~ /\?$/) ||
-                                           ($op eq '?' && $cc =~ /^:/)) {
-                                               $ok = 1;
+                                               $ok = 1;
                                        }
 
+                                       # messages are ERROR, but ?: are CHK
                                        if ($ok == 0) {
-                                               ERROR("spaces required around 
that '$op' $at\n" . $hereptr);
+                                               my $msg_type = \&ERROR;
+                                               $msg_type = \&CHK if (($op eq 
'?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/);
+
+                                               if (&{$msg_type}("SPACING",
+                                                                "spaces 
required around that '$op' $at\n" . $hereptr)) {
+                                                       $good = 
rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       if (defined 
$fix_elements[$n + 2]) {
+                                                               
$fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                                       $line_fixed = 1;
+                                               }
                                        }
                                }
                                $off += length($elements[$n + 1]);
+
+##                             print("n: <$n> GOOD: <$good>\n");
+
+                               $fixed_line = $fixed_line . $good;
+                       }
+
+                       if (($#elements % 2) == 0) {
+                               $fixed_line = $fixed_line . 
$fix_elements[$#elements];
+                       }
+
+                       if ($fix && $line_fixed && $fixed_line ne 
$fixed[$linenr - 1]) {
+                               $fixed[$linenr - 1] = $fixed_line;
+                       }
+
+
+               }
+
+# check for whitespace before a non-naked semicolon
+               if ($line =~ /^\+.*\S\s+;\s*$/) {
+                       if (WARN("SPACING",
+                                "space prohibited before semicolon\n" . 
$herecurr) &&
+                           $fix) {
+                               1 while $fixed[$linenr - 1] =~
+                                   s/^(\+.*\S)\s+;/$1;/;
                        }
                }
 
 # check for multiple assignments
                if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
-                       CHK("multiple assignments should be avoided\n" . 
$herecurr);
+                       CHK("MULTIPLE_ASSIGNMENTS",
+                           "multiple assignments should be avoided\n" . 
$herecurr);
                }
 
 ## # check for multiple declarations, allowing for a function declaration
@@ -2196,79 +3302,146 @@ sub process {
 ##                     while ($ln =~ s/\([^\(\)]*\)//g) {
 ##                     }
 ##                     if ($ln =~ /,/) {
-##                             WARN("declaring multiple variables together 
should be avoided\n" . $herecurr);
+##                             WARN("MULTIPLE_DECLARATION",
+##                                  "declaring multiple variables together 
should be avoided\n" . $herecurr);
 ##                     }
 ##             }
 
 #need space before brace following if, while, etc
                if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
                    $line =~ /do{/) {
-                       ERROR("space required before the open brace '{'\n" . 
$herecurr);
+                       if (ERROR("SPACING",
+                                 "space required before the open brace '{'\n" 
. $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/^(\+.*(?:do|\))){/$1 
{/;
+                       }
                }
 
+## # check for blank lines before declarations
+##             if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ &&
+##                 $prevrawline =~ /^.\s*$/) {
+##                     WARN("SPACING",
+##                          "No blank lines before declarations\n" . 
$hereprev);
+##             }
+##
+
 # closing brace should have a space following it when it has anything
 # on the line
                if ($line =~ /}(?!(?:,|;|\)))\S/) {
-                       ERROR("space required after that close brace '}'\n" . 
$herecurr);
+                       if (ERROR("SPACING",
+                                 "space required after that close brace '}'\n" 
. $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/}((?!(?:,|;|\)))\S)/} $1/;
+                       }
                }
 
 # check spacing on square brackets
                if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
-                       ERROR("space prohibited after that open square bracket 
'['\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited after that open square 
bracket '['\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\[\s+/\[/;
+                       }
                }
                if ($line =~ /\s\]/) {
-                       ERROR("space prohibited before that close square 
bracket ']'\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited before that close square 
bracket ']'\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\s+\]/\]/;
+                       }
                }
 
 # check spacing on parentheses
                if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
                    $line !~ /for\s*\(\s+;/) {
-                       ERROR("space prohibited after that open parenthesis 
'('\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited after that open parenthesis 
'('\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\(\s+/\(/;
+                       }
                }
                if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
                    $line !~ /for\s*\(.*;\s+\)/ &&
                    $line !~ /:\s+\)/) {
-                       ERROR("space prohibited before that close parenthesis 
')'\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited before that close 
parenthesis ')'\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\s+\)/\)/;
+                       }
                }
 
-# Return is not a function.
-               if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
-                       my $spacing = $1;
-                       my $value = $2;
-
-                       # Flatten any parentheses
-                       $value =~ s/\(/ \(/g;
-                       $value =~ s/\)/\) /g;
-                       while ($value =~ s/\[[^\{\}]*\]/1/ ||
-                              $value !~ /(?:$Ident|-?$Constant)\s*
-                                            $Compare\s*
-                                            (?:$Ident|-?$Constant)/x &&
-                              $value =~ s/\([^\(\)]*\)/1/) {
+#goto labels aren't indented, allow a single space however
+               if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
+                  !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+                       if (WARN("INDENTED_LABEL",
+                                "labels should not be indented\n" . $herecurr) 
&&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(.)\s+/$1/;
                        }
-#print "value<$value>\n";
-                       if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) {
-                               ERROR("return is not a function, parentheses 
are not required\n" . $herecurr);
+               }
 
+# return is not a function
+               if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
+                       my $spacing = $1;
+                       if ($^V && $^V ge 5.10.0 &&
+                           $stat =~ 
/^.\s*return\s*($balanced_parens)\s*;\s*$/) {
+                               my $value = $1;
+                               $value = deparenthesize($value);
+                               if ($value =~ m/^\s*$FuncArg\s*(?:\?|$)/) {
+                                       ERROR("RETURN_PARENTHESES",
+                                             "return is not a function, 
parentheses are not required\n" . $herecurr);
+                               }
                        } elsif ($spacing !~ /\s+/) {
-                               ERROR("space required before the open 
parenthesis '('\n" . $herecurr);
+                               ERROR("SPACING",
+                                     "space required before the open 
parenthesis '('\n" . $herecurr);
                        }
                }
+
+# if statements using unnecessary parentheses - ie: if ((foo == bar))
+               if ($^V && $^V ge 5.10.0 &&
+                   $line =~ /\bif\s*((?:\(\s*){2,})/) {
+                       my $openparens = $1;
+                       my $count = $openparens =~ address@hidden(@\(@;
+                       my $msg = "";
+                       if ($line =~ 
/\bif\s*(?:\(\s*){$count,$count}$LvalOrFunc\s*($Compare)\s*$LvalOrFunc(?:\s*\)){$count,$count}/)
 {
+                               my $comp = $4;  #Not $1 because of $LvalOrFunc
+                               $msg = " - maybe == should be = ?" if ($comp eq 
"==");
+                               WARN("UNNECESSARY_PARENTHESES",
+                                    "Unnecessary parentheses$msg\n" . 
$herecurr);
+                       }
+               }
+
 # Return of what appears to be an errno should normally be -'ve
                if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) {
                        my $name = $1;
                        if ($name ne 'EOF' && $name ne 'ERROR') {
-                               CHK("return of an errno should typically be -ve 
(return -$1)\n" . $herecurr);
+                               WARN("USE_NEGATIVE_ERRNO",
+                                    "return of an errno should typically be 
-ve (return -$1)\n" . $herecurr);
                        }
                }
 
 # Need a space before open parenthesis after if, while etc
-               if ($line=~/\b(if|while|for|switch)\(/) {
-                       ERROR("space required before the open parenthesis 
'('\n" . $herecurr);
+               if ($line =~ /\b(if|while|for|switch)\(/) {
+                       if (ERROR("SPACING",
+                                 "space required before the open parenthesis 
'('\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\b(if|while|for|switch)\(/$1 \(/;
+                       }
                }
 
 # Check for illegal assignment in if conditional -- and check for trailing
 # statements after the conditional.
                if ($line =~ /do\s*(?!{)/) {
+                       ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+                               ctx_statement_block($linenr, $realcnt, 0)
+                                       if (!defined $stat);
                        my ($stat_next) = ctx_statement_block($line_nr_next,
                                                $remain_next, $off_next);
                        $stat_next =~ s/\n./\n /g;
@@ -2287,11 +3460,13 @@ sub process {
                        }
                }
                if (!defined $suppress_whiletrailers{$linenr} &&
+                   defined($stat) && defined($cond) &&
                    $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
                        my ($s, $c) = ($stat, $cond);
 
                        if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
-                               ERROR("do not use assignment in if condition\n" 
. $herecurr);
+                               ERROR("ASSIGN_IN_IF",
+                                     "do not use assignment in if condition\n" 
. $herecurr);
                        }
 
                        # Find out what is on the end of the line after the
@@ -2313,7 +3488,8 @@ sub process {
                                        $stat_real = "[...]\n$stat_real";
                                }
 
-                               ERROR("trailing statements should be on next 
line\n" . $herecurr . $stat_real);
+                               ERROR("TRAILING_STATEMENTS",
+                                     "trailing statements should be on next 
line\n" . $herecurr . $stat_real);
                        }
                }
 
@@ -2329,7 +3505,8 @@ sub process {
                                (?:\&\&|\|\||\)|\])
                        )/x)
                {
-                       WARN("boolean test with hexadecimal, perhaps just 1 \& 
or \|?\n" . $herecurr);
+                       WARN("HEXADECIMAL_BOOLEAN_TEST",
+                            "boolean test with hexadecimal, perhaps just 1 \& 
or \|?\n" . $herecurr);
                }
 
 # if and else should not have general statements after it
@@ -2337,12 +3514,14 @@ sub process {
                        my $s = $1;
                        $s =~ s/$;//g;  # Remove any comments
                        if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
-                               ERROR("trailing statements should be on next 
line\n" . $herecurr);
+                               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 should be on next line\n" .
+                       ERROR("TRAILING_STATEMENTS",
+                             "trailing statements should be on next line\n" .
                                $herecurr);
                }
 # case and default should not have general statements after them
@@ -2352,14 +3531,16 @@ sub process {
                        \s*return\s+
                    )/xg)
                {
-                       ERROR("trailing statements should be on next line\n" . 
$herecurr);
+                       ERROR("TRAILING_STATEMENTS",
+                             "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.
                if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
                                                $previndent == $indent) {
-                       ERROR("else should follow close brace '}'\n" . 
$hereprev);
+                       ERROR("ELSE_AFTER_BRACE",
+                             "else should follow close brace '}'\n" . 
$hereprev);
                }
 
                if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
@@ -2372,20 +3553,59 @@ sub process {
                        $s =~ s/\n.*//g;
 
                        if ($s =~ /^\s*;/) {
-                               ERROR("while should follow close brace '}'\n" . 
$hereprev);
+                               ERROR("WHILE_AFTER_BRACE",
+                                     "while should follow close brace '}'\n" . 
$hereprev);
                        }
                }
 
-#studly caps, commented out until figure out how to distinguish between use of 
existing and adding new
-#              if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) {
-#                  print "No studly caps, use _\n";
-#                  print "$herecurr";
-#                  $clean = 0;
-#              }
+#Specific variable tests
+               while ($line =~ m{($Constant|$Lval)}g) {
+                       my $var = $1;
+
+#gcc binary extension
+                       if ($var =~ /^$Binary$/) {
+                               if (WARN("GCC_BINARY_CONSTANT",
+                                        "Avoid gcc v4.3+ binary constant 
extension: <$var>\n" . $herecurr) &&
+                                   $fix) {
+                                       my $hexval = sprintf("0x%x", oct($var));
+                                       $fixed[$linenr - 1] =~
+                                           s/\b$var\b/$hexval/;
+                               }
+                       }
+
+#CamelCase
+                       if ($var !~ /^$Constant$/ &&
+                           $var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
+#Ignore Page<foo> 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_]+)?$/) {
+                               while ($var =~ m{($Ident)}g) {
+                                       my $word = $1;
+                                       next if ($word !~ 
/[A-Z][a-z]|[a-z][A-Z]/);
+                                       if ($check) {
+                                               seed_camelcase_includes();
+                                               if (!$file && 
!$camelcase_file_seeded) {
+                                                       
seed_camelcase_file($realfile);
+                                                       $camelcase_file_seeded 
= 1;
+                                               }
+                                       }
+                                       if (!defined $camelcase{$word}) {
+                                               $camelcase{$word} = 1;
+                                               CHK("CAMELCASE",
+                                                   "Avoid CamelCase: 
<$word>\n" . $herecurr);
+                                       }
+                               }
+                       }
+               }
 
 #no spaces allowed after \ in define
-               if ($line=~/\#\s*define.*\\\s$/) {
-                       WARN("Whitepspace after \\ makes next lines useless\n" 
. $herecurr);
+               if ($line =~ /\#\s*define.*\\\s+$/) {
+                       if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
+                                "Whitespace after \\ makes next lines 
useless\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\s+$//;
+                       }
                }
 
 #warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW 
line)
@@ -2397,9 +3617,11 @@ sub process {
                            $1 !~ /$allowed_asm_includes/)
                        {
                                if ($realfile =~ m{^arch/}) {
-                                       CHK("Consider using #include 
<linux/$file> instead of <asm/$file>\n" . $herecurr);
+                                       CHK("ARCH_INCLUDE_LINUX",
+                                           "Consider using #include 
<linux/$file> instead of <asm/$file>\n" . $herecurr);
                                } else {
-                                       WARN("Use #include <linux/$file> 
instead of <asm/$file>\n" . $herecurr);
+                                       WARN("INCLUDE_LINUX",
+                                            "Use #include <linux/$file> 
instead of <asm/$file>\n" . $herecurr);
                                }
                        }
                }
@@ -2413,47 +3635,13 @@ sub process {
                        my $cnt = $realcnt;
                        my ($off, $dstat, $dcond, $rest);
                        my $ctx = '';
-
-                       my $args = defined($1);
-
-                       # Find the end of the macro and limit our statement
-                       # search to that.
-                       while ($cnt > 0 && defined $lines[$ln - 1] &&
-                               $lines[$ln - 1] =~ /^(?:-|..*\\$)/)
-                       {
-                               $ctx .= $rawlines[$ln - 1] . "\n";
-                               $cnt-- if ($lines[$ln - 1] !~ /^-/);
-                               $ln++;
-                       }
-                       $ctx .= $rawlines[$ln - 1];
-
                        ($dstat, $dcond, $ln, $cnt, $off) =
-                               ctx_statement_block($linenr, $ln - $linenr + 1, 
0);
+                               ctx_statement_block($linenr, $realcnt, 0);
+                       $ctx = $dstat;
                        #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> 
off<$off>\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 = '';
-                       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++;
-                               $off = 0;
-                       }
-                       $rest =~ s/\\\n.//g;
-                       $rest =~ s/^\s*//s;
-                       $rest =~ s/\s*$//s;
-
-                       # Clean up the original statement.
-                       if ($args) {
-                               substr($dstat, 0, length($dcond), '');
-                       } else {
-                               $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//;
-                       }
+                       $dstat =~ 
s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//;
                        $dstat =~ s/$;//g;
                        $dstat =~ s/\\\n.//g;
                        $dstat =~ s/^\s*//s;
@@ -2462,14 +3650,20 @@ sub process {
                        # Flatten any parentheses and braces
                        while ($dstat =~ s/\([^\(\)]*\)/1/ ||
                               $dstat =~ s/\{[^\{\}]*\}/1/ ||
-                              $dstat =~ s/\[[^\{\}]*\]/1/)
+                              $dstat =~ s/\[[^\[\]]*\]/1/)
+                       {
+                       }
+
+                       # Flatten any obvious string concatentation.
+                       while ($dstat =~ s/("X*")\s*$Ident/$1/ ||
+                              $dstat =~ s/$Ident\s*("X*")/$1/)
                        {
                        }
 
                        my $exceptions = qr{
                                $Declare|
                                module_param_named|
-                               MODULE_PARAM_DESC|
+                               MODULE_PARM_DESC|
                                DECLARE_PER_CPU|
                                DEFINE_PER_CPU|
                                __typeof__\(|
@@ -2479,21 +3673,86 @@ sub process {
                                ^\"|\"$
                        }x;
                        #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
-                       if ($rest ne '' && $rest ne ',') {
-                               if ($rest !~ /while\s*\(/ &&
-                                   $dstat !~ /$exceptions/)
-                               {
-                                       ERROR("Macros with multiple statements 
should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
+                       if ($dstat ne '' &&
+                           $dstat !~ /^(?:$Ident|-?$Constant),$/ &&            
        # 10, // foo(),
+                           $dstat !~ /^(?:$Ident|-?$Constant);$/ &&            
        # foo();
+                           $dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ &&          
# 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz
+                           $dstat !~ /^'X'$/ &&                                
        # character constants
+                           $dstat !~ /$exceptions/ &&
+                           $dstat !~ /^\.$Ident\s*=/ &&                        
        # .foo =
+                           $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ &&  
        # stringification #foo
+                           $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ 
&&       # do {...} while (...); // do {...} while (...)
+                           $dstat !~ /^for\s*$Constant$/ &&                    
        # for (...)
+                           $dstat !~ 
/^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ &&   # for (...) bar()
+                           $dstat !~ /^do\s*{/ &&                              
        # do {...
+                           $dstat !~ /^\({/ &&                                 
        # ({...
+                           $ctx !~ 
/^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/)
+                       {
+                               $ctx =~ s/\n*$//;
+                               my $herectx = $here . "\n";
+                               my $cnt = statement_rawlines($ctx);
+
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . 
"\n";
                                }
 
-                       } elsif ($ctx !~ /;/) {
-                               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");
+                               if ($dstat =~ /;/) {
+                                       
ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
+                                             "Macros with multiple statements 
should be enclosed in a do - while loop\n" . "$herectx");
+                               } else {
+                                       ERROR("COMPLEX_MACRO",
+                                             "Macros with complex values 
should be enclosed in parenthesis\n" . "$herectx");
+                               }
+                       }
+
+# check for line continuations outside of #defines, preprocessor #, and asm
+
+               } else {
+                       if ($prevline !~ /^..*\\$/ &&
+                           $line !~ /^\+\s*\#.*\\$/ &&         # preprocessor
+                           $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ &&   # asm
+                           $line =~ /^\+.*\\$/) {
+                               WARN("LINE_CONTINUATIONS",
+                                    "Avoid unnecessary line continuations\n" . 
$herecurr);
+                       }
+               }
+
+# do {} while (0) macro tests:
+# single-statement macros do not need to be enclosed in do while (0) loop,
+# macro should not end with a semicolon
+               if ($^V && $^V ge 5.10.0 &&
+                   $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;
+
+                       $dstat =~ s/\\\n.//g;
+
+                       if ($dstat =~ 
/^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/)
 {
+                               my $stmts = $2;
+                               my $semis = $3;
+
+                               $ctx =~ s/\n*$//;
+                               my $cnt = statement_rawlines($ctx);
+                               my $herectx = $here . "\n";
+
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . 
"\n";
+                               }
+
+                               if (($stmts =~ tr/;/;/) == 1 &&
+                                   $stmts !~ /^\s*(if|while|for|switch)\b/) {
+                                       WARN("SINGLE_STATEMENT_DO_WHILE_MACRO",
+                                            "Single statement macros should 
not use a do {} while (0) loop\n" . "$herectx");
+                               }
+                               if (defined $semis && $semis ne "") {
+                                       
WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON",
+                                            "do {} while (0) macros should not 
be semicolon terminated\n" . "$herectx");
                                }
                        }
                }
@@ -2504,20 +3763,19 @@ sub process {
 #      ALIGN(...)
 #      VMLINUX_SYMBOL(...)
                if ($realfile eq 'vmlinux.lds.h' && $line =~ 
/(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
-                       WARN("vmlinux.lds.h needs VMLINUX_SYMBOL() around 
C-visible symbols\n" . $herecurr);
+                       WARN("MISSING_VMLINUX_SYMBOL",
+                            "vmlinux.lds.h needs VMLINUX_SYMBOL() around 
C-visible symbols\n" . $herecurr);
                }
 
-# check for missing bracing round if etc
-               if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) {
+# check for redundant bracing round if etc
+               if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
                        my ($level, $endln, @chunks) =
                                ctx_statement_full($linenr, $realcnt, 1);
-                        if ($dbg_adv_apw) {
-                            print "APW: chunks<$#chunks> linenr<$linenr> 
endln<$endln> level<$level>\n";
-                            print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"
-                                if $#chunks >= 1;
-                        }
-                       if ($#chunks >= 0 && $level == 0) {
-                               my $allowed = 0;
+                       #print "chunks<$#chunks> linenr<$linenr> endln<$endln> 
level<$level>\n";
+                       #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+                       if ($#chunks > 0 && $level == 0) {
+                               my @allowed = ();
+                               my $allow = 0;
                                my $seen = 0;
                                my $herectx = $here . "\n";
                                my $ln = $linenr - 1;
@@ -2528,6 +3786,7 @@ sub process {
                                        my ($whitespace) = ($cond =~ 
/^((?:\s*\n[+-])*\s*)/s);
                                        my $offset = 
statement_rawlines($whitespace) - 1;
 
+                                       $allowed[$allow] = 0;
                                        #print "COND<$cond> 
whitespace<$whitespace> offset<$offset>\n";
 
                                        # We have looked at and allowed this 
specific line.
@@ -2540,70 +3799,67 @@ sub process {
 
                                        $seen++ if ($block =~ /^\s*{/);
 
-                                        print "APW: cond<$cond> block<$block> 
allowed<$allowed>\n"
-                                            if $dbg_adv_apw;
+                                       #print "cond<$cond> block<$block> 
allowed<$allowed[$allow]>\n";
                                        if (statement_lines($cond) > 1) {
-                                            print "APW: ALLOWED: cond<$cond>\n"
-                                                if $dbg_adv_apw;
-                                            $allowed = 1;
+                                               #print "APW: ALLOWED: 
cond<$cond>\n";
+                                               $allowed[$allow] = 1;
                                        }
                                        if ($block =~/\b(?:if|for|while)\b/) {
-                                            print "APW: ALLOWED: 
block<$block>\n"
-                                                if $dbg_adv_apw;
-                                            $allowed = 1;
+                                               #print "APW: ALLOWED: 
block<$block>\n";
+                                               $allowed[$allow] = 1;
                                        }
                                        if (statement_block_size($block) > 1) {
-                                            print "APW: ALLOWED: lines 
block<$block>\n"
-                                                if $dbg_adv_apw;
-                                            $allowed = 1;
+                                               #print "APW: ALLOWED: lines 
block<$block>\n";
+                                               $allowed[$allow] = 1;
                                        }
+                                       $allow++;
                                }
-                               if ($seen != ($#chunks + 1)) {
-                                       WARN("braces {} are necessary for all 
arms of this statement\n" . $herectx);
+                               if ($seen) {
+                                       my $sum_allowed = 0;
+                                       foreach (@allowed) {
+                                               $sum_allowed += $_;
+                                       }
+                                       if ($sum_allowed == 0) {
+                                               WARN("BRACES",
+                                                    "braces {} are not 
necessary for any arm of this statement\n" . $herectx);
+                                       } elsif ($sum_allowed != $allow &&
+                                                $seen != $allow) {
+                                               CHK("BRACES",
+                                                   "braces {} should be used 
on all arms of this statement\n" . $herectx);
+                                       }
                                }
                        }
                }
                if (!defined $suppress_ifbraces{$linenr - 1} &&
-                                       $line =~ /\b(if|while|for|else)\b/ &&
-                                       $line !~ /\#\s*if/ &&
-                                       $line !~ /\#\s*else/) {
+                                       $line =~ /\b(if|while|for|else)\b/) {
                        my $allowed = 0;
 
-                        # Check the pre-context.
-                        if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
-                            my $pre = $1;
-
-                            if ($line !~ /else/) {
-                                print "APW: ALLOWED: pre<$pre> line<$line>\n"
-                                    if $dbg_adv_apw;
-                                $allowed = 1;
-                            }
-                        }
+                       # Check the pre-context.
+                       if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+                               #print "APW: ALLOWED: pre<$1>\n";
+                               $allowed = 1;
+                       }
 
                        my ($level, $endln, @chunks) =
                                ctx_statement_full($linenr, $realcnt, $-[0]);
 
                        # Check the condition.
                        my ($cond, $block) = @{$chunks[0]};
-                        print "CHECKING<$linenr> cond<$cond> block<$block>\n"
-                            if $dbg_adv_checking;
+                       #print "CHECKING<$linenr> cond<$cond> block<$block>\n";
                        if (defined $cond) {
                                substr($block, 0, length($cond), '');
                        }
                        if (statement_lines($cond) > 1) {
-                            print "APW: ALLOWED: cond<$cond>\n"
-                                if $dbg_adv_apw;
-                            $allowed = 1;
+                               #print "APW: ALLOWED: cond<$cond>\n";
+                               $allowed = 1;
                        }
                        if ($block =~/\b(?:if|for|while)\b/) {
-                            print "APW: ALLOWED: block<$block>\n"
-                                if $dbg_adv_apw;
-                            $allowed = 1;
+                               #print "APW: ALLOWED: block<$block>\n";
+                               $allowed = 1;
                        }
                        if (statement_block_size($block) > 1) {
-                            print "APW: ALLOWED: lines block<$block>\n"
-                                if $dbg_adv_apw;
-                            $allowed = 1;
+                               #print "APW: ALLOWED: lines block<$block>\n";
+                               $allowed = 1;
                        }
                        # Check the post-context.
                        if (defined $chunks[1]) {
@@ -2612,86 +3868,150 @@ sub process {
                                        substr($block, 0, length($cond), '');
                                }
                                if ($block =~ /^\s*\{/) {
-                                    print "APW: ALLOWED: chunk-1 
block<$block>\n"
-                                        if $dbg_adv_apw;
-                                    $allowed = 1;
+                                       #print "APW: ALLOWED: chunk-1 
block<$block>\n";
+                                       $allowed = 1;
                                }
                        }
-                        print "DCS: level=$level block<$block> 
allowed=$allowed\n"
-                            if $dbg_adv_dcs;
-                       if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) {
-                               my $herectx = $here . "\n";;
+                       if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
+                               my $herectx = $here . "\n";
                                my $cnt = statement_rawlines($block);
 
                                for (my $n = 0; $n < $cnt; $n++) {
-                                       $herectx .= raw_line($linenr, $n) . 
"\n";;
+                                       $herectx .= raw_line($linenr, $n) . 
"\n";
                                }
 
-                               WARN("braces {} are necessary even for single 
statement blocks\n" . $herectx);
+                               WARN("BRACES",
+                                    "braces {} are not necessary for single 
statement blocks\n" . $herectx);
                        }
                }
 
-# don't include deprecated include files (uses RAW line)
-               for my $inc (@dep_includes) {
-                       if ($rawline =~ address@hidden<$inc>@) {
-                               ERROR("Don't use <$inc>: see 
Documentation/feature-removal-schedule.txt\n" . $herecurr);
-                       }
+# check for unnecessary blank lines around braces
+               if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) {
+                       CHK("BRACES",
+                           "Blank lines aren't necessary before a close brace 
'}'\n" . $hereprev);
                }
-
-# don't use deprecated functions
-               for my $func (@dep_functions) {
-                       if ($line =~ /\b$func\b/) {
-                               ERROR("Don't use $func(): see 
Documentation/feature-removal-schedule.txt\n" . $herecurr);
-                       }
+               if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) {
+                       CHK("BRACES",
+                           "Blank lines aren't necessary after an open brace 
'{'\n" . $hereprev);
                }
 
 # no volatiles please
                my $asm_volatile = 
qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
                if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
-                       WARN("Use of volatile is usually wrong: see 
Documentation/volatile-considered-harmful.txt\n" . $herecurr);
-               }
-
-# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated
-               if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) {
-                       ERROR("Use of $1 is deprecated: see 
Documentation/spinlocks.txt\n" . $herecurr);
+                       WARN("VOLATILE",
+                            "Use of volatile is usually wrong: see 
Documentation/volatile-considered-harmful.txt\n" . $herecurr);
                }
 
 # warn about #if 0
                if ($line =~ /^.\s*\#\s*if\s+0\b/) {
-                       CHK("if this code is redundant consider removing it\n" .
+                       CHK("REDUNDANT_CODE",
+                           "if this code is redundant consider removing it\n" .
                                $herecurr);
                }
 
-# check for needless kfree() checks
-               if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
-                       my $expr = $1;
-                       if ($line =~ /\bkfree\(\Q$expr\E\);/) {
-                               WARN("kfree(NULL) is safe this check is 
probably not required\n" . $hereprev);
+# check for needless "if (<foo>) fn(<foo>)" uses
+               if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) {
+                       my $expr = '\s*\(\s*' . quotemeta($1) . '\s*\)\s*;';
+                       if ($line =~ 
/\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?)$expr/) {
+                               WARN('NEEDLESS_IF',
+                                    "$1(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);
+
+# check for bad placement of section $InitAttribute (e.g.: __initdata)
+               if ($line =~ /(\b$InitAttribute\b)/) {
+                       my $attr = $1;
+                       if ($line =~ 
/^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/)
 {
+                               my $ptr = $1;
+                               my $var = $2;
+                               if ((($ptr =~ /\b(union|struct)\s+$attr\b/ &&
+                                     ERROR("MISPLACED_INIT",
+                                           "$attr should be placed after 
$var\n" . $herecurr)) ||
+                                    ($ptr !~ /\b(union|struct)\s+$attr\b/ &&
+                                     WARN("MISPLACED_INIT",
+                                          "$attr should be placed after 
$var\n" . $herecurr))) &&
+                                   $fix) {
+                                       $fixed[$linenr - 1] =~ 
s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1"
 . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . 
trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? 
";" : " = ")/e;
+                               }
+                       }
+               }
+
+# check for $InitAttributeData (ie: __initdata) with const
+               if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) {
+                       my $attr = $1;
+                       $attr =~ /($InitAttributePrefix)(.*)/;
+                       my $attr_prefix = $1;
+                       my $attr_type = $2;
+                       if (ERROR("INIT_ATTRIBUTE",
+                                 "Use of const init definition must use 
${attr_prefix}initconst\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   
s/$InitAttributeData/${attr_prefix}initconst/;
+                       }
+               }
+
+# check for $InitAttributeConst (ie: __initconst) without const
+               if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) {
+                       my $attr = $1;
+                       if (ERROR("INIT_ATTRIBUTE",
+                                 "Use of $attr requires a separate use of 
const\n" . $herecurr) &&
+                           $fix) {
+                               my $lead = $fixed[$linenr - 1] =~
+                                   /(^\+\s*(?:static\s+))/;
+                               $lead = rtrim($1);
+                               $lead = "$lead " if ($lead !~ /^\+$/);
+                               $lead = "${lead}const ";
+                               $fixed[$linenr - 1] =~ 
s/(^\+\s*(?:static\s+))/$lead/;
+                       }
+               }
+
+# don't use __constant_<foo> functions outside of include/uapi/
+               if ($realfile !~ address@hidden/uapi/@ &&
+                   $line =~ 
/(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/)
 {
+                       my $constant_func = $1;
+                       my $func = $constant_func;
+                       $func =~ s/^__constant_//;
+                       if (WARN("CONSTANT_CONVERSION",
+                                "$constant_func should be $func\n" . 
$herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\b$constant_func\b/$func/g;
                        }
                }
 
 # prefer usleep_range over udelay
-               if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) {
+               if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
+                       my $delay = $1;
                        # ignore udelay's < 10, however
-                       if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) {
-                               CHK("usleep_range is preferred over udelay; see 
Documentation/timers/timers-howto.txt\n" . $line);
+                       if (! ($delay < 10) ) {
+                               CHK("USLEEP_RANGE",
+                                   "usleep_range is preferred over udelay; see 
Documentation/timers/timers-howto.txt\n" . $herecurr);
+                       }
+                       if ($delay > 2000) {
+                               WARN("LONG_UDELAY",
+                                    "long udelay - prefer mdelay; see 
arch/arm/include/asm/delay.h\n" . $herecurr);
                        }
                }
 
 # warn about unexpectedly long msleep's
                if ($line =~ /\bmsleep\s*\((\d+)\);/) {
                        if ($1 < 20) {
-                               WARN("msleep < 20ms can sleep for up to 20ms; 
see Documentation/timers/timers-howto.txt\n" . $line);
+                               WARN("MSLEEP",
+                                    "msleep < 20ms can sleep for up to 20ms; 
see Documentation/timers/timers-howto.txt\n" . $herecurr);
                        }
                }
 
+# check for comparisons of jiffies
+               if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) {
+                       WARN("JIFFIES_COMPARISON",
+                            "Comparing jiffies is almost always wrong; prefer 
time_after, time_before and friends\n" . $herecurr);
+               }
+
+# check for comparisons of get_jiffies_64()
+               if ($line =~ 
/\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) {
+                       WARN("JIFFIES_COMPARISON",
+                            "Comparing get_jiffies_64() is almost always 
wrong; prefer time_after64, time_before64 and friends\n" . $herecurr);
+               }
+
 # warn about #ifdefs in C files
 #              if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
 #                      print "#ifdef in C files should be avoided\n";
@@ -2701,7 +4021,13 @@ sub process {
 
 # warn about spacing in #ifdefs
                if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
-                       ERROR("exactly one space required after that #$1\n" . 
$herecurr);
+                       if (ERROR("SPACING",
+                                 "exactly one space required after that #$1\n" 
. $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 
/;
+                       }
+
                }
 
 # check for spinlock_t definitions without a comment.
@@ -2709,40 +4035,215 @@ sub process {
                    $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
                        my $which = $1;
                        if (!ctx_has_comment($first_line, $linenr)) {
-                               CHK("$1 definition without comment\n" . 
$herecurr);
+                               CHK("UNCOMMENTED_DEFINITION",
+                                   "$1 definition without comment\n" . 
$herecurr);
                        }
                }
 # check for memory barriers without a comment.
                if ($line =~ 
/\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/)
 {
                        if (!ctx_has_comment($first_line, $linenr)) {
-                               CHK("memory barrier without comment\n" . 
$herecurr);
+                               WARN("MEMORY_BARRIER",
+                                    "memory barrier without comment\n" . 
$herecurr);
                        }
                }
 # check of hardware specific defines
                if ($line =~ 
address@hidden(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ 
address@hidden/asm-@) {
-                       CHK("architecture specific defines should be avoided\n" 
.  $herecurr);
+                       CHK("ARCH_DEFINES",
+                           "architecture specific defines should be avoided\n" 
.  $herecurr);
                }
 
 # Check that the storage class is at the beginning of a declaration
                if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
-                       WARN("storage class should be at the beginning of the 
declaration\n" . $herecurr)
+                       WARN("STORAGE_CLASS",
+                            "storage class should be at the beginning of the 
declaration\n" . $herecurr)
                }
 
 # check the location of the inline attribute, that it is between
 # storage class and type.
                if ($line =~ /\b$Type\s+$Inline\b/ ||
                    $line =~ /\b$Inline\s+$Storage\b/) {
-                       ERROR("inline keyword should sit between storage class 
and type\n" . $herecurr);
+                       ERROR("INLINE_LOCATION",
+                             "inline keyword should sit between storage class 
and type\n" . $herecurr);
                }
 
 # Check for __inline__ and __inline, prefer inline
-               if ($line =~ /\b(__inline__|__inline)\b/) {
-                       WARN("plain inline is preferred over $1\n" . $herecurr);
+               if ($realfile !~ address@hidden/uapi/@ &&
+                   $line =~ /\b(__inline__|__inline)\b/) {
+                       if (WARN("INLINE",
+                                "plain inline is preferred over $1\n" . 
$herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\b(__inline__|__inline)\b/inline/;
+
+                       }
+               }
+
+# Check for __attribute__ packed, prefer __packed
+               if ($realfile !~ address@hidden/uapi/@ &&
+                   $line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) {
+                       WARN("PREFER_PACKED",
+                            "__packed is preferred over 
__attribute__((packed))\n" . $herecurr);
+               }
+
+# Check for __attribute__ aligned, prefer __aligned
+               if ($realfile !~ address@hidden/uapi/@ &&
+                   $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) {
+                       WARN("PREFER_ALIGNED",
+                            "__aligned(size) is preferred over 
__attribute__((aligned(size)))\n" . $herecurr);
+               }
+
+# Check for __attribute__ format(printf, prefer __printf
+               if ($realfile !~ address@hidden/uapi/@ &&
+                   $line =~ 
/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) {
+                       if (WARN("PREFER_PRINTF",
+                                "__printf(string-index, first-to-check) is 
preferred over __attribute__((format(printf, string-index, first-to-check)))\n" 
. $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf("
 . trim($1) . ")"/ex;
+
+                       }
+               }
+
+# Check for __attribute__ format(scanf, prefer __scanf
+               if ($realfile !~ address@hidden/uapi/@ &&
+                   $line =~ 
/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) {
+                       if (WARN("PREFER_SCANF",
+                                "__scanf(string-index, first-to-check) is 
preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" 
. $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf("
 . trim($1) . ")"/ex;
+                       }
                }
 
 # check for sizeof(&)
                if ($line =~ /\bsizeof\s*\(\s*\&/) {
-                       WARN("sizeof(& should be avoided\n" . $herecurr);
+                       WARN("SIZEOF_ADDRESS",
+                            "sizeof(& should be avoided\n" . $herecurr);
+               }
+
+# check for sizeof without parenthesis
+               if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) 
{
+                       if (WARN("SIZEOF_PARENTHESIS",
+                                "sizeof $1 should be sizeof($1)\n" . 
$herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex;
+                       }
+               }
+
+# check for line continuations in quoted strings with odd counts of "
+               if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
+                       WARN("LINE_CONTINUATIONS",
+                            "Avoid line continuations in quoted strings\n" . 
$herecurr);
+               }
+
+# check for struct spinlock declarations
+               if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) {
+                       WARN("USE_SPINLOCK_T",
+                            "struct spinlock should be spinlock_t\n" . 
$herecurr);
+               }
+
+# check for seq_printf uses that could be seq_puts
+               if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) {
+                       my $fmt = get_quoted_string($line, $rawline);
+                       if ($fmt ne "" && $fmt !~ /[^\\]\%/) {
+                               if (WARN("PREFER_SEQ_PUTS",
+                                        "Prefer seq_puts to seq_printf\n" . 
$herecurr) &&
+                                   $fix) {
+                                       $fixed[$linenr - 1] =~ 
s/\bseq_printf\b/seq_puts/;
+                               }
+                       }
+               }
+
+# Check for misused memsets
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
+                   $stat =~ 
/^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) {
+
+                       my $ms_addr = $2;
+                       my $ms_val = $7;
+                       my $ms_size = $12;
+
+                       if ($ms_size =~ /^(0x|)0$/i) {
+                               ERROR("MEMSET",
+                                     "memset to 0's uses 0 as the 2nd 
argument, not the 3rd\n" . "$here\n$stat\n");
+                       } elsif ($ms_size =~ /^(0x|)1$/i) {
+                               WARN("MEMSET",
+                                    "single byte memset is suspicious. Swapped 
2nd/3rd argument?\n" . "$here\n$stat\n");
+                       }
+               }
+
+# Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar)
+               if ($^V && $^V ge 5.10.0 &&
+                   $line =~ 
/^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/s) {
+                       if (WARN("PREFER_ETHER_ADDR_COPY",
+                                "Prefer ether_addr_copy() over memcpy() if the 
Ethernet addresses are __aligned(2)\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2,
 $7)/;
+                       }
+               }
+
+# typecasts on min/max could be min_t/max_t
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
+                   $stat =~ 
/^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
+                       if (defined $2 || defined $7) {
+                               my $call = $1;
+                               my $cast1 = deparenthesize($2);
+                               my $arg1 = $3;
+                               my $cast2 = deparenthesize($7);
+                               my $arg2 = $8;
+                               my $cast;
+
+                               if ($cast1 ne "" && $cast2 ne "" && $cast1 ne 
$cast2) {
+                                       $cast = "$cast1 or $cast2";
+                               } elsif ($cast1 ne "") {
+                                       $cast = $cast1;
+                               } else {
+                                       $cast = $cast2;
+                               }
+                               WARN("MINMAX",
+                                    "$call() should probably be 
${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n");
+                       }
+               }
+
+# check usleep_range arguments
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
+                   $stat =~ 
/^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
+                       my $min = $1;
+                       my $max = $7;
+                       if ($min eq $max) {
+                               WARN("USLEEP_RANGE",
+                                    "usleep_range should not use min == max 
args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+                       } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ &&
+                                $min > $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 naked sscanf
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
+                   $line =~ /\bsscanf\b/ &&
+                   ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ &&
+                    $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ &&
+                    $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) {
+                       my $lc = $stat =~ address@hidden@@;
+                       $lc = $lc + $linenr;
+                       my $stat_real = raw_line($linenr, 0);
+                       for (my $count = $linenr + 1; $count <= $lc; $count++) {
+                               $stat_real = $stat_real . "\n" . 
raw_line($count, 0);
+                       }
+                       WARN("NAKED_SSCANF",
+                            "unchecked sscanf return value\n" . 
"$here\n$stat_real\n");
+               }
+
+# check for new externs in .h files.
+               if ($realfile =~ /\.h$/ &&
+                   $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) {
+                       if (CHK("AVOID_EXTERNS",
+                               "extern prototypes should be avoided in .h 
files\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/(.*)\bextern\b\s*(.*)/$1$2/;
+                       }
                }
 
 # check for new externs in .c files.
@@ -2759,17 +4260,20 @@ sub process {
                        if ($s =~ /^\s*;/ &&
                            $function_name ne 'uninitialized_var')
                        {
-                               WARN("externs should be avoided in .c files\n" 
.  $herecurr);
+                               WARN("AVOID_EXTERNS",
+                                    "externs should be avoided in .c files\n" 
.  $herecurr);
                        }
 
                        if ($paren_space =~ /\n/) {
-                               WARN("arguments for function declarations 
should follow identifier\n" . $herecurr);
+                               WARN("FUNCTION_ARGUMENTS",
+                                    "arguments for function declarations 
should follow identifier\n" . $herecurr);
                        }
 
                } elsif ($realfile =~ /\.c$/ && defined $stat &&
                    $stat =~ /^.\s*extern\s+/)
                {
-                       WARN("externs should be avoided in .c files\n" .  
$herecurr);
+                       WARN("AVOID_EXTERNS",
+                            "externs should be avoided in .c files\n" .  
$herecurr);
                }
 
 # checks for new __setup's
@@ -2777,37 +4281,146 @@ sub process {
                        my $name = $1;
 
                        if (!grep(/$name/, @setup_docs)) {
-                               CHK("__setup appears un-documented -- check 
Documentation/kernel-parameters.txt\n" . $herecurr);
+                               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*k[czm]alloc\b/) {
-                       WARN("unnecessary cast may hide bugs, see 
http://c-faq.com/malloc/mallocnocast.html\n"; . $herecurr);
+               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*$/) {
+                       if (WARN("ONE_SEMICOLON",
+                                "Statements terminations use 1 semicolon\n" . 
$herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/(\s*;\s*){2,}$/;/g;
+                       }
+               }
+
+# check for case / default statements not preceeded by break/fallthrough/switch
+               if ($line =~ 
/^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) {
+                       my $has_break = 0;
+                       my $has_statement = 0;
+                       my $count = 0;
+                       my $prevline = $linenr;
+                       while ($prevline > 1 && $count < 3 && !$has_break) {
+                               $prevline--;
+                               my $rline = $rawlines[$prevline - 1];
+                               my $fline = $lines[$prevline - 1];
+                               last if ($fline =~ /address@hidden@/);
+                               next if ($fline =~ /^\-/);
+                               next if ($fline =~ 
/^.(?:\s*(?:case\s+(?:$Ident|$Constant)[\s$;]*|default):[\s$;]*)*$/);
+                               $has_break = 1 if ($rline =~ 
/fall[\s_-]*(through|thru)/i);
+                               next if ($fline =~ /^.[\s$;]*$/);
+                               $has_statement = 1;
+                               $count++;
+                               $has_break = 1 if ($fline =~ 
/\bswitch\b|\b(?:break\s*;[\s$;]*$|return\b|goto\b|continue\b)/);
+                       }
+                       if (!$has_break && $has_statement) {
+                               WARN("MISSING_BREAK",
+                                    "Possible switch case/default not 
preceeded by break or fallthrough comment\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("__func__ should be used instead of gcc specific 
__FUNCTION__\n"  . $herecurr);
+               if ($line =~ /\b__FUNCTION__\b/) {
+                       if (WARN("USE_FUNC",
+                                "__func__ should be used instead of gcc 
specific __FUNCTION__\n"  . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ 
s/\b__FUNCTION__\b/__func__/g;
+                       }
                }
 
-# check for semaphores used as mutexes
-               if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
-                       WARN("mutexes are preferred for single holder 
semaphores\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 semaphores used as mutexes
-               if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
-                       WARN("consider using a completion\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 strict_strto* over simple_strto*
-               if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
-                       WARN("consider using strict_$1 in preference to 
simple_$1\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("please use device_initcall() instead of 
__initcall()\n" . $herecurr);
+                       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|
@@ -2848,7 +4461,8 @@ sub process {
                                wd_ops}x;
                if ($line !~ /\bconst\b/ &&
                    $line =~ /\bstruct\s+($struct_ops)\b/) {
-                       WARN("struct $1 should normally be const\n" .
+                       WARN("CONST_STRUCT",
+                            "struct $1 should normally be const\n" .
                                $herecurr);
                }
 
@@ -2861,7 +4475,14 @@ sub process {
                    $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
                    $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
                {
-                       WARN("usage of NR_CPUS is often wrong - consider using 
cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . 
$herecurr);
+                       WARN("NR_CPUS",
+                            "usage of NR_CPUS is often wrong - consider using 
cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . 
$herecurr);
+               }
+
+# Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong.
+               if ($line =~ 
/\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) {
+                       ERROR("DEFINE_ARCH_HAS",
+                             "#define of '$1' is wrong - use Kconfig variables 
or standard guards instead\n" . $herecurr);
                }
 
 # check for %L{u,d,i} in strings
@@ -2870,7 +4491,8 @@ sub process {
                        $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);
+                               WARN("PRINTF_L",
+                                    "\%Ld/%Lu are not-standard C, use 
%lld/%llu\n" . $herecurr);
                                last;
                        }
                }
@@ -2878,9 +4500,11 @@ sub process {
 # whine mightly about in_atomic
                if ($line =~ /\bin_atomic\s*\(/) {
                        if ($realfile =~ address@hidden/@) {
-                               ERROR("do not use in_atomic in drivers\n" . 
$herecurr);
+                               ERROR("IN_ATOMIC",
+                                     "do not use in_atomic in drivers\n" . 
$herecurr);
                        } elsif ($realfile !~ address@hidden/@) {
-                               WARN("use of in_atomic() is incorrect outside 
core kernel code\n" . $herecurr);
+                               WARN("IN_ATOMIC",
+                                    "use of in_atomic() is incorrect outside 
core kernel code\n" . $herecurr);
                        }
                }
 
@@ -2890,13 +4514,43 @@ sub process {
                        if ($realfile !~ address@hidden/lockdep@ &&
                            $realfile !~ address@hidden/linux/lockdep@ &&
                            $realfile !~ address@hidden/base/core@) {
-                               ERROR("lockdep_no_validate class is reserved 
for device->mutex.\n" . $herecurr);
+                               ERROR("LOCKDEP",
+                                     "lockdep_no_validate class is reserved 
for device->mutex.\n" . $herecurr);
                        }
                }
 
-# QEMU specific tests
-               if ($rawline =~ /\b(?:Qemu|QEmu)\b/) {
-                       WARN("use QEMU instead of Qemu or QEmu\n" . $herecurr);
+               if ($line =~ /debugfs_create_file.*S_IWUGO/ ||
+                   $line =~ /DEVICE_ATTR.*S_IWUGO/ ) {
+                       WARN("EXPORTED_WORLD_WRITABLE",
+                            "Exporting world writable files is usually an 
error. Consider more restrictive permissions.\n" . $herecurr);
+               }
+
+# Mode permission misuses where it seems decimal should be octal
+# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop
+               if ($^V && $^V ge 5.10.0 &&
+                   $line =~ /$mode_perms_search/) {
+                       foreach my $entry (@mode_permission_funcs) {
+                               my $func = $entry->[0];
+                               my $arg_pos = $entry->[1];
+
+                               my $skip_args = "";
+                               if ($arg_pos > 1) {
+                                       $arg_pos--;
+                                       $skip_args = 
"(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}";
+                               }
+                               my $test = 
"\\b$func\\s*\\(${skip_args}([\\d]+)\\s*[,\\)]";
+                               if ($line =~ /$test/) {
+                                       my $val = $1;
+                                       $val = $6 if ($skip_args ne "");
+
+                                       if ($val !~ /^0$/ &&
+                                           (($val =~ /^$Int$/ && $val !~ 
/^$Octal$/) ||
+                                            length($val) ne 4)) {
+                                               ERROR("NON_OCTAL_PERMISSIONS",
+                                                     "Use 4 digit octal (0777) 
not decimal permissions\n" . $herecurr);
+                                       }
+                               }
+                       }
                }
        }
 
@@ -2919,10 +4573,12 @@ sub process {
        }
 
        if (!$is_patch) {
-               ERROR("Does not appear to be a unified-diff format patch\n");
+               ERROR("NOT_UNIFIED_DIFF",
+                     "Does not appear to be a unified-diff format patch\n");
        }
        if ($is_patch && $chk_signoff && $signoff == 0) {
-               ERROR("Missing Signed-off-by: line(s)\n");
+               ERROR("MISSING_SIGN_OFF",
+                     "Missing Signed-off-by: line(s)\n");
        }
 
        print report_dump();
@@ -2935,21 +4591,61 @@ sub process {
        }
 
        if ($quiet == 0) {
-               # If there were whitespace errors which cleanpatch can fix
-               # then suggest that.
-#              if ($rpt_cleaners) {
-#                      print "NOTE: whitespace errors detected, you may wish 
to use scripts/cleanpatch or\n";
-#                      print "      scripts/cleanfile\n\n";
-#              }
+
+               if ($^V lt 5.10.0) {
+                       print("NOTE: perl $^V is not modern enough to detect 
all possible issues.\n");
+                       print("An upgrade to at least perl v5.10.0 is 
suggested.\n\n");
+               }
+       }
+
+       hash_show_words(\%use_type, "Used");
+       hash_show_words(\%ignore_type, "Ignored");
+
+       if ($clean == 0 && $fix && "@rawlines" ne "@fixed") {
+               my $newfile = $filename;
+               $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace);
+               my $linecount = 0;
+               my $f;
+
+               open($f, '>', $newfile)
+                   or die "$P: Can't open $newfile for write\n";
+               foreach my $fixed_line (@fixed) {
+                       $linecount++;
+                       if ($file) {
+                               if ($linecount > 3) {
+                                       $fixed_line =~ s/^\+//;
+                                       print $f $fixed_line. "\n";
+                               }
+                       } else {
+                               print $f $fixed_line . "\n";
+                       }
+               }
+               close($f);
+
+               if (!$quiet) {
+                       print << "EOM";
+Wrote EXPERIMENTAL --fix correction(s) to '$newfile'
+
+Do _NOT_ trust the results written to this file.
+Do _NOT_ submit these changes without inspecting them for correctness.
+
+This EXPERIMENTAL file is simply a convenience to help rewrite patches.
+No warranties, expressed or implied...
+
+EOM
+               }
        }
 
        if ($clean == 1 && $quiet == 0) {
                print "$vname has no obvious style problems and is ready for 
submission.\n"
        }
        if ($clean == 0 && $quiet == 0) {
-               print "$vname has style problems, please review.  If any of 
these errors\n";
-               print "are false positives report them to the maintainer, 
see\n";
-               print "CHECKPATCH in MAINTAINERS.\n";
+               print << "EOM";
+$vname has style problems, please review.
+
+If any of these errors are false positives, please report
+them to the maintainer, see CHECKPATCH in MAINTAINERS.
+EOM
        }
 
        return $clean;
-- 
1.9.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]