diff options
Diffstat (limited to 'scripts/checkpatch.pl')
| -rwxr-xr-x | scripts/checkpatch.pl | 164 | 
1 files changed, 141 insertions, 23 deletions
| diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d12435992dea..89b1df4e72ab 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -47,6 +47,8 @@ my $ignore_perl_version = 0;  my $minimum_perl_version = 5.10.0;  my $min_conf_desc_length = 4;  my $spelling_file = "$D/spelling.txt"; +my $codespell = 0; +my $codespellfile = "/usr/local/share/codespell/dictionary.txt";  sub help {  	my ($exitcode) = @_; @@ -88,6 +90,9 @@ Options:                               file.  It's your fault if there's no backup or git    --ignore-perl-version      override checking of perl version.  expect                               runtime errors. +  --codespell                Use the codespell dictionary for spelling/typos +                             (default:/usr/local/share/codespell/dictionary.txt) +  --codespellfile            Use this codespell dictionary    -h, --help, --version      display this help and exit  When FILE is - read standard input. @@ -146,6 +151,8 @@ GetOptions(  	'ignore-perl-version!' => \$ignore_perl_version,  	'debug=s'	=> \%debug,  	'test-only=s'	=> \$tst_only, +	'codespell!'	=> \$codespell, +	'codespellfile=s'	=> \$codespellfile,  	'h|help'	=> \$help,  	'version'	=> \$help  ) or help(1); @@ -316,6 +323,7 @@ our $Operators	= qr{  our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; +our $BasicType;  our $NonptrType;  our $NonptrTypeMisordered;  our $NonptrTypeWithAttr; @@ -436,6 +444,14 @@ foreach my $entry (@mode_permission_funcs) {  	$mode_perms_search .= $entry->[0];  } +our $mode_perms_world_writable = qr{ +	S_IWUGO		| +	S_IWOTH		| +	S_IRWXUGO	| +	S_IALLUGO	| +	0[0-7][0-7][2367] +}x; +  our $allowed_asm_includes = qr{(?x:  	irq|  	memory| @@ -449,7 +465,6 @@ my $misspellings;  my %spelling_fix;  if (open(my $spelling, '<', $spelling_file)) { -	my @spelling_list;  	while (<$spelling>) {  		my $line = $_; @@ -461,21 +476,50 @@ if (open(my $spelling, '<', $spelling_file)) {  		my ($suspect, $fix) = split(/\|\|/, $line); -		push(@spelling_list, $suspect);  		$spelling_fix{$suspect} = $fix;  	}  	close($spelling); -	$misspellings = join("|", @spelling_list);  } else {  	warn "No typos will be found - file '$spelling_file': $!\n";  } +if ($codespell) { +	if (open(my $spelling, '<', $codespellfile)) { +		while (<$spelling>) { +			my $line = $_; + +			$line =~ s/\s*\n?$//g; +			$line =~ s/^\s*//g; + +			next if ($line =~ m/^\s*#/); +			next if ($line =~ m/^\s*$/); +			next if ($line =~ m/, disabled/i); + +			$line =~ s/,.*$//; + +			my ($suspect, $fix) = split(/->/, $line); + +			$spelling_fix{$suspect} = $fix; +		} +		close($spelling); +	} else { +		warn "No codespell typos will be found - file '$codespellfile': $!\n"; +	} +} + +$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix; +  sub build_types {  	my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";  	my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";  	my $Misordered = "(?x:  \n" . join("|\n  ", @typeListMisordered) . "\n)";  	my $allWithAttr = "(?x:  \n" . join("|\n  ", @typeListWithAttr) . "\n)";  	$Modifier	= qr{(?:$Attribute|$Sparse|$mods)}; +	$BasicType	= qr{ +				(?:$typeOtherOSTypedefs\b)| +				(?:$typeTypedefs\b)| +				(?:${all}\b) +		}x;  	$NonptrType	= qr{  			(?:$Modifier\s+|const\s+)*  			(?: @@ -1646,7 +1690,7 @@ sub fix_inserted_deleted_lines {  	foreach my $old_line (@{$linesRef}) {  		my $save_line = 1;  		my $line = $old_line;	#don't modify the array -		if ($line =~ /^(?:\+\+\+\|\-\-\-)\s+\S+/) {	#new filename +		if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) {	#new filename  			$delta_offset = 0;  		} elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) {	#new hunk  			$range_last_linenr = $new_linenr; @@ -1854,6 +1898,7 @@ sub process {  	my $in_header_lines = $file ? 0 : 1;  	my $in_commit_log = 0;		#Scanning lines before patch +	my $commit_log_long_line = 0;  	my $reported_maintainer_file = 0;  	my $non_utf8_charset = 0; @@ -2189,6 +2234,14 @@ sub process {  			      "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr);  		} +# Check for line lengths > 75 in commit log, warn once +		if ($in_commit_log && !$commit_log_long_line && +		    length($line) > 75) { +			WARN("COMMIT_LOG_LONG_LINE", +			     "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); +			$commit_log_long_line = 1; +		} +  # Check for git id commit length and improperly formed commit descriptions  		if ($in_commit_log && $line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i) {  			my $init_char = $1; @@ -2303,8 +2356,9 @@ sub process {  		}  # Check for various typo / spelling mistakes -		if (defined($misspellings) && ($in_commit_log || $line =~ /^\+/)) { -			while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:$|[^a-z@])/gi) { +		if (defined($misspellings) && +		    ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { +			while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:\b|$|[^a-z@])/gi) {  				my $typo = $1;  				my $typo_fix = $spelling_fix{lc($typo)};  				$typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/); @@ -2459,8 +2513,9 @@ sub process {  #line length limit  		if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&  		    $rawline !~ /^.\s*\*\s*\@$Ident\s/ && -		    !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ || -		    $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && +		    !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?$String\s*(?:|,|\)\s*;)\s*$/ || +		      $line =~ /^\+\s*$String\s*(?:\s*|,|\)\s*;)\s*$/ || +		      $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) &&  		    $length > $max_line_length)  		{  			WARN("LONG_LINE", @@ -2552,8 +2607,15 @@ sub process {  			}  		} -		if ($line =~ /^\+.*(\w+\s*)?\(\s*$Type\s*\)[ \t]+(?!$Assignment|$Arithmetic|[,;:\?\(\{\}\[\<\>]|&&|\|\||\\$)/ && -		    (!defined($1) || $1 !~ /sizeof\s*/)) { +# check for space after cast like "(int) foo" or "(struct foo) bar" +# avoid checking a few false positives: +#   "sizeof(<type>)" or "__alignof__(<type>)" +#   function pointer declarations like "(*foo)(int) = bar;" +#   structure definitions like "(struct foo) { 0 };" +#   multiline macros that define functions +#   known attributes or the __attribute__ keyword +		if ($line =~ /^\+(.*)\(\s*$Type\s*\)([ \t]++)((?![={]|\\$|$Attribute|__attribute__))/ && +		    (!defined($1) || $1 !~ /\b(?:sizeof|__alignof__)\s*$/)) {  			if (CHK("SPACING",  				"No space is necessary after a cast\n" . $herecurr) &&  			    $fix) { @@ -3146,6 +3208,18 @@ sub process {  				$herecurr);                 } +# check for const <foo> const where <foo> is not a pointer or array type +		if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) { +			my $found = $1; +			if ($sline =~ /\bconst\s+\Q$found\E\s+const\b\s*\*/) { +				WARN("CONST_CONST", +				     "'const $found const *' should probably be 'const $found * const'\n" . $herecurr); +			} elsif ($sline !~ /\bconst\s+\Q$found\E\s+const\s+\w+\s*\[/) { +				WARN("CONST_CONST", +				     "'const $found const' should probably be 'const $found'\n" . $herecurr); +			} +		} +  # check for non-global char *foo[] = {"bar", ...} declarations.  		if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) {  			WARN("STATIC_CONST_CHAR_ARRAY", @@ -3153,6 +3227,19 @@ sub process {  				$herecurr);                 } +# check for sizeof(foo)/sizeof(foo[0]) that could be ARRAY_SIZE(foo) +		if ($line =~ m@\bsizeof\s*\(\s*($Lval)\s*\)@) { +			my $array = $1; +			if ($line =~ m@\b(sizeof\s*\(\s*\Q$array\E\s*\)\s*/\s*sizeof\s*\(\s*\Q$array\E\s*\[\s*0\s*\]\s*\))@) { +				my $array_div = $1; +				if (WARN("ARRAY_SIZE", +					 "Prefer ARRAY_SIZE($array)\n" . $herecurr) && +				    $fix) { +					$fixed[$fixlinenr] =~ s/\Q$array_div\E/ARRAY_SIZE($array)/; +				} +			} +		} +  # check for function declarations without arguments like "int foo()"  		if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) {  			if (ERROR("FUNCTION_WITHOUT_ARGS", @@ -3309,6 +3396,14 @@ sub process {  			     "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr);  		} +# ENOSYS means "bad syscall nr" and nothing else.  This will have a small +# number of false positives, but assembly files are not checked, so at +# least the arch entry code will not trigger this warning. +		if ($line =~ /\bENOSYS\b/) { +			WARN("ENOSYS", +			     "ENOSYS means 'invalid syscall nr' and nothing else\n" . $herecurr); +		} +  # function brace can't be on same line, except for #defines of do while,  # or if closed on same line  		if (($line=~/$Type\s*$Ident\(.*\).*\s*{/) and @@ -3565,7 +3660,7 @@ sub process {  				# Ignore operators passed as parameters.  				if ($op_type ne 'V' && -				    $ca =~ /\s$/ && $cc =~ /^\s*,/) { +				    $ca =~ /\s$/ && $cc =~ /^\s*[,\)]/) {  #				# Ignore comments  #				} elsif ($op =~ /^$;+$/) { @@ -3750,6 +3845,14 @@ sub process {  					    	$ok = 1;  					} +					# 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  					if ($ok == 0) {  						my $msg_type = \&ERROR; @@ -3963,12 +4066,12 @@ sub process {  			}  		} -# Return of what appears to be an errno should normally be -'ve -		if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { +# 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 -ve (return -$1)\n" . $herecurr); +				     "return of an errno should typically be negative (ie: return -$1)\n" . $herecurr);  			}  		} @@ -4178,7 +4281,8 @@ sub process {  			}  		} -#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line) +# 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"; @@ -4186,12 +4290,15 @@ sub process {  			    $realfile ne $checkfile &&  			    $1 !~ /$allowed_asm_includes/)  			{ -				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); +				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); +					}  				}  			}  		} @@ -4700,6 +4807,16 @@ sub process {  			}  		} +# 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*\(/) { @@ -5261,6 +5378,7 @@ sub process {  				stacktrace_ops|  				sysfs_ops|  				tty_operations| +				uart_ops|  				usb_mon_operations|  				wd_ops}x;  		if ($line !~ /\bconst\b/ && @@ -5318,8 +5436,8 @@ sub process {  			}  		} -		if ($line =~ /debugfs_create_file.*S_IWUGO/ || -		    $line =~ /DEVICE_ATTR.*S_IWUGO/ ) { +		if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || +		    $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) {  			WARN("EXPORTED_WORLD_WRITABLE",  			     "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);  		} | 
