checkpatch: add fix_insert_line and fix_delete_line helpers
[linux-2.6-block.git] / scripts / checkpatch.pl
index 182be0f124074c6d508d8a97e498ea7925665a1f..7c290693b8af680d6331f6fdd9c690beba5373e4 100755 (executable)
@@ -435,7 +435,7 @@ sub build_types {
                  }x;
        $Type   = qr{
                        $NonptrType
-                       (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
+                       (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)?
                        (?:\s+$Inline|\s+$Modifier)*
                  }x;
        $Declare        = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type};
@@ -550,11 +550,43 @@ sub seed_camelcase_includes {
        }
 }
 
+sub git_commit_info {
+       my ($commit, $id, $desc) = @_;
+
+       return ($id, $desc) if ((which("git") eq "") || !(-e ".git"));
+
+       my $output = `git log --no-color --format='%H %s' -1 $commit 2>&1`;
+       $output =~ s/^\s*//gm;
+       my @lines = split("\n", $output);
+
+       if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous\./) {
+# Maybe one day convert this block of bash into something that returns
+# all matching commit ids, but it's very slow...
+#
+#              echo "checking commits $1..."
+#              git rev-list --remotes | grep -i "^$1" |
+#              while read line ; do
+#                  git log --format='%H %s' -1 $line |
+#                  echo "commit $(cut -c 1-12,41-)"
+#              done
+       } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./) {
+       } else {
+               $id = substr($lines[0], 0, 12);
+               $desc = substr($lines[0], 41);
+       }
+
+       return ($id, $desc);
+}
+
 $chk_signoff = 0 if ($file);
 
 my @rawlines = ();
 my @lines = ();
 my @fixed = ();
+my @fixed_inserted = ();
+my @fixed_deleted = ();
+my $fixlinenr = -1;
+
 my $vname;
 for my $filename (@ARGV) {
        my $FILE;
@@ -583,6 +615,9 @@ for my $filename (@ARGV) {
        @rawlines = ();
        @lines = ();
        @fixed = ();
+       @fixed_inserted = ();
+       @fixed_deleted = ();
+       $fixlinenr = -1;
 }
 
 exit($exit);
@@ -674,6 +709,18 @@ sub format_email {
        return $formatted_email;
 }
 
+sub which {
+    my ($bin) = @_;
+
+    foreach my $path (split(/:/, $ENV{PATH})) {
+       if (-e "$path/$bin") {
+           return "$path/$bin";
+       }
+    }
+
+    return "";
+}
+
 sub which_conf {
        my ($conf) = @_;
 
@@ -1483,6 +1530,90 @@ sub report_dump {
        our @report;
 }
 
+sub fixup_current_range {
+       my ($lineRef, $offset, $length) = @_;
+
+       if ($$lineRef =~ /^\@\@ -\d+,\d+ \+(\d+),(\d+) \@\@/) {
+               my $o = $1;
+               my $l = $2;
+               my $no = $o + $offset;
+               my $nl = $l + $length;
+               $$lineRef =~ s/\+$o,$l \@\@/\+$no,$nl \@\@/;
+       }
+}
+
+sub fix_inserted_deleted_lines {
+       my ($linesRef, $insertedRef, $deletedRef) = @_;
+
+       my $range_last_linenr = 0;
+       my $delta_offset = 0;
+
+       my $old_linenr = 0;
+       my $new_linenr = 0;
+
+       my $next_insert = 0;
+       my $next_delete = 0;
+
+       my @lines = ();
+
+       my $inserted = @{$insertedRef}[$next_insert++];
+       my $deleted = @{$deletedRef}[$next_delete++];
+
+       foreach my $old_line (@{$linesRef}) {
+               my $save_line = 1;
+               my $line = $old_line;   #don't modify the array
+               if ($line =~ /^(?:\+\+\+\|\-\-\-)\s+\S+/) {     #new filename
+                       $delta_offset = 0;
+               } elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) {    #new hunk
+                       $range_last_linenr = $new_linenr;
+                       fixup_current_range(\$line, $delta_offset, 0);
+               }
+
+               while (defined($deleted) && ${$deleted}{'LINENR'} == $old_linenr) {
+                       $deleted = @{$deletedRef}[$next_delete++];
+                       $save_line = 0;
+                       fixup_current_range(\$lines[$range_last_linenr], $delta_offset--, -1);
+               }
+
+               while (defined($inserted) && ${$inserted}{'LINENR'} == $old_linenr) {
+                       push(@lines, ${$inserted}{'LINE'});
+                       $inserted = @{$insertedRef}[$next_insert++];
+                       $new_linenr++;
+                       fixup_current_range(\$lines[$range_last_linenr], $delta_offset++, 1);
+               }
+
+               if ($save_line) {
+                       push(@lines, $line);
+                       $new_linenr++;
+               }
+
+               $old_linenr++;
+       }
+
+       return @lines;
+}
+
+sub fix_insert_line {
+       my ($linenr, $line) = @_;
+
+       my $inserted = {
+               LINENR => $linenr,
+               LINE => $line,
+       };
+       push(@fixed_inserted, $inserted);
+}
+
+sub fix_delete_line {
+       my ($linenr, $line) = @_;
+
+       my $deleted = {
+               LINENR => $linenr,
+               LINE => $line,
+       };
+
+       push(@fixed_deleted, $deleted);
+}
+
 sub ERROR {
        my ($type, $msg) = @_;
 
@@ -1637,11 +1768,13 @@ sub process {
        my $signoff = 0;
        my $is_patch = 0;
 
-       my $in_header_lines = 1;
+       my $in_header_lines = $file ? 0 : 1;
        my $in_commit_log = 0;          #Scanning lines before patch
-
+       my $reported_maintainer_file = 0;
        my $non_utf8_charset = 0;
 
+       my $last_blank_line = 0;
+
        our @report = ();
        our $cnt_lines = 0;
        our $cnt_error = 0;
@@ -1759,8 +1892,10 @@ sub process {
 
        $realcnt = 0;
        $linenr = 0;
+       $fixlinenr = -1;
        foreach my $line (@lines) {
                $linenr++;
+               $fixlinenr++;
                my $sline = $line;      #copy of $line
                $sline =~ s/$;/ /g;     #with comments as spaces
 
@@ -1891,7 +2026,7 @@ sub process {
                                if (WARN("BAD_SIGN_OFF",
                                         "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) &&
                                    $fix) {
-                                       $fixed[$linenr - 1] =
+                                       $fixed[$fixlinenr] =
                                            "$ucfirst_sign_off $email";
                                }
                        }
@@ -1899,7 +2034,7 @@ sub process {
                                if (WARN("BAD_SIGN_OFF",
                                         "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) &&
                                    $fix) {
-                                       $fixed[$linenr - 1] =
+                                       $fixed[$fixlinenr] =
                                            "$ucfirst_sign_off $email";
                                }
 
@@ -1908,7 +2043,7 @@ sub process {
                                if (WARN("BAD_SIGN_OFF",
                                         "Use a single space after $ucfirst_sign_off\n" . $herecurr) &&
                                    $fix) {
-                                       $fixed[$linenr - 1] =
+                                       $fixed[$fixlinenr] =
                                            "$ucfirst_sign_off $email";
                                }
                        }
@@ -1956,6 +2091,31 @@ sub process {
                              "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr);
                }
 
+# Check for improperly formed commit descriptions
+               if ($in_commit_log &&
+                   $line =~ /\bcommit\s+[0-9a-f]{5,}/i &&
+                   $line !~ /\b[Cc]ommit [0-9a-f]{12,16} \("/) {
+                       $line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i;
+                       my $init_char = $1;
+                       my $orig_commit = lc($2);
+                       my $id = '01234567890ab';
+                       my $desc = 'commit description';
+                       ($id, $desc) = git_commit_info($orig_commit, $id, $desc);
+                       ERROR("GIT_COMMIT_ID",
+                             "Please use 12 to 16 chars for the git commit ID like: '${init_char}ommit $id (\"$desc\")'\n" . $herecurr);
+               }
+
+# Check for added, moved or deleted files
+               if (!$reported_maintainer_file && !$in_commit_log &&
+                   ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ ||
+                    $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ ||
+                    ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ &&
+                     (defined($1) || defined($2))))) {
+                       $reported_maintainer_file = 1;
+                       WARN("FILE_PATH_CHANGES",
+                            "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
+               }
+
 # Check for wrappage within a valid hunk of the file
                if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
                        ERROR("CORRUPTED_PATCH",
@@ -1993,7 +2153,8 @@ sub process {
 # 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) {
+                   !($rawline =~ /^\s+\S/ ||
+                     $rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) {
                        $in_header_lines = 0;
                        $in_commit_log = 1;
                }
@@ -2021,14 +2182,14 @@ sub process {
                        if (ERROR("DOS_LINE_ENDINGS",
                                  "DOS line endings\n" . $herevet) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/[\s\015]+$//;
+                               $fixed[$fixlinenr] =~ s/[\s\015]+$//;
                        }
                } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        if (ERROR("TRAILING_WHITESPACE",
                                  "trailing whitespace\n" . $herevet) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/\s+$//;
+                               $fixed[$fixlinenr] =~ s/\s+$//;
                        }
 
                        $rpt_cleaners = 1;
@@ -2049,7 +2210,7 @@ sub process {
 # 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*config\s+/) {
+                   $line =~ /^\+\s*config\s+/) {
                        my $length = 0;
                        my $cnt = $realcnt;
                        my $ln = $linenr + 1;
@@ -2062,10 +2223,11 @@ sub process {
                                $is_end = $lines[$ln - 1] =~ /^\+/;
 
                                next if ($f =~ /^-/);
+                               last if (!$file && $f =~ /^\@\@/);
 
-                               if ($lines[$ln - 1] =~ /.\s*(?:bool|tristate)\s*\"/) {
+                               if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) {
                                        $is_start = 1;
-                               } elsif ($lines[$ln - 1] =~ /.\s*(?:---)?help(?:---)?$/) {
+                               } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) {
                                        $length = -1;
                                }
 
@@ -2166,7 +2328,7 @@ sub process {
                        if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
                                 "unnecessary whitespace before a quoted newline\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/^(\+.*\".*)\s+\\n/$1\\n/;
+                               $fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/;
                        }
 
                }
@@ -2203,7 +2365,7 @@ sub process {
                        if (ERROR("CODE_INDENT",
                                  "code indent should use tabs where possible\n" . $herevet) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e;
+                               $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e;
                        }
                }
 
@@ -2213,9 +2375,9 @@ sub process {
                        if (WARN("SPACE_BEFORE_TAB",
                                "please, no space before tabs\n" . $herevet) &&
                            $fix) {
-                               while ($fixed[$linenr - 1] =~
+                               while ($fixed[$fixlinenr] =~
                                           s/(^\+.*) {8,8}+\t/$1\t\t/) {}
-                               while ($fixed[$linenr - 1] =~
+                               while ($fixed[$fixlinenr] =~
                                           s/(^\+.*) +\t/$1\t/) {}
                        }
                }
@@ -2249,19 +2411,19 @@ sub process {
                                        if (CHK("PARENTHESIS_ALIGNMENT",
                                                "Alignment should match open parenthesis\n" . $hereprev) &&
                                            $fix && $line =~ /^\+/) {
-                                               $fixed[$linenr - 1] =~
+                                               $fixed[$fixlinenr] =~
                                                    s/^\+[ \t]*/\+$goodtabindent/;
                                        }
                                }
                        }
                }
 
-               if ($line =~ /^\+.*\*[ \t]*\)[ \t]+(?!$Assignment|$Arithmetic)/) {
+               if ($line =~ /^\+.*\(\s*$Type\s*\)[ \t]+(?!$Assignment|$Arithmetic)/) {
                        if (CHK("SPACING",
-                               "No space is necessary after a cast\n" . $hereprev) &&
+                               "No space is necessary after a cast\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
-                                   s/^(\+.*\*[ \t]*\))[ \t]+/$1/;
+                               $fixed[$fixlinenr] =~
+                                   s/(\(\s*$Type\s*\))[ \t]+/$1/;
                        }
                }
 
@@ -2291,10 +2453,44 @@ sub process {
                             "networking block comments put the trailing */ on a separate line\n" . $herecurr);
                }
 
+# check for missing blank lines after struct/union declarations
+# with exceptions for various attributes and macros
+               if ($prevline =~ /^[\+ ]};?\s*$/ &&
+                   $line =~ /^\+/ &&
+                   !($line =~ /^\+\s*$/ ||
+                     $line =~ /^\+\s*EXPORT_SYMBOL/ ||
+                     $line =~ /^\+\s*MODULE_/i ||
+                     $line =~ /^\+\s*\#\s*(?:end|elif|else)/ ||
+                     $line =~ /^\+[a-z_]*init/ ||
+                     $line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ ||
+                     $line =~ /^\+\s*DECLARE/ ||
+                     $line =~ /^\+\s*__setup/)) {
+                       if (CHK("LINE_SPACING",
+                               "Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) &&
+                           $fix) {
+                               fix_insert_line($fixlinenr, "\+");
+                       }
+               }
+
+# check for multiple consecutive blank lines
+               if ($prevline =~ /^[\+ ]\s*$/ &&
+                   $line =~ /^\+\s*$/ &&
+                   $last_blank_line != ($linenr - 1)) {
+                       if (CHK("LINE_SPACING",
+                               "Please don't use multiple blank lines\n" . $hereprev) &&
+                           $fix) {
+                               fix_delete_line($fixlinenr, $rawline);
+                       }
+
+                       $last_blank_line = $linenr;
+               }
+
 # check for missing blank lines after declarations
                if ($sline =~ /^\+\s+\S/ &&                     #Not at char 1
                        # actual declarations
                    ($prevline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ ||
+                       # function pointer declarations
+                    $prevline =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ ||
                        # foo bar; where foo is some local typedef or #define
                     $prevline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ ||
                        # known declaration macros
@@ -2307,6 +2503,8 @@ sub process {
                      $prevline =~ /(?:\{\s*|\\)$/) &&
                        # looks like a declaration
                    !($sline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ ||
+                       # function pointer declarations
+                     $sline =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ ||
                        # foo bar; where foo is some local typedef or #define
                      $sline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ ||
                        # known declaration macros
@@ -2321,8 +2519,11 @@ sub process {
                      $sline =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/) &&
                        # indentation of previous and current line are the same
                    (($prevline =~ /\+(\s+)\S/) && $sline =~ /^\+$1\S/)) {
-                       WARN("SPACING",
-                            "Missing a blank line after declarations\n" . $hereprev);
+                       if (WARN("LINE_SPACING",
+                                "Missing a blank line after declarations\n" . $hereprev) &&
+                           $fix) {
+                               fix_insert_line($fixlinenr, "\+");
+                       }
                }
 
 # check for spaces at the beginning of a line.
@@ -2335,13 +2536,33 @@ sub process {
                        if (WARN("LEADING_SPACE",
                                 "please, no spaces at the start of a line\n" . $herevet) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e;
+                               $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e;
                        }
                }
 
 # check we are in a valid C source file if not then ignore this hunk
                next if ($realfile !~ /\.(h|c)$/);
 
+# check indentation of any line with a bare else
+# if the previous line is a break or return and is indented 1 tab more...
+               if ($sline =~ /^\+([\t]+)(?:}[ \t]*)?else(?:[ \t]*{)?\s*$/) {
+                       my $tabs = length($1) + 1;
+                       if ($prevline =~ /^\+\t{$tabs,$tabs}(?:break|return)\b/) {
+                               WARN("UNNECESSARY_ELSE",
+                                    "else is not generally useful after a break or return\n" . $hereprev);
+                       }
+               }
+
+# check indentation of a line with a break;
+# if the previous line is a goto or return and is indented the same # of tabs
+               if ($sline =~ /^\+([\t]+)break\s*;\s*$/) {
+                       my $tabs = $1;
+                       if ($prevline =~ /^\+$tabs(?:goto|return)\b/) {
+                               WARN("UNNECESSARY_BREAK",
+                                    "break is not useful after a goto or return\n" . $hereprev);
+                       }
+               }
+
 # discourage the addition of CONFIG_EXPERIMENTAL in #if(def).
                if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) {
                        WARN("CONFIG_EXPERIMENTAL",
@@ -2504,7 +2725,7 @@ sub process {
                        #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
                        #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
 
-                       if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+                       if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
                                ERROR("OPEN_BRACE",
                                      "that open brace { should be on the previous line\n" .
                                        "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
@@ -2654,8 +2875,18 @@ sub process {
 # check for initialisation to aggregates open brace on the next line
                if ($line =~ /^.\s*{/ &&
                    $prevline =~ /(?:^|[^=])=\s*$/) {
-                       ERROR("OPEN_BRACE",
-                             "that open brace { should be on the previous line\n" . $hereprev);
+                       if (ERROR("OPEN_BRACE",
+                                 "that open brace { should be on the previous line\n" . $hereprev) &&
+                           $fix && $prevline =~ /^\+/ && $line =~ /^\+/) {
+                               fix_delete_line($fixlinenr - 1, $prevrawline);
+                               fix_delete_line($fixlinenr, $rawline);
+                               my $fixedline = $prevrawline;
+                               $fixedline =~ s/\s*=\s*$/ = {/;
+                               fix_insert_line($fixlinenr, $fixedline);
+                               $fixedline = $line;
+                               $fixedline =~ s/^(.\s*){\s*/$1/;
+                               fix_insert_line($fixlinenr, $fixedline);
+                       }
                }
 
 #
@@ -2680,10 +2911,10 @@ sub process {
                        if (ERROR("C99_COMMENTS",
                                  "do not use C99 // comments\n" . $herecurr) &&
                            $fix) {
-                               my $line = $fixed[$linenr - 1];
+                               my $line = $fixed[$fixlinenr];
                                if ($line =~ /\/\/(.*)$/) {
                                        my $comment = trim($1);
-                                       $fixed[$linenr - 1] =~ s@\/\/(.*)$@/\* $comment \*/@;
+                                       $fixed[$fixlinenr] =~ s@\/\/(.*)$@/\* $comment \*/@;
                                }
                        }
                }
@@ -2742,7 +2973,7 @@ sub process {
                                  "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;/;
+                               $fixed[$fixlinenr] =~ s/($Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/$1;/;
                        }
                }
 # check for static initialisers.
@@ -2751,7 +2982,7 @@ sub process {
                                  "do not initialise statics to 0 or NULL\n" .
                                      $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/(\bstatic\s.*?)\s*=\s*(0|NULL|false)\s*;/$1;/;
+                               $fixed[$fixlinenr] =~ s/(\bstatic\s.*?)\s*=\s*(0|NULL|false)\s*;/$1;/;
                        }
                }
 
@@ -2781,7 +3012,7 @@ sub process {
                        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)/;
+                               $fixed[$fixlinenr] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/;
                        }
                }
 
@@ -2790,7 +3021,7 @@ sub process {
                        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\[\] = /;
+                               $fixed[$fixlinenr] =~ s/\b(?:static\s+|)DEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=\s*/static const struct pci_device_id $1\[\] = /;
                        }
                }
 
@@ -2827,7 +3058,7 @@ sub process {
                                        my $sub_from = $ident;
                                        my $sub_to = $ident;
                                        $sub_to =~ s/\Q$from\E/$to/;
-                                       $fixed[$linenr - 1] =~
+                                       $fixed[$fixlinenr] =~
                                            s@\Q$sub_from\E@$sub_to@;
                                }
                        }
@@ -2855,7 +3086,7 @@ sub process {
                                        my $sub_from = $match;
                                        my $sub_to = $match;
                                        $sub_to =~ s/\Q$from\E/$to/;
-                                       $fixed[$linenr - 1] =~
+                                       $fixed[$fixlinenr] =~
                                            s@\Q$sub_from\E@$sub_to@;
                                }
                        }
@@ -2917,7 +3148,7 @@ sub process {
                        if (WARN("PREFER_PR_LEVEL",
                                 "Prefer pr_warn(... to pr_warning(...\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/\bpr_warning\b/pr_warn/;
                        }
                }
@@ -2951,7 +3182,7 @@ sub process {
                        if (WARN("SPACING",
                                 "missing space after $1 definition\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/;
                        }
                }
@@ -3021,7 +3252,7 @@ sub process {
                        }
 
                        if (show_type("SPACING") && $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex;
                        }
                }
@@ -3038,7 +3269,7 @@ sub process {
                                if (ERROR("BRACKET_SPACE",
                                          "space prohibited before open square bracket '['\n" . $herecurr) &&
                                    $fix) {
-                                   $fixed[$linenr - 1] =~
+                                   $fixed[$fixlinenr] =~
                                        s/^(\+.*?)\s+\[/$1\[/;
                                }
                        }
@@ -3073,7 +3304,7 @@ sub process {
                                if (WARN("SPACING",
                                         "space prohibited between function name and open parenthesis '('\n" . $herecurr) &&
                                             $fix) {
-                                       $fixed[$linenr - 1] =~
+                                       $fixed[$fixlinenr] =~
                                            s/\b$name\s+\(/$name\(/;
                                }
                        }
@@ -3341,8 +3572,8 @@ sub process {
                                $fixed_line = $fixed_line . $fix_elements[$#elements];
                        }
 
-                       if ($fix && $line_fixed && $fixed_line ne $fixed[$linenr - 1]) {
-                               $fixed[$linenr - 1] = $fixed_line;
+                       if ($fix && $line_fixed && $fixed_line ne $fixed[$fixlinenr]) {
+                               $fixed[$fixlinenr] = $fixed_line;
                        }
 
 
@@ -3353,7 +3584,7 @@ sub process {
                        if (WARN("SPACING",
                                 "space prohibited before semicolon\n" . $herecurr) &&
                            $fix) {
-                               1 while $fixed[$linenr - 1] =~
+                               1 while $fixed[$fixlinenr] =~
                                    s/^(\+.*\S)\s+;/$1;/;
                        }
                }
@@ -3386,7 +3617,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "space required before the open brace '{'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/^(\+.*(?:do|\))){/$1 {/;
+                               $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\))){/$1 {/;
                        }
                }
 
@@ -3404,7 +3635,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "space required after that close brace '}'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/}((?!(?:,|;|\)))\S)/} $1/;
                        }
                }
@@ -3414,7 +3645,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "space prohibited after that open square bracket '['\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/\[\s+/\[/;
                        }
                }
@@ -3422,7 +3653,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "space prohibited before that close square bracket ']'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/\s+\]/\]/;
                        }
                }
@@ -3433,7 +3664,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "space prohibited after that open parenthesis '('\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/\(\s+/\(/;
                        }
                }
@@ -3443,18 +3674,27 @@ sub process {
                        if (ERROR("SPACING",
                                  "space prohibited before that close parenthesis ')'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               print("fixlinenr: <$fixlinenr> fixed[fixlinenr]: <$fixed[$fixlinenr]>\n");
+                               $fixed[$fixlinenr] =~
                                    s/\s+\)/\)/;
                        }
                }
 
+# check unnecessary parentheses around addressof/dereference single $Lvals
+# ie: &(foo->bar) should be &foo->bar and *(foo->bar) should be *foo->bar
+
+               while ($line =~ /(?:[^&]&\s*|\*)\(\s*($Ident\s*(?:$Member\s*)+)\s*\)/g) {
+                       CHK("UNNECESSARY_PARENTHESES",
+                           "Unnecessary parentheses around $1\n" . $herecurr);
+                   }
+
 #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] =~
+                               $fixed[$fixlinenr] =~
                                    s/^(.)\s+/$1/;
                        }
                }
@@ -3516,7 +3756,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "space required before the open parenthesis '('\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/\b(if|while|for|switch)\(/$1 \(/;
                        }
                }
@@ -3606,7 +3846,7 @@ sub process {
 # if should not continue a brace
                if ($line =~ /}\s*if\b/) {
                        ERROR("TRAILING_STATEMENTS",
-                             "trailing statements should be on next line\n" .
+                             "trailing statements should be on next line (or did you mean 'else if'?)\n" .
                                $herecurr);
                }
 # case and default should not have general statements after them
@@ -3653,7 +3893,7 @@ sub process {
                                         "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr) &&
                                    $fix) {
                                        my $hexval = sprintf("0x%x", oct($var));
-                                       $fixed[$linenr - 1] =~
+                                       $fixed[$fixlinenr] =~
                                            s/\b$var\b/$hexval/;
                                }
                        }
@@ -3689,7 +3929,7 @@ sub process {
                        if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
                                 "Whitespace after \\ makes next lines useless\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/\s+$//;
+                               $fixed[$fixlinenr] =~ s/\s+$//;
                        }
                }
 
@@ -3762,7 +4002,7 @@ sub process {
                            $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 !~ /^'X'$/ && $dstat !~ /^'XX'$/ &&                  # character constants
                            $dstat !~ /$exceptions/ &&
                            $dstat !~ /^\.$Ident\s*=/ &&                                # .foo =
                            $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ &&          # stringification #foo
@@ -4014,6 +4254,23 @@ sub process {
                        }
                }
 
+# check for unnecessary "Out of Memory" messages
+               if ($line =~ /^\+.*\b$logFunctions\s*\(/ &&
+                   $prevline =~ /^[ \+]\s*if\s*\(\s*(\!\s*|NULL\s*==\s*)?($Lval)(\s*==\s*NULL\s*)?\s*\)/ &&
+                   (defined $1 || defined $3) &&
+                   $linenr > 3) {
+                       my $testval = $2;
+                       my $testline = $lines[$linenr - 3];
+
+                       my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0);
+#                      print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n");
+
+                       if ($c =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*(?:devm_)?(?:[kv][czm]alloc(?:_node|_array)?\b|kstrdup|(?:dev_)?alloc_skb)/) {
+                               WARN("OOM_MESSAGE",
+                                    "Possible unnecessary 'out of memory' message\n" . $hereprev);
+                       }
+               }
+
 # check for bad placement of section $InitAttribute (e.g.: __initdata)
                if ($line =~ /(\b$InitAttribute\b)/) {
                        my $attr = $1;
@@ -4027,7 +4284,7 @@ sub process {
                                      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;
+                                       $fixed[$fixlinenr] =~ 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;
                                }
                        }
                }
@@ -4041,7 +4298,7 @@ sub process {
                        if (ERROR("INIT_ATTRIBUTE",
                                  "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/$InitAttributeData/${attr_prefix}initconst/;
                        }
                }
@@ -4052,12 +4309,12 @@ sub process {
                        if (ERROR("INIT_ATTRIBUTE",
                                  "Use of $attr requires a separate use of const\n" . $herecurr) &&
                            $fix) {
-                               my $lead = $fixed[$linenr - 1] =~
+                               my $lead = $fixed[$fixlinenr] =~
                                    /(^\+\s*(?:static\s+))/;
                                $lead = rtrim($1);
                                $lead = "$lead " if ($lead !~ /^\+$/);
                                $lead = "${lead}const ";
-                               $fixed[$linenr - 1] =~ s/(^\+\s*(?:static\s+))/$lead/;
+                               $fixed[$fixlinenr] =~ s/(^\+\s*(?:static\s+))/$lead/;
                        }
                }
 
@@ -4070,7 +4327,7 @@ sub process {
                        if (WARN("CONSTANT_CONVERSION",
                                 "$constant_func should be $func\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/\b$constant_func\b/$func/g;
+                               $fixed[$fixlinenr] =~ s/\b$constant_func\b/$func/g;
                        }
                }
 
@@ -4120,7 +4377,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "exactly one space required after that #$1\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
+                               $fixed[$fixlinenr] =~
                                    s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /;
                        }
 
@@ -4168,7 +4425,7 @@ sub process {
                        if (WARN("INLINE",
                                 "plain inline is preferred over $1\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/\b(__inline__|__inline)\b/inline/;
+                               $fixed[$fixlinenr] =~ s/\b(__inline__|__inline)\b/inline/;
 
                        }
                }
@@ -4193,7 +4450,7 @@ sub process {
                        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;
+                               $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex;
 
                        }
                }
@@ -4204,7 +4461,7 @@ sub process {
                        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;
+                               $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex;
                        }
                }
 
@@ -4219,7 +4476,7 @@ sub process {
                        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;
+                               $fixed[$fixlinenr] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex;
                        }
                }
 
@@ -4242,7 +4499,7 @@ sub process {
                                if (WARN("PREFER_SEQ_PUTS",
                                         "Prefer seq_puts to seq_printf\n" . $herecurr) &&
                                    $fix) {
-                                       $fixed[$linenr - 1] =~ s/\bseq_printf\b/seq_puts/;
+                                       $fixed[$fixlinenr] =~ s/\bseq_printf\b/seq_puts/;
                                }
                        }
                }
@@ -4271,7 +4528,7 @@ sub process {
                        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)/;
+                               $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/;
                        }
                }
 
@@ -4359,7 +4616,7 @@ sub process {
                        if (CHK("AVOID_EXTERNS",
                                "extern prototypes should be avoided in .h files\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/(.*)\bextern\b\s*(.*)/$1$2/;
+                               $fixed[$fixlinenr] =~ s/(.*)\bextern\b\s*(.*)/$1$2/;
                        }
                }
 
@@ -4419,23 +4676,24 @@ sub process {
 
 # check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
                if ($^V && $^V ge 5.10.0 &&
-                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/) {
+                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
                        my $oldfunc = $3;
                        my $a1 = $4;
                        my $a2 = $10;
                        my $newfunc = "kmalloc_array";
                        $newfunc = "kcalloc" if ($oldfunc eq "kzalloc");
-                       if ($a1 =~ /^sizeof\s*\S/ || $a2 =~ /^sizeof\s*\S/) {
+                       my $r1 = $a1;
+                       my $r2 = $a2;
+                       if ($a1 =~ /^sizeof\s*\S/) {
+                               $r1 = $a2;
+                               $r2 = $a1;
+                       }
+                       if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ &&
+                           !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) {
                                if (WARN("ALLOC_WITH_MULTIPLY",
                                         "Prefer $newfunc over $oldfunc with multiply\n" . $herecurr) &&
                                    $fix) {
-                                       my $r1 = $a1;
-                                       my $r2 = $a2;
-                                       if ($a1 =~ /^sizeof\s*\S/) {
-                                               $r1 = $a2;
-                                               $r2 = $a1;
-                                       }
-                                       $fixed[$linenr - 1] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e;
+                                       $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e;
 
                                }
                        }
@@ -4459,7 +4717,7 @@ sub process {
                        if (WARN("ONE_SEMICOLON",
                                 "Statements terminations use 1 semicolon\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/(\s*;\s*){2,}$/;/g;
+                               $fixed[$fixlinenr] =~ s/(\s*;\s*){2,}$/;/g;
                        }
                }
 
@@ -4507,7 +4765,7 @@ sub process {
                        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;
+                               $fixed[$fixlinenr] =~ s/\b__FUNCTION__\b/__func__/g;
                        }
                }
 
@@ -4750,12 +5008,16 @@ sub process {
        hash_show_words(\%use_type, "Used");
        hash_show_words(\%ignore_type, "Ignored");
 
-       if ($clean == 0 && $fix && "@rawlines" ne "@fixed") {
+       if ($clean == 0 && $fix &&
+           ("@rawlines" ne "@fixed" ||
+            $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) {
                my $newfile = $filename;
                $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace);
                my $linecount = 0;
                my $f;
 
+               @fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted);
+
                open($f, '>', $newfile)
                    or die "$P: Can't open $newfile for write\n";
                foreach my $fixed_line (@fixed) {
@@ -4763,7 +5025,7 @@ sub process {
                        if ($file) {
                                if ($linecount > 3) {
                                        $fixed_line =~ s/^\+//;
-                                       print $f $fixed_line. "\n";
+                                       print $f $fixed_line . "\n";
                                }
                        } else {
                                print $f $fixed_line . "\n";