Skip to content
Snippets Groups Projects
checkpatch.pl 187 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			}
    
    			if (show_type("SPACING") && $fix) {
    
    				$fixed[$fixlinenr] =~
    				    s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex;
    
    		}
    
    # check for spacing round square brackets; allowed:
    #  1. with a type on the left -- int [] a;
    #  2. at the beginning of a line for slice initialisers -- [0...10] = 5,
    #  3. inside a curly brace -- = { [0...10] = 5 }
    		while ($line =~ /(.*?\s)\[/g) {
    			my ($where, $prefix) = ($-[1], $1);
    			if ($prefix !~ /$Type\s+$/ &&
    			    ($where != 0 || $prefix !~ /^.\s+$/) &&
    
    			    $prefix !~ /[{,]\s+$/) {
    
    				if (ERROR("BRACKET_SPACE",
    					  "space prohibited before open square bracket '['\n" . $herecurr) &&
    				    $fix) {
    
    				    $fixed[$fixlinenr] =~
    
    			}
    		}
    
    # check for spaces between functions and their parentheses.
    		while ($line =~ /($Ident)\s+\(/g) {
    			my $name = $1;
    			my $ctx_before = substr($line, 0, $-[1]);
    			my $ctx = "$ctx_before$name";
    
    			# Ignore those directives where spaces _are_ permitted.
    			if ($name =~ /^(?:
    				if|for|while|switch|return|case|
    				volatile|__volatile__|
    				__attribute__|format|__extension__|
    				asm|__asm__)$/x)
    			{
    			# 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*\#\s*define\s*$/) {
    
    			# cpp #elif statement condition may start with a (
    			} elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {
    
    			# If this whole things ends with a type its most
    			# likely a typedef for a function.
    			} elsif ($ctx =~ /$Type$/) {
    
    			} else {
    
    				if (WARN("SPACING",
    					 "space prohibited between function name and open parenthesis '('\n" . $herecurr) &&
    					     $fix) {
    
    					$fixed[$fixlinenr] =~
    
    					    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 = ();
    
    			foreach my $el (@elements) {
    				push(@fix_elements, substr($rawline, $off, length($el)));
    				$off += length($el);
    			}
    
    			$off = 0;
    
    
    			my $blank = copy_spacing($opline);
    
    
    			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.
    				my $ca = substr($opline, 0, $off);
    				my $cc = '';
    				if (length($opline) >= ($off + length($elements[$n + 1]))) {
    					$cc = substr($opline, $off + length($elements[$n + 1]));
    				}
    				my $cb = "$ca$;$cc";
    
    				my $a = '';
    				$a = 'V' if ($elements[$n] ne '');
    				$a = 'W' if ($elements[$n] =~ /\s$/);
    				$a = 'C' if ($elements[$n] =~ /$;$/);
    				$a = 'B' if ($elements[$n] =~ /(\[|\()$/);
    				$a = 'O' if ($elements[$n] eq '');
    				$a = 'E' if ($ca =~ /^\s*$/);
    
    				my $op = $elements[$n + 1];
    
    				my $c = '';
    				if (defined $elements[$n + 2]) {
    					$c = 'V' if ($elements[$n + 2] ne '');
    					$c = 'W' if ($elements[$n + 2] =~ /^\s/);
    					$c = 'C' if ($elements[$n + 2] =~ /^$;/);
    					$c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
    					$c = 'O' if ($elements[$n + 2] eq '');
    					$c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/);
    				} else {
    					$c = 'E';
    				}
    
    				my $ctx = "${a}x${c}";
    
    				my $at = "(ctx:$ctx)";
    
    				my $ptr = substr($blank, 0, $off) . "^";
    				my $hereptr = "$hereline$ptr\n";
    
    				# Pull out the value of this operator.
    				my $op_type = substr($curr_values, $off + 1, 1);
    
    				# Get the full operator variant.
    				my $opv = $op . substr($curr_vars, $off, 1);
    
    				# Ignore operators passed as parameters.
    				if ($op_type ne 'V' &&
    
    				    $ca =~ /\s$/ && $cc =~ /^\s*[,\)]/) {
    
    
    #				# Ignore comments
    #				} elsif ($op =~ /^$;+$/) {
    
    				# ; should have either the end of line or a space or \ after it
    				} elsif ($op eq ';') {
    					if ($ctx !~ /.x[WEBC]/ &&
    					    $cc !~ /^\\/ && $cc !~ /^;/) {
    
    						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 '//') {
    
    
    				#   :   when part of a bitfield
    				} elsif ($opv eq ':B') {
    					# skip the bitfield test for now
    
    
    				} elsif ($op eq '->') {
    
    					if ($ctx =~ /Wx.|.xW/) {
    
    						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 not have a space before and must have a space on the right.
    
    				} elsif ($op eq ',') {
    
    					my $rtrim_before = 0;
    					my $space_after = 0;
    					if ($ctx =~ /Wx./) {
    						if (ERROR("SPACING",
    							  "space prohibited before that '$op' $at\n" . $hereptr)) {
    							$line_fixed = 1;
    							$rtrim_before = 1;
    						}
    					}
    
    					if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
    
    						if (ERROR("SPACING",
    							  "space required after that '$op' $at\n" . $hereptr)) {
    							$line_fixed = 1;
    							$last_after = $n;
    
    							$space_after = 1;
    						}
    					}
    					if ($rtrim_before || $space_after) {
    						if ($rtrim_before) {
    							$good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
    						} else {
    							$good = $fix_elements[$n] . trim($fix_elements[$n + 1]);
    						}
    						if ($space_after) {
    							$good .= " ";
    
    					}
    
    				# '*' as part of a type definition -- reported already.
    				} elsif ($opv eq '*_') {
    					#warn "'*' is part of type\n";
    
    				# unary operators should have a space before and
    				# none after.  May be left adjacent to another
    				# unary operator, or a cast
    				} elsif ($op eq '!' || $op eq '~' ||
    					 $opv eq '*U' || $opv eq '-U' ||
    					 $opv eq '&U' || $opv eq '&&U') {
    					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/) {
    
    						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]/) {
    
    						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 =~ /^;/)) {
    
    						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 (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
    					 $op eq '+' or $op eq '-' or
    					 $op eq '*' or $op eq '/' or
    					 $op eq '%')
    				{
    
    					if ($check) {
    						if (defined $fix_elements[$n + 2] && $ctx !~ /[EW]x[EW]/) {
    							if (CHK("SPACING",
    								"spaces preferred around that '$op' $at\n" . $hereptr)) {
    								$good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
    								$fix_elements[$n + 2] =~ s/^\s+//;
    								$line_fixed = 1;
    							}
    						} elsif (!defined $fix_elements[$n + 2] && $ctx !~ /Wx[OE]/) {
    							if (CHK("SPACING",
    								"space preferred before that '$op' $at\n" . $hereptr)) {
    								$good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]);
    								$line_fixed = 1;
    							}
    						}
    					} elsif ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
    
    						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./) {
    
    						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;
    
    					# Ignore email addresses <foo@bar>
    					if (($op eq '<' &&
    					     $cc =~ /^\S+\@\S+>/) ||
    					    ($op eq '>' &&
    					     $ca =~ /<\S+\@\S+$/))
    					{
    
    					# for asm volatile statements
    					# ignore a colon with another
    					# colon immediately before or after
    					if (($op eq ':') &&
    					    ($ca =~ /:$/ || $cc =~ /^:/)) {
    						$ok = 1;
    					}
    
    
    					# messages are ERROR, but ?: are CHK
    
    						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[$fixlinenr]) {
    				$fixed[$fixlinenr] = $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[$fixlinenr] =~
    
    				    s/^(\+.*\S)\s+;/$1;/;
    
    			}
    		}
    
    # check for multiple assignments
    		if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
    			CHK("MULTIPLE_ASSIGNMENTS",
    			    "multiple assignments should be avoided\n" . $herecurr);
    		}
    
    ## # check for multiple declarations, allowing for a function declaration
    ## # continuation.
    ## 		if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
    ## 		    $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
    ##
    ## 			# Remove any bracketed sections to ensure we do not
    ## 			# falsly report the parameters of functions.
    ## 			my $ln = $line;
    ## 			while ($ln =~ s/\([^\(\)]*\)//g) {
    ## 			}
    ## 			if ($ln =~ /,/) {
    ## 				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\{/) {
    
    			if (ERROR("SPACING",
    				  "space required before the open brace '{'\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~ 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/) {
    
    			if (ERROR("SPACING",
    				  "space required after that close brace '}'\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    				    s/}((?!(?:,|;|\)))\S)/} $1/;
    			}
    
    		}
    
    # check spacing on square brackets
    		if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
    
    			if (ERROR("SPACING",
    				  "space prohibited after that open square bracket '['\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    		}
    		if ($line =~ /\s\]/) {
    
    			if (ERROR("SPACING",
    				  "space prohibited before that close square bracket ']'\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    		}
    
    # check spacing on parentheses
    		if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
    		    $line !~ /for\s*\(\s+;/) {
    
    			if (ERROR("SPACING",
    				  "space prohibited after that open parenthesis '('\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    		}
    		if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
    		    $line !~ /for\s*\(.*;\s+\)/ &&
    		    $line !~ /:\s+\)/) {
    
    			if (ERROR("SPACING",
    				  "space prohibited before that close parenthesis ')'\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    # 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) {
    			my $var = $1;
    			if (CHK("UNNECESSARY_PARENTHESES",
    				"Unnecessary parentheses around $var\n" . $herecurr) &&
    			    $fix) {
    				$fixed[$fixlinenr] =~ s/\(\s*\Q$var\E\s*\)/$var/;
    			}
    		}
    
    # check for unnecessary parentheses around function pointer uses
    # ie: (foo->bar)(); should be foo->bar();
    # but not "if (foo->bar) (" to avoid some false positives
    		if ($line =~ /(\bif\s*|)(\(\s*$Ident\s*(?:$Member\s*)+\))[ \t]*\(/ && $1 !~ /^if/) {
    			my $var = $2;
    			if (CHK("UNNECESSARY_PARENTHESES",
    				"Unnecessary parentheses around function pointer $var\n" . $herecurr) &&
    			    $fix) {
    				my $var2 = deparenthesize($var);
    				$var2 =~ s/\s//g;
    				$fixed[$fixlinenr] =~ s/\Q$var\E/$var2/;
    			}
    		}
    
    
    #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[$fixlinenr] =~
    
    # return is not a function
    
    		if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
    
    			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("SPACING",
    				      "space required before the open parenthesis '('\n" . $herecurr);
    			}
    		}
    
    # unnecessary return in a void function
    # at end-of-function, with the previous line a single leading tab, then return;
    # and the line before that not a goto label target like "out:"
    		if ($sline =~ /^[ \+]}\s*$/ &&
    		    $prevline =~ /^\+\treturn\s*;\s*$/ &&
    		    $linenr >= 3 &&
    		    $lines[$linenr - 3] =~ /^[ +]/ &&
    		    $lines[$linenr - 3] !~ /^[ +]\s*$Ident\s*:/) {
    			WARN("RETURN_VOID",
    			     "void function return statements are not generally useful\n" . $hereprev);
                   }
    
    
    # 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 =~ tr@\(@\(@;
    			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);
    			}
    		}
    
    
    # comparisons with a constant or upper case identifier on the left
    #	avoid cases like "foo + BAR < baz"
    #	only fix matches surrounded by parentheses to avoid incorrect
    #	conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5"
    		if ($^V && $^V ge 5.10.0 &&
    		    $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) {
    			my $lead = $1;
    			my $const = $2;
    			my $comp = $3;
    			my $to = $4;
    			my $newcomp = $comp;
    			if ($lead !~ /(?:$Operators|\.)\s*$/ &&
    			    $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ &&
    			    WARN("CONSTANT_COMPARISON",
    				 "Comparisons should place the constant on the right side of the test\n" . $herecurr) &&
    			    $fix) {
    				if ($comp eq "<") {
    					$newcomp = ">";
    				} elsif ($comp eq "<=") {
    					$newcomp = ">=";
    				} elsif ($comp eq ">") {
    					$newcomp = "<";
    				} elsif ($comp eq ">=") {
    					$newcomp = "<=";
    				}
    				$fixed[$fixlinenr] =~ s/\(\s*\Q$const\E\s*$Compare\s*\Q$to\E\s*\)/($to $newcomp $const)/;
    			}
    		}
    
    # Return of what appears to be an errno should normally be negative
    		if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) {
    
    			my $name = $1;
    			if ($name ne 'EOF' && $name ne 'ERROR') {
    				WARN("USE_NEGATIVE_ERRNO",
    
    				     "return of an errno should typically be negative (ie: return -$1)\n" . $herecurr);
    
    			}
    		}
    
    # Need a space before open parenthesis after if, while etc
    
    		if ($line =~ /\b(if|while|for|switch)\(/) {
    			if (ERROR("SPACING",
    				  "space required before the open parenthesis '('\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    				    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;
    			##print "stat<$stat> stat_next<$stat_next>\n";
    
    			if ($stat_next =~ /^\s*while\b/) {
    				# If the statement carries leading newlines,
    				# then count those as offsets.
    				my ($whitespace) =
    					($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
    				my $offset =
    					statement_rawlines($whitespace) - 1;
    
    				$suppress_whiletrailers{$line_nr_next +
    								$offset} = 1;
    			}
    		}
    		if (!defined $suppress_whiletrailers{$linenr} &&
    
    		    defined($stat) && defined($cond) &&
    
    		    $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
    			my ($s, $c) = ($stat, $cond);
    
    			if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
    				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
    			# conditional.
    			substr($s, 0, length($c), '');
    			$s =~ s/\n.*//g;
    			$s =~ s/$;//g; 	# Remove any comments
    			if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
    			    $c !~ /}\s*while\s*/)
    			{
    				# Find out how long the conditional actually is.
    				my @newlines = ($c =~ /\n/gs);
    				my $cond_lines = 1 + $#newlines;
    				my $stat_real = '';
    
    				$stat_real = raw_line($linenr, $cond_lines)
    							. "\n" if ($cond_lines);
    				if (defined($stat_real) && $cond_lines > 1) {
    					$stat_real = "[...]\n$stat_real";
    				}
    
    				ERROR("TRAILING_STATEMENTS",
    				      "trailing statements should be on next line\n" . $herecurr . $stat_real);
    			}
    		}
    
    # Check for bitwise tests written as boolean
    		if ($line =~ /
    			(?:
    				(?:\[|\(|\&\&|\|\|)
    				\s*0[xX][0-9]+\s*
    				(?:\&\&|\|\|)
    			|
    				(?:\&\&|\|\|)
    				\s*0[xX][0-9]+\s*
    				(?:\&\&|\|\||\)|\])
    			)/x)
    		{
    			WARN("HEXADECIMAL_BOOLEAN_TEST",
    			     "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
    		}
    
    # if and else should not have general statements after it
    		if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
    			my $s = $1;
    			$s =~ s/$;//g; 	# Remove any comments
    			if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
    				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",
    
    			      "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
    		if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
    		    $line !~ /\G(?:
    			(?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
    			\s*return\s+
    		    )/xg)
    		{
    			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*/ &&
    		    $previndent == $indent) {
    			if (ERROR("ELSE_AFTER_BRACE",
    				  "else should follow close brace '}'\n" . $hereprev) &&
    			    $fix && $prevline =~ /^\+/ && $line =~ /^\+/) {
    				fix_delete_line($fixlinenr - 1, $prevrawline);
    				fix_delete_line($fixlinenr, $rawline);
    				my $fixedline = $prevrawline;
    				$fixedline =~ s/}\s*$//;
    				if ($fixedline !~ /^\+\s*$/) {
    					fix_insert_line($fixlinenr, $fixedline);
    				}
    				$fixedline = $rawline;
    				$fixedline =~ s/^(.\s*)else/$1} else/;
    				fix_insert_line($fixlinenr, $fixedline);
    			}
    
    		if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ &&
    		    $previndent == $indent) {
    
    			my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
    
    			# Find out what is on the end of the line after the
    			# conditional.
    			substr($s, 0, length($c), '');
    			$s =~ s/\n.*//g;
    
    			if ($s =~ /^\s*;/) {
    
    				if (ERROR("WHILE_AFTER_BRACE",
    					  "while should follow close brace '}'\n" . $hereprev) &&
    				    $fix && $prevline =~ /^\+/ && $line =~ /^\+/) {
    					fix_delete_line($fixlinenr - 1, $prevrawline);
    					fix_delete_line($fixlinenr, $rawline);
    					my $fixedline = $prevrawline;
    					my $trailing = $rawline;
    					$trailing =~ s/^\+//;
    					$trailing = trim($trailing);
    					$fixedline =~ s/}\s*$/} $trailing/;
    					fix_insert_line($fixlinenr, $fixedline);
    				}
    
    #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[$fixlinenr] =~
    
    					    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_]+)?$/ &&
    #Ignore some three character SI units explicitly, like MiB and KHz
    			    $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[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+$/) {
    			if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
    				 "Whitespace after \\ makes next lines useless\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~ s/\s+$//;
    
    # warn if <asm/foo.h> is #included and <linux/foo.h> is available and includes
    # itself <asm/foo.h> (uses RAW line)
    
    		if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
    			my $file = "$1.h";
    			my $checkfile = "include/linux/$file";
    			if (-f "$root/$checkfile" &&
    			    $realfile ne $checkfile &&
    			    $1 !~ /$allowed_asm_includes/)
    			{
    
    				my $asminclude = `grep -Ec "#include\\s+<asm/$file>" $root/$checkfile`;
    				if ($asminclude > 0) {
    					if ($realfile =~ m{^arch/}) {
    						CHK("ARCH_INCLUDE_LINUX",
    						    "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
    					} else {
    						WARN("INCLUDE_LINUX",
    						     "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
    					}
    
    				}
    			}
    		}
    
    # multi-statement macros should be enclosed in a do while loop, grab the
    # first statement and ensure its the whole macro if its not enclosed
    # in a known good container
    		if ($realfile !~ m@/vmlinux.lds.h$@ &&
    		    $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
    			my $ln = $linenr;
    			my $cnt = $realcnt;
    			my ($off, $dstat, $dcond, $rest);
    			my $ctx = '';
    
    			my $has_flow_statement = 0;
    			my $has_arg_concat = 0;
    
    			($dstat, $dcond, $ln, $cnt, $off) =
    
    				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";
    
    
    			$has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/);
    			$has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/);
    
    			$dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//;
    			my $define_args = $1;
    			my $define_stmt = $dstat;
    			my @def_args = ();
    
    			if (defined $define_args && $define_args ne "") {
    				$define_args = substr($define_args, 1, length($define_args) - 2);
    				$define_args =~ s/\s*//g;
    				@def_args = split(",", $define_args);
    			}
    
    
    			$dstat =~ s/$;//g;
    			$dstat =~ s/\\\n.//g;
    			$dstat =~ s/^\s*//s;
    			$dstat =~ s/\s*$//s;
    
    			# Flatten any parentheses and braces
    			while ($dstat =~ s/\([^\(\)]*\)/1/ ||
    			       $dstat =~ s/\{[^\{\}]*\}/1/ ||
    
    			       $dstat =~ s/.\[[^\[\]]*\]/1/)
    
    			{
    			}
    
    			# Flatten any obvious string concatentation.
    
    			while ($dstat =~ s/($String)\s*$Ident/$1/ ||
    			       $dstat =~ s/$Ident\s*($String)/$1/)
    
    			# Make asm volatile uses seem like a generic function
    			$dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g;
    
    
    			my $exceptions = qr{
    				$Declare|
    				module_param_named|
    
    				DECLARE_PER_CPU|
    				DEFINE_PER_CPU|
    				__typeof__\(|
    				union|
    				struct|
    				\.$Ident\s*=\s*|
    
    			}x;
    			#print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
    
    
    			$ctx =~ s/\n*$//;
    			my $herectx = $here . "\n";
    			my $stmt_cnt = statement_rawlines($ctx);
    
    			for (my $n = 0; $n < $stmt_cnt; $n++) {
    				$herectx .= raw_line($linenr, $n) . "\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'$/ && $dstat !~ /^'XX'$/ &&			# 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/)
    
    				if ($dstat =~ /^\s*if\b/) {
    					ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
    					      "Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects\n" . "$herectx");
    				} elsif ($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 parentheses\n" . "$herectx");
    				}
    
    			}
    
    			# Make $define_stmt single line, comment-free, etc
    			my @stmt_array = split('\n', $define_stmt);
    			my $first = 1;
    			$define_stmt = "";
    			foreach my $l (@stmt_array) {
    				$l =~ s/\\$//;
    				if ($first) {
    					$define_stmt = $l;
    					$first = 0;
    				} elsif ($l =~ /^[\+ ]/) {
    					$define_stmt .= substr($l, 1);
    				}
    			}
    			$define_stmt =~ s/$;//g;
    			$define_stmt =~ s/\s+/ /g;
    			$define_stmt = trim($define_stmt);
    
    # check if any macro arguments are reused (ignore '...' and 'type')
    			foreach my $arg (@def_args) {
    			        next if ($arg =~ /\.\.\./);
    			        next if ($arg =~ /^type$/i);
    				my $tmp_stmt = $define_stmt;
    				$tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
    				$tmp_stmt =~ s/\#+\s*$arg\b//g;
    				$tmp_stmt =~ s/\b$arg\s*\#\#//g;
    				my $use_cnt = $tmp_stmt =~ s/\b$arg\b//g;
    				if ($use_cnt > 1) {
    					CHK("MACRO_ARG_REUSE",
    					    "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx");
    				    }
    # check if any macro arguments may have other precedence issues
    				if ($tmp_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m &&
    				    ((defined($1) && $1 ne ',') ||
    				     (defined($2) && $2 ne ','))) {
    					CHK("MACRO_ARG_PRECEDENCE",
    					    "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx");
    				}
    			}
    
    # check for macros with flow control, but without ## concatenation
    # ## concatenation is commonly a macro that defines a function so ignore those
    			if ($has_flow_statement && !$has_arg_concat) {
    
    				my $herectx = $here . "\n";
    				my $cnt = statement_rawlines($ctx);
    
    				for (my $n = 0; $n < $cnt; $n++) {
    					$herectx .= raw_line($linenr, $n) . "\n";
    
    				WARN("MACRO_WITH_FLOW_CONTROL",
    				     "Macros with flow control statements should be avoided\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;