Skip to content
Snippets Groups Projects
checkpatch.pl 187 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			$dstat =~ s/$;/ /g;
    
    
    			if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) {
    				my $stmts = $2;
    				my $semis = $3;
    
    				$ctx =~ s/\n*$//;
    				my $cnt = statement_rawlines($ctx);
    				my $herectx = $here . "\n";
    
    				for (my $n = 0; $n < $cnt; $n++) {
    					$herectx .= raw_line($linenr, $n) . "\n";
    				}
    
    				if (($stmts =~ tr/;/;/) == 1 &&
    				    $stmts !~ /^\s*(if|while|for|switch)\b/) {
    					WARN("SINGLE_STATEMENT_DO_WHILE_MACRO",
    					     "Single statement macros should not use a do {} while (0) loop\n" . "$herectx");
    				}
    				if (defined $semis && $semis ne "") {
    					WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON",
    					     "do {} while (0) macros should not be semicolon terminated\n" . "$herectx");
    
    			} elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) {
    				$ctx =~ s/\n*$//;
    				my $cnt = statement_rawlines($ctx);
    				my $herectx = $here . "\n";
    
    				for (my $n = 0; $n < $cnt; $n++) {
    					$herectx .= raw_line($linenr, $n) . "\n";
    				}
    
    				WARN("TRAILING_SEMICOLON",
    				     "macros should not use a trailing semicolon\n" . "$herectx");
    
    			}
    		}
    
    # make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
    # all assignments may have only one of the following with an assignment:
    #	.
    #	ALIGN(...)
    #	VMLINUX_SYMBOL(...)
    		if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
    			WARN("MISSING_VMLINUX_SYMBOL",
    			     "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
    		}
    
    # check for redundant bracing round if etc
    		if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
    			my ($level, $endln, @chunks) =
    				ctx_statement_full($linenr, $realcnt, 1);
    			#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
    			#print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
    			if ($#chunks > 0 && $level == 0) {
    
    				my @allowed = ();
    				my $allow = 0;
    
    				my $seen = 0;
    				my $herectx = $here . "\n";
    				my $ln = $linenr - 1;
    				for my $chunk (@chunks) {
    					my ($cond, $block) = @{$chunk};
    
    					# If the condition carries leading newlines, then count those as offsets.
    					my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
    					my $offset = statement_rawlines($whitespace) - 1;
    
    
    					$allowed[$allow] = 0;
    
    					#print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
    
    					# We have looked at and allowed this specific line.
    					$suppress_ifbraces{$ln + $offset} = 1;
    
    					$herectx .= "$rawlines[$ln + $offset]\n[...]\n";
    					$ln += statement_rawlines($block) - 1;
    
    					substr($block, 0, length($cond), '');
    
    					$seen++ if ($block =~ /^\s*{/);
    
    
    					#print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n";
    
    					if (statement_lines($cond) > 1) {
    						#print "APW: ALLOWED: cond<$cond>\n";
    
    						$allowed[$allow] = 1;
    
    					}
    					if ($block =~/\b(?:if|for|while)\b/) {
    						#print "APW: ALLOWED: block<$block>\n";
    
    						$allowed[$allow] = 1;
    
    					}
    					if (statement_block_size($block) > 1) {
    						#print "APW: ALLOWED: lines block<$block>\n";
    
    						$allowed[$allow] = 1;
    
    				if ($seen) {
    					my $sum_allowed = 0;
    					foreach (@allowed) {
    						$sum_allowed += $_;
    					}
    					if ($sum_allowed == 0) {
    						WARN("BRACES",
    						     "braces {} are not necessary for any arm of this statement\n" . $herectx);
    					} elsif ($sum_allowed != $allow &&
    						 $seen != $allow) {
    						CHK("BRACES",
    						    "braces {} should be used on all arms of this statement\n" . $herectx);
    					}
    
    				}
    			}
    		}
    		if (!defined $suppress_ifbraces{$linenr - 1} &&
    					$line =~ /\b(if|while|for|else)\b/) {
    			my $allowed = 0;
    
    			# Check the pre-context.
    			if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
    				#print "APW: ALLOWED: pre<$1>\n";
    				$allowed = 1;
    			}
    
    			my ($level, $endln, @chunks) =
    				ctx_statement_full($linenr, $realcnt, $-[0]);
    
    			# Check the condition.
    			my ($cond, $block) = @{$chunks[0]};
    			#print "CHECKING<$linenr> cond<$cond> block<$block>\n";
    			if (defined $cond) {
    				substr($block, 0, length($cond), '');
    			}
    			if (statement_lines($cond) > 1) {
    				#print "APW: ALLOWED: cond<$cond>\n";
    				$allowed = 1;
    			}
    			if ($block =~/\b(?:if|for|while)\b/) {
    				#print "APW: ALLOWED: block<$block>\n";
    				$allowed = 1;
    			}
    			if (statement_block_size($block) > 1) {
    				#print "APW: ALLOWED: lines block<$block>\n";
    				$allowed = 1;
    			}
    			# Check the post-context.
    			if (defined $chunks[1]) {
    				my ($cond, $block) = @{$chunks[1]};
    				if (defined $cond) {
    					substr($block, 0, length($cond), '');
    				}
    				if ($block =~ /^\s*\{/) {
    					#print "APW: ALLOWED: chunk-1 block<$block>\n";
    					$allowed = 1;
    				}
    			}
    			if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
    
    				my $herectx = $here . "\n";
    
    				my $cnt = statement_rawlines($block);
    
    				for (my $n = 0; $n < $cnt; $n++) {
    
    					$herectx .= raw_line($linenr, $n) . "\n";
    
    				}
    
    				WARN("BRACES",
    				     "braces {} are not necessary for single statement blocks\n" . $herectx);
    			}
    		}
    
    
    # check for single line unbalanced braces
    		if ($sline =~ /^.\s*\}\s*else\s*$/ ||
    		    $sline =~ /^.\s*else\s*\{\s*$/) {
    			CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr);
    		}
    
    
    # check for unnecessary blank lines around braces
    
    		if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) {
    
    			if (CHK("BRACES",
    				"Blank lines aren't necessary before a close brace '}'\n" . $hereprev) &&
    			    $fix && $prevrawline =~ /^\+/) {
    				fix_delete_line($fixlinenr - 1, $prevrawline);
    			}
    
    		if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) {
    
    			if (CHK("BRACES",
    				"Blank lines aren't necessary after an open brace '{'\n" . $hereprev) &&
    			    $fix) {
    				fix_delete_line($fixlinenr, $rawline);
    			}
    
    		}
    
    # no volatiles please
    		my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
    		if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
    			WARN("VOLATILE",
    
    			     "Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst\n" . $herecurr);
    		}
    
    # Check for user-visible strings broken across lines, which breaks the ability
    # to grep for the string.  Make exceptions when the previous string ends in a
    # newline (multiple lines in one string constant) or '\t', '\r', ';', or '{'
    # (common in inline assembly) or is a octal \123 or hexadecimal \xaf value
    		if ($line =~ /^\+\s*$String/ &&
    		    $prevline =~ /"\s*$/ &&
    		    $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) {
    			if (WARN("SPLIT_STRING",
    				 "quoted string split across lines\n" . $hereprev) &&
    				     $fix &&
    				     $prevrawline =~ /^\+.*"\s*$/ &&
    				     $last_coalesced_string_linenr != $linenr - 1) {
    				my $extracted_string = get_quoted_string($line, $rawline);
    				my $comma_close = "";
    				if ($rawline =~ /\Q$extracted_string\E(\s*\)\s*;\s*$|\s*,\s*)/) {
    					$comma_close = $1;
    				}
    
    				fix_delete_line($fixlinenr - 1, $prevrawline);
    				fix_delete_line($fixlinenr, $rawline);
    				my $fixedline = $prevrawline;
    				$fixedline =~ s/"\s*$//;
    				$fixedline .= substr($extracted_string, 1) . trim($comma_close);
    				fix_insert_line($fixlinenr - 1, $fixedline);
    				$fixedline = $rawline;
    				$fixedline =~ s/\Q$extracted_string\E\Q$comma_close\E//;
    				if ($fixedline !~ /\+\s*$/) {
    					fix_insert_line($fixlinenr, $fixedline);
    				}
    				$last_coalesced_string_linenr = $linenr;
    			}
    		}
    
    # check for missing a space in a string concatenation
    		if ($prevrawline =~ /[^\\]\w"$/ && $rawline =~ /^\+[\t ]+"\w/) {
    			WARN('MISSING_SPACE',
    			     "break quoted strings at a space character\n" . $hereprev);
    		}
    
    # check for an embedded function name in a string when the function is known
    # This does not work very well for -f --file checking as it depends on patch
    # context providing the function name or a single line form for in-file
    # function declarations
    		if ($line =~ /^\+.*$String/ &&
    		    defined($context_function) &&
    		    get_quoted_string($line, $rawline) =~ /\b$context_function\b/ &&
    		    length(get_quoted_string($line, $rawline)) != (length($context_function) + 2)) {
    			WARN("EMBEDDED_FUNCTION_NAME",
    			     "Prefer using '\"%s...\", __func__' to using '$context_function', this function's name, in a string\n" . $herecurr);
    		}
    
    # check for spaces before a quoted newline
    		if ($rawline =~ /^.*\".*\s\\n/) {
    			if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
    				 "unnecessary whitespace before a quoted newline\n" . $herecurr) &&
    			    $fix) {
    				$fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/;
    			}
    
    		}
    
    # concatenated string without spaces between elements
    		if ($line =~ /$String[A-Z_]/ || $line =~ /[A-Za-z0-9_]$String/) {
    			CHK("CONCATENATED_STRING",
    			    "Concatenated strings should use spaces between elements\n" . $herecurr);
    		}
    
    # uncoalesced string fragments
    		if ($line =~ /$String\s*"/) {
    			WARN("STRING_FRAGMENTS",
    			     "Consecutive strings are generally better as a single string\n" . $herecurr);
    		}
    
    # check for non-standard and hex prefixed decimal printf formats
    		my $show_L = 1;	#don't show the same defect twice
    		my $show_Z = 1;
    		while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
    			my $string = substr($rawline, $-[1], $+[1] - $-[1]);
    			$string =~ s/%%/__/g;
    			# check for %L
    			if ($show_L && $string =~ /%[\*\d\.\$]*L([diouxX])/) {
    				WARN("PRINTF_L",
    				     "\%L$1 is non-standard C, use %ll$1\n" . $herecurr);
    				$show_L = 0;
    			}
    			# check for %Z
    			if ($show_Z && $string =~ /%[\*\d\.\$]*Z([diouxX])/) {
    				WARN("PRINTF_Z",
    				     "%Z$1 is non-standard C, use %z$1\n" . $herecurr);
    				$show_Z = 0;
    			}
    			# check for 0x<decimal>
    			if ($string =~ /0x%[\*\d\.\$\Llzth]*[diou]/) {
    				ERROR("PRINTF_0XDECIMAL",
    				      "Prefixing 0x with decimal output is defective\n" . $herecurr);
    			}
    		}
    
    # check for line continuations in quoted strings with odd counts of "
    		if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
    			WARN("LINE_CONTINUATIONS",
    			     "Avoid line continuations in quoted strings\n" . $herecurr);
    
    		}
    
    # warn about #if 0
    		if ($line =~ /^.\s*\#\s*if\s+0\b/) {
    			CHK("REDUNDANT_CODE",
    			    "if this code is redundant consider removing it\n" .
    				$herecurr);
    		}
    
    
    # check for needless "if (<foo>) fn(<foo>)" uses
    		if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) {
    
    			my $tested = quotemeta($1);
    			my $expr = '\s*\(\s*' . $tested . '\s*\)\s*;';
    			if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?|(?:kmem_cache|mempool|dma_pool)_destroy)$expr/) {
    				my $func = $1;
    				if (WARN('NEEDLESS_IF',
    					 "$func(NULL) is safe and this check is probably not required\n" . $hereprev) &&
    				    $fix) {
    					my $do_fix = 1;
    					my $leading_tabs = "";
    					my $new_leading_tabs = "";
    					if ($lines[$linenr - 2] =~ /^\+(\t*)if\s*\(\s*$tested\s*\)\s*$/) {
    						$leading_tabs = $1;
    					} else {
    						$do_fix = 0;
    					}
    					if ($lines[$linenr - 1] =~ /^\+(\t+)$func\s*\(\s*$tested\s*\)\s*;\s*$/) {
    						$new_leading_tabs = $1;
    						if (length($leading_tabs) + 1 ne length($new_leading_tabs)) {
    							$do_fix = 0;
    						}
    					} else {
    						$do_fix = 0;
    					}
    					if ($do_fix) {
    						fix_delete_line($fixlinenr - 1, $prevrawline);
    						$fixed[$fixlinenr] =~ s/^\+$new_leading_tabs/\+$leading_tabs/;
    					}
    				}
    			}
    		}
    
    # 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 ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*(?:devm_)?(?:[kv][czm]alloc(?:_node|_array)?\b|kstrdup|kmemdup|(?:dev_)?alloc_skb)/) {
    				WARN("OOM_MESSAGE",
    				     "Possible unnecessary 'out of memory' message\n" . $hereprev);
    			}
    		}
    
    # check for logging functions with KERN_<LEVEL>
    		if ($line !~ /printk(?:_ratelimited|_once)?\s*\(/ &&
    		    $line =~ /\b$logFunctions\s*\(.*\b(KERN_[A-Z]+)\b/) {
    			my $level = $1;
    			if (WARN("UNNECESSARY_KERN_LEVEL",
    				 "Possible unnecessary $level\n" . $herecurr) &&
    			    $fix) {
    				$fixed[$fixlinenr] =~ s/\s*$level\s*//;
    			}
    		}
    
    # check for logging continuations
    		if ($line =~ /\bprintk\s*\(\s*KERN_CONT\b|\bpr_cont\s*\(/) {
    			WARN("LOGGING_CONTINUATION",
    			     "Avoid logging continuation uses where feasible\n" . $herecurr);
    		}
    
    # check for mask then right shift without a parentheses
    		if ($^V && $^V ge 5.10.0 &&
    		    $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ &&
    		    $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so
    			WARN("MASK_THEN_SHIFT",
    			     "Possible precedence defect with mask then right shift - may need parentheses\n" . $herecurr);
    		}
    
    # check for pointer comparisons to NULL
    		if ($^V && $^V ge 5.10.0) {
    			while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) {
    				my $val = $1;
    				my $equal = "!";
    				$equal = "" if ($4 eq "!=");
    				if (CHK("COMPARISON_TO_NULL",
    					"Comparison to NULL could be written \"${equal}${val}\"\n" . $herecurr) &&
    					    $fix) {
    					$fixed[$fixlinenr] =~ s/\b\Q$val\E\s*(?:==|\!=)\s*NULL\b/$equal$val/;
    				}
    
    # check for bad placement of section $InitAttribute (e.g.: __initdata)
    		if ($line =~ /(\b$InitAttribute\b)/) {
    			my $attr = $1;
    			if ($line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/) {
    				my $ptr = $1;
    				my $var = $2;
    				if ((($ptr =~ /\b(union|struct)\s+$attr\b/ &&
    				      ERROR("MISPLACED_INIT",
    					    "$attr should be placed after $var\n" . $herecurr)) ||
    				     ($ptr !~ /\b(union|struct)\s+$attr\b/ &&
    				      WARN("MISPLACED_INIT",
    					   "$attr should be placed after $var\n" . $herecurr))) &&
    				    $fix) {
    
    					$fixed[$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;
    
    				}
    			}
    		}
    
    # check for $InitAttributeData (ie: __initdata) with const
    		if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) {
    			my $attr = $1;
    			$attr =~ /($InitAttributePrefix)(.*)/;
    			my $attr_prefix = $1;
    			my $attr_type = $2;
    			if (ERROR("INIT_ATTRIBUTE",
    				  "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    				    s/$InitAttributeData/${attr_prefix}initconst/;
    			}
    		}
    
    # check for $InitAttributeConst (ie: __initconst) without const
    		if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) {
    			my $attr = $1;
    			if (ERROR("INIT_ATTRIBUTE",
    				  "Use of $attr requires a separate use of const\n" . $herecurr) &&
    			    $fix) {
    
    				my $lead = $fixed[$fixlinenr] =~
    
    				    /(^\+\s*(?:static\s+))/;
    				$lead = rtrim($1);
    				$lead = "$lead " if ($lead !~ /^\+$/);
    				$lead = "${lead}const ";
    
    				$fixed[$fixlinenr] =~ s/(^\+\s*(?:static\s+))/$lead/;
    			}
    		}
    
    # check for __read_mostly with const non-pointer (should just be const)
    		if ($line =~ /\b__read_mostly\b/ &&
    		    $line =~ /($Type)\s*$Ident/ && $1 !~ /\*\s*$/ && $1 =~ /\bconst\b/) {
    			if (ERROR("CONST_READ_MOSTLY",
    				  "Invalid use of __read_mostly with const type\n" . $herecurr) &&
    			    $fix) {
    				$fixed[$fixlinenr] =~ s/\s+__read_mostly\b//;
    			}
    		}
    
    # don't use __constant_<foo> functions outside of include/uapi/
    		if ($realfile !~ m@^include/uapi/@ &&
    		    $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) {
    			my $constant_func = $1;
    			my $func = $constant_func;
    			$func =~ s/^__constant_//;
    			if (WARN("CONSTANT_CONVERSION",
    				 "$constant_func should be $func\n" . $herecurr) &&
    			    $fix) {
    				$fixed[$fixlinenr] =~ s/\b$constant_func\b/$func/g;
    
    # prefer usleep_range over udelay
    
    		if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
    
    			# ignore udelay's < 10, however
    
    			if (! ($delay < 10) ) {
    
    				CHK("USLEEP_RANGE",
    
    				    "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $herecurr);
    			}
    			if ($delay > 2000) {
    				WARN("LONG_UDELAY",
    				     "long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $herecurr);
    
    			}
    		}
    
    # warn about unexpectedly long msleep's
    		if ($line =~ /\bmsleep\s*\((\d+)\);/) {
    			if ($1 < 20) {
    				WARN("MSLEEP",
    
    				     "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $herecurr);
    
    # check for comparisons of jiffies
    		if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) {
    			WARN("JIFFIES_COMPARISON",
    			     "Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $herecurr);
    		}
    
    # check for comparisons of get_jiffies_64()
    		if ($line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) {
    			WARN("JIFFIES_COMPARISON",
    			     "Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $herecurr);
    		}
    
    
    # warn about #ifdefs in C files
    #		if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
    #			print "#ifdef in C files should be avoided\n";
    #			print "$herecurr";
    #			$clean = 0;
    #		}
    
    # warn about spacing in #ifdefs
    		if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
    
    			if (ERROR("SPACING",
    				  "exactly one space required after that #$1\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~
    
    				    s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /;
    			}
    
    
    		}
    
    # check for spinlock_t definitions without a comment.
    		if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
    		    $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
    			my $which = $1;
    			if (!ctx_has_comment($first_line, $linenr)) {
    				CHK("UNCOMMENTED_DEFINITION",
    				    "$1 definition without comment\n" . $herecurr);
    			}
    		}
    # check for memory barriers without a comment.
    
    
    		my $barriers = qr{
    			mb|
    			rmb|
    			wmb|
    			read_barrier_depends
    		}x;
    		my $barrier_stems = qr{
    			mb__before_atomic|
    			mb__after_atomic|
    			store_release|
    			load_acquire|
    			store_mb|
    			(?:$barriers)
    		}x;
    		my $all_barriers = qr{
    			(?:$barriers)|
    			smp_(?:$barrier_stems)|
    			virt_(?:$barrier_stems)
    		}x;
    
    		if ($line =~ /\b(?:$all_barriers)\s*\(/) {
    
    			if (!ctx_has_comment($first_line, $linenr)) {
    
    				WARN("MEMORY_BARRIER",
    				     "memory barrier without comment\n" . $herecurr);
    
    
    		my $underscore_smp_barriers = qr{__smp_(?:$barrier_stems)}x;
    
    		if ($realfile !~ m@^include/asm-generic/@ &&
    		    $realfile !~ m@/barrier\.h$@ &&
    		    $line =~ m/\b(?:$underscore_smp_barriers)\s*\(/ &&
    		    $line !~ m/^.\s*\#\s*define\s+(?:$underscore_smp_barriers)\s*\(/) {
    			WARN("MEMORY_BARRIER",
    			     "__smp memory barriers shouldn't be used outside barrier.h and asm-generic\n" . $herecurr);
    		}
    
    # check for waitqueue_active without a comment.
    		if ($line =~ /\bwaitqueue_active\s*\(/) {
    			if (!ctx_has_comment($first_line, $linenr)) {
    				WARN("WAITQUEUE_ACTIVE",
    				     "waitqueue_active without comment\n" . $herecurr);
    			}
    		}
    
    
    # check of hardware specific defines
    		if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
    			CHK("ARCH_DEFINES",
    			    "architecture specific defines should be avoided\n" .  $herecurr);
    		}
    
    
    # check that the storage class is not after a type
    		if ($line =~ /\b($Type)\s+($Storage)\b/) {
    			WARN("STORAGE_CLASS",
    			     "storage class '$2' should be located before type '$1'\n" . $herecurr);
    		}
    
    # Check that the storage class is at the beginning of a declaration
    
    		if ($line =~ /\b$Storage\b/ &&
    		    $line !~ /^.\s*$Storage/ &&
    		    $line =~ /^.\s*(.+?)\$Storage\s/ &&
    		    $1 !~ /[\,\)]\s*$/) {
    
    			WARN("STORAGE_CLASS",
    
    			     "storage class should be at the beginning of the declaration\n" . $herecurr);
    
    		}
    
    # check the location of the inline attribute, that it is between
    # storage class and type.
    		if ($line =~ /\b$Type\s+$Inline\b/ ||
    		    $line =~ /\b$Inline\s+$Storage\b/) {
    			ERROR("INLINE_LOCATION",
    			      "inline keyword should sit between storage class and type\n" . $herecurr);
    		}
    
    # Check for __inline__ and __inline, prefer inline
    
    		if ($realfile !~ m@\binclude/uapi/@ &&
    		    $line =~ /\b(__inline__|__inline)\b/) {
    			if (WARN("INLINE",
    				 "plain inline is preferred over $1\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~ s/\b(__inline__|__inline)\b/inline/;
    
    		}
    
    # Check for __attribute__ packed, prefer __packed
    
    		if ($realfile !~ m@\binclude/uapi/@ &&
    		    $line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) {
    
    			WARN("PREFER_PACKED",
    			     "__packed is preferred over __attribute__((packed))\n" . $herecurr);
    		}
    
    
    # Check for new packed members, warn to use care
    		if ($realfile !~ m@\binclude/uapi/@ &&
    		    $line =~ /\b(__attribute__\s*\(\s*\(.*\bpacked|__packed)\b/) {
    			WARN("NEW_PACKED",
    			     "Adding new packed members is to be done with care\n" . $herecurr);
    		}
    
    
    # Check for __attribute__ aligned, prefer __aligned
    
    		if ($realfile !~ m@\binclude/uapi/@ &&
    		    $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) {
    
    			WARN("PREFER_ALIGNED",
    			     "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr);
    		}
    
    
    # Check for __attribute__ format(printf, prefer __printf
    
    		if ($realfile !~ m@\binclude/uapi/@ &&
    		    $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) {
    			if (WARN("PREFER_PRINTF",
    				 "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex;
    
    		}
    
    # Check for __attribute__ format(scanf, prefer __scanf
    
    		if ($realfile !~ m@\binclude/uapi/@ &&
    		    $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) {
    			if (WARN("PREFER_SCANF",
    				 "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex;
    			}
    		}
    
    # Check for __attribute__ weak, or __weak declarations (may have link issues)
    		if ($^V && $^V ge 5.10.0 &&
    		    $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ &&
    		    ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ ||
    		     $line =~ /\b__weak\b/)) {
    			ERROR("WEAK_DECLARATION",
    			      "Using weak declarations can have unintended link defects\n" . $herecurr);
    		}
    
    # check for c99 types like uint8_t used outside of uapi/ and tools/
    		if ($realfile !~ m@\binclude/uapi/@ &&
    		    $realfile !~ m@\btools/@ &&
    		    $line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) {
    			my $type = $1;
    			if ($type =~ /\b($typeC99Typedefs)\b/) {
    				$type = $1;
    				my $kernel_type = 'u';
    				$kernel_type = 's' if ($type =~ /^_*[si]/);
    				$type =~ /(\d+)/;
    				$kernel_type .= $1;
    				if (CHK("PREFER_KERNEL_TYPES",
    					"Prefer kernel type '$kernel_type' over '$type'\n" . $herecurr) &&
    				    $fix) {
    					$fixed[$fixlinenr] =~ s/\b$type\b/$kernel_type/;
    				}
    			}
    		}
    
    # check for cast of C90 native int or longer types constants
    		if ($line =~ /(\(\s*$C90_int_types\s*\)\s*)($Constant)\b/) {
    			my $cast = $1;
    			my $const = $2;
    			if (WARN("TYPECAST_INT_CONSTANT",
    				 "Unnecessary typecast of c90 int constant\n" . $herecurr) &&
    			    $fix) {
    				my $suffix = "";
    				my $newconst = $const;
    				$newconst =~ s/${Int_type}$//;
    				$suffix .= 'U' if ($cast =~ /\bunsigned\b/);
    				if ($cast =~ /\blong\s+long\b/) {
    					$suffix .= 'LL';
    				} elsif ($cast =~ /\blong\b/) {
    					$suffix .= 'L';
    				}
    				$fixed[$fixlinenr] =~ s/\Q$cast\E$const\b/$newconst$suffix/;
    
    # check for sizeof(&)
    		if ($line =~ /\bsizeof\s*\(\s*\&/) {
    			WARN("SIZEOF_ADDRESS",
    			     "sizeof(& should be avoided\n" . $herecurr);
    		}
    
    
    # check for sizeof without parenthesis
    		if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) {
    
    			if (WARN("SIZEOF_PARENTHESIS",
    				 "sizeof $1 should be sizeof($1)\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex;
    
    		}
    
    # check for struct spinlock declarations
    		if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) {
    			WARN("USE_SPINLOCK_T",
    			     "struct spinlock should be spinlock_t\n" . $herecurr);
    		}
    
    
    # check for seq_printf uses that could be seq_puts
    		if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) {
    			my $fmt = get_quoted_string($line, $rawline);
    
    			$fmt =~ s/%%//g;
    			if ($fmt !~ /%/) {
    
    				if (WARN("PREFER_SEQ_PUTS",
    					 "Prefer seq_puts to seq_printf\n" . $herecurr) &&
    				    $fix) {
    
    					$fixed[$fixlinenr] =~ s/\bseq_printf\b/seq_puts/;
    				}
    			}
    		}
    
    		# check for vsprintf extension %p<foo> misuses
    		if ($^V && $^V ge 5.10.0 &&
    		    defined $stat &&
    		    $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
    		    $1 !~ /^_*volatile_*$/) {
    			my $bad_extension = "";
    			my $lc = $stat =~ tr@\n@@;
    			$lc = $lc + $linenr;
    		        for (my $count = $linenr; $count <= $lc; $count++) {
    				my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
    				$fmt =~ s/%%//g;
    				if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) {
    					$bad_extension = $1;
    					last;
    
    			if ($bad_extension ne "") {
    				my $stat_real = raw_line($linenr, 0);
    				for (my $count = $linenr + 1; $count <= $lc; $count++) {
    					$stat_real = $stat_real . "\n" . raw_line($count, 0);
    				}
    				WARN("VSPRINTF_POINTER_EXTENSION",
    				     "Invalid vsprintf pointer extension '$bad_extension'\n" . "$here\n$stat_real\n");
    			}
    
    # Check for misused memsets
    		if ($^V && $^V ge 5.10.0 &&
    		    defined $stat &&
    
    		    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) {
    
    
    			my $ms_addr = $2;
    			my $ms_val = $7;
    			my $ms_size = $12;
    
    			if ($ms_size =~ /^(0x|)0$/i) {
    				ERROR("MEMSET",
    				      "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n");
    			} elsif ($ms_size =~ /^(0x|)1$/i) {
    				WARN("MEMSET",
    				     "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n");
    			}
    		}
    
    
    # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar)
    
    #		if ($^V && $^V ge 5.10.0 &&
    #		    defined $stat &&
    #		    $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
    #			if (WARN("PREFER_ETHER_ADDR_COPY",
    #				 "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") &&
    #			    $fix) {
    #				$fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/;
    #			}
    #		}
    
    # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar)
    #		if ($^V && $^V ge 5.10.0 &&
    #		    defined $stat &&
    #		    $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
    #			WARN("PREFER_ETHER_ADDR_EQUAL",
    #			     "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n")
    #		}
    
    # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr
    # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr
    #		if ($^V && $^V ge 5.10.0 &&
    #		    defined $stat &&
    #		    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
    #
    #			my $ms_val = $7;
    #
    #			if ($ms_val =~ /^(?:0x|)0+$/i) {
    #				if (WARN("PREFER_ETH_ZERO_ADDR",
    #					 "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") &&
    #				    $fix) {
    #					$fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/;
    #				}
    #			} elsif ($ms_val =~ /^(?:0xff|255)$/i) {
    #				if (WARN("PREFER_ETH_BROADCAST_ADDR",
    #					 "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") &&
    #				    $fix) {
    #					$fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/;
    #				}
    #			}
    #		}
    
    # typecasts on min/max could be min_t/max_t
    		if ($^V && $^V ge 5.10.0 &&
    		    defined $stat &&
    		    $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
    			if (defined $2 || defined $7) {
    				my $call = $1;
    				my $cast1 = deparenthesize($2);
    				my $arg1 = $3;
    				my $cast2 = deparenthesize($7);
    				my $arg2 = $8;
    				my $cast;
    
    				if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) {
    					$cast = "$cast1 or $cast2";
    				} elsif ($cast1 ne "") {
    					$cast = $cast1;
    				} else {
    					$cast = $cast2;
    				}
    				WARN("MINMAX",
    				     "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n");
    			}
    		}
    
    # check usleep_range arguments
    		if ($^V && $^V ge 5.10.0 &&
    		    defined $stat &&
    		    $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
    			my $min = $1;
    			my $max = $7;
    			if ($min eq $max) {
    				WARN("USLEEP_RANGE",
    				     "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
    			} elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ &&
    				 $min > $max) {
    				WARN("USLEEP_RANGE",
    				     "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
    			}
    		}
    
    
    # check for naked sscanf
    		if ($^V && $^V ge 5.10.0 &&
    		    defined $stat &&
    
    		    $line =~ /\bsscanf\b/ &&
    
    		    ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ &&
    		     $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ &&
    		     $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) {
    			my $lc = $stat =~ tr@\n@@;
    			$lc = $lc + $linenr;
    			my $stat_real = raw_line($linenr, 0);
    		        for (my $count = $linenr + 1; $count <= $lc; $count++) {
    				$stat_real = $stat_real . "\n" . raw_line($count, 0);
    			}
    			WARN("NAKED_SSCANF",
    			     "unchecked sscanf return value\n" . "$here\n$stat_real\n");
    		}
    
    
    # check for simple sscanf that should be kstrto<foo>
    		if ($^V && $^V ge 5.10.0 &&
    		    defined $stat &&
    		    $line =~ /\bsscanf\b/) {
    			my $lc = $stat =~ tr@\n@@;
    			$lc = $lc + $linenr;
    			my $stat_real = raw_line($linenr, 0);
    		        for (my $count = $linenr + 1; $count <= $lc; $count++) {
    				$stat_real = $stat_real . "\n" . raw_line($count, 0);
    			}
    			if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) {
    				my $format = $6;
    				my $count = $format =~ tr@%@%@;
    				if ($count == 1 &&
    				    $format =~ /^"\%(?i:ll[udxi]|[udxi]ll|ll|[hl]h?[udxi]|[udxi][hl]h?|[hl]h?|[udxi])"$/) {
    					WARN("SSCANF_TO_KSTRTO",
    					     "Prefer kstrto<type> to single variable sscanf\n" . "$here\n$stat_real\n");
    				}
    			}
    		}
    
    
    # check for new externs in .h files.
    		if ($realfile =~ /\.h$/ &&
    		    $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) {
    			if (CHK("AVOID_EXTERNS",
    				"extern prototypes should be avoided in .h files\n" . $herecurr) &&
    			    $fix) {
    
    				$fixed[$fixlinenr] =~ s/(.*)\bextern\b\s*(.*)/$1$2/;
    
    # check for new externs in .c files.
    		if ($realfile =~ /\.c$/ && defined $stat &&
    		    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
    		{
    			my $function_name = $1;
    			my $paren_space = $2;
    
    			my $s = $stat;
    			if (defined $cond) {
    				substr($s, 0, length($cond), '');
    			}
    			if ($s =~ /^\s*;/ &&
    			    $function_name ne 'uninitialized_var')
    			{
    				WARN("AVOID_EXTERNS",
    				     "externs should be avoided in .c files\n" .  $herecurr);
    			}
    
    			if ($paren_space =~ /\n/) {
    				WARN("FUNCTION_ARGUMENTS",
    				     "arguments for function declarations should follow identifier\n" . $herecurr);
    			}
    
    		} elsif ($realfile =~ /\.c$/ && defined $stat &&
    		    $stat =~ /^.\s*extern\s+/)
    		{
    			WARN("AVOID_EXTERNS",
    			     "externs should be avoided in .c files\n" .  $herecurr);
    		}
    
    
    # check for function declarations that have arguments without identifier names
    		if (defined $stat &&
    		    $stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s &&
    		    $1 ne "void") {
    			my $args = trim($1);
    			while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) {
    				my $arg = trim($1);
    				if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) {
    					WARN("FUNCTION_ARGUMENTS",
    					     "function definition argument '$arg' should also have an identifier name\n" . $herecurr);
    				}
    			}
    		}
    
    # check for function definitions
    		if ($^V && $^V ge 5.10.0 &&
    		    defined $stat &&
    		    $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) {
    			$context_function = $1;
    
    # check for multiline function definition with misplaced open brace
    			my $ok = 0;
    			my $cnt = statement_rawlines($stat);
    			my $herectx = $here . "\n";
    			for (my $n = 0; $n < $cnt; $n++) {
    				my $rl = raw_line($linenr, $n);
    				$herectx .=  $rl . "\n";
    				$ok = 1 if ($rl =~ /^[ \+]\{/);
    				$ok = 1 if ($rl =~ /\{/ && $n == 0);
    				last if $rl =~ /^[ \+].*\{/;
    			}
    			if (!$ok) {
    				ERROR("OPEN_BRACE",
    				      "open brace '{' following function definitions go on the next line\n" . $herectx);
    			}
    		}
    
    
    # checks for new __setup's
    		if ($rawline =~ /\b__setup\("([^"]*)"/) {
    			my $name = $1;
    
    			if (!grep(/$name/, @setup_docs)) {
    				CHK("UNDOCUMENTED_SETUP",
    
    				    "__setup appears un-documented -- check Documentation/admin-guide/kernel-parameters.rst\n" . $herecurr);
    
    			}
    		}
    
    # check for pointless casting of kmalloc return
    		if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) {
    			WARN("UNNECESSARY_CASTS",
    			     "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
    		}
    
    
    # alloc style
    # p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
    		if ($^V && $^V ge 5.10.0 &&
    		    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
    			CHK("ALLOC_SIZEOF_STRUCT",
    			    "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
    		}