summaryrefslogtreecommitdiff
path: root/scripts/checkpatch.pl
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/checkpatch.pl')
-rwxr-xr-xscripts/checkpatch.pl164
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);
}