diff options
Diffstat (limited to 'scripts/checkpatch.pl')
| -rwxr-xr-x | scripts/checkpatch.pl | 155 | 
1 files changed, 119 insertions, 36 deletions
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index a63380c6b0d2..d64c67b67e3c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -64,6 +64,7 @@ my $color = "auto";  my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE  # git output parsing needs US English output, so first set backtick child process LANGUAGE  my $git_command ='export LANGUAGE=en_US.UTF-8; git'; +my $tabsize = 8;  sub help {  	my ($exitcode) = @_; @@ -98,6 +99,7 @@ Options:    --show-types               show the specific message type in the output    --max-line-length=n        set the maximum line length, if exceeded, warn    --min-conf-desc-length=n   set the min description length, if shorter, warn +  --tab-size=n               set the number of spaces for tab (default 8)    --root=PATH                PATH to the kernel tree root    --no-summary               suppress the per-file summary    --mailback                 only produce a report in case of warnings/errors @@ -215,6 +217,7 @@ GetOptions(  	'list-types!'	=> \$list_types,  	'max-line-length=i' => \$max_line_length,  	'min-conf-desc-length=i' => \$min_conf_desc_length, +	'tab-size=i'	=> \$tabsize,  	'root=s'	=> \$root,  	'summary!'	=> \$summary,  	'mailback!'	=> \$mailback, @@ -267,6 +270,9 @@ if ($color =~ /^[01]$/) {  	die "Invalid color mode: $color\n";  } +# skip TAB size 1 to avoid additional checks on $tabsize - 1 +die "Invalid TAB size: $tabsize\n" if ($tabsize < 2); +  sub hash_save_array_words {  	my ($hashRef, $arrayRef) = @_; @@ -804,12 +810,12 @@ sub build_types {  		  }x;  	$Type	= qr{  			$NonptrType -			(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? +			(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4}  			(?:\s+$Inline|\s+$Modifier)*  		  }x;  	$TypeMisordered	= qr{  			$NonptrTypeMisordered -			(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? +			(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4}  			(?:\s+$Inline|\s+$Modifier)*  		  }x;  	$Declare	= qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type}; @@ -1118,6 +1124,7 @@ sub parse_email {  	my ($formatted_email) = @_;  	my $name = ""; +	my $name_comment = "";  	my $address = "";  	my $comment = ""; @@ -1150,6 +1157,10 @@ sub parse_email {  	$name = trim($name);  	$name =~ s/^\"|\"$//g; +	$name =~ s/(\s*\([^\)]+\))\s*//; +	if (defined($1)) { +		$name_comment = trim($1); +	}  	$address = trim($address);  	$address =~ s/^\<|\>$//g; @@ -1158,7 +1169,7 @@ sub parse_email {  		$name = "\"$name\"";  	} -	return ($name, $address, $comment); +	return ($name, $name_comment, $address, $comment);  }  sub format_email { @@ -1184,6 +1195,23 @@ sub format_email {  	return $formatted_email;  } +sub reformat_email { +	my ($email) = @_; + +	my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); +	return format_email($email_name, $email_address); +} + +sub same_email_addresses { +	my ($email1, $email2) = @_; + +	my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1); +	my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2); + +	return $email1_name eq $email2_name && +	       $email1_address eq $email2_address; +} +  sub which {  	my ($bin) = @_; @@ -1217,7 +1245,7 @@ sub expand_tabs {  		if ($c eq "\t") {  			$res .= ' ';  			$n++; -			for (; ($n % 8) != 0; $n++) { +			for (; ($n % $tabsize) != 0; $n++) {  				$res .= ' ';  			}  			next; @@ -2230,7 +2258,7 @@ sub string_find_replace {  sub tabify {  	my ($leading) = @_; -	my $source_indent = 8; +	my $source_indent = $tabsize;  	my $max_spaces_before_tab = $source_indent - 1;  	my $spaces_to_tab = " " x $source_indent; @@ -2272,6 +2300,19 @@ sub pos_last_openparen {  	return length(expand_tabs(substr($line, 0, $last_openparen))) + 1;  } +sub get_raw_comment { +	my ($line, $rawline) = @_; +	my $comment = ''; + +	for my $i (0 .. (length($line) - 1)) { +		if (substr($line, $i, 1) eq "$;") { +			$comment .= substr($rawline, $i, 1); +		} +	} + +	return $comment; +} +  sub process {  	my $filename = shift; @@ -2294,6 +2335,7 @@ sub process {  	my $is_binding_patch = -1;  	my $in_header_lines = $file ? 0 : 1;  	my $in_commit_log = 0;		#Scanning lines before patch +	my $has_patch_separator = 0;	#Found a --- line  	my $has_commit_log = 0;		#Encountered lines before patch  	my $commit_log_lines = 0;	#Number of commit log lines  	my $commit_log_possible_stack_dump = 0; @@ -2433,6 +2475,7 @@ sub process {  		$sline =~ s/$;/ /g;	#with comments as spaces  		my $rawline = $rawlines[$linenr - 1]; +		my $raw_comment = get_raw_comment($line, $rawline);  # check if it's a mode change, rename or start of a patch  		if (!$in_commit_log && @@ -2604,21 +2647,26 @@ sub process {  			$author = $1;  			$author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i);  			$author =~ s/"//g; +			$author = reformat_email($author);  		}  # Check the patch for a signoff: -		if ($line =~ /^\s*signed-off-by:/i) { +		if ($line =~ /^\s*signed-off-by:\s*(.*)/i) {  			$signoff++;  			$in_commit_log = 0;  			if ($author ne '') { -				my $l = $line; -				$l =~ s/"//g; -				if ($l =~ /^\s*signed-off-by:\s*\Q$author\E/i) { -				    $authorsignoff = 1; +				if (same_email_addresses($1, $author)) { +					$authorsignoff = 1;  				}  			}  		} +# Check for patch separator +		if ($line =~ /^---$/) { +			$has_patch_separator = 1; +			$in_commit_log = 0; +		} +  # Check if MAINTAINERS is being updated.  If so, there's probably no need to  # emit the "does MAINTAINERS need updating?" message on file add/move/delete  		if ($line =~ /^\s*MAINTAINERS\s*\|/) { @@ -2664,7 +2712,7 @@ sub process {  				}  			} -			my ($email_name, $email_address, $comment) = parse_email($email); +			my ($email_name, $name_comment, $email_address, $comment) = parse_email($email);  			my $suggested_email = format_email(($email_name, $email_address));  			if ($suggested_email eq "") {  				ERROR("BAD_SIGN_OFF", @@ -2675,9 +2723,7 @@ sub process {  				$dequoted =~ s/" </ </;  				# Don't force email to have quotes  				# Allow just an angle bracketed address -				if ("$dequoted$comment" ne $email && -				    "<$email_address>$comment" ne $email && -				    "$suggested_email$comment" ne $email) { +				if (!same_email_addresses($email, $suggested_email)) {  					WARN("BAD_SIGN_OFF",  					     "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr);  				} @@ -2720,10 +2766,10 @@ sub process {  			     "A patch subject line should describe the change not the tool that found it\n" . $herecurr);  		} -# Check for unwanted Gerrit info -		if ($in_commit_log && $line =~ /^\s*change-id:/i) { +# Check for Gerrit Change-Ids not in any patch context +		if ($realfile eq '' && !$has_patch_separator && $line =~ /^\s*change-id:/i) {  			ERROR("GERRIT_CHANGE_ID", -			      "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); +			      "Remove Gerrit Change-Id's before submitting upstream\n" . $herecurr);  		}  # Check if the commit log is in a possible stack dump @@ -2761,7 +2807,7 @@ sub process {  # Check for git id commit length and improperly formed commit descriptions  		if ($in_commit_log && !$commit_log_possible_stack_dump && -		    $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink):/i && +		    $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink|base-commit):/i &&  		    $line !~ /^This reverts commit [0-9a-f]{7,40}/ &&  		    ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i ||  		     ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i && @@ -3087,7 +3133,7 @@ sub process {  					$comment = '/*';  				} elsif ($realfile =~ /\.(c|dts|dtsi)$/) {  					$comment = '//'; -				} elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc)$/) { +				} elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc|yaml)$/) {  					$comment = '#';  				} elsif ($realfile =~ /\.rst$/) {  					$comment = '..'; @@ -3111,6 +3157,17 @@ sub process {  						WARN("SPDX_LICENSE_TAG",  						     "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr);  					} +					if ($realfile =~ m@^Documentation/devicetree/bindings/@ && +					    not $spdx_license =~ /GPL-2\.0.*BSD-2-Clause/) { +						my $msg_level = \&WARN; +						$msg_level = \&CHK if ($file); +						if (&{$msg_level}("SPDX_LICENSE_TAG", + +								  "DT binding documents should be licensed (GPL-2.0-only OR BSD-2-Clause)\n" . $herecurr) && +						    $fix) { +							$fixed[$fixlinenr] =~ s/SPDX-License-Identifier: .*/SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)/; +						} +					}  				}  			}  		} @@ -3198,7 +3255,7 @@ sub process {  		next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/);  # at the beginning of a line any tabs must come first and anything -# more than 8 must use tabs. +# more than $tabsize must use tabs.  		if ($rawline =~ /^\+\s* \t\s*\S/ ||  		    $rawline =~ /^\+\s*        \s*/) {  			my $herevet = "$here\n" . cat_vet($rawline) . "\n"; @@ -3217,7 +3274,7 @@ sub process {  				"please, no space before tabs\n" . $herevet) &&  			    $fix) {  				while ($fixed[$fixlinenr] =~ -					   s/(^\+.*) {8,8}\t/$1\t\t/) {} +					   s/(^\+.*) {$tabsize,$tabsize}\t/$1\t\t/) {}  				while ($fixed[$fixlinenr] =~  					   s/(^\+.*) +\t/$1\t/) {}  			} @@ -3239,11 +3296,11 @@ sub process {  		if ($perl_version_ok &&  		    $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) {  			my $indent = length($1); -			if ($indent % 8) { +			if ($indent % $tabsize) {  				if (WARN("TABSTOP",  					 "Statements should start on a tabstop\n" . $herecurr) &&  				    $fix) { -					$fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/8)@e; +					$fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/$tabsize)@e;  				}  			}  		} @@ -3261,8 +3318,8 @@ sub process {  				my $newindent = $2;  				my $goodtabindent = $oldindent . -					"\t" x ($pos / 8) . -					" "  x ($pos % 8); +					"\t" x ($pos / $tabsize) . +					" "  x ($pos % $tabsize);  				my $goodspaceindent = $oldindent . " "  x $pos;  				if ($newindent ne $goodtabindent && @@ -3733,11 +3790,11 @@ sub process {  			#print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";  			if ($check && $s ne '' && -			    (($sindent % 8) != 0 || +			    (($sindent % $tabsize) != 0 ||  			     ($sindent < $indent) ||  			     ($sindent == $indent &&  			      ($s !~ /^\s*(?:\}|\{|else\b)/)) || -			     ($sindent > $indent + 8))) { +			     ($sindent > $indent + $tabsize))) {  				WARN("SUSPECT_CODE_INDENT",  				     "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");  			} @@ -4014,7 +4071,7 @@ sub process {  		}  # check for function declarations without arguments like "int foo()" -		if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) { +		if ($line =~ /(\b$Type\s*$Ident)\s*\(\s*\)/) {  			if (ERROR("FUNCTION_WITHOUT_ARGS",  				  "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) &&  			    $fix) { @@ -4582,7 +4639,7 @@ sub process {  					    ($op eq '>' &&  					     $ca =~ /<\S+\@\S+$/))  					{ -					    	$ok = 1; +						$ok = 1;  					}  					# for asm volatile statements @@ -4917,7 +4974,7 @@ sub process {  			# conditional.  			substr($s, 0, length($c), '');  			$s =~ s/\n.*//g; -			$s =~ s/$;//g; 	# Remove any comments +			$s =~ s/$;//g;	# Remove any comments  			if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&  			    $c !~ /}\s*while\s*/)  			{ @@ -4956,7 +5013,7 @@ sub process {  # 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 +			$s =~ s/$;//g;	# Remove any comments  			if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {  				ERROR("TRAILING_STATEMENTS",  				      "trailing statements should be on next line\n" . $herecurr); @@ -5132,7 +5189,7 @@ sub process {  			{  			} -			# Flatten any obvious string concatentation. +			# Flatten any obvious string concatenation.  			while ($dstat =~ s/($String)\s*$Ident/$1/ ||  			       $dstat =~ s/$Ident\s*($String)/$1/)  			{ @@ -6230,13 +6287,17 @@ sub process {  		}  # check for function declarations that have arguments without identifier names +# while avoiding uninitialized_var(x)  		if (defined $stat && -		    $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s && -		    $1 ne "void") { -			my $args = trim($1); +		    $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:($Ident)|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s && +		    (!defined($1) || +		     (defined($1) && $1 ne "uninitialized_var")) && +		     $2 ne "void") { +			my $args = trim($2);  			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$/) { +				if ($arg =~ /^$Type$/ && +					$arg !~ /enum\s+$Ident$/) {  					WARN("FUNCTION_ARGUMENTS",  					     "function definition argument '$arg' should also have an identifier name\n" . $herecurr);  				} @@ -6389,6 +6450,28 @@ sub process {  			}  		} +# check for /* fallthrough */ like comment, prefer fallthrough; +		my @fallthroughs = ( +			'fallthrough', +			'@fallthrough@', +			'lint -fallthrough[ \t]*', +			'intentional(?:ly)?[ \t]*fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)', +			'(?:else,?\s*)?FALL(?:S | |-)?THR(?:OUGH|U|EW)[ \t.!]*(?:-[^\n\r]*)?', +			'Fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', +			'fall(?:s | |-)?thr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', +		    ); +		if ($raw_comment ne '') { +			foreach my $ft (@fallthroughs) { +				if ($raw_comment =~ /$ft/) { +					my $msg_level = \&WARN; +					$msg_level = \&CHK if ($file); +					&{$msg_level}("PREFER_FALLTHROUGH", +						      "Prefer 'fallthrough;' over fallthrough comment\n" . $herecurr); +					last; +				} +			} +		} +  # check for switch/default statements without a break;  		if ($perl_version_ok &&  		    defined $stat &&  | 
