checkpatch: suspect indent count condition lines correctly
[pandora-kernel.git] / scripts / checkpatch.pl
index 303c363..2e513fd 100755 (executable)
@@ -9,7 +9,7 @@ use strict;
 my $P = $0;
 $P =~ s@.*/@@g;
 
-my $V = '0.21';
+my $V = '0.22';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -335,7 +335,7 @@ sub sanitise_line {
                        $off++;
                        next;
                }
-               if (substr($line, $off, 2) eq '*/') {
+               if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
                        $sanitise_quote = '';
                        substr($res, $off, 2, "$;$;");
                        $off++;
@@ -408,6 +408,7 @@ sub ctx_statement_block {
                # context.
                if ($off >= $len) {
                        for (; $remain > 0; $line++) {
+                               last if (!defined $lines[$line]);
                                next if ($lines[$line] =~ /^-/);
                                $remain--;
                                $loff = $len;
@@ -673,6 +674,22 @@ sub ctx_has_comment {
        return ($cmt ne '');
 }
 
+sub raw_line {
+       my ($linenr, $cnt) = @_;
+
+       my $offset = $linenr - 1;
+       $cnt++;
+
+       my $line;
+       while ($cnt) {
+               $line = $rawlines[$offset++];
+               next if (defined($line) && $line =~ /^-/);
+               $cnt--;
+       }
+
+       return $line;
+}
+
 sub cat_vet {
        my ($vet) = @_;
        my ($res, $coded);
@@ -958,6 +975,33 @@ sub CHK {
        }
 }
 
+sub check_absolute_file {
+       my ($absolute, $herecurr) = @_;
+       my $file = $absolute;
+
+       ##print "absolute<$absolute>\n";
+
+       # See if any suffix of this path is a path within the tree.
+       while ($file =~ s@^[^/]*/@@) {
+               if (-f "$root/$file") {
+                       ##print "file<$file>\n";
+                       last;
+               }
+       }
+       if (! -f _)  {
+               return 0;
+       }
+
+       # It is, so see if the prefix is acceptable.
+       my $prefix = $absolute;
+       substr($prefix, -length($file)) = '';
+
+       ##print "prefix<$prefix>\n";
+       if ($prefix ne ".../") {
+               WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+       }
+}
+
 sub process {
        my $filename = shift;
 
@@ -1029,9 +1073,14 @@ sub process {
                        # edge is a close comment then we must be in a comment
                        # at context start.
                        my $edge;
-                       for (my $ln = $linenr + 1; $ln < ($linenr + $realcnt); $ln++) {
-                               next if ($line =~ /^-/);
-                               ($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@);
+                       my $cnt = $realcnt;
+                       for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+                               next if (defined $rawlines[$ln - 1] &&
+                                        $rawlines[$ln - 1] =~ /^-/);
+                               $cnt--;
+                               #print "RAW<$rawlines[$ln - 1]>\n";
+                               ($edge) = (defined $rawlines[$ln - 1] &&
+                                       $rawlines[$ln - 1] =~ m@(/\*|\*/)@);
                                last if (defined $edge);
                        }
                        if (defined $edge && $edge eq '*/') {
@@ -1129,7 +1178,7 @@ sub process {
                        $realfile = $1;
                        $realfile =~ s@^[^/]*/@@;
 
-                       if ($realfile =~ m@include/asm/@) {
+                       if ($realfile =~ m@^include/asm/@) {
                                ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
                        }
                        next;
@@ -1163,6 +1212,20 @@ sub process {
                                $herecurr) if (!$emitted_corrupt++);
                }
 
+# Check for absolute kernel paths.
+               if ($tree) {
+                       while ($line =~ m{(?:^|\s)(/\S*)}g) {
+                               my $file = $1;
+
+                               if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+                                   check_absolute_file($1, $herecurr)) {
+                                       #
+                               } else {
+                                       check_absolute_file($file, $herecurr);
+                               }
+                       }
+               }
+
 # UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
                if (($realfile =~ /^$/ || $line =~ /^\+/) &&
                    $rawline !~ m/^$UTF8*$/) {
@@ -1178,9 +1241,6 @@ sub process {
 #ignore lines being removed
                if ($line=~/^-/) {next;}
 
-# check we are in a valid source file if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
-
 #trailing whitespace
                if ($line =~ /^\+.*\015/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
@@ -1190,6 +1250,10 @@ sub process {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        ERROR("trailing whitespace\n" . $herevet);
                }
+
+# check we are in a valid source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
 #80 column limit
                if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
                    $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
@@ -1204,8 +1268,8 @@ sub process {
                        WARN("adding a line without newline at end of file\n" . $herecurr);
                }
 
-# check we are in a valid source file *.[hc] if not then ignore this hunk
-               next if ($realfile !~ /\.[hc]$/);
+# check we are in a valid source file C or perl if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|pl)$/);
 
 # at the beginning of a line any tabs must come first and anything
 # more than 8 must use tabs.
@@ -1215,6 +1279,9 @@ sub process {
                        ERROR("code indent should use tabs where possible\n" . $herevet);
                }
 
+# check we are in a valid C source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c)$/);
+
 # check for RCS/CVS revision markers
                if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
                        WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
@@ -1298,14 +1365,6 @@ sub process {
                                ERROR("switch and case should be at the same indent\n$hereline$err");
                        }
                }
-               if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
-                   $line !~ /\G(?:
-                       (?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
-                       \s*return\s+
-                   )/xg)
-               {
-                       ERROR("trailing statements should be on next line\n" . $herecurr);
-               }
 
 # if/while/etc brace do not go on next line, unless defining a do while loop,
 # or if that brace on the next line is for something else
@@ -1346,6 +1405,82 @@ sub process {
                        }
                }
 
+# Check relative indent for conditionals and blocks.
+               if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+                       my ($s, $c) = ($stat, $cond);
+
+                       substr($s, 0, length($c), '');
+
+                       # Make sure we remove the line prefixes as we have
+                       # none on the first line, and are going to readd them
+                       # where necessary.
+                       $s =~ s/\n./\n/gs;
+
+                       # Find out how long the conditional actually is.
+                       my @newlines = ($c =~ /\n/gs);
+                       my $cond_lines = 1 + $#newlines;
+
+                       # We want to check the first line inside the block
+                       # starting at the end of the conditional, so remove:
+                       #  1) any blank line termination
+                       #  2) any opening brace { on end of the line
+                       #  3) any do (...) {
+                       my $continuation = 0;
+                       my $check = 0;
+                       $s =~ s/^.*\bdo\b//;
+                       $s =~ s/^\s*{//;
+                       if ($s =~ s/^\s*\\//) {
+                               $continuation = 1;
+                       }
+                       if ($s =~ s/^\s*?\n//) {
+                               $check = 1;
+                               $cond_lines++;
+                       }
+
+                       # Also ignore a loop construct at the end of a
+                       # preprocessor statement.
+                       if (($prevline =~ /^.\s*#\s*define\s/ ||
+                           $prevline =~ /\\\s*$/) && $continuation == 0) {
+                               $check = 0;
+                       }
+
+                       my $cond_ptr = -1;
+                       while ($cond_ptr != $cond_lines) {
+                               $cond_ptr = $cond_lines;
+
+                               # Ignore:
+                               #  1) blank lines, they should be at 0,
+                               #  2) preprocessor lines, and
+                               #  3) labels.
+                               if ($s =~ /^\s*?\n/ ||
+                                   $s =~ /^\s*#\s*?/ ||
+                                   $s =~ /^\s*$Ident\s*:/) {
+                                       $s =~ s/^.*?\n//;
+                                       $cond_lines++;
+                               }
+                       }
+
+                       my (undef, $sindent) = line_stats("+" . $s);
+                       my $stat_real = raw_line($linenr, $cond_lines);
+
+                       # Check if either of these lines are modified, else
+                       # this is not this patch's fault.
+                       if (!defined($stat_real) ||
+                           $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+                               $check = 0;
+                       }
+                       if (defined($stat_real) && $cond_lines > 1) {
+                               $stat_real = "[...]\n$stat_real";
+                       }
+
+                       #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+                       if ($check && (($sindent % 8) != 0 ||
+                           ($sindent <= $indent && $s ne ''))) {
+                               WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+                       }
+               }
+
                # Track the 'values' across context and added lines.
                my $opline = $line; $opline =~ s/^./ /;
                my ($curr_values, $curr_vars) =
@@ -1823,61 +1958,6 @@ sub process {
                        }
                }
 
-# Check relative indent for conditionals and blocks.
-               if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
-                       my ($s, $c) = ($stat, $cond);
-
-                       substr($s, 0, length($c), '');
-
-                       # Make sure we remove the line prefixes as we have
-                       # none on the first line, and are going to readd them
-                       # where necessary.
-                       $s =~ s/\n./\n/gs;
-
-                       # We want to check the first line inside the block
-                       # starting at the end of the conditional, so remove:
-                       #  1) any blank line termination
-                       #  2) any opening brace { on end of the line
-                       #  3) any do (...) {
-                       my $continuation = 0;
-                       my $check = 0;
-                       $s =~ s/^.*\bdo\b//;
-                       $s =~ s/^\s*{//;
-                       if ($s =~ s/^\s*\\//) {
-                               $continuation = 1;
-                       }
-                       if ($s =~ s/^\s*\n//) {
-                               $check = 1;
-                       }
-
-                       # Also ignore a loop construct at the end of a
-                       # preprocessor statement.
-                       if (($prevline =~ /^.\s*#\s*define\s/ ||
-                           $prevline =~ /\\\s*$/) && $continuation == 0) {
-                               $check = 0;
-                       }
-
-                       # Ignore the current line if its is a preprocessor
-                       # line.
-                       if ($s =~ /^\s*#\s*/) {
-                               $check = 0;
-                       }
-
-                       # Ignore the current line if it is label.
-                       if ($s =~ /^\s*$Ident\s*:/) {
-                               $check = 0;
-                       }
-
-                       my (undef, $sindent) = line_stats("+" . $s);
-
-                       ##print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s>\n";
-
-                       if ($check && (($sindent % 8) != 0 ||
-                           ($sindent <= $indent && $s ne ''))) {
-                               WARN("suspect code indent for conditional statements\n" . $herecurr);
-                       }
-               }
-
 # Check for bitwise tests written as boolean
                if ($line =~ /
                        (?:
@@ -1901,6 +1981,15 @@ sub process {
                                ERROR("trailing statements should be on next line\n" . $herecurr);
                        }
                }
+# case and default should not have general statements after them
+               if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+                   $line !~ /\G(?:
+                       (?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+                       \s*return\s+
+                   )/xg)
+               {
+                       ERROR("trailing statements should be on next line\n" . $herecurr);
+               }
 
                # Check for }<nl>else {, these must be at the same
                # indent level to be relevant to each other.
@@ -1937,12 +2026,17 @@ sub process {
 
 #warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
                if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
-                       my $checkfile = "include/linux/$1.h";
-                       if (-f "$root/$checkfile" && $realfile ne $checkfile &&
+                       my $file = "$1.h";
+                       my $checkfile = "include/linux/$file";
+                       if (-f "$root/$checkfile" &&
+                           $realfile ne $checkfile &&
                            $1 ne 'irq')
                        {
-                               WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
-                                       $herecurr);
+                               if ($realfile =~ m{^arch/}) {
+                                       CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+                               } else {
+                                       WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+                               }
                        }
                }
 
@@ -1977,8 +2071,8 @@ sub process {
                        # 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 $off <" . substr($lines[$ln - 1], $off) . ">\n";
+                       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--;
@@ -2127,10 +2221,10 @@ sub process {
                        }
                        if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
                                my $herectx = $here . "\n";;
-                               my $end = $linenr + statement_rawlines($block) - 1;
+                               my $cnt = statement_rawlines($block);
 
-                               for (my $ln = $linenr - 1; $ln < $end; $ln++) {
-                                       $herectx .= $rawlines[$ln] . "\n";;
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";;
                                }
 
                                WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
@@ -2305,6 +2399,7 @@ sub process {
                my $string;
                while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
                        $string = substr($rawline, $-[1], $+[1] - $-[1]);
+                       $string =~ s/%%/__/g;
                        if ($string =~ /(?<!%)%L[udi]/) {
                                WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
                                last;