Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c45dcabd authored by Andy Whitcroft's avatar Andy Whitcroft Committed by Linus Torvalds
Browse files

update checkpatch.pl to version 0.19



This version is a bit of a whopper.  This version brings a few new checks,
improvements to a number of checks mostly through modifications to the
way types are parsed, several fixes to quote/comment handling, as well as
the usual slew of fixes for false positives.

Of note:
 - return is not a function and is now reported,
 - preprocessor directive detection is loosened to match C99 standard,
 - we now intuit new type modifiers, and
 - comment handling is much improved

Andy Whitcroft (18):
      Version: 0.19
      fix up a couple of missing newlines in reports
      colon to parenthesis spacing varies on asm
      values: #include is a preprocessor statement
      quotes: fix single character quotes at line end
      add typedef exception for the non-pointer "function types"
      kerneldoc parameters must be on one line, relax line length
      types: word boundary is not always required
      improved #define bracketing reports
      uninitialized_var is an annotation not a function name
      possible types: add possible modifier handling
      possible types: fastcall is a type modifier
      types: unsigned is not a modifier on all types
      static/external initialisation to zero should allow modifiers
      checkpatch: fix recognition of preprocessor directives -- part 2
      comments: fix inter-hunk comment tracking
      return is not a function
      do not report include/asm/foo.h use in include/linux/foo.h
      return is not a function -- tighten test

[jengelh@computergmbh.de: fix recognition of preprocessor directives]
Signed-off-by: default avatarAndy Whitcroft <apw@shadowen.org>
Cc: Jan Engelhardt <jengelh@computergmbh.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 4feead71
Loading
Loading
Loading
Loading
+182 −102
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ use strict;
my $P = $0;
$P =~ s@.*/@@g;

my $V = '0.18';
my $V = '0.19';

use Getopt::Long qw(:config no_auto_abbrev);

@@ -115,6 +115,7 @@ our $Attribute = qr{
			__kprobes|
			__(?:mem|cpu|dev|)(?:initdata|init)
		  }x;
our $Modifier;
our $Inline	= qr{inline|__always_inline|noinline};
our $Member	= qr{->$Ident|\.$Ident|\[[^]]*\]};
our $Lval	= qr{$Ident(?:$Member)*};
@@ -144,17 +145,17 @@ our $UTF8 = qr {

our @typeList = (
	qr{void},
	qr{char},
	qr{short},
	qr{int},
	qr{long},
	qr{(?:unsigned\s+)?char},
	qr{(?:unsigned\s+)?short},
	qr{(?:unsigned\s+)?int},
	qr{(?:unsigned\s+)?long},
	qr{(?:unsigned\s+)?long\s+int},
	qr{(?:unsigned\s+)?long\s+long},
	qr{(?:unsigned\s+)?long\s+long\s+int},
	qr{unsigned},
	qr{float},
	qr{double},
	qr{bool},
	qr{long\s+int},
	qr{long\s+long},
	qr{long\s+long\s+int},
	qr{(?:__)?(?:u|s|be|le)(?:8|16|32|64)},
	qr{struct\s+$Ident},
	qr{union\s+$Ident},
@@ -163,26 +164,29 @@ our @typeList = (
	qr{${Ident}_handler},
	qr{${Ident}_handler_fn},
);
our @modifierList = (
	qr{fastcall},
);

sub build_types {
	my $mods = "(?:  \n" . join("|\n  ", @modifierList) . "\n)";
	my $all = "(?:  \n" . join("|\n  ", @typeList) . "\n)";
	$NonptrType	= qr{
			\b
			(?:const\s+)?
			(?:unsigned\s+)?
			(?:$mods\s+)?
			(?:
				$all|
				(?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)
				(?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
				(?:${all}\b)
			)
			(?:\s+$Sparse|\s+const)*
			\b
		  }x;
	$Type	= qr{
			\b$NonptrType\b
			$NonptrType
			(?:\s*\*+\s*const|\s*\*+|(?:\s*\[\s*\])+)?
			(?:\s+$Inline|\s+$Sparse|\s+$Attribute)*
			(?:\s+$Inline|\s+$Sparse|\s+$Attribute|\s+$mods)*
		  }x;
	$Declare	= qr{(?:$Storage\s+)?$Type};
	$Modifier	= qr{(?:$Attribute|$Sparse|$mods)};
}
build_types();

@@ -329,7 +333,7 @@ sub sanitise_line {
			$off++;
			next;
		}
		if (substr($line, $off, 2) eq $sanitise_quote) {
		if (substr($line, $off, 2) eq '*/') {
			$sanitise_quote = '';
			substr($res, $off, 2, "$;$;");
			$off++;
@@ -366,14 +370,14 @@ sub sanitise_line {
	}

	# The pathname on a #include may be surrounded by '<' and '>'.
	if ($res =~ /^.#\s*include\s+\<(.*)\>/) {
	if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
		my $clean = 'X' x length($1);
		$res =~ s@\<.*\>@<$clean>@;

	# The whole of a #error is a string.
	} elsif ($res =~ /^.#\s*(?:error|warning)\s+(.*)\b/) {
	} elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
		my $clean = 'X' x length($1);
		$res =~ s@(#\s*(?:error|warning)\s+).*@$1$clean@;
		$res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
	}

	return $res;
@@ -715,7 +719,7 @@ sub annotate_values {
			print "DECLARE($1)\n" if ($dbg_values > 1);
			$type = 'T';

		} elsif ($cur =~ /^(#\s*define\s*$Ident)(\(?)/o) {
		} elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
			print "DEFINE($1,$2)\n" if ($dbg_values > 1);
			$av_preprocessor = 1;
			push(@av_paren_type, $type);
@@ -724,12 +728,12 @@ sub annotate_values {
			}
			$type = 'E';

		} elsif ($cur =~ /^(#\s*undef\s*$Ident)/o) {
		} elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
			print "UNDEF($1)\n" if ($dbg_values > 1);
			$av_preprocessor = 1;
			push(@av_paren_type, $type);

		} elsif ($cur =~ /^(#\s*(?:ifdef|ifndef|if))/o) {
		} elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
			print "PRE_START($1)\n" if ($dbg_values > 1);
			$av_preprocessor = 1;

@@ -737,7 +741,7 @@ sub annotate_values {
			push(@av_paren_type, $type);
			$type = 'E';

		} elsif ($cur =~ /^(#\s*(?:else|elif))/o) {
		} elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
			print "PRE_RESTART($1)\n" if ($dbg_values > 1);
			$av_preprocessor = 1;

@@ -745,7 +749,7 @@ sub annotate_values {

			$type = 'E';

		} elsif ($cur =~ /^(#\s*(?:endif))/o) {
		} elsif ($cur =~ /^(\#\s*(?:endif))/o) {
			print "PRE_END($1)\n" if ($dbg_values > 1);

			$av_preprocessor = 1;
@@ -837,14 +841,26 @@ sub annotate_values {
sub possible {
	my ($possible, $line) = @_;

	#print "CHECK<$possible>\n";
	print "CHECK<$possible> ($line)\n" if ($dbg_possible > 1);
	if ($possible !~ /^(?:$Storage|$Type|DEFINE_\S+)$/ &&
	    $possible ne 'goto' && $possible ne 'return' &&
	    $possible ne 'struct' && $possible ne 'enum' &&
	    $possible ne 'case' && $possible ne 'else' &&
	    $possible ne 'typedef') {
	    $possible ne 'asm' &&
	    $possible !~ /^(typedef|struct|enum)\b/) {
		# Check for modifiers.
		$possible =~ s/\s*$Storage\s*//g;
		$possible =~ s/\s*$Sparse\s*//g;
		if ($possible =~ /^\s*$/) {

		} elsif ($possible =~ /\s/) {
			$possible =~ s/\s*$Type\s*//g;
			warn "MODIFIER: $possible ($line)\n" if ($dbg_possible);
			push(@modifierList, $possible);

		} else {
			warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
			push(@typeList, $possible);
		}
		build_types();
	}
}
@@ -949,6 +965,7 @@ sub process {
			} else {
				$realcnt=1+1;
			}
			$in_comment = 0;

			# Guestimate if this is a continuing comment.  Run
			# the context looking for a comment "edge".  If this
@@ -1117,7 +1134,9 @@ sub process {
			ERROR("trailing whitespace\n" . $herevet);
		}
#80 column limit
		if ($line =~ /^\+/ && !($prevrawline=~/\/\*\*/) && $length > 80) {
		if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
		    $rawline !~ /^.\s*\*\s*\@$Ident\s/ && $length > 80)
		{
			WARN("line over 80 characters\n" . $herecurr);
		}

@@ -1159,18 +1178,20 @@ sub process {
			# Ignore functions being called
			} elsif ($s =~ /^.\s*$Ident\s*\(/s) {

			# declarations always start with types
			} elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))\s*(?:;|=|,|\()/s) {
				my $type = $1;
				$type =~ s/\s+/ /g;
				possible($type, "A:" . $s);

			# definitions in global scope can only start with types
			} elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/s) {
				possible($1, $s);

			# declarations always start with types
			} elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:const\s+)?($Ident)\b(:?\s+$Sparse)?\s*\**\s*$Ident\s*(?:;|=|,)/s) {
				possible($1, $s);
				possible($1, "B:" . $s);
			}

			# any (foo ... *) is a pointer cast, and foo is a type
			while ($s =~ /\(($Ident)(?:\s+$Sparse)*\s*\*+\s*\)/sg) {
				possible($1, $s);
				possible($1, "C:" . $s);
			}

			# Check for any sort of function declaration.
@@ -1184,9 +1205,9 @@ sub process {
				$ctx =~ s/\)[^\)]*$//;

				for my $arg (split(/\s*,\s*/, $ctx)) {
					if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/ || $arg =~ /^($Ident)$/) {
					if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {

						possible($1, $s);
						possible($1, "D:" . $s);
					}
				}
			}
@@ -1221,7 +1242,7 @@ sub process {

# 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
		if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.#/) {
		if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
			my $pre_ctx = "$1$2";

			my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
@@ -1239,7 +1260,7 @@ sub process {

			if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
				ERROR("that open brace { should be on the previous line\n" .
					"$here\n$ctx\n$lines[$ctx_ln - 1]");
					"$here\n$ctx\n$lines[$ctx_ln - 1]\n");
			}
			if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
			    $ctx =~ /\)\s*\;\s*$/ &&
@@ -1248,7 +1269,7 @@ sub process {
				my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
				if ($nindent > $indent) {
					WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
						"$here\n$ctx\n$lines[$ctx_ln - 1]");
						"$here\n$ctx\n$lines[$ctx_ln - 1]\n");
				}
			}
		}
@@ -1284,7 +1305,7 @@ sub process {
#

# check for malformed paths in #include statements (uses RAW line)
		if ($rawline =~ m{^.#\s*include\s+[<"](.*)[">]}) {
		if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
			my $path = $1;
			if ($path =~ m{//}) {
				ERROR("malformed #include filename\n" .
@@ -1316,7 +1337,7 @@ sub process {
		}

# check for external initialisers.
		if ($line =~ /^.$Type\s*$Ident\s*=\s*(0|NULL|false)\s*;/) {
		if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
			ERROR("do not initialise externals to 0 or NULL\n" .
				$herecurr);
		}
@@ -1330,6 +1351,7 @@ sub process {
# make sense.
		if ($line =~ /\btypedef\s/ &&
		    $line !~ /\btypedef\s+$Type\s+\(\s*\*?$Ident\s*\)\s*\(/ &&
		    $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
		    $line !~ /\b__bitwise(?:__|)\b/) {
			WARN("do not add new typedefs\n" . $herecurr);
		}
@@ -1388,8 +1410,8 @@ sub process {

# function brace can't be on same line, except for #defines of do while,
# or if closed on same line
		if (($line=~/$Type\s*[A-Za-z\d_]+\(.*\).*\s{/) and
		    !($line=~/\#define.*do\s{/) and !($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);
		}

@@ -1416,10 +1438,10 @@ sub process {
			# 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.
			} elsif ($ctx_before =~ /^.\#\s*define\s*$/) {
			} elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) {

			# cpp #elif statement condition may start with a (
			} elsif ($ctx =~ /^.\#\s*elif\s*$/) {
			} elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {

			# If this whole things ends with a type its most
			# likely a typedef for a function.
@@ -1625,13 +1647,14 @@ sub process {
			ERROR("space prohibited before that close square bracket ']'\n" . $herecurr);
		}

# check spacing on paretheses
# check spacing on parentheses
		if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
		    $line !~ /for\s*\(\s+;/) {
			ERROR("space prohibited after that open parenthesis '('\n" . $herecurr);
		}
		if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
		    $line !~ /for\s*\(.*;\s+\)/) {
		    $line !~ /for\s*\(.*;\s+\)/ &&
		    $line !~ /:\s+\)/) {
			ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr);
		}

@@ -1641,6 +1664,23 @@ sub process {
			WARN("labels should not be indented\n" . $herecurr);
		}

# Return is not a function.
		if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
			my $spacing = $1;
			my $value = $2;

			# Flatten any parentheses and braces
			while ($value =~ s/\([^\(\)]*\)/1/) {
			}

			if ($value =~ /^(?:$Ident|-?$Constant)$/) {
				ERROR("return is not a function, parentheses are not required\n" . $herecurr);

			} elsif ($spacing !~ /\s+/) {
				ERROR("space required before the open parenthesis '('\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);
@@ -1660,7 +1700,7 @@ sub process {
			$s =~ s/\n.*//g;
			$s =~ s/$;//g; 	# Remove any comments
			if (length($c) && $s !~ /^\s*({|;|)\s*\\*\s*$/ &&
			    $c !~ /^.\#\s*if/)
			    $c !~ /^.\s*\#\s*if/)
			{
				ERROR("trailing statements should be on next line\n" . $herecurr);
			}
@@ -1719,14 +1759,16 @@ sub process {
#		}

#no spaces allowed after \ in define
		if ($line=~/\#define.*\\\s$/) {
		if ($line=~/\#\s*define.*\\\s$/) {
			WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr);
		}

#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
		if ($tree && $rawline =~ m{^.\#\s*include\s*\<asm\/(.*)\.h\>}) {
			my $checkfile = "$root/include/linux/$1.h";
			if (-f $checkfile && $1 ne 'irq') {
		if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
			my $checkfile = "include/linux/$1.h";
			if (-f "$root/$checkfile" && $realfile ne $checkfile &&
			    $1 ne 'irq')
			{
				WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
					$herecurr);
			}
@@ -1735,45 +1777,87 @@ sub process {
# multi-statement macros should be enclosed in a do while loop, grab the
# first statement and ensure its the whole macro if its not enclosed
# in a known good container
		if ($prevline =~ /\#define.*\\/ &&
		   $prevline !~/(?:do\s+{|\(\{|\{)/ &&
		   $line !~ /(?:do\s+{|\(\{|\{)/ &&
		   $line !~ /^.\s*$Declare\s/) {
			# Grab the first statement, if that is the entire macro
			# its ok.  This may start either on the #define line
			# or the one below.
		if ($line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
			my $ln = $linenr;
			my $cnt = $realcnt;
			my $off = 0;
			my ($off, $dstat, $dcond, $rest);
			my $ctx = '';

			# If the macro starts on the define line start
			# grabbing the statement after the identifier
			$prevline =~ m{^(.#\s*define\s*$Ident(?:\([^\)]*\))?\s*)(.*)\\\s*$};
			##print "1<$1> 2<$2>\n";
			if (defined $2 && $2 ne '') {
				$off = length($1);
				$ln--;
				$cnt++;
				while ($lines[$ln - 1] =~ /^-/) {
					$ln--;
					$cnt++;
				}
			}
			my @ctx = ctx_statement($ln, $cnt, $off);
			my $ctx_ln = $ln + $#ctx + 1;
			my $ctx = join("\n", @ctx);
			my $args = defined($1);

			# Pull in any empty extension lines.
			while ($ctx =~ /\\$/ &&
			       $lines[$ctx_ln - 1] =~ /^.\s*(?:\\)?$/) {
				$ctx .= $lines[$ctx_ln - 1];
				$ctx_ln++;
			# 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";
				$ln++;
				$cnt--;
			}
			$ctx .= $rawlines[$ln - 1];

			($dstat, $dcond, $ln, $cnt, $off) =
				ctx_statement_block($linenr, $ln - $linenr + 1, 0);
			#print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
			#print "LINE<$lines[$ln]> len<" . length($lines[$ln]) . "\n";

			# Extract the remainder of the define (if any) and
			# rip off surrounding spaces, and trailing \'s.
			$rest = '';
			if (defined $lines[$ln - 1] &&
			    $off > length($lines[$ln - 1]))
			{
				$ln++;
				$cnt--;
				$off = 0;
			}
			while ($cnt > 0) {
				$rest .= substr($lines[$ln - 1], $off) . "\n";
				$ln++;
				$cnt--;
				$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/\\\n.//g;
			$dstat =~ s/^\s*//s;
			$dstat =~ s/\s*$//s;

			if ($ctx =~ /\\$/) {
				if ($ctx =~ /;/) {
			# Flatten any parentheses and braces
			while ($dstat =~ s/\([^\(\)]*\)/1/) {
			}
			while ($dstat =~ s/\{[^\{\}]*\}/1/) {
			}

			my $exceptions = qr{
				$Declare|
				module_param_named|
				MODULE_PARAM_DESC|
				DECLARE_PER_CPU|
				DEFINE_PER_CPU|
				__typeof__\(
			}x;
			if ($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");
				} else {
				}

			} elsif ($ctx !~ /;/) {
				if ($dstat ne '' &&
				    $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
				    $dstat !~ /$exceptions/ &&
				    $dstat =~ /$Operators/)
				{
					ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
				}
			}
@@ -1884,7 +1968,7 @@ sub process {

# don't include deprecated include files (uses RAW line)
		for my $inc (@dep_includes) {
			if ($rawline =~ m@\#\s*include\s*\<$inc>@) {
			if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) {
				ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr);
			}
		}
@@ -1908,7 +1992,7 @@ sub process {
		}

# warn about #if 0
		if ($line =~ /^.#\s*if\s+0\b/) {
		if ($line =~ /^.\s*\#\s*if\s+0\b/) {
			CHK("if this code is redundant consider removing it\n" .
				$herecurr);
		}
@@ -1920,23 +2004,16 @@ sub process {
				WARN("kfree(NULL) is safe this check is probabally 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 probabally not required\n" . $hereprev);
			}
		}

# warn about #ifdefs in C files
#		if ($line =~ /^.#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
#		if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
#			print "#ifdef in C files should be avoided\n";
#			print "$herecurr";
#			$clean = 0;
#		}

# warn about spacing in #ifdefs
		if ($line =~ /^.#\s*(ifdef|ifndef|elif)\s\s+/) {
		if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
			ERROR("exactly one space required after that #$1\n" . $herecurr);
		}

@@ -1955,7 +2032,7 @@ sub process {
			}
		}
# check of hardware specific defines
		if ($line =~ m@^.#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
		if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
			CHK("architecture specific defines should be avoided\n" .  $herecurr);
		}

@@ -1973,15 +2050,18 @@ sub process {

# check for new externs in .c files.
		if ($realfile =~ /\.c$/ && defined $stat &&
		    $stat =~ /^.\s*(?:extern\s+)?$Type\s+$Ident(\s*)\(/s)
		    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
		{
			my $paren_space = $1;
			my $function_name = $1;
			my $paren_space = $2;

			my $s = $stat;
			if (defined $cond) {
				substr($s, 0, length($cond), '');
			}
			if ($s =~ /^\s*;/) {
			if ($s =~ /^\s*;/ &&
			    $function_name ne 'uninitialized_var')
			{
				WARN("externs should be avoided in .c files\n" .  $herecurr);
			}

@@ -2030,8 +2110,8 @@ sub process {
# use of NR_CPUS is usually wrong
# ignore definitions of NR_CPUS and usage to define arrays as likely right
		if ($line =~ /\bNR_CPUS\b/ &&
		    $line !~ /^.#\s*if\b.*\bNR_CPUS\b/ &&
		    $line !~ /^.#\s*define\b.*\bNR_CPUS\b/ &&
		    $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
		    $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
		    $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
		    $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
		    $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)