2017-05-07 23:25:26 +02:00
# ! / usr / bin / env perl
2018-06-07 17:04:33 -07:00
# SPDX - License - Identifier : GPL - 2.0
#
2010-01-12 16:59:52 -05:00
# ( c ) 2001 , Dave Jones . ( the file handling bit )
2007-06-08 13:47:06 -07:00
# ( c ) 2005 , Joel Schopp < jschopp @ austin . ibm . com > ( the ugly bit )
2009-01-06 14:41:23 -08:00
# ( c ) 2007 , 2008 , Andy Whitcroft < apw @ uk . ibm . com > ( new conditions , test suite )
2010-10-26 14:23:17 -07:00
# ( c ) 2008 - 2010 Andy Whitcroft < apw @ canonical . com >
2018-06-07 17:04:33 -07:00
# ( c ) 2010 - 2018 Joe Perches < joe @ perches . com >
2007-06-01 00:46:48 -07:00
use strict ;
2017-05-07 23:25:26 +02:00
use warnings ;
2013-07-08 16:00:43 -07:00
use POSIX ;
2014-12-10 15:51:43 -08:00
use File :: Basename ;
use Cwd 'abs_path' ;
2015-06-25 15:03:03 -07:00
use Term :: ANSIColor qw ( : constants ) ;
2018-08-21 21:57:40 -07:00
use Encode qw ( decode encode ) ;
2007-06-01 00:46:48 -07:00
my $ P = $ 0 ;
2014-12-10 15:51:43 -08:00
my $ D = dirname ( abs_path ( $ P ) ) ;
2007-06-01 00:46:48 -07:00
2011-07-25 17:13:25 -07:00
my $ V = '0.32' ;
2007-06-01 00:46:48 -07:00
use Getopt :: Long qw ( : config no_auto_abbrev ) ;
my $ quiet = 0 ;
my $ tree = 1 ;
my $ chk_signoff = 1 ;
my $ chk_patch = 1 ;
2008-03-28 14:15:58 -07:00
my $ tst_only ;
2007-10-18 03:05:08 -07:00
my $ emacs = 0 ;
2007-11-28 16:21:06 -08:00
my $ terse = 0 ;
2015-06-25 15:03:05 -07:00
my $ showfile = 0 ;
2007-10-18 03:05:08 -07:00
my $ file = 0 ;
2016-05-20 17:04:16 -07:00
my $ git = 0 ;
2016-05-20 17:04:19 -07:00
my %git_commits = ();
2007-10-18 03:05:08 -07:00
my $ check = 0 ;
2014-06-04 16:12:05 -07:00
my $ check_orig = 0 ;
2007-11-28 16:21:06 -08:00
my $ summary = 1 ;
my $ mailback = 0 ;
2008-02-08 04:22:03 -08:00
my $ summary_file = 0 ;
2011-07-25 17:13:25 -07:00
my $ show_types = 0 ;
2016-05-20 17:04:14 -07:00
my $ list_types = 0 ;
2013-07-03 15:05:31 -07:00
my $ fix = 0 ;
2014-01-23 15:54:44 -08:00
my $ fix_inplace = 0 ;
2007-10-18 03:05:08 -07:00
my $ root ;
2020-10-24 16:59:04 -07:00
my $ gitroot = $ ENV { 'GIT_DIR' } ;
$ gitroot = ".git" if ! defined ( $ gitroot ) ;
2008-02-08 04:20:54 -08:00
my %debug;
2013-07-03 15:05:34 -07:00
my %camelcase = ();
2013-09-11 14:23:59 -07:00
my %use_type = ();
my @ use = ( ) ;
my %ignore_type = ();
2011-07-25 17:13:25 -07:00
my @ ignore = ( ) ;
2009-09-21 17:04:37 -07:00
my $ help = 0 ;
2011-07-25 17:13:25 -07:00
my $ configuration_file = ".checkpatch.conf" ;
2020-05-29 16:12:21 -07:00
my $ max_line_length = 100 ;
2013-09-11 14:23:56 -07:00
my $ ignore_perl_version = 0 ;
my $ minimum_perl_version = 5.10 .0 ;
2014-10-13 15:51:48 -07:00
my $ min_conf_desc_length = 4 ;
2014-10-13 15:51:57 -07:00
my $ spelling_file = "$D/spelling.txt" ;
2015-04-16 12:44:14 -07:00
my $ codespell = 0 ;
2015-06-25 15:03:08 -07:00
my $ codespellfile = "/usr/share/codespell/dictionary.txt" ;
2016-10-11 13:51:56 -07:00
my $ conststructsfile = "$D/const_structs.checkpatch" ;
2020-08-11 18:35:13 -07:00
my $ typedefsfile ;
2017-07-10 15:52:24 -07:00
my $ color = "auto" ;
2019-03-07 16:28:38 -08:00
my $ allow_c99_comments = 1 ; # Can be overridden by -- ignore C99_COMMENT_TOLERANCE
2019-09-25 16:46:52 -07:00
# git output parsing needs US English output , so first set backtick child process LANGUAGE
my $ git_command = 'export LANGUAGE=en_US.UTF-8; git' ;
2020-04-06 20:11:07 -07:00
my $ tabsize = 8 ;
2020-10-15 20:11:49 -07:00
my $ { CONFIG_ } = "CONFIG_" ;
2009-09-21 17:04:37 -07:00
sub help {
my ( $ exitcode ) = @ _ ;
print << "EOM" ;
Usage : $ P [ OPTION ] . . . [ FILE ] . . .
Version : $ V
Options :
- q , -- quiet quiet
-- no - tree run without a kernel tree
-- no - signoff do not check for 'Signed-off-by' line
-- patch treat FILE as patchfile ( default )
-- emacs emacs compile window format
-- terse one line per report
2015-06-25 15:03:05 -07:00
-- showfile emit diffed file position , not input file position
2016-05-20 17:04:16 -07:00
- g , -- git treat FILE as a single commit or git revision range
single git commit with :
< rev >
< rev >^
< rev >~ n
multiple git commits with :
< rev1 >..< rev2 >
< rev1 >...< rev2 >
< rev >-< count >
git merges are ignored
2009-09-21 17:04:37 -07:00
- f , -- file treat FILE as regular source file
-- subjective , -- strict enable more subjective tests
2016-05-20 17:04:14 -07:00
-- list - types list the possible message types
2013-09-11 14:23:59 -07:00
-- types TYPE ( , TYPE2 . . . ) show only these comma separated message types
2011-07-25 17:13:25 -07:00
-- ignore TYPE ( , TYPE2 . . . ) ignore various comma separated message types
2016-05-20 17:04:14 -07:00
-- show - types show the specific message type in the output
2020-05-29 16:12:21 -07:00
-- max - line - length = n set the maximum line length , ( default $ max_line_length )
if exceeded , warn on patches
requires -- strict for use with -- file
2014-10-13 15:51:48 -07:00
-- min - conf - desc - length = n set the min description length , if shorter , warn
2020-05-29 16:12:21 -07:00
-- tab - size = n set the number of spaces for tab ( default $ tabsize )
2009-09-21 17:04:37 -07:00
-- 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
-- summary - file include the filename in summary
-- debug KEY = [ 0 | 1 ] turn on / off debugging of KEY , where KEY is one of
'values' , 'possible' , 'type' , and 'attr' ( default
is all off )
-- test - only = WORD report only warnings / errors containing WORD
literally
2013-07-03 15:05:31 -07:00
-- fix EXPERIMENTAL - may create horrible results
If correctable single - line errors exist , create
"<inputfile>.EXPERIMENTAL-checkpatch-fixes"
with potential errors corrected to the preferred
checkpatch style
2014-01-23 15:54:44 -08:00
-- fix - inplace EXPERIMENTAL - may create horrible results
Is the same as -- fix , but overwrites the input
file . It 's your fault if there' s no backup or git
2013-09-11 14:23:56 -07:00
-- ignore - perl - version override checking of perl version . expect
runtime errors .
2015-04-16 12:44:14 -07:00
-- codespell Use the codespell dictionary for spelling / typos
2015-06-25 15:03:08 -07:00
( default : / usr / share / codespell / dictionary . txt )
2015-04-16 12:44:14 -07:00
-- codespellfile Use this codespell dictionary
2017-05-08 15:56:00 -07:00
-- typedefsfile Read additional types from this file
2017-07-10 15:52:24 -07:00
-- color [ = WHEN ] Use colors 'always' , 'never' , or only when output
is a terminal ( 'auto' ) . Default is 'auto' .
2020-10-15 20:11:49 -07:00
-- kconfig - prefix = WORD use WORD as a prefix for Kconfig symbols ( default
$ { CONFIG_ } )
2009-09-21 17:04:37 -07:00
- h , -- help , -- version display this help and exit
When FILE is - read standard input .
EOM
exit ( $ exitcode ) ;
}
2016-05-20 17:04:14 -07:00
sub uniq {
my %seen;
return grep { ! $ seen { $ _ } ++ } @ _ ;
}
sub list_types {
my ( $ exitcode ) = @ _ ;
my $ count = 0 ;
local $ / = undef ;
open ( my $ script , '<' , abs_path ( $ P ) ) or
die "$P: Can't read '$P' $!\n" ;
my $ text = < $ script > ;
close ( $ script ) ;
my @ types = ( ) ;
2017-09-08 16:16:11 -07:00
# Also catch when type or level is passed through a variable
for ( $ text =~ / ( ?: ( ?:\ bCHK | \ bWARN | \ bERROR | &\ { \ $ msg_level } ) \ s *\ ( | \ $ msg_type \ s *= ) \ s * "([^" ] + ) "/g) {
2016-05-20 17:04:14 -07:00
push (@types, $_);
}
@types = sort(uniq(@types));
print(" #\ tMessage type \ n \ n ");
foreach my $type (@types) {
print(++$count . " \ t " . $type . " \ n ");
}
exit($exitcode);
}
2011-07-25 17:13:25 -07:00
my $conf = which_conf($configuration_file);
if (-f $conf) {
my @conf_args;
open(my $conffile, '<', " $ conf ")
or warn " $ P : Can 't find a readable $configuration_file file $!\n";
while (<$conffile>) {
my $line = $_;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
$line =~ s/\s+/ /g;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
my @words = split(" ", $line);
foreach my $word (@words) {
last if ($word =~ m/^#/);
push (@conf_args, $word);
}
}
close($conffile);
unshift(@ARGV, @conf_args) if @conf_args;
}
2017-07-10 15:52:24 -07:00
# Perl' s Getopt :: Long allows options to take optional arguments after a space .
# Prevent -- color by itself from consuming other arguments
foreach ( @ ARGV ) {
if ( $ _ eq "--color" | | $ _ eq "-color" ) {
$ _ = "--color=$color" ;
}
}
2007-06-01 00:46:48 -07:00
GetOptions (
2007-10-18 03:05:08 -07:00
'q|quiet+' => \ $ quiet ,
2007-06-01 00:46:48 -07:00
'tree!' => \ $ tree ,
'signoff!' => \ $ chk_signoff ,
'patch!' => \ $ chk_patch ,
2007-10-18 03:05:08 -07:00
'emacs!' => \ $ emacs ,
2007-11-28 16:21:06 -08:00
'terse!' => \ $ terse ,
2015-06-25 15:03:05 -07:00
'showfile!' => \ $ showfile ,
2009-09-21 17:04:37 -07:00
'f|file!' => \ $ file ,
2016-05-20 17:04:16 -07:00
'g|git!' => \ $ git ,
2007-10-18 03:05:08 -07:00
'subjective!' => \ $ check ,
'strict!' => \ $ check ,
2011-07-25 17:13:25 -07:00
'ignore=s' => \@ ignore ,
2013-09-11 14:23:59 -07:00
'types=s' => \@ use ,
2011-07-25 17:13:25 -07:00
'show-types!' => \ $ show_types ,
2016-05-20 17:04:14 -07:00
'list-types!' => \ $ list_types ,
2012-12-17 16:01:54 -08:00
'max-line-length=i' => \ $ max_line_length ,
2014-10-13 15:51:48 -07:00
'min-conf-desc-length=i' => \ $ min_conf_desc_length ,
2020-04-06 20:11:07 -07:00
'tab-size=i' => \ $ tabsize ,
2007-10-18 03:05:08 -07:00
'root=s' => \ $ root ,
2007-11-28 16:21:06 -08:00
'summary!' => \ $ summary ,
'mailback!' => \ $ mailback ,
2008-02-08 04:22:03 -08:00
'summary-file!' => \ $ summary_file ,
2013-07-03 15:05:31 -07:00
'fix!' => \ $ fix ,
2014-01-23 15:54:44 -08:00
'fix-inplace!' => \ $ fix_inplace ,
2013-09-11 14:23:56 -07:00
'ignore-perl-version!' => \ $ ignore_perl_version ,
2008-02-08 04:20:54 -08:00
'debug=s' => \ %debug,
2008-03-28 14:15:58 -07:00
'test-only=s' => \ $ tst_only ,
2015-04-16 12:44:14 -07:00
'codespell!' => \ $ codespell ,
'codespellfile=s' => \ $ codespellfile ,
2017-05-08 15:56:00 -07:00
'typedefsfile=s' => \ $ typedefsfile ,
2017-07-10 15:52:24 -07:00
'color=s' => \ $ color ,
'no-color' => \ $ color , # keep old behaviors of - nocolor
'nocolor' => \ $ color , # keep old behaviors of - nocolor
2020-10-15 20:11:49 -07:00
'kconfig-prefix=s' => \ $ { CONFIG_ } ,
2009-09-21 17:04:37 -07:00
'h|help' => \ $ help ,
'version' => \ $ help
) or help ( 1 ) ;
help ( 0 ) if ( $ help ) ;
2007-06-01 00:46:48 -07:00
2016-05-20 17:04:14 -07:00
list_types ( 0 ) if ( $ list_types ) ;
2014-01-23 15:54:44 -08:00
$ fix = 1 if ( $ fix_inplace ) ;
2014-06-04 16:12:05 -07:00
$ check_orig = $ check ;
2014-01-23 15:54:44 -08:00
2020-06-04 16:50:40 -07:00
die "$P: --git cannot be used with --file or --fix\n" if ( $ git && ( $ file | | $ fix ) ) ;
2007-06-01 00:46:48 -07:00
my $ exit = 0 ;
2018-08-21 21:57:33 -07:00
my $ perl_version_ok = 1 ;
2013-09-11 14:23:56 -07:00
if ( $ ^ V && $ ^ V lt $ minimum_perl_version ) {
2018-08-21 21:57:33 -07:00
$ perl_version_ok = 0 ;
2013-09-11 14:23:56 -07:00
printf "$P: requires at least perl version %vd\n" , $ minimum_perl_version ;
2018-08-21 21:57:33 -07:00
exit ( 1 ) if ( ! $ ignore_perl_version ) ;
2013-09-11 14:23:56 -07:00
}
2016-08-02 14:04:47 -07:00
# if no filenames are given , push '-' to read patch from stdin
2007-06-01 00:46:48 -07:00
if ( $ # ARGV < 0 ) {
2016-08-02 14:04:47 -07:00
push ( @ ARGV , '-' ) ;
2007-06-01 00:46:48 -07:00
}
2017-07-10 15:52:24 -07:00
if ( $ color =~ /^ [ 01 ] $ / ) {
$ color = ! $ color ;
} elsif ( $ color =~ /^ always$ / i ) {
$ color = 1 ;
} elsif ( $ color =~ /^ never$ / i ) {
$ color = 0 ;
} elsif ( $ color =~ /^ auto$ / i ) {
$ color = ( - t STDOUT ) ;
} else {
2020-06-04 16:50:40 -07:00
die "$P: Invalid color mode: $color\n" ;
2017-07-10 15:52:24 -07:00
}
2020-04-06 20:11:07 -07:00
# skip TAB size 1 to avoid additional checks on $ tabsize - 1
2020-06-04 16:50:40 -07:00
die "$P: Invalid TAB size: $tabsize\n" if ( $ tabsize < 2 ) ;
2020-04-06 20:11:07 -07:00
2013-09-11 14:23:59 -07:00
sub hash_save_array_words {
my ( $ hashRef , $ arrayRef ) = @ _ ;
2011-07-25 17:13:25 -07:00
2013-09-11 14:23:59 -07:00
my @ array = split ( / , / , join ( ',' , @ $ arrayRef ) ) ;
foreach my $ word ( @ array ) {
$ word =~ s /\ s *\ n ? $ // g ;
$ word =~ s /^\ s *// g ;
$ word =~ s /\ s +/ / g ;
$ word =~ tr / [ a - z ] / [ A - Z ] / ;
2011-07-25 17:13:25 -07:00
2013-09-11 14:23:59 -07:00
next if ( $ word =~ m /^\ s *#/ ) ;
next if ( $ word =~ m /^\ s * $ / ) ;
$ hashRef -> { $ word } ++ ;
}
2011-07-25 17:13:25 -07:00
}
2013-09-11 14:23:59 -07:00
sub hash_show_words {
my ( $ hashRef , $ prefix ) = @ _ ;
2015-06-25 15:03:29 -07:00
if ( keys %$hashRef) {
2015-06-25 15:03:00 -07:00
print "\nNOTE: $prefix message types:" ;
2013-09-11 14:24:04 -07:00
foreach my $ word ( sort keys %$hashRef) {
2013-09-11 14:23:59 -07:00
print " $word" ;
}
2015-06-25 15:03:00 -07:00
print "\n" ;
2013-09-11 14:23:59 -07:00
}
}
hash_save_array_words ( \ %ignore_type, \@ignore);
hash_save_array_words ( \ %use_type, \@use);
2008-02-08 04:20:54 -08:00
my $ dbg_values = 0 ;
my $ dbg_possible = 0 ;
2008-07-23 21:29:06 -07:00
my $ dbg_type = 0 ;
2008-10-15 22:02:17 -07:00
my $ dbg_attr = 0 ;
2008-02-08 04:20:54 -08:00
for my $ key ( keys %debug) {
2009-01-06 14:41:30 -08:00
## no critic
eval " \ $ { dbg_$key } = '$debug{$key}' ; ";
die " $ @ " if ($@);
2008-02-08 04:20:54 -08:00
}
2010-10-26 14:23:12 -07:00
my $rpt_cleaners = 0;
2007-11-28 16:21:06 -08:00
if ($terse) {
$emacs = 1;
$quiet++;
}
2007-10-18 03:05:08 -07:00
if ($tree) {
if (defined $root) {
if (!top_of_kernel_tree($root)) {
die " $ P : $ root : -- root does not point at a valid tree \ n ";
}
} else {
if (top_of_kernel_tree('.')) {
$root = '.';
} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
top_of_kernel_tree($1)) {
$root = $1;
}
}
if (!defined $root) {
print " Must be run from the top - level dir . of a kernel tree \ n " ;
exit ( 2 ) ;
}
2007-06-01 00:46:48 -07:00
}
2007-10-18 03:05:08 -07:00
my $ emitted_corrupt = 0 ;
2009-10-26 16:50:14 -07:00
our $ Ident = qr {
[ A - Za - z_ ] [ A - Za - z \ d_ ] *
( ?:\ s *\#\#\ s * [ A - Za - z_ ] [ A - Za - z \ d_ ] * ) *
} x ;
2007-10-18 03:05:08 -07:00
our $ Storage = qr { extern | static | asmlinkage } ;
our $ Sparse = qr {
_ _ user |
_ _ kernel |
_ _ force |
_ _ iomem |
_ _ must_check |
2009-02-27 14:03:08 -08:00
_ _ kprobes |
2011-07-25 17:13:23 -07:00
_ _ ref |
2018-08-21 21:57:36 -07:00
_ _ refconst |
_ _ refdata |
2015-12-29 12:18:46 +08:00
_ _ rcu |
_ _ private
2007-10-18 03:05:08 -07:00
} x ;
2013-11-12 15:10:10 -08:00
our $ InitAttributePrefix = qr { _ _ ( ?: mem | cpu | dev | net_ | ) } ;
our $ InitAttributeData = qr { $ InitAttributePrefix ( ?: initdata \ b ) } ;
our $ InitAttributeConst = qr { $ InitAttributePrefix ( ?: initconst \ b ) } ;
our $ InitAttributeInit = qr { $ InitAttributePrefix ( ?: init \ b ) } ;
our $ InitAttribute = qr { $ InitAttributeData | $ InitAttributeConst | $ InitAttributeInit } ;
2013-09-11 14:24:05 -07:00
2010-03-05 13:43:51 -08:00
# Notes to $ Attribute :
# We need \ b after 'init' otherwise 'initconst' will cause a false positive in a check
2007-10-18 03:05:08 -07:00
our $ Attribute = qr {
const |
2010-10-26 14:23:16 -07:00
_ _ percpu |
_ _ nocast |
_ _ safe |
2016-12-11 06:29:58 +02:00
_ _ bitwise |
2010-10-26 14:23:16 -07:00
_ _ packed__ |
_ _ packed2__ |
_ _ naked |
_ _ maybe_unused |
_ _ always_unused |
_ _ noreturn |
_ _ used |
_ _ cold |
2015-02-13 14:38:24 -08:00
_ _ pure |
2010-10-26 14:23:16 -07:00
_ _ noclone |
_ _ deprecated |
2007-10-18 03:05:08 -07:00
_ _ read_mostly |
2018-09-04 15:46:20 -07:00
_ _ ro_after_init |
2007-10-18 03:05:08 -07:00
_ _ kprobes |
2013-09-11 14:24:05 -07:00
$ InitAttribute |
2008-10-15 22:02:18 -07:00
_ _ _ _ cacheline_aligned |
_ _ _ _ cacheline_aligned_in_smp |
2009-01-06 14:41:18 -08:00
_ _ _ _ cacheline_internodealigned_in_smp |
_ _ weak
2007-10-18 03:05:08 -07:00
} x ;
2008-06-05 22:46:01 -07:00
our $ Modifier ;
2014-04-03 14:49:32 -07:00
our $ Inline = qr { inline | _ _ always_inline | noinline | _ _ inline | _ _ inline__ } ;
2007-10-18 03:05:08 -07:00
our $ Member = qr { -> $ Ident | \. $ Ident | \ [ [ ^ ] ] *\ ] } ;
our $ Lval = qr { $ Ident ( ?: $ Member ) * } ;
2013-07-03 15:05:20 -07:00
our $ Int_type = qr { ( ? i ) llu | ull | ll | lu | ul | l | u } ;
our $ Binary = qr { ( ? i ) 0 b [ 01 ] + $ Int_type ? } ;
our $ Hex = qr { ( ? i ) 0 x [ 0 - 9 a - f ] + $ Int_type ? } ;
our $ Int = qr { [ 0 - 9 ] + $ Int_type ? } ;
2014-04-03 14:49:13 -07:00
our $ Octal = qr { 0 [ 0 - 7 ] + $ Int_type ? } ;
2015-02-13 14:38:21 -08:00
our $ String = qr { "[X\t]*" } ;
2013-02-04 14:28:51 -08:00
our $ Float_hex = qr { ( ? i ) 0 x [ 0 - 9 a - f ] + p -? [ 0 - 9 ] + [ fl ] ? } ;
our $ Float_dec = qr { ( ? i ) ( ?: [ 0 - 9 ] +\. [ 0 - 9 ] * | [ 0 - 9 ] *\. [ 0 - 9 ] + ) ( ?: e -? [ 0 - 9 ] + ) ? [ fl ] ? } ;
our $ Float_int = qr { ( ? i ) [ 0 - 9 ] + e -? [ 0 - 9 ] + [ fl ] ? } ;
2012-12-17 16:02:05 -08:00
our $ Float = qr { $ Float_hex | $ Float_dec | $ Float_int } ;
2014-04-03 14:49:13 -07:00
our $ Constant = qr { $ Float | $ Binary | $ Octal | $ Hex | $ Int } ;
2013-02-04 14:28:51 -08:00
our $ Assignment = qr { \*\= | /= | %=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
2014-04-03 14:49:17 -07:00
our $ Compare = qr { <= | >= | == | ! = | < | ( ?< ! - ) > } ;
2013-07-03 15:05:31 -07:00
our $ Arithmetic = qr { \+ | - | \* | \/ | %};
2007-10-18 03:05:08 -07:00
our $ Operators = qr {
<= | >= | == | ! = |
=> | -> | << | >> | < | > | ! | ~ |
2013-07-03 15:05:31 -07:00
&& | \ | \ | | , | \^ | \+\+ | -- | & | \ | | $ Arithmetic
2007-10-18 03:05:08 -07:00
} x ;
2014-04-03 14:49:32 -07:00
our $ c90_Keywords = qr { do | for | while | if | else | return | goto | continue | switch | default | case | break } x ;
2015-04-16 12:44:22 -07:00
our $ BasicType ;
2007-11-28 16:21:06 -08:00
our $ NonptrType ;
2014-08-06 16:11:22 -07:00
our $ NonptrTypeMisordered ;
2013-09-11 14:24:05 -07:00
our $ NonptrTypeWithAttr ;
2007-11-28 16:21:06 -08:00
our $ Type ;
2014-08-06 16:11:22 -07:00
our $ TypeMisordered ;
2007-11-28 16:21:06 -08:00
our $ Declare ;
2014-08-06 16:11:22 -07:00
our $ DeclareMisordered ;
2007-11-28 16:21:06 -08:00
2011-10-31 17:13:12 -07:00
our $ NON_ASCII_UTF8 = qr {
[ \ xC2 -\ xDF ] [ \ x80 -\ xBF ] # non - overlong 2 - byte
2008-04-29 00:59:32 -07:00
| \ xE0 [ \ xA0 -\ xBF ] [ \ x80 -\ xBF ] # excluding overlongs
| [ \ xE1 -\ xEC \ xEE \ xEF ] [ \ x80 -\ xBF ] { 2 } # straight 3 - byte
| \ xED [ \ x80 -\ x9F ] [ \ x80 -\ xBF ] # excluding surrogates
| \ xF0 [ \ x90 -\ xBF ] [ \ x80 -\ xBF ] { 2 } # planes 1 - 3
| [ \ xF1 -\ xF3 ] [ \ x80 -\ xBF ] { 3 } # planes 4 - 15
| \ xF4 [ \ x80 -\ x8F ] [ \ x80 -\ xBF ] { 2 } # plane 16
} x ;
2011-10-31 17:13:12 -07:00
our $ UTF8 = qr {
[ \ x09 \ x0A \ x0D \ x20 -\ x7E ] # ASCII
| $ NON_ASCII_UTF8
} x ;
2015-06-25 15:02:49 -07:00
our $ typeC99Typedefs = qr { ( ?: _ _ ) ? ( ?: [ us ] _ ? ) ? int_ ? ( ?: 8 | 16 | 32 | 64 ) _ t } ;
2015-02-13 14:38:43 -08:00
our $ typeOtherOSTypedefs = qr { ( ? x :
u_ ( ?: char | short | int | long ) | # bsd
u ( ?: nchar | short | int | long ) # sysv
) } ;
2015-06-25 15:02:49 -07:00
our $ typeKernelTypedefs = qr { ( ? x :
2009-09-21 17:04:38 -07:00
( ?: _ _ ) ? ( ?: u | s | be | le ) ( ?: 8 | 16 | 32 | 64 ) |
2008-10-15 22:02:32 -07:00
atomic_t
) } ;
2015-06-25 15:02:49 -07:00
our $ typeTypedefs = qr { ( ? x :
$ typeC99Typedefs \ b |
$ typeOtherOSTypedefs \ b |
$ typeKernelTypedefs \ b
) } ;
2008-10-15 22:02:32 -07:00
2015-11-06 16:31:37 -08:00
our $ zero_initializer = qr { ( ?: ( ?: 0 [ xX ] ) ? 0 + $ Int_type ? | NULL | false ) \ b } ;
2010-03-05 13:43:51 -08:00
our $ logFunctions = qr { ( ? x :
2017-02-24 15:01:34 -08:00
printk ( ?: _ ratelimited | _ once | _ deferred_once | _ deferred | ) |
2013-07-03 15:05:35 -07:00
( ?: [ a - z0 - 9 ] + _ ) { 1 , 2 } ( ?: printk | emerg | alert | crit | err | warning | warn | notice | info | debug | dbg | vdbg | devel | cont | WARN ) ( ?: _ ratelimited | _ once | ) |
2017-11-17 15:28:48 -08:00
TP_printk |
2011-07-25 17:13:27 -07:00
WARN ( ?: _ RATELIMIT | _ ONCE | ) |
2011-05-24 17:13:40 -07:00
panic |
2013-11-12 15:10:07 -08:00
MODULE_ [ A - Z_ ] + |
seq_vprintf | seq_printf | seq_puts
2010-03-05 13:43:51 -08:00
) } ;
2019-03-07 16:28:35 -08:00
our $ allocFunctions = qr { ( ? x :
( ?: ( ?: devm_ ) ?
( ?: kv | k | v ) [ czm ] alloc ( ?: _ node | _ array ) ? |
kstrdup ( ?: _ const ) ? |
kmemdup ( ?: _ nul ) ? ) |
2020-04-20 18:13:58 -07:00
( ?:\ w + ) ? alloc_skb ( ?: _ ip_align ) ? |
2019-03-07 16:28:35 -08:00
# dev_alloc_skb / netdev_alloc_skb , et al
dma_alloc_coherent
) } ;
2011-07-25 17:13:23 -07:00
our $ signature_tags = qr { ( ? xi :
Signed - off - by : |
2019-01-03 15:29:12 -08:00
Co - developed - by : |
2011-07-25 17:13:23 -07:00
Acked - by : |
Tested - by : |
Reviewed - by : |
Reported - by : |
2013-04-29 16:18:17 -07:00
Suggested - by : |
2011-07-25 17:13:23 -07:00
To : |
Cc :
) } ;
2020-12-15 20:45:12 -08:00
sub edit_distance_min {
my ( @ arr ) = @ _ ;
my $ len = scalar @ arr ;
if ( ( scalar @ arr ) < 1 ) {
# if underflow , return
return ;
}
my $ min = $ arr [ 0 ] ;
for my $ i ( 0 . . ( $ len - 1 ) ) {
if ( $ arr [ $ i ] < $ min ) {
$ min = $ arr [ $ i ] ;
}
}
return $ min ;
}
sub get_edit_distance {
my ( $ str1 , $ str2 ) = @ _ ;
$ str1 = lc ( $ str1 ) ;
$ str2 = lc ( $ str2 ) ;
$ str1 =~ s /-// g ;
$ str2 =~ s /-// g ;
my $ len1 = length ( $ str1 ) ;
my $ len2 = length ( $ str2 ) ;
# two dimensional array storing minimum edit distance
my @ distance ;
for my $ i ( 0 . . $ len1 ) {
for my $ j ( 0 . . $ len2 ) {
if ( $ i == 0 ) {
$ distance [ $ i ] [ $ j ] = $ j ;
} elsif ( $ j == 0 ) {
$ distance [ $ i ] [ $ j ] = $ i ;
} elsif ( substr ( $ str1 , $ i - 1 , 1 ) eq substr ( $ str2 , $ j - 1 , 1 ) ) {
$ distance [ $ i ] [ $ j ] = $ distance [ $ i - 1 ] [ $ j - 1 ] ;
} else {
my $ dist1 = $ distance [ $ i ] [ $ j - 1 ] ; # insert distance
my $ dist2 = $ distance [ $ i - 1 ] [ $ j ] ; # remove
my $ dist3 = $ distance [ $ i - 1 ] [ $ j - 1 ] ; # replace
$ distance [ $ i ] [ $ j ] = 1 + edit_distance_min ( $ dist1 , $ dist2 , $ dist3 ) ;
}
}
}
return $ distance [ $ len1 ] [ $ len2 ] ;
}
sub find_standard_signature {
my ( $ sign_off ) = @ _ ;
my @ standard_signature_tags = (
'Signed-off-by:' , 'Co-developed-by:' , 'Acked-by:' , 'Tested-by:' ,
'Reviewed-by:' , 'Reported-by:' , 'Suggested-by:'
) ;
foreach my $ signature ( @ standard_signature_tags ) {
return $ signature if ( get_edit_distance ( $ sign_off , $ signature ) <= 2 ) ;
}
return "" ;
}
2014-08-06 16:11:22 -07:00
our @ typeListMisordered = (
qr { char \ s + ( ?: un ) ? signed } ,
qr { int \ s + ( ?: ( ?: un ) ? signed \ s + ) ? short \ s } ,
qr { int \ s + short ( ?:\ s + ( ?: un ) ? signed ) } ,
qr { short \ s + int ( ?:\ s + ( ?: un ) ? signed ) } ,
qr { ( ?: un ) ? signed \ s + int \ s + short } ,
qr { short \ s + ( ?: un ) ? signed } ,
qr { long \ s + int \ s + ( ?: un ) ? signed } ,
qr { int \ s + long \ s + ( ?: un ) ? signed } ,
qr { long \ s + ( ?: un ) ? signed \ s + int } ,
qr { int \ s + ( ?: un ) ? signed \ s + long } ,
qr { int \ s + ( ?: un ) ? signed } ,
qr { int \ s + long \ s + long \ s + ( ?: un ) ? signed } ,
qr { long \ s + long \ s + int \ s + ( ?: un ) ? signed } ,
qr { long \ s + long \ s + ( ?: un ) ? signed \ s + int } ,
qr { long \ s + long \ s + ( ?: un ) ? signed } ,
qr { long \ s + ( ?: un ) ? signed } ,
) ;
2007-11-28 16:21:06 -08:00
our @ typeList = (
qr { void } ,
2014-08-06 16:11:20 -07:00
qr { ( ?: ( ?: un ) ? signed \ s + ) ? char } ,
qr { ( ?: ( ?: un ) ? signed \ s + ) ? short \ s + int } ,
qr { ( ?: ( ?: un ) ? signed \ s + ) ? short } ,
qr { ( ?: ( ?: un ) ? signed \ s + ) ? int } ,
qr { ( ?: ( ?: un ) ? signed \ s + ) ? long \ s + int } ,
qr { ( ?: ( ?: un ) ? signed \ s + ) ? long \ s + long \ s + int } ,
qr { ( ?: ( ?: un ) ? signed \ s + ) ? long \ s + long } ,
qr { ( ?: ( ?: un ) ? signed \ s + ) ? long } ,
qr { ( ?: un ) ? signed } ,
2007-11-28 16:21:06 -08:00
qr { float } ,
qr { double } ,
qr { bool } ,
qr { struct \ s + $ Ident } ,
qr { union \ s + $ Ident } ,
qr { enum \ s + $ Ident } ,
qr { $ { Ident } _ t } ,
qr { $ { Ident } _ handler } ,
qr { $ { Ident } _ handler_fn } ,
2014-08-06 16:11:22 -07:00
@ typeListMisordered ,
2007-11-28 16:21:06 -08:00
) ;
2016-01-20 14:59:15 -08:00
our $ C90_int_types = qr { ( ? x :
long \ s + long \ s + int \ s + ( ?: un ) ? signed |
long \ s + long \ s + ( ?: un ) ? signed \ s + int |
long \ s + long \ s + ( ?: un ) ? signed |
( ?: ( ?: un ) ? signed \ s + ) ? long \ s + long \ s + int |
( ?: ( ?: un ) ? signed \ s + ) ? long \ s + long |
int \ s + long \ s + long \ s + ( ?: un ) ? signed |
int \ s + ( ?: ( ?: un ) ? signed \ s + ) ? long \ s + long |
long \ s + int \ s + ( ?: un ) ? signed |
long \ s + ( ?: un ) ? signed \ s + int |
long \ s + ( ?: un ) ? signed |
( ?: ( ?: un ) ? signed \ s + ) ? long \ s + int |
( ?: ( ?: un ) ? signed \ s + ) ? long |
int \ s + long \ s + ( ?: un ) ? signed |
int \ s + ( ?: ( ?: un ) ? signed \ s + ) ? long |
int \ s + ( ?: un ) ? signed |
( ?: ( ?: un ) ? signed \ s + ) ? int
) } ;
2015-06-25 15:02:52 -07:00
our @ typeListFile = ( ) ;
2013-09-11 14:24:05 -07:00
our @ typeListWithAttr = (
@ typeList ,
qr { struct \ s + $ InitAttribute \ s + $ Ident } ,
qr { union \ s + $ InitAttribute \ s + $ Ident } ,
) ;
2008-06-05 22:46:01 -07:00
our @ modifierList = (
qr { fastcall } ,
) ;
2015-06-25 15:02:52 -07:00
our @ modifierListFile = ( ) ;
2007-11-28 16:21:06 -08:00
2014-04-03 14:49:13 -07:00
our @ mode_permission_funcs = (
[ "module_param" , 3 ] ,
[ "module_param_(?:array|named|string)" , 4 ] ,
[ "module_param_array_named" , 5 ] ,
[ "debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)" , 2 ] ,
[ "proc_create(?:_data|)" , 2 ] ,
2016-10-11 13:52:19 -07:00
[ "(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR" , 2 ] ,
[ "IIO_DEV_ATTR_[A-Z_]+" , 1 ] ,
[ "SENSOR_(?:DEVICE_|)ATTR_2" , 2 ] ,
[ "SENSOR_TEMPLATE(?:_2|)" , 3 ] ,
[ "__ATTR" , 2 ] ,
2014-04-03 14:49:13 -07:00
) ;
2020-08-11 18:35:16 -07:00
my $ word_pattern = '\b[A-Z]?[a-z]{2,}\b' ;
2014-04-03 14:49:24 -07:00
# Create a search pattern for all these functions to speed up a loop below
our $ mode_perms_search = "" ;
foreach my $ entry ( @ mode_permission_funcs ) {
$ mode_perms_search . = '|' if ( $ mode_perms_search ne "" ) ;
$ mode_perms_search . = $ entry -> [ 0 ] ;
}
2018-02-06 15:38:55 -08:00
$ mode_perms_search = "(?:${mode_perms_search})" ;
2014-04-03 14:49:24 -07:00
2018-09-07 15:26:18 -07:00
our %deprecated_apis = (
"synchronize_rcu_bh" => "synchronize_rcu" ,
"synchronize_rcu_bh_expedited" => "synchronize_rcu_expedited" ,
"call_rcu_bh" => "call_rcu" ,
"rcu_barrier_bh" => "rcu_barrier" ,
"synchronize_sched" => "synchronize_rcu" ,
"synchronize_sched_expedited" => "synchronize_rcu_expedited" ,
"call_rcu_sched" => "call_rcu" ,
"rcu_barrier_sched" => "rcu_barrier" ,
"get_state_synchronize_sched" => "get_state_synchronize_rcu" ,
"cond_synchronize_sched" => "cond_synchronize_rcu" ,
) ;
# Create a search pattern for all these strings to speed up a loop below
our $ deprecated_apis_search = "" ;
foreach my $ entry ( keys %deprecated_apis) {
$ deprecated_apis_search . = '|' if ( $ deprecated_apis_search ne "" ) ;
$ deprecated_apis_search . = $ entry ;
}
$ deprecated_apis_search = "(?:${deprecated_apis_search})" ;
2015-04-16 12:44:16 -07:00
our $ mode_perms_world_writable = qr {
S_IWUGO |
S_IWOTH |
S_IRWXUGO |
S_IALLUGO |
0 [ 0 - 7 ] [ 0 - 7 ] [ 2367 ]
} x ;
2016-10-11 13:51:47 -07:00
our %mode_permission_string_types = (
"S_IRWXU" => 0700 ,
"S_IRUSR" => 0400 ,
"S_IWUSR" => 0200 ,
"S_IXUSR" => 0100 ,
"S_IRWXG" => 0070 ,
"S_IRGRP" => 0040 ,
"S_IWGRP" => 0020 ,
"S_IXGRP" => 0010 ,
"S_IRWXO" => 0007 ,
"S_IROTH" => 0004 ,
"S_IWOTH" => 0002 ,
"S_IXOTH" => 0001 ,
"S_IRWXUGO" => 0777 ,
"S_IRUGO" => 0444 ,
"S_IWUGO" => 0222 ,
"S_IXUGO" => 0111 ,
) ;
# Create a search pattern for all these strings to speed up a loop below
our $ mode_perms_string_search = "" ;
foreach my $ entry ( keys %mode_permission_string_types) {
$ mode_perms_string_search . = '|' if ( $ mode_perms_string_search ne "" ) ;
$ mode_perms_string_search . = $ entry ;
}
2018-02-06 15:38:55 -08:00
our $ single_mode_perms_string_search = "(?:${mode_perms_string_search})" ;
our $ multi_mode_perms_string_search = qr {
$ { single_mode_perms_string_search }
( ?:\ s *\ | \ s * $ { single_mode_perms_string_search } ) *
} x ;
sub perms_to_octal {
my ( $ string ) = @ _ ;
return trim ( $ string ) if ( $ string =~ /^\ s * 0 [ 0 - 7 ] { 3 , 3 } \ s * $ / ) ;
my $ val = "" ;
my $ oval = "" ;
my $ to = 0 ;
my $ curpos = 0 ;
my $ lastpos = 0 ;
while ( $ string =~ /\ b ( ( $ single_mode_perms_string_search ) \ b ( ?:\ s *\ | \ s * ) ?\ s * ) / g ) {
$ curpos = pos ( $ string ) ;
my $ match = $ 2 ;
my $ omatch = $ 1 ;
last if ( $ lastpos > 0 && ( $ curpos - length ( $ omatch ) ! = $ lastpos ) ) ;
$ lastpos = $ curpos ;
$ to | = $ mode_permission_string_types { $ match } ;
$ val . = '\s*\|\s*' if ( $ val ne "" ) ;
$ val . = $ match ;
$ oval . = $ omatch ;
}
$ oval =~ s /^\ s *\ | \ s *// ;
$ oval =~ s /\ s *\ | \ s * $ // ;
return sprintf ( "%04o" , $ to ) ;
}
2016-10-11 13:51:47 -07:00
2010-08-09 17:20:57 -07:00
our $ allowed_asm_includes = qr { ( ? x :
irq |
2014-10-13 15:51:44 -07:00
memory |
time |
reboot
2010-08-09 17:20:57 -07:00
) } ;
# memory . h : ARM has a custom one
2014-10-13 15:51:57 -07:00
# Load common spelling mistakes and build regular expression list .
my $ misspellings ;
my %spelling_fix;
2014-12-10 15:51:43 -08:00
if ( open ( my $ spelling , '<' , $ spelling_file ) ) {
while ( < $ spelling > ) {
my $ line = $ _ ;
2014-10-13 15:51:57 -07:00
2014-12-10 15:51:43 -08:00
$ line =~ s /\ s *\ n ? $ // g ;
$ line =~ s /^\ s *// g ;
2014-10-13 15:51:57 -07:00
2014-12-10 15:51:43 -08:00
next if ( $ line =~ m /^\ s *#/ ) ;
next if ( $ line =~ m /^\ s * $ / ) ;
2014-10-13 15:51:57 -07:00
2014-12-10 15:51:43 -08:00
my ( $ suspect , $ fix ) = split ( /\ | \ | / , $ line ) ;
$ spelling_fix { $ suspect } = $ fix ;
}
close ( $ spelling ) ;
} else {
warn "No typos will be found - file '$spelling_file': $!\n" ;
2014-10-13 15:51:57 -07:00
}
2015-04-16 12:44:14 -07:00
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;
2017-05-08 15:56:00 -07:00
sub read_words {
my ( $ wordsRef , $ file ) = @ _ ;
2016-10-11 13:51:56 -07:00
2017-05-08 15:56:00 -07:00
if ( open ( my $ words , '<' , $ file ) ) {
while ( < $ words > ) {
my $ line = $ _ ;
2016-10-11 13:51:56 -07:00
2017-05-08 15:56:00 -07:00
$ line =~ s /\ s *\ n ? $ // g ;
$ line =~ s /^\ s *// g ;
next if ( $ line =~ m /^\ s *#/ ) ;
next if ( $ line =~ m /^\ s * $ / ) ;
if ( $ line =~ /\ s / ) {
print ( "$file: '$line' invalid - ignored\n" ) ;
next ;
}
2020-08-11 18:35:13 -07:00
$ $ wordsRef . = '|' if ( defined $ $ wordsRef ) ;
2017-05-08 15:56:00 -07:00
$ $ wordsRef . = $ line ;
2016-10-11 13:51:56 -07:00
}
2017-05-08 15:56:00 -07:00
close ( $ file ) ;
return 1 ;
2016-10-11 13:51:56 -07:00
}
2017-05-08 15:56:00 -07:00
return 0 ;
2016-10-11 13:51:56 -07:00
}
2020-08-11 18:35:13 -07:00
my $ const_structs ;
if ( show_type ( "CONST_STRUCT" ) ) {
read_words ( \ $ const_structs , $ conststructsfile )
or warn "No structs that should be const will be found - file '$conststructsfile': $!\n" ;
}
2017-05-08 15:56:00 -07:00
2020-08-11 18:35:13 -07:00
if ( defined ( $ typedefsfile ) ) {
my $ typeOtherTypedefs ;
2017-05-08 15:56:00 -07:00
read_words ( \ $ typeOtherTypedefs , $ typedefsfile )
or warn "No additional types will be considered - file '$typedefsfile': $!\n" ;
2020-08-11 18:35:13 -07:00
$ typeTypedefs . = '|' . $ typeOtherTypedefs if ( defined $ typeOtherTypedefs ) ;
2017-05-08 15:56:00 -07:00
}
2007-11-28 16:21:06 -08:00
sub build_types {
2015-06-25 15:02:52 -07:00
my $ mods = "(?x: \n" . join ( "|\n " , ( @ modifierList , @ modifierListFile ) ) . "\n)" ;
my $ all = "(?x: \n" . join ( "|\n " , ( @ typeList , @ typeListFile ) ) . "\n)" ;
2014-08-06 16:11:22 -07:00
my $ Misordered = "(?x: \n" . join ( "|\n " , @ typeListMisordered ) . "\n)" ;
2013-09-11 14:24:05 -07:00
my $ allWithAttr = "(?x: \n" . join ( "|\n " , @ typeListWithAttr ) . "\n)" ;
2008-07-23 21:28:57 -07:00
$ Modifier = qr { ( ?: $ Attribute | $ Sparse | $ mods ) } ;
2015-04-16 12:44:22 -07:00
$ BasicType = qr {
( ?: $ typeTypedefs \ b ) |
( ?: $ { all } \ b )
} x ;
2007-11-28 16:21:06 -08:00
$ NonptrType = qr {
2008-07-23 21:29:07 -07:00
( ?: $ Modifier \ s + | const \ s + ) *
2008-03-04 14:28:20 -08:00
( ?:
2012-01-10 15:10:13 -08:00
( ?: typeof | _ _ typeof__ ) \ s *\ ( [ ^\ ) ] *\ ) |
2008-10-15 22:02:32 -07:00
( ?: $ typeTypedefs \ b ) |
2008-06-05 22:46:01 -07:00
( ?: $ { all } \ b )
2008-03-04 14:28:20 -08:00
)
2008-07-23 21:28:57 -07:00
( ?:\ s + $ Modifier | \ s + const ) *
2007-11-28 16:21:06 -08:00
} x ;
2014-08-06 16:11:22 -07:00
$ NonptrTypeMisordered = qr {
( ?: $ Modifier \ s + | const \ s + ) *
( ?:
( ?: $ { Misordered } \ b )
)
( ?:\ s + $ Modifier | \ s + const ) *
} x ;
2013-09-11 14:24:05 -07:00
$ NonptrTypeWithAttr = qr {
( ?: $ Modifier \ s + | const \ s + ) *
( ?:
( ?: typeof | _ _ typeof__ ) \ s *\ ( [ ^\ ) ] *\ ) |
( ?: $ typeTypedefs \ b ) |
( ?: $ { allWithAttr } \ b )
)
( ?:\ s + $ Modifier | \ s + const ) *
} x ;
2007-11-28 16:21:06 -08:00
$ Type = qr {
2008-06-05 22:46:01 -07:00
$ NonptrType
2020-04-06 20:11:04 -07:00
( ?: ( ?:\ s | \* | \ [ \ ] ) +\ s * const | ( ?:\ s | \*\ s * ( ?: const \ s * ) ? | \ [ \ ] ) + | ( ?:\ s *\ [ \ s *\ ] ) + ) { 0 , 4 }
2008-07-23 21:28:57 -07:00
( ?:\ s + $ Inline | \ s + $ Modifier ) *
2007-11-28 16:21:06 -08:00
} x ;
2014-08-06 16:11:22 -07:00
$ TypeMisordered = qr {
$ NonptrTypeMisordered
2020-04-06 20:11:04 -07:00
( ?: ( ?:\ s | \* | \ [ \ ] ) +\ s * const | ( ?:\ s | \*\ s * ( ?: const \ s * ) ? | \ [ \ ] ) + | ( ?:\ s *\ [ \ s *\ ] ) + ) { 0 , 4 }
2014-08-06 16:11:22 -07:00
( ?:\ s + $ Inline | \ s + $ Modifier ) *
} x ;
2014-04-03 14:49:32 -07:00
$ Declare = qr { ( ?: $ Storage \ s + ( ?: $ Inline \ s + ) ? ) ? $ Type } ;
2014-08-06 16:11:22 -07:00
$ DeclareMisordered = qr { ( ?: $ Storage \ s + ( ?: $ Inline \ s + ) ? ) ? $ TypeMisordered } ;
2007-11-28 16:21:06 -08:00
}
build_types ( ) ;
2007-10-18 03:05:08 -07:00
2011-07-25 17:13:22 -07:00
our $ Typecast = qr { \ s * ( \ ( \ s * $ NonptrType \ s *\ ) ) { 0 , 1 } \ s * } ;
2012-03-23 15:02:16 -07:00
# Using $ balanced_parens , $ LvalOrFunc , or $ FuncArg
# requires at least perl version v5 .10 .0
# Any use must be runtime checked with $ ^ V
our $ balanced_parens = qr / ( \ ( ( ?: [ ^\ ( \ ) ] ++ | ( ?- 1 ) ) *\ ) ) / ;
2014-04-03 14:49:13 -07:00
our $ LvalOrFunc = qr { ( ( ?: [ \&\* ] \ s * ) ? $ Lval ) \ s * ( $ balanced_parens { 0 , 1 } ) \ s * } ;
2015-02-13 14:38:21 -08:00
our $ FuncArg = qr { $ Typecast { 0 , 1 } ( $ LvalOrFunc | $ Constant | $ String ) } ;
2011-07-25 17:13:22 -07:00
2014-08-06 16:11:31 -07:00
our $ declaration_macros = qr { ( ? x :
2015-09-09 15:37:33 -07:00
( ?: $ Storage \ s + ) ? ( ?: [ A - Z_ ] [ A - Z0 - 9 ] * _ ) { 0 , 2 } ( ?: DEFINE | DECLARE ) ( ?: _ [ A - Z0 - 9 ] + ) { 1 , 6 } \ s *\ ( |
2017-07-10 15:52:10 -07:00
( ?: $ Storage \ s + ) ? [ HLP ] ? LIST_HEAD \ s *\ ( |
2018-04-10 16:33:17 -07:00
( ?: SKCIPHER_REQUEST | SHASH_DESC | AHASH_REQUEST ) _ ON_STACK \ s *\ (
2014-08-06 16:11:31 -07:00
) } ;
2020-12-15 20:44:24 -08:00
our %allow_repeated_words = (
add => '' ,
added => '' ,
bad => '' ,
be => '' ,
) ;
2011-07-25 17:13:22 -07:00
sub deparenthesize {
my ( $ string ) = @ _ ;
return "" if ( ! defined ( $ string ) ) ;
2014-04-03 14:49:21 -07:00
while ( $ string =~ /^\ s *\ ( . *\ ) \ s * $ / ) {
$ string =~ s @^\ s *\ ( \ s *@@ ;
$ string =~ s @\ s *\ ) \ s * $ @@ ;
}
2011-07-25 17:13:22 -07:00
$ string =~ s @\ s +@ @ g ;
2014-04-03 14:49:21 -07:00
2011-07-25 17:13:22 -07:00
return $ string ;
}
2013-07-03 15:05:34 -07:00
sub seed_camelcase_file {
my ( $ file ) = @ _ ;
return if ( ! ( - f $ file ) ) ;
local $ / ;
open ( my $ include_file , '<' , "$file" )
or warn "$P: Can't read '$file' $!\n" ;
my $ text = < $ include_file > ;
close ( $ include_file ) ;
my @ lines = split ( '\n' , $ text ) ;
foreach my $ line ( @ lines ) {
next if ( $ line ! ~ / ( ?: [ A - Z ] [ a - z ] | [ a - z ] [ A - Z ] ) / ) ;
if ( $ line =~ /^ [ \ t ] * ( ?:# [ \ t ] * define | typedef \ s + $ Type ) \ s + ( \ w * ( ?: [ A - Z ] [ a - z ] | [ a - z ] [ A - Z ] ) \ w * ) / ) {
$ camelcase { $ 1 } = 1 ;
2013-11-12 15:10:08 -08:00
} elsif ( $ line =~ /^\ s * $ Declare \ s + ( \ w * ( ?: [ A - Z ] [ a - z ] | [ a - z ] [ A - Z ] ) \ w * ) \ s * [ \ ( \ [ , ; ] / ) {
$ camelcase { $ 1 } = 1 ;
} elsif ( $ line =~ /^\ s * ( ?: union | struct | enum ) \ s + ( \ w * ( ?: [ A - Z ] [ a - z ] | [ a - z ] [ A - Z ] ) \ w * ) \ s * [ ; \ { ] / ) {
2013-07-03 15:05:34 -07:00
$ camelcase { $ 1 } = 1 ;
}
}
}
2019-12-04 16:52:09 -08:00
our %maintained_status = ();
2016-10-11 13:51:44 -07:00
sub is_maintained_obsolete {
my ( $ filename ) = @ _ ;
2016-12-12 16:46:23 -08:00
return 0 if ( ! $ tree | | ! ( - e "$root/scripts/get_maintainer.pl" ) ) ;
2016-10-11 13:51:44 -07:00
2019-12-04 16:52:09 -08:00
if ( ! exists ( $ maintained_status { $ filename } ) ) {
$ maintained_status { $ filename } = ` perl $ root / scripts / get_maintainer . pl -- status -- nom -- nol -- nogit -- nogit - fallback - f $ filename 2 >& 1 ` ;
}
2016-10-11 13:51:44 -07:00
2019-12-04 16:52:09 -08:00
return $ maintained_status { $ filename } =~ / obsolete / i ;
2016-10-11 13:51:44 -07:00
}
2018-08-21 21:57:47 -07:00
sub is_SPDX_License_valid {
my ( $ license ) = @ _ ;
2020-10-24 16:59:04 -07:00
return 1 if ( ! $ tree | | which ( "python" ) eq "" | | ! ( - e "$root/scripts/spdxcheck.py" ) | | ! ( - e "$gitroot" ) ) ;
2018-08-21 21:57:47 -07:00
2018-08-21 21:58:04 -07:00
my $ root_path = abs_path ( $ root ) ;
my $ status = ` cd "$root_path" ; echo "$license" | python scripts / spdxcheck . py - ` ;
2018-08-21 21:57:47 -07:00
return 0 if ( $ status ne "" ) ;
return 1 ;
}
2013-07-03 15:05:34 -07:00
my $ camelcase_seeded = 0 ;
sub seed_camelcase_includes {
return if ( $ camelcase_seeded ) ;
my $ files ;
2013-07-08 16:00:43 -07:00
my $ camelcase_cache = "" ;
my @ include_files = ( ) ;
$ camelcase_seeded = 1 ;
2013-07-03 15:05:36 -07:00
2020-10-24 16:59:04 -07:00
if ( - e "$gitroot" ) {
2019-09-25 16:46:52 -07:00
my $ git_last_include_commit = ` $ { git_command } log -- no - merges -- pretty = format : "%h%n" - 1 -- include ` ;
2013-07-03 15:05:36 -07:00
chomp $ git_last_include_commit ;
2013-07-08 16:00:43 -07:00
$ camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit" ;
2013-07-03 15:05:34 -07:00
} else {
2013-07-08 16:00:43 -07:00
my $ last_mod_date = 0 ;
2013-07-03 15:05:34 -07:00
$ files = ` find $ root / include - name "*.h" ` ;
2013-07-08 16:00:43 -07:00
@ include_files = split ( '\n' , $ files ) ;
foreach my $ file ( @ include_files ) {
my $ date = POSIX :: strftime ( "%Y%m%d%H%M" ,
localtime ( ( stat $ file ) [ 9 ] ) ) ;
$ last_mod_date = $ date if ( $ last_mod_date < $ date ) ;
}
$ camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date" ;
2013-07-03 15:05:34 -07:00
}
2013-07-08 16:00:43 -07:00
if ( $ camelcase_cache ne "" && - f $ camelcase_cache ) {
open ( my $ camelcase_file , '<' , "$camelcase_cache" )
or warn "$P: Can't read '$camelcase_cache' $!\n" ;
while ( < $ camelcase_file > ) {
chomp ;
$ camelcase { $ _ } = 1 ;
}
close ( $ camelcase_file ) ;
return ;
}
2020-10-24 16:59:04 -07:00
if ( - e "$gitroot" ) {
2019-09-25 16:46:52 -07:00
$ files = ` $ { git_command } ls - files "include/*.h" ` ;
2013-07-08 16:00:43 -07:00
@ include_files = split ( '\n' , $ files ) ;
}
2013-07-03 15:05:34 -07:00
foreach my $ file ( @ include_files ) {
seed_camelcase_file ( $ file ) ;
}
2013-07-03 15:05:36 -07:00
2013-07-08 16:00:43 -07:00
if ( $ camelcase_cache ne "" ) {
2013-07-03 15:05:36 -07:00
unlink glob ".checkpatch-camelcase.*" ;
2013-07-08 16:00:43 -07:00
open ( my $ camelcase_file , '>' , "$camelcase_cache" )
or warn "$P: Can't write '$camelcase_cache' $!\n" ;
2013-07-03 15:05:36 -07:00
foreach ( sort { lc ( $ a ) cmp lc ( $ b ) } keys ( %camelcase)) {
print $ camelcase_file ( "$_\n" ) ;
}
close ( $ camelcase_file ) ;
}
2013-07-03 15:05:34 -07:00
}
2020-10-15 20:12:12 -07:00
sub git_is_single_file {
my ( $ filename ) = @ _ ;
return 0 if ( ( which ( "git" ) eq "" ) | | ! ( - e "$gitroot" ) ) ;
my $ output = ` $ { git_command } ls - files -- $ filename 2 >/ dev / null ` ;
my $ count = $ output =~ tr /\ n // ;
return $ count eq 1 && $ output =~ m { ^ $ { filename } $ } ;
}
2014-08-06 16:10:57 -07:00
sub git_commit_info {
my ( $ commit , $ id , $ desc ) = @ _ ;
2020-10-24 16:59:04 -07:00
return ( $ id , $ desc ) if ( ( which ( "git" ) eq "" ) | | ! ( - e "$gitroot" ) ) ;
2014-08-06 16:10:57 -07:00
2019-09-25 16:46:52 -07:00
my $ output = ` $ { git_command } log -- no - color -- format = '%H %s' - 1 $ commit 2 >& 1 ` ;
2014-08-06 16:10:57 -07:00
$ output =~ s /^\ s *// gm ;
my @ lines = split ( "\n" , $ output ) ;
2015-02-13 14:38:35 -08:00
return ( $ id , $ desc ) if ( $ # lines < 0 ) ;
2019-09-25 16:46:49 -07:00
if ( $ lines [ 0 ] =~ /^ error : short SHA1 $ commit is ambiguous / ) {
2014-08-06 16:10:57 -07:00
# Maybe one day convert this block of bash into something that returns
# all matching commit ids , but it 's very slow...
#
# echo "checking commits $1..."
# git rev-list --remotes | grep -i "^$1" |
# while read line ; do
# git log --format=' %H %s' -1 $line |
# echo "commit $(cut -c 1-12,41-)"
# done
} elsif ( $ lines [ 0 ] =~ /^ fatal : ambiguous argument '$commit' : unknown revision or path not in the working tree \./ ) {
2017-07-10 15:52:16 -07:00
$ id = undef ;
2014-08-06 16:10:57 -07:00
} else {
$ id = substr ( $ lines [ 0 ] , 0 , 12 ) ;
$ desc = substr ( $ lines [ 0 ] , 41 ) ;
}
return ( $ id , $ desc ) ;
}
2007-10-18 03:05:08 -07:00
$ chk_signoff = 0 if ( $ file ) ;
2007-06-08 13:47:06 -07:00
my @ rawlines = ( ) ;
2008-02-08 04:20:54 -08:00
my @ lines = ( ) ;
2013-07-03 15:05:31 -07:00
my @ fixed = ( ) ;
2014-08-06 16:11:05 -07:00
my @ fixed_inserted = ( ) ;
my @ fixed_deleted = ( ) ;
2014-08-06 16:11:03 -07:00
my $ fixlinenr = - 1 ;
2016-05-20 17:04:16 -07:00
# If input is git commits , extract all commits from the commit expressions .
# For example , HEAD - 3 means we need check 'HEAD, HEAD~1, HEAD~2' .
2020-10-24 16:59:04 -07:00
die "$P: No git repository found\n" if ( $ git && ! - e "$gitroot" ) ;
2016-05-20 17:04:16 -07:00
if ( $ git ) {
my @ commits = ( ) ;
2016-05-20 17:04:19 -07:00
foreach my $ commit_expr ( @ ARGV ) {
2016-05-20 17:04:16 -07:00
my $ git_range ;
2016-05-20 17:04:22 -07:00
if ( $ commit_expr =~ m /^ ( . * ) - ( \ d + ) $ / ) {
$ git_range = "-$2 $1" ;
2016-05-20 17:04:16 -07:00
} elsif ( $ commit_expr =~ m /\.\./ ) {
$ git_range = "$commit_expr" ;
} else {
2016-05-20 17:04:19 -07:00
$ git_range = "-1 $commit_expr" ;
}
2019-09-25 16:46:52 -07:00
my $ lines = ` $ { git_command } log -- no - color -- no - merges -- pretty = format : '%H %s' $ git_range ` ;
2016-05-20 17:04:19 -07:00
foreach my $ line ( split ( /\ n / , $ lines ) ) {
2016-05-20 17:04:22 -07:00
$ line =~ /^ ( [ 0 - 9 a - fA - F ] { 40 , 40 } ) ( . * ) $ / ;
next if ( ! defined ( $ 1 ) | | ! defined ( $ 2 ) ) ;
2016-05-20 17:04:19 -07:00
my $ sha1 = $ 1 ;
my $ subject = $ 2 ;
unshift ( @ commits , $ sha1 ) ;
$ git_commits { $ sha1 } = $ subject ;
2016-05-20 17:04:16 -07:00
}
}
die "$P: no git commits after extraction!\n" if ( @ commits == 0 ) ;
@ ARGV = @ commits ;
}
2008-02-08 04:20:54 -08:00
my $ vname ;
2019-03-07 16:28:38 -08:00
$ allow_c99_comments = ! defined $ ignore_type { "C99_COMMENT_TOLERANCE" } ;
2007-10-18 03:05:08 -07:00
for my $ filename ( @ ARGV ) {
2009-01-06 14:41:30 -08:00
my $ FILE ;
2020-10-15 20:12:12 -07:00
my $ is_git_file = git_is_single_file ( $ filename ) ;
my $ oldfile = $ file ;
$ file = 1 if ( $ is_git_file ) ;
2016-05-20 17:04:16 -07:00
if ( $ git ) {
open ( $ FILE , '-|' , "git format-patch -M --stdout -1 $filename" ) | |
die "$P: $filename: git format-patch failed - $!\n" ;
} elsif ( $ file ) {
2009-01-06 14:41:30 -08:00
open ( $ FILE , '-|' , "diff -u /dev/null $filename" ) | |
2007-10-18 03:05:08 -07:00
die "$P: $filename: diff failed - $!\n" ;
2009-01-06 14:41:30 -08:00
} elsif ( $ filename eq '-' ) {
open ( $ FILE , '<&STDIN' ) ;
2007-10-18 03:05:08 -07:00
} else {
2009-01-06 14:41:30 -08:00
open ( $ FILE , '<' , "$filename" ) | |
2007-10-18 03:05:08 -07:00
die "$P: $filename: open failed - $!\n" ;
2007-06-01 00:46:48 -07:00
}
2008-02-08 04:20:54 -08:00
if ( $ filename eq '-' ) {
$ vname = 'Your patch' ;
2016-05-20 17:04:16 -07:00
} elsif ( $ git ) {
2016-05-20 17:04:19 -07:00
$ vname = "Commit " . substr ( $ filename , 0 , 12 ) . ' ("' . $ git_commits { $ filename } . '")' ;
2008-02-08 04:20:54 -08:00
} else {
$ vname = $ filename ;
}
2009-01-06 14:41:30 -08:00
while ( < $ FILE > ) {
2007-10-18 03:05:08 -07:00
chomp ;
push ( @ rawlines , $ _ ) ;
2020-06-04 16:50:43 -07:00
$ vname = qq ( "$1" ) if ( $ filename eq '-' && $ _ =~ m /^ Subject :\ s + ( . + ) / i ) ;
2007-10-18 03:05:08 -07:00
}
2009-01-06 14:41:30 -08:00
close ( $ FILE ) ;
2015-06-25 15:03:00 -07:00
if ( $ # ARGV > 0 && $ quiet == 0 ) {
print '-' x length ( $ vname ) . "\n" ;
print "$vname\n" ;
print '-' x length ( $ vname ) . "\n" ;
}
2008-02-08 04:20:54 -08:00
if ( ! process ( $ filename ) ) {
2007-10-18 03:05:08 -07:00
$ exit = 1 ;
}
@ rawlines = ( ) ;
2008-02-08 04:22:03 -08:00
@ lines = ( ) ;
2013-07-03 15:05:31 -07:00
@ fixed = ( ) ;
2014-08-06 16:11:05 -07:00
@ fixed_inserted = ( ) ;
@ fixed_deleted = ( ) ;
2014-08-06 16:11:03 -07:00
$ fixlinenr = - 1 ;
2015-06-25 15:02:52 -07:00
@ modifierListFile = ( ) ;
@ typeListFile = ( ) ;
build_types ( ) ;
2020-10-15 20:12:12 -07:00
$ file = $ oldfile if ( $ is_git_file ) ;
2007-06-01 00:46:48 -07:00
}
2015-06-25 15:03:00 -07:00
if ( ! $ quiet ) {
2015-06-25 15:03:29 -07:00
hash_show_words ( \ %use_type, "Used");
hash_show_words ( \ %ignore_type, "Ignored");
2018-08-21 21:57:33 -07:00
if ( ! $ perl_version_ok ) {
2015-06-25 15:03:00 -07:00
print << "EOM"
NOTE : perl $ ^ V is not modern enough to detect all possible issues .
2018-08-21 21:57:33 -07:00
An upgrade to at least perl $ minimum_perl_version is suggested .
2015-06-25 15:03:00 -07:00
EOM
}
if ( $ exit ) {
print << "EOM"
NOTE : If any of the errors are false positives , please report
them to the maintainer , see CHECKPATCH in MAINTAINERS .
EOM
}
}
2007-06-01 00:46:48 -07:00
exit ( $ exit ) ;
sub top_of_kernel_tree {
2007-10-18 03:05:08 -07:00
my ( $ root ) = @ _ ;
my @ tree_check = (
"COPYING" , "CREDITS" , "Kbuild" , "MAINTAINERS" , "Makefile" ,
"README" , "Documentation" , "arch" , "include" , "drivers" ,
"fs" , "init" , "ipc" , "kernel" , "lib" , "scripts" ,
) ;
foreach my $ check ( @ tree_check ) {
if ( ! - e $ root . '/' . $ check ) {
return 0 ;
}
2007-06-01 00:46:48 -07:00
}
2007-10-18 03:05:08 -07:00
return 1 ;
2012-10-04 17:13:32 -07:00
}
2007-06-01 00:46:48 -07:00
2011-07-25 17:13:23 -07:00
sub parse_email {
my ( $ formatted_email ) = @ _ ;
my $ name = "" ;
2020-12-15 20:44:53 -08:00
my $ quoted = "" ;
2020-04-06 20:10:48 -07:00
my $ name_comment = "" ;
2011-07-25 17:13:23 -07:00
my $ address = "" ;
my $ comment = "" ;
if ( $ formatted_email =~ /^ ( . * ) < ( \ S +\@\ S + ) > ( . * ) $ / ) {
$ name = $ 1 ;
$ address = $ 2 ;
$ comment = $ 3 if defined $ 3 ;
} elsif ( $ formatted_email =~ /^\ s *< ( \ S +\@\ S + ) > ( . * ) $ / ) {
$ address = $ 1 ;
$ comment = $ 2 if defined $ 2 ;
} elsif ( $ formatted_email =~ / ( \ S +\@\ S + ) ( . * ) $ / ) {
$ address = $ 1 ;
$ comment = $ 2 if defined $ 2 ;
2018-04-10 16:33:09 -07:00
$ formatted_email =~ s /\ Q $ address \ E . * $ // ;
2011-07-25 17:13:23 -07:00
$ name = $ formatted_email ;
2013-07-03 15:05:31 -07:00
$ name = trim ( $ name ) ;
2011-07-25 17:13:23 -07:00
$ name =~ s /^\ "|\"$//g;
# If there's a name left after stripping spaces and
# leading quotes, and the address doesn't have both
# leading and trailing angle brackets, the address
# is invalid. ie:
# " joe smith joe @ smith . com " bad
# " joe smith < joe @ smith . com " bad
if ($name ne " " && $address !~ /^<[^>]+>$/) {
$name = " ";
$address = " ";
$comment = " ";
}
}
2020-12-15 20:44:53 -08:00
# Extract comments from names excluding quoted parts
# " John D . ( Doe ) " - Do not extract
if ($name =~ s/\"(.+)\"//) {
$quoted = $1;
2020-04-06 20:10:48 -07:00
}
2020-12-15 20:44:53 -08:00
while ($name =~ s/\s*($balanced_parens)\s*/ /) {
$name_comment .= trim($1);
}
$name =~ s/^[ \"]+|[ \"]+$//g;
$name = trim(" $ quoted $ name " ) ;
2013-07-03 15:05:31 -07:00
$ address = trim ( $ address ) ;
2011-07-25 17:13:23 -07:00
$ address =~ s /^\< | \> $ // g ;
2020-12-15 20:44:53 -08:00
$ comment = trim ( $ comment ) ;
2011-07-25 17:13:23 -07:00
if ( $ name =~ / [ ^\ w \- ] / i ) { ## has "must quote" chars
$ name =~ s / ( ?< ! \\ ) " /\\ "/g; ##escape quotes
$name = " \ "$name\"" ;
}
2020-04-06 20:10:48 -07:00
return ( $ name , $ name_comment , $ address , $ comment ) ;
2011-07-25 17:13:23 -07:00
}
sub format_email {
2020-10-15 20:12:28 -07:00
my ( $ name , $ name_comment , $ address , $ comment ) = @ _ ;
2011-07-25 17:13:23 -07:00
my $ formatted_email ;
2020-12-15 20:44:53 -08:00
$ name =~ s /^ [ \ " ] + | [ \ " ] + $ // g ;
2013-07-03 15:05:31 -07:00
$ address = trim ( $ address ) ;
2020-12-15 20:44:53 -08:00
$ address =~ s / ( ?:\. | \ , | \ " ) + $ // ; ## trailing commas , dots or quotes
2011-07-25 17:13:23 -07:00
if ( $ name =~ / [ ^\ w \- ] / i ) { ## has "must quote" chars
$ name =~ s / ( ?< ! \\ ) " /\\ "/g; ##escape quotes
$name = " \ "$name\"" ;
}
2020-12-15 20:44:53 -08:00
$ name_comment = trim ( $ name_comment ) ;
$ name_comment = " $name_comment" if ( $ name_comment ne "" ) ;
$ comment = trim ( $ comment ) ;
$ comment = " $comment" if ( $ comment ne "" ) ;
2011-07-25 17:13:23 -07:00
if ( "$name" eq "" ) {
$ formatted_email = "$address" ;
} else {
2020-10-15 20:12:28 -07:00
$ formatted_email = "$name$name_comment <$address>" ;
2011-07-25 17:13:23 -07:00
}
2020-10-15 20:12:28 -07:00
$ formatted_email . = "$comment" ;
2011-07-25 17:13:23 -07:00
return $ formatted_email ;
}
2020-04-06 20:10:48 -07:00
sub reformat_email {
my ( $ email ) = @ _ ;
my ( $ email_name , $ name_comment , $ email_address , $ comment ) = parse_email ( $ email ) ;
2020-10-15 20:12:28 -07:00
return format_email ( $ email_name , $ name_comment , $ email_address , $ comment ) ;
2020-04-06 20:10:48 -07:00
}
sub same_email_addresses {
2020-12-15 20:44:53 -08:00
my ( $ email1 , $ email2 ) = @ _ ;
2020-04-06 20:10:48 -07:00
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 &&
2020-10-15 20:12:28 -07:00
$ email1_address eq $ email2_address &&
$ name1_comment eq $ name2_comment &&
$ comment1 eq $ comment2 ;
2020-04-06 20:10:48 -07:00
}
2014-08-06 16:10:57 -07:00
sub which {
2014-08-06 16:11:10 -07:00
my ( $ bin ) = @ _ ;
2014-08-06 16:10:57 -07:00
2014-08-06 16:11:10 -07:00
foreach my $ path ( split ( /:/ , $ ENV { PATH } ) ) {
if ( - e "$path/$bin" ) {
return "$path/$bin" ;
}
2014-08-06 16:10:57 -07:00
}
2014-08-06 16:11:10 -07:00
return "" ;
2014-08-06 16:10:57 -07:00
}
2011-07-25 17:13:25 -07:00
sub which_conf {
my ( $ conf ) = @ _ ;
foreach my $ path ( split ( /:/ , ".:$ENV{HOME}:.scripts" ) ) {
if ( - e "$path/$conf" ) {
return "$path/$conf" ;
}
}
return "" ;
}
2007-06-01 00:46:48 -07:00
sub expand_tabs {
my ( $ str ) = @ _ ;
my $ res = '' ;
my $ n = 0 ;
for my $ c ( split ( // , $ str ) ) {
if ( $ c eq "\t" ) {
$ res . = ' ' ;
$ n ++ ;
2020-04-06 20:11:07 -07:00
for ( ; ( $ n % $tabsize) != 0; $n++) {
2007-06-01 00:46:48 -07:00
$ res . = ' ' ;
}
next ;
}
$ res . = $ c ;
$ n ++ ;
}
return $ res ;
}
2007-10-18 03:05:08 -07:00
sub copy_spacing {
2008-03-28 14:15:58 -07:00
( my $ res = shift ) =~ tr /\ t / / c ;
2007-10-18 03:05:08 -07:00
return $ res ;
}
2007-06-01 00:46:48 -07:00
2007-06-08 13:46:39 -07:00
sub line_stats {
my ( $ line ) = @ _ ;
# Drop the diff line leader and expand tabs
$ line =~ s /^.// ;
$ line = expand_tabs ( $ line ) ;
# Pick the indent from the front of the line .
my ( $ white ) = ( $ line =~ /^ ( \ s * ) / ) ;
return ( length ( $ line ) , length ( $ white ) ) ;
}
2008-03-28 14:15:58 -07:00
my $ sanitise_quote = '' ;
sub sanitise_line_reset {
my ( $ in_comment ) = @ _ ;
if ( $ in_comment ) {
$ sanitise_quote = '*/' ;
} else {
$ sanitise_quote = '' ;
}
}
2007-06-08 13:47:06 -07:00
sub sanitise_line {
my ( $ line ) = @ _ ;
my $ res = '' ;
my $ l = '' ;
2008-02-08 04:20:54 -08:00
my $ qlen = 0 ;
2008-03-28 14:15:58 -07:00
my $ off = 0 ;
my $ c ;
2007-06-08 13:47:06 -07:00
2008-03-28 14:15:58 -07:00
# Always copy over the diff marker .
$ res = substr ( $ line , 0 , 1 ) ;
for ( $ off = 1 ; $ off < length ( $ line ) ; $ off ++ ) {
$ c = substr ( $ line , $ off , 1 ) ;
2018-04-10 16:33:42 -07:00
# Comments we are whacking completely including the begin
2008-03-28 14:15:58 -07:00
# and end , all to $ ; .
if ( $ sanitise_quote eq '' && substr ( $ line , $ off , 2 ) eq '/*' ) {
$ sanitise_quote = '*/' ;
substr ( $ res , $ off , 2 , "$;$;" ) ;
$ off ++ ;
next ;
2008-02-08 04:20:54 -08:00
}
2008-10-15 22:02:26 -07:00
if ( $ sanitise_quote eq '*/' && substr ( $ line , $ off , 2 ) eq '*/' ) {
2008-03-28 14:15:58 -07:00
$ sanitise_quote = '' ;
substr ( $ res , $ off , 2 , "$;$;" ) ;
$ off ++ ;
next ;
}
2009-09-21 17:04:35 -07:00
if ( $ sanitise_quote eq '' && substr ( $ line , $ off , 2 ) eq '//' ) {
$ sanitise_quote = '//' ;
substr ( $ res , $ off , 2 , $ sanitise_quote ) ;
$ off ++ ;
next ;
}
2008-03-28 14:15:58 -07:00
# A \ in a string means ignore the next character .
if ( ( $ sanitise_quote eq "'" | | $ sanitise_quote eq '"' ) &&
$ c eq " \\ ") {
substr($res, $off, 2, 'XX');
$off++;
next;
}
# Regular quotes.
if ($c eq " '" || $c eq ' "') {
if ($sanitise_quote eq '') {
$sanitise_quote = $c;
substr($res, $off, 1, $c);
2007-06-08 13:47:06 -07:00
next;
2008-03-28 14:15:58 -07:00
} elsif ($sanitise_quote eq $c) {
$sanitise_quote = '';
2007-06-08 13:47:06 -07:00
}
}
2008-03-28 14:15:58 -07:00
2009-01-06 14:41:20 -08:00
#print " c < $ c > SQ < $ sanitise_quote >\ n ";
2008-03-28 14:15:58 -07:00
if ($off != 0 && $sanitise_quote eq '*/' && $c ne " \ t ") {
substr($res, $off, 1, $;);
2009-09-21 17:04:35 -07:00
} elsif ($off != 0 && $sanitise_quote eq '//' && $c ne " \ t ") {
substr($res, $off, 1, $;);
2008-03-28 14:15:58 -07:00
} elsif ($off != 0 && $sanitise_quote && $c ne " \ t " ) {
substr ( $ res , $ off , 1 , 'X' ) ;
2007-06-08 13:47:06 -07:00
} else {
2008-03-28 14:15:58 -07:00
substr ( $ res , $ off , 1 , $ c ) ;
2007-06-08 13:47:06 -07:00
}
2008-02-08 04:20:54 -08:00
}
2009-09-21 17:04:35 -07:00
if ( $ sanitise_quote eq '//' ) {
$ sanitise_quote = '' ;
}
2008-02-08 04:20:54 -08:00
# The pathname on a # include may be surrounded by '<' and '>' .
2008-06-05 22:46:01 -07:00
if ( $ res =~ /^.\ s *\#\ s * include \ s +\< ( . * ) \>/ ) {
2008-02-08 04:20:54 -08:00
my $ clean = 'X' x length ( $ 1 ) ;
$ res =~ s @\<.*\>@< $ clean >@ ;
# The whole of a # error is a string .
2008-06-05 22:46:01 -07:00
} elsif ( $ res =~ /^.\ s *\#\ s * ( ?: error | warning ) \ s + ( . * ) \ b / ) {
2008-02-08 04:20:54 -08:00
my $ clean = 'X' x length ( $ 1 ) ;
2008-06-05 22:46:01 -07:00
$ res =~ s @ ( \#\ s * ( ?: error | warning ) \ s + ) . *@ $ 1 $ clean @ ;
2008-02-08 04:20:54 -08:00
}
2016-08-02 14:04:33 -07:00
if ( $ allow_c99_comments && $ res =~ m @ ( //.* $ ) @ ) {
my $ match = $ 1 ;
$ res =~ s /\ Q $ match \ E / "$;" x length ( $ match ) / e ;
}
2007-06-08 13:47:06 -07:00
return $ res ;
}
2013-04-29 16:18:13 -07:00
sub get_quoted_string {
my ( $ line , $ rawline ) = @ _ ;
2018-04-10 16:33:34 -07:00
return "" if ( ! defined ( $ line ) | | ! defined ( $ rawline ) ) ;
2015-06-25 15:02:54 -07:00
return "" if ( $ line ! ~ m / ( $ String ) / g ) ;
2013-04-29 16:18:13 -07:00
return substr ( $ rawline , $ - [ 0 ] , $ + [ 0 ] - $ - [ 0 ] ) ;
}
2007-11-28 16:21:06 -08:00
sub ctx_statement_block {
my ( $ linenr , $ remain , $ off ) = @ _ ;
my $ line = $ linenr - 1 ;
my $ blk = '' ;
my $ soff = $ off ;
my $ coff = $ off - 1 ;
2008-03-28 14:15:58 -07:00
my $ coff_set = 0 ;
2007-11-28 16:21:06 -08:00
2008-02-08 04:22:03 -08:00
my $ loff = 0 ;
2007-11-28 16:21:06 -08:00
my $ type = '' ;
my $ level = 0 ;
2009-01-15 13:51:04 -08:00
my @ stack = ( ) ;
2008-03-04 14:28:20 -08:00
my $ p ;
2007-11-28 16:21:06 -08:00
my $ c ;
my $ len = 0 ;
2008-02-08 04:22:03 -08:00
my $ remainder ;
2007-11-28 16:21:06 -08:00
while ( 1 ) {
2009-01-15 13:51:04 -08:00
@ stack = ( [ '' , 0 ] ) if ( $ # stack == - 1 ) ;
2008-03-28 14:15:58 -07:00
# warn "CSB: blk<$blk> remain<$remain>\n" ;
2007-11-28 16:21:06 -08:00
# If we are about to drop off the end , pull in more
# context .
if ( $ off >= $ len ) {
for ( ; $ remain > 0 ; $ line ++ ) {
2008-10-15 22:02:25 -07:00
last if ( ! defined $ lines [ $ line ] ) ;
2008-02-08 04:20:54 -08:00
next if ( $ lines [ $ line ] =~ /^-/ ) ;
2007-11-28 16:21:06 -08:00
$ remain -- ;
2008-02-08 04:22:03 -08:00
$ loff = $ len ;
2008-02-08 04:20:54 -08:00
$ blk . = $ lines [ $ line ] . "\n" ;
2007-11-28 16:21:06 -08:00
$ len = length ( $ blk ) ;
$ line ++ ;
last ;
}
# Bail if there is no further context .
# warn "CSB: blk<$blk> off<$off> len<$len>\n" ;
2008-02-08 04:22:03 -08:00
if ( $ off >= $ len ) {
2007-11-28 16:21:06 -08:00
last ;
}
2012-01-10 15:09:54 -08:00
if ( $ level == 0 && substr ( $ blk , $ off ) =~ /^.\ s *#\ s * define / ) {
$ level ++ ;
$ type = '#' ;
}
2007-11-28 16:21:06 -08:00
}
2008-03-04 14:28:20 -08:00
$ p = $ c ;
2007-11-28 16:21:06 -08:00
$ c = substr ( $ blk , $ off , 1 ) ;
2008-02-08 04:22:03 -08:00
$ remainder = substr ( $ blk , $ off ) ;
2007-11-28 16:21:06 -08:00
2008-03-28 14:15:58 -07:00
# warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n" ;
2009-01-06 14:41:27 -08:00
# Handle nested # if /# else .
if ( $ remainder =~ /^#\ s * ( ?: ifndef | ifdef | if ) \ s / ) {
push ( @ stack , [ $ type , $ level ] ) ;
} elsif ( $ remainder =~ /^#\ s * ( ?: else | elif ) \ b / ) {
( $ type , $ level ) = @ { $ stack [ $ # stack - 1 ] } ;
} elsif ( $ remainder =~ /^#\ s * endif \ b / ) {
( $ type , $ level ) = @ { pop ( @ stack ) } ;
}
2007-11-28 16:21:06 -08:00
# Statement ends at the ';' or a close '}' at the
# outermost level .
if ( $ level == 0 && $ c eq ';' ) {
last ;
}
2008-02-08 04:22:03 -08:00
# An else is really a conditional as long as its not else if
2008-03-28 14:15:58 -07:00
if ( $ level == 0 && $ coff_set == 0 &&
( ! defined ( $ p ) | | $ p =~ / ( ?:\ s | \ } | \+ ) / ) &&
$ remainder =~ /^ ( else ) ( ?:\ s | { ) / &&
$ remainder ! ~ /^ else \ s + if \ b / ) {
$ coff = $ off + length ( $ 1 ) - 1 ;
$ coff_set = 1 ;
# warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n" ;
# warn "[" . substr ( $ blk , $ soff , $ coff - $ soff + 1 ) . "]\n" ;
2008-02-08 04:22:03 -08:00
}
2007-11-28 16:21:06 -08:00
if ( ( $ type eq '' | | $ type eq '(' ) && $ c eq '(' ) {
$ level ++ ;
$ type = '(' ;
}
if ( $ type eq '(' && $ c eq ')' ) {
$ level -- ;
$ type = ( $ level ! = 0 ) ? '(' : '' ;
if ( $ level == 0 && $ coff < $ soff ) {
$ coff = $ off ;
2008-03-28 14:15:58 -07:00
$ coff_set = 1 ;
# warn "CSB: mark coff<$coff>\n" ;
2007-11-28 16:21:06 -08:00
}
}
if ( ( $ type eq '' | | $ type eq '{' ) && $ c eq '{' ) {
$ level ++ ;
$ type = '{' ;
}
if ( $ type eq '{' && $ c eq '}' ) {
$ level -- ;
$ type = ( $ level ! = 0 ) ? '{' : '' ;
if ( $ level == 0 ) {
2010-08-09 17:21:03 -07:00
if ( substr ( $ blk , $ off + 1 , 1 ) eq ';' ) {
$ off ++ ;
}
2007-11-28 16:21:06 -08:00
last ;
}
}
2012-01-10 15:09:54 -08:00
# Preprocessor commands end at the newline unless escaped .
if ( $ type eq '#' && $ c eq "\n" && $ p ne " \\ ") {
$level--;
$type = '';
$off++;
last;
}
2007-11-28 16:21:06 -08:00
$off++;
}
2008-07-23 21:29:00 -07:00
# We are truly at the end, so shuffle to the next line.
2008-02-08 04:22:03 -08:00
if ($off == $len) {
2008-07-23 21:29:00 -07:00
$loff = $len + 1;
2008-02-08 04:22:03 -08:00
$line++;
$remain--;
}
2007-11-28 16:21:06 -08:00
my $statement = substr($blk, $soff, $off - $soff + 1);
my $condition = substr($blk, $soff, $coff - $soff + 1);
#warn " STATEMENT < $ statement >\ n ";
#warn " CONDITION < $ condition >\ n ";
2008-03-28 14:15:58 -07:00
#print " coff < $ coff > soff < $ off > loff < $ loff >\ n ";
2008-02-08 04:22:03 -08:00
return ($statement, $condition,
$line, $remain + 1, $off - $loff + 1, $level);
}
2008-03-04 14:28:20 -08:00
sub statement_lines {
my ($stmt) = @_;
# Strip the diff line prefixes and rip blank lines at start and end.
$stmt =~ s/(^|\n)./$1/g;
$stmt =~ s/^\s*//;
$stmt =~ s/\s*$//;
my @stmt_lines = ($stmt =~ /\n/g);
return $#stmt_lines + 2;
}
sub statement_rawlines {
my ($stmt) = @_;
my @stmt_lines = ($stmt =~ /\n/g);
return $#stmt_lines + 2;
}
sub statement_block_size {
my ($stmt) = @_;
$stmt =~ s/(^|\n)./$1/g;
$stmt =~ s/^\s*{//;
$stmt =~ s/}\s*$//;
$stmt =~ s/^\s*//;
$stmt =~ s/\s*$//;
my @stmt_lines = ($stmt =~ /\n/g);
my @stmt_statements = ($stmt =~ /;/g);
my $stmt_lines = $#stmt_lines + 2;
my $stmt_statements = $#stmt_statements + 1;
if ($stmt_lines > $stmt_statements) {
return $stmt_lines;
} else {
return $stmt_statements;
}
}
2008-02-08 04:22:03 -08:00
sub ctx_statement_full {
my ($linenr, $remain, $off) = @_;
my ($statement, $condition, $level);
my (@chunks);
2008-03-04 14:28:20 -08:00
# Grab the first conditional/block pair.
2008-02-08 04:22:03 -08:00
($statement, $condition, $linenr, $remain, $off, $level) =
ctx_statement_block($linenr, $remain, $off);
2008-03-28 14:15:58 -07:00
#print " F : c < $ condition > s < $ statement > remain < $ remain >\ n ";
2008-03-04 14:28:20 -08:00
push(@chunks, [ $condition, $statement ]);
if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
return ($level, $linenr, @chunks);
}
# Pull in the following conditional/block pairs and see if they
# could continue the statement.
2008-02-08 04:22:03 -08:00
for (;;) {
($statement, $condition, $linenr, $remain, $off, $level) =
ctx_statement_block($linenr, $remain, $off);
2008-03-04 14:28:20 -08:00
#print " C : c < $ condition > s < $ statement > remain < $ remain >\ n ";
2008-03-28 14:15:58 -07:00
last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
2008-03-04 14:28:20 -08:00
#print " C : push \ n ";
push(@chunks, [ $condition, $statement ]);
2008-02-08 04:22:03 -08:00
}
return ($level, $linenr, @chunks);
2007-11-28 16:21:06 -08:00
}
2007-06-08 13:46:39 -07:00
sub ctx_block_get {
2007-07-19 01:48:34 -07:00
my ($linenr, $remain, $outer, $open, $close, $off) = @_;
2007-06-08 13:46:39 -07:00
my $line;
my $start = $linenr - 1;
my $blk = '';
my @o;
my @c;
my @res = ();
2007-07-19 01:48:34 -07:00
my $level = 0;
2009-01-06 14:41:27 -08:00
my @stack = ($level);
2007-06-08 13:47:06 -07:00
for ($line = $start; $remain > 0; $line++) {
next if ($rawlines[$line] =~ /^-/);
$remain--;
$blk .= $rawlines[$line];
2009-01-06 14:41:27 -08:00
# Handle nested #if/#else.
2010-10-26 14:23:19 -07:00
if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
2009-01-06 14:41:27 -08:00
push(@stack, $level);
2010-10-26 14:23:19 -07:00
} elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
2009-01-06 14:41:27 -08:00
$level = $stack[$#stack - 1];
2010-10-26 14:23:19 -07:00
} elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
2009-01-06 14:41:27 -08:00
$level = pop(@stack);
}
2010-10-26 14:23:19 -07:00
foreach my $c (split(//, $lines[$line])) {
2007-07-19 01:48:34 -07:00
##print " C < $ c > L < $ level >< $ open$close > O < $ off >\ n " ;
if ( $ off > 0 ) {
$ off -- ;
next ;
}
2007-06-08 13:46:39 -07:00
2007-07-19 01:48:34 -07:00
if ( $ c eq $ close && $ level > 0 ) {
$ level -- ;
last if ( $ level == 0 ) ;
} elsif ( $ c eq $ open ) {
$ level ++ ;
}
}
2007-06-08 13:46:39 -07:00
2007-07-19 01:48:34 -07:00
if ( ! $ outer | | $ level <= 1 ) {
2007-06-08 13:47:06 -07:00
push ( @ res , $ rawlines [ $ line ] ) ;
2007-06-08 13:46:39 -07:00
}
2007-07-19 01:48:34 -07:00
last if ( $ level == 0 ) ;
2007-06-08 13:46:39 -07:00
}
2007-07-19 01:48:34 -07:00
return ( $ level , @ res ) ;
2007-06-08 13:46:39 -07:00
}
sub ctx_block_outer {
my ( $ linenr , $ remain ) = @ _ ;
2007-07-19 01:48:34 -07:00
my ( $ level , @ r ) = ctx_block_get ( $ linenr , $ remain , 1 , '{' , '}' , 0 ) ;
return @ r ;
2007-06-08 13:46:39 -07:00
}
sub ctx_block {
my ( $ linenr , $ remain ) = @ _ ;
2007-07-19 01:48:34 -07:00
my ( $ level , @ r ) = ctx_block_get ( $ linenr , $ remain , 0 , '{' , '}' , 0 ) ;
return @ r ;
2007-06-23 17:16:34 -07:00
}
sub ctx_statement {
2007-07-19 01:48:34 -07:00
my ( $ linenr , $ remain , $ off ) = @ _ ;
my ( $ level , @ r ) = ctx_block_get ( $ linenr , $ remain , 0 , '(' , ')' , $ off ) ;
return @ r ;
}
sub ctx_block_level {
2007-06-23 17:16:34 -07:00
my ( $ linenr , $ remain ) = @ _ ;
2007-07-19 01:48:34 -07:00
return ctx_block_get ( $ linenr , $ remain , 0 , '{' , '}' , 0 ) ;
2007-06-08 13:46:39 -07:00
}
2007-10-16 23:29:38 -07:00
sub ctx_statement_level {
my ( $ linenr , $ remain , $ off ) = @ _ ;
return ctx_block_get ( $ linenr , $ remain , 0 , '(' , ')' , $ off ) ;
}
2007-06-08 13:46:39 -07:00
sub ctx_locate_comment {
my ( $ first_line , $ end_line ) = @ _ ;
2020-06-04 16:50:36 -07:00
# If c99 comment on the current line , or the line before or after
my ( $ current_comment ) = ( $ rawlines [ $ end_line - 1 ] =~ m @^\+.* ( //.* $ ) @ ) ;
return $ current_comment if ( defined $ current_comment ) ;
( $ current_comment ) = ( $ rawlines [ $ end_line - 2 ] =~ m @^ [ \+ ] . * ( //.* $ ) @ ) ;
return $ current_comment if ( defined $ current_comment ) ;
( $ current_comment ) = ( $ rawlines [ $ end_line ] =~ m @^ [ \+ ] . * ( //.* $ ) @ ) ;
return $ current_comment if ( defined $ current_comment ) ;
2007-06-08 13:46:39 -07:00
# Catch a comment on the end of the line itself .
2020-06-04 16:50:36 -07:00
( $ current_comment ) = ( $ rawlines [ $ end_line - 1 ] =~ m @.* ( /\*.*\*/ ) \ s * ( ?:\\\ s * ) ? $ @ ) ;
2007-06-08 13:46:39 -07:00
return $ current_comment if ( defined $ current_comment ) ;
# Look through the context and try and figure out if there is a
# comment .
my $ in_comment = 0 ;
$ current_comment = '' ;
for ( my $ linenr = $ first_line ; $ linenr < $ end_line ; $ linenr ++ ) {
2007-06-08 13:47:06 -07:00
my $ line = $ rawlines [ $ linenr - 1 ] ;
# warn " $line\n" ;
2007-06-08 13:46:39 -07:00
if ( $ linenr == $ first_line and $ line =~ m @^.\ s *\*@ ) {
$ in_comment = 1 ;
}
if ( $ line =~ m @/\*@ ) {
$ in_comment = 1 ;
}
if ( ! $ in_comment && $ current_comment ne '' ) {
$ current_comment = '' ;
}
$ current_comment . = $ line . "\n" if ( $ in_comment ) ;
if ( $ line =~ m @\*/@ ) {
$ in_comment = 0 ;
}
}
chomp ( $ current_comment ) ;
return ( $ current_comment ) ;
}
sub ctx_has_comment {
my ( $ first_line , $ end_line ) = @ _ ;
my $ cmt = ctx_locate_comment ( $ first_line , $ end_line ) ;
2007-06-08 13:47:06 -07:00
## print "LINE: $rawlines[$end_line - 1 ]\n" ;
2007-06-08 13:46:39 -07:00
## print "CMMT: $cmt\n" ;
return ( $ cmt ne '' ) ;
}
2008-10-15 22:02:21 -07:00
sub raw_line {
my ( $ linenr , $ cnt ) = @ _ ;
my $ offset = $ linenr - 1 ;
$ cnt ++ ;
my $ line ;
while ( $ cnt ) {
$ line = $ rawlines [ $ offset ++ ] ;
next if ( defined ( $ line ) && $ line =~ /^-/ ) ;
$ cnt -- ;
}
return $ line ;
}
2018-04-10 16:33:20 -07:00
sub get_stat_real {
my ( $ linenr , $ lc ) = @ _ ;
my $ stat_real = raw_line ( $ linenr , 0 ) ;
for ( my $ count = $ linenr + 1 ; $ count <= $ lc ; $ count ++ ) {
$ stat_real = $ stat_real . "\n" . raw_line ( $ count , 0 ) ;
}
return $ stat_real ;
}
2018-04-10 16:33:27 -07:00
sub get_stat_here {
my ( $ linenr , $ cnt , $ here ) = @ _ ;
my $ herectx = $ here . "\n" ;
for ( my $ n = 0 ; $ n < $ cnt ; $ n ++ ) {
$ herectx . = raw_line ( $ linenr , $ n ) . "\n" ;
}
return $ herectx ;
}
2007-06-01 00:46:48 -07:00
sub cat_vet {
my ( $ vet ) = @ _ ;
2007-10-16 23:29:38 -07:00
my ( $ res , $ coded ) ;
2007-06-01 00:46:48 -07:00
2007-10-16 23:29:38 -07:00
$ res = '' ;
2007-10-18 03:05:08 -07:00
while ( $ vet =~ / ( [ ^ [ : cntrl : ] ] * ) ( [ [ : cntrl : ] ] | $ ) / g ) {
$ res . = $ 1 ;
if ( $ 2 ne '' ) {
$ coded = sprintf ( "^%c" , unpack ( 'C' , $ 2 ) + 64 ) ;
$ res . = $ coded ;
}
2007-10-16 23:29:38 -07:00
}
$ res =~ s / $ /\ $ / ;
2007-06-01 00:46:48 -07:00
2007-10-16 23:29:38 -07:00
return $ res ;
2007-06-01 00:46:48 -07:00
}
2008-02-08 04:20:54 -08:00
my $ av_preprocessor = 0 ;
2008-03-04 14:28:20 -08:00
my $ av_pending ;
2008-02-08 04:20:54 -08:00
my @ av_paren_type ;
2008-07-23 21:29:10 -07:00
my $ av_pend_colon ;
2008-02-08 04:20:54 -08:00
sub annotate_reset {
$ av_preprocessor = 0 ;
2008-03-04 14:28:20 -08:00
$ av_pending = '_' ;
@ av_paren_type = ( 'E' ) ;
2008-07-23 21:29:10 -07:00
$ av_pend_colon = 'O' ;
2008-02-08 04:20:54 -08:00
}
2007-10-18 03:05:08 -07:00
sub annotate_values {
my ( $ stream , $ type ) = @ _ ;
my $ res ;
2008-07-23 21:29:10 -07:00
my $ var = '_' x length ( $ stream ) ;
2007-10-18 03:05:08 -07:00
my $ cur = $ stream ;
2008-02-08 04:20:54 -08:00
print "$stream\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
while ( length ( $ cur ) ) {
2008-03-28 14:15:58 -07:00
@ av_paren_type = ( 'E' ) if ( $ # av_paren_type < 0 ) ;
2008-03-04 14:28:20 -08:00
print " <" . join ( '' , @ av_paren_type ) .
2008-04-29 00:59:32 -07:00
"> <$type> <$av_pending>" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
if ( $ cur =~ /^ ( \ s + ) / o ) {
2008-02-08 04:20:54 -08:00
print "WS($1)\n" if ( $ dbg_values > 1 ) ;
if ( $ 1 =~ /\ n / && $ av_preprocessor ) {
2008-03-04 14:28:20 -08:00
$ type = pop ( @ av_paren_type ) ;
2008-02-08 04:20:54 -08:00
$ av_preprocessor = 0 ;
2007-10-18 03:05:08 -07:00
}
2011-01-12 16:59:58 -08:00
} elsif ( $ cur =~ /^ ( \ ( \ s * $ Type \ s * ) \ ) / && $ av_pending eq '_' ) {
2010-10-26 14:23:13 -07:00
print "CAST($1)\n" if ( $ dbg_values > 1 ) ;
push ( @ av_paren_type , $ type ) ;
2012-01-10 15:10:11 -08:00
$ type = 'c' ;
2010-10-26 14:23:13 -07:00
2010-10-26 14:23:11 -07:00
} elsif ( $ cur =~ /^ ( $ Type ) \ s * ( ?: $ Ident | , | \ ) | \ ( | \ s * $ ) / ) {
2008-02-08 04:20:54 -08:00
print "DECLARE($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
$ type = 'T' ;
2008-07-23 21:29:05 -07:00
} elsif ( $ cur =~ /^ ( $ Modifier ) \ s */ ) {
print "MODIFIER($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'T' ;
2008-06-05 22:46:01 -07:00
} elsif ( $ cur =~ /^ ( \#\ s * define \ s * $ Ident ) ( \ ( ? ) / o ) {
2008-04-29 00:59:32 -07:00
print "DEFINE($1,$2)\n" if ( $ dbg_values > 1 ) ;
2008-02-08 04:20:54 -08:00
$ av_preprocessor = 1 ;
2008-04-29 00:59:32 -07:00
push ( @ av_paren_type , $ type ) ;
if ( $ 2 ne '' ) {
$ av_pending = 'N' ;
}
$ type = 'E' ;
2008-06-05 22:46:01 -07:00
} elsif ( $ cur =~ /^ ( \#\ s * ( ?: undef \ s * $ Ident | include \ b ) ) / o ) {
2008-04-29 00:59:32 -07:00
print "UNDEF($1)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
push ( @ av_paren_type , $ type ) ;
2007-10-18 03:05:08 -07:00
2008-06-05 22:46:01 -07:00
} elsif ( $ cur =~ /^ ( \#\ s * ( ?: ifdef | ifndef | if ) ) / o ) {
2008-03-04 14:28:20 -08:00
print "PRE_START($1)\n" if ( $ dbg_values > 1 ) ;
2008-02-08 04:20:54 -08:00
$ av_preprocessor = 1 ;
2008-03-04 14:28:20 -08:00
push ( @ av_paren_type , $ type ) ;
push ( @ av_paren_type , $ type ) ;
2008-04-29 00:59:32 -07:00
$ type = 'E' ;
2008-03-04 14:28:20 -08:00
2008-06-05 22:46:01 -07:00
} elsif ( $ cur =~ /^ ( \#\ s * ( ?: else | elif ) ) / o ) {
2008-03-04 14:28:20 -08:00
print "PRE_RESTART($1)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
push ( @ av_paren_type , $ av_paren_type [ $ # av_paren_type ] ) ;
2008-04-29 00:59:32 -07:00
$ type = 'E' ;
2008-03-04 14:28:20 -08:00
2008-06-05 22:46:01 -07:00
} elsif ( $ cur =~ /^ ( \#\ s * ( ?: endif ) ) / o ) {
2008-03-04 14:28:20 -08:00
print "PRE_END($1)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
# Assume all arms of the conditional end as this
# one does , and continue as if the # endif was not here .
pop ( @ av_paren_type ) ;
push ( @ av_paren_type , $ type ) ;
2008-04-29 00:59:32 -07:00
$ type = 'E' ;
2007-10-18 03:05:08 -07:00
} elsif ( $ cur =~ /^ ( \\\ n ) / o ) {
2008-02-08 04:20:54 -08:00
print "PRECONT($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
2008-04-29 00:59:32 -07:00
} elsif ( $ cur =~ /^ ( _ _ attribute__ ) \ s *\ ( ?/ o ) {
print "ATTR($1)\n" if ( $ dbg_values > 1 ) ;
$ av_pending = $ type ;
$ type = 'N' ;
2007-10-18 03:05:08 -07:00
} elsif ( $ cur =~ /^ ( sizeof ) \ s * ( \ ( ) ?/ o ) {
2008-02-08 04:20:54 -08:00
print "SIZEOF($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
if ( defined $ 2 ) {
2008-03-04 14:28:20 -08:00
$ av_pending = 'V' ;
2007-10-18 03:05:08 -07:00
}
$ type = 'N' ;
2008-10-15 22:02:16 -07:00
} elsif ( $ cur =~ /^ ( if | while | for ) \ b / o ) {
2008-02-08 04:20:54 -08:00
print "COND($1)\n" if ( $ dbg_values > 1 ) ;
2008-10-15 22:02:16 -07:00
$ av_pending = 'E' ;
2007-10-18 03:05:08 -07:00
$ type = 'N' ;
2008-07-23 21:29:10 -07:00
} elsif ( $ cur =~/^ ( case ) / o ) {
print "CASE($1)\n" if ( $ dbg_values > 1 ) ;
$ av_pend_colon = 'C' ;
$ type = 'N' ;
2008-10-15 22:02:16 -07:00
} elsif ( $ cur =~/^ ( return | else | goto | typeof | _ _ typeof__ ) \ b / o ) {
2008-02-08 04:20:54 -08:00
print "KEYWORD($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
$ type = 'N' ;
} elsif ( $ cur =~ /^ ( \ ( ) / o ) {
2008-02-08 04:20:54 -08:00
print "PAREN('$1')\n" if ( $ dbg_values > 1 ) ;
2008-03-04 14:28:20 -08:00
push ( @ av_paren_type , $ av_pending ) ;
$ av_pending = '_' ;
2007-10-18 03:05:08 -07:00
$ type = 'N' ;
} elsif ( $ cur =~ /^ ( \ ) ) / o ) {
2008-03-04 14:28:20 -08:00
my $ new_type = pop ( @ av_paren_type ) ;
if ( $ new_type ne '_' ) {
$ type = $ new_type ;
2008-02-08 04:20:54 -08:00
print "PAREN('$1') -> $type\n"
if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
} else {
2008-02-08 04:20:54 -08:00
print "PAREN('$1')\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
}
2008-07-23 21:28:57 -07:00
} elsif ( $ cur =~ /^ ( $ Ident ) \ s *\ ( / o ) {
2008-02-08 04:20:54 -08:00
print "FUNC($1)\n" if ( $ dbg_values > 1 ) ;
2008-07-23 21:28:57 -07:00
$ type = 'V' ;
2008-03-04 14:28:20 -08:00
$ av_pending = 'V' ;
2007-10-18 03:05:08 -07:00
2009-01-06 14:41:19 -08:00
} elsif ( $ cur =~ /^ ( $ Ident \ s * ) : ( ?:\ s *\ d +\ s * ( , | = | ; ) ) ?/ ) {
if ( defined $ 2 && $ type eq 'C' | | $ type eq 'T' ) {
2008-07-23 21:29:10 -07:00
$ av_pend_colon = 'B' ;
2009-01-06 14:41:19 -08:00
} elsif ( $ type eq 'E' ) {
$ av_pend_colon = 'L' ;
2008-07-23 21:29:10 -07:00
}
print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ( $ dbg_values > 1 ) ;
$ type = 'V' ;
2007-10-18 03:05:08 -07:00
} elsif ( $ cur =~ /^ ( $ Ident | $ Constant ) / o ) {
2008-02-08 04:20:54 -08:00
print "IDENT($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
$ type = 'V' ;
} elsif ( $ cur =~ /^ ( $ Assignment ) / o ) {
2008-02-08 04:20:54 -08:00
print "ASSIGN($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
$ type = 'N' ;
2008-03-04 14:28:20 -08:00
} elsif ( $ cur =~/^ ( ; | { | } ) / ) {
2008-02-08 04:20:54 -08:00
print "END($1)\n" if ( $ dbg_values > 1 ) ;
2008-02-08 04:22:03 -08:00
$ type = 'E' ;
2008-07-23 21:29:10 -07:00
$ av_pend_colon = 'O' ;
2008-02-08 04:22:03 -08:00
2009-01-06 14:41:19 -08:00
} elsif ( $ cur =~/^ ( , ) / ) {
print "COMMA($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'C' ;
2008-07-23 21:29:10 -07:00
} elsif ( $ cur =~ /^ ( \? ) / o ) {
print "QUESTION($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'N' ;
} elsif ( $ cur =~ /^ ( : ) / o ) {
print "COLON($1,$av_pend_colon)\n" if ( $ dbg_values > 1 ) ;
substr ( $ var , length ( $ res ) , 1 , $ av_pend_colon ) ;
if ( $ av_pend_colon eq 'C' | | $ av_pend_colon eq 'L' ) {
$ type = 'E' ;
} else {
$ type = 'N' ;
}
$ av_pend_colon = 'O' ;
2009-01-06 14:41:19 -08:00
} elsif ( $ cur =~ /^ ( \ [ ) / o ) {
2008-02-08 04:22:03 -08:00
print "CLOSE($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
$ type = 'N' ;
2008-10-15 22:02:16 -07:00
} elsif ( $ cur =~ /^ ( - ( ? ! [ -> ] ) | \+ ( ? ! \+ ) | \* | \&\& | \& ) / o ) {
2008-07-23 21:29:10 -07:00
my $ variant ;
print "OPV($1)\n" if ( $ dbg_values > 1 ) ;
if ( $ type eq 'V' ) {
$ variant = 'B' ;
} else {
$ variant = 'U' ;
}
substr ( $ var , length ( $ res ) , 1 , $ variant ) ;
$ type = 'N' ;
2007-10-18 03:05:08 -07:00
} elsif ( $ cur =~ /^ ( $ Operators ) / o ) {
2008-02-08 04:20:54 -08:00
print "OP($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
if ( $ 1 ne '++' && $ 1 ne '--' ) {
$ type = 'N' ;
}
} elsif ( $ cur =~ / ( ^. ) / o ) {
2008-02-08 04:20:54 -08:00
print "C($1)\n" if ( $ dbg_values > 1 ) ;
2007-10-18 03:05:08 -07:00
}
if ( defined $ 1 ) {
$ cur = substr ( $ cur , length ( $ 1 ) ) ;
$ res . = $ type x length ( $ 1 ) ;
}
}
2008-07-23 21:29:10 -07:00
return ( $ res , $ var ) ;
2007-10-18 03:05:08 -07:00
}
2007-11-28 16:21:06 -08:00
sub possible {
2008-02-08 04:22:03 -08:00
my ( $ possible , $ line ) = @ _ ;
2009-10-26 16:50:12 -07:00
my $ notPermitted = qr { ( ?:
2008-10-15 22:02:29 -07:00
^ ( ?:
$ Modifier |
$ Storage |
$ Type |
2009-10-26 16:50:12 -07:00
DEFINE_ \ S +
) $ |
^ ( ?:
2008-10-15 22:02:29 -07:00
goto |
return |
case |
else |
asm | _ _ asm__ |
2012-01-10 15:10:00 -08:00
do |
\# |
\#\# |
2009-10-26 16:50:12 -07:00
) ( ?:\ s | $ ) |
2008-10-15 22:02:29 -07:00
^ ( ?: typedef | struct | enum ) \ b
2009-10-26 16:50:12 -07:00
) } x ;
warn "CHECK<$possible> ($line)\n" if ( $ dbg_possible > 2 ) ;
if ( $ possible ! ~ $ notPermitted ) {
2008-06-05 22:46:01 -07:00
# Check for modifiers .
$ possible =~ s /\ s * $ Storage \ s *// g ;
$ possible =~ s /\ s * $ Sparse \ s *// g ;
if ( $ possible =~ /^\ s * $ / ) {
} elsif ( $ possible =~ /\ s / ) {
$ possible =~ s /\ s * $ Type \ s *// g ;
2008-07-23 21:29:09 -07:00
for my $ modifier ( split ( ' ' , $ possible ) ) {
2009-10-26 16:50:12 -07:00
if ( $ modifier ! ~ $ notPermitted ) {
warn "MODIFIER: $modifier ($possible) ($line)\n" if ( $ dbg_possible ) ;
2015-06-25 15:02:52 -07:00
push ( @ modifierListFile , $ modifier ) ;
2009-10-26 16:50:12 -07:00
}
2008-07-23 21:29:09 -07:00
}
2008-06-05 22:46:01 -07:00
} else {
warn "POSSIBLE: $possible ($line)\n" if ( $ dbg_possible ) ;
2015-06-25 15:02:52 -07:00
push ( @ typeListFile , $ possible ) ;
2008-06-05 22:46:01 -07:00
}
2007-11-28 16:21:06 -08:00
build_types ( ) ;
2008-10-15 22:02:29 -07:00
} else {
warn "NOTPOSS: $possible ($line)\n" if ( $ dbg_possible > 1 ) ;
2007-11-28 16:21:06 -08:00
}
}
2007-10-18 03:05:08 -07:00
my $ prefix = '' ;
2011-07-25 17:13:25 -07:00
sub show_type {
2014-04-03 14:49:19 -07:00
my ( $ type ) = @ _ ;
2013-09-11 14:23:59 -07:00
2017-02-27 14:30:05 -08:00
$ type =~ tr / [ a - z ] / [ A - Z ] / ;
2014-04-03 14:49:19 -07:00
return defined $ use_type { $ type } if ( scalar keys %use_type > 0);
return ! defined $ ignore_type { $ type } ;
2011-07-25 17:13:25 -07:00
}
2007-07-19 01:48:34 -07:00
sub report {
2014-04-03 14:49:19 -07:00
my ( $ level , $ type , $ msg ) = @ _ ;
if ( ! show_type ( $ type ) | |
( defined $ tst_only && $ msg ! ~ /\ Q $ tst_only \ E / ) ) {
2008-03-28 14:15:58 -07:00
return 0 ;
}
2015-06-25 15:03:03 -07:00
my $ output = '' ;
2017-07-10 15:52:24 -07:00
if ( $ color ) {
2015-06-25 15:03:03 -07:00
if ( $ level eq 'ERROR' ) {
$ output . = RED ;
} elsif ( $ level eq 'WARNING' ) {
$ output . = YELLOW ;
} else {
$ output . = GREEN ;
}
2011-07-25 17:13:25 -07:00
}
2015-06-25 15:03:03 -07:00
$ output . = $ prefix . $ level . ':' ;
if ( $ show_types ) {
2017-07-10 15:52:24 -07:00
$ output . = BLUE if ( $ color ) ;
2015-06-25 15:03:03 -07:00
$ output . = "$type:" ;
}
2017-07-10 15:52:24 -07:00
$ output . = RESET if ( $ color ) ;
2015-06-25 15:03:03 -07:00
$ output . = ' ' . $ msg . "\n" ;
2015-06-25 15:03:05 -07:00
if ( $ showfile ) {
my @ lines = split ( "\n" , $ output , - 1 ) ;
splice ( @ lines , 1 , 1 ) ;
$ output = join ( "\n" , @ lines ) ;
}
2015-06-25 15:03:03 -07:00
$ output = ( split ( '\n' , $ output ) ) [ 0 ] . "\n" if ( $ terse ) ;
2007-11-28 16:21:06 -08:00
2015-06-25 15:03:03 -07:00
push ( our @ report , $ output ) ;
2008-03-28 14:15:58 -07:00
return 1 ;
2007-07-19 01:48:34 -07:00
}
2014-04-03 14:49:19 -07:00
2007-07-19 01:48:34 -07:00
sub report_dump {
2008-02-08 04:22:03 -08:00
our @ report ;
2007-07-19 01:48:34 -07:00
}
2011-07-25 17:13:25 -07:00
2014-08-06 16:11:05 -07:00
sub fixup_current_range {
my ( $ lineRef , $ offset , $ length ) = @ _ ;
if ( $ $ lineRef =~ /^\@\@ -\ d + , \ d + \+ ( \ d + ) , ( \ d + ) \@\@/ ) {
my $ o = $ 1 ;
my $ l = $ 2 ;
my $ no = $ o + $ offset ;
my $ nl = $ l + $ length ;
$ $ lineRef =~ s /\+ $ o , $ l \@\@/\+ $ no , $ nl \@\@/ ;
}
}
sub fix_inserted_deleted_lines {
my ( $ linesRef , $ insertedRef , $ deletedRef ) = @ _ ;
my $ range_last_linenr = 0 ;
my $ delta_offset = 0 ;
my $ old_linenr = 0 ;
my $ new_linenr = 0 ;
my $ next_insert = 0 ;
my $ next_delete = 0 ;
my @ lines = ( ) ;
my $ inserted = @ { $ insertedRef } [ $ next_insert ++ ] ;
my $ deleted = @ { $ deletedRef } [ $ next_delete ++ ] ;
foreach my $ old_line ( @ { $ linesRef } ) {
my $ save_line = 1 ;
my $ line = $ old_line ; # don 't modify the array
2015-04-16 12:44:50 -07:00
if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) { #new filename
2014-08-06 16:11:05 -07:00
$delta_offset = 0;
} elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) { #new hunk
$range_last_linenr = $new_linenr;
fixup_current_range(\$line, $delta_offset, 0);
}
while (defined($deleted) && ${$deleted}{' LINENR '} == $old_linenr) {
$deleted = @{$deletedRef}[$next_delete++];
$save_line = 0;
fixup_current_range(\$lines[$range_last_linenr], $delta_offset--, -1);
}
while (defined($inserted) && ${$inserted}{' LINENR '} == $old_linenr) {
push(@lines, ${$inserted}{' LINE '});
$inserted = @{$insertedRef}[$next_insert++];
$new_linenr++;
fixup_current_range(\$lines[$range_last_linenr], $delta_offset++, 1);
}
if ($save_line) {
push(@lines, $line);
$new_linenr++;
}
$old_linenr++;
}
return @lines;
}
2014-08-06 16:11:07 -07:00
sub fix_insert_line {
my ($linenr, $line) = @_;
my $inserted = {
LINENR => $linenr,
LINE => $line,
};
push(@fixed_inserted, $inserted);
}
sub fix_delete_line {
my ($linenr, $line) = @_;
my $deleted = {
LINENR => $linenr,
LINE => $line,
};
push(@fixed_deleted, $deleted);
}
2007-07-15 23:37:22 -07:00
sub ERROR {
2014-04-03 14:49:19 -07:00
my ($type, $msg) = @_;
if (report("ERROR", $type, $msg)) {
2008-03-28 14:15:58 -07:00
our $clean = 0;
our $cnt_error++;
2013-07-03 15:05:31 -07:00
return 1;
2008-03-28 14:15:58 -07:00
}
2013-07-03 15:05:31 -07:00
return 0;
2007-07-15 23:37:22 -07:00
}
sub WARN {
2014-04-03 14:49:19 -07:00
my ($type, $msg) = @_;
if (report("WARNING", $type, $msg)) {
2008-03-28 14:15:58 -07:00
our $clean = 0;
our $cnt_warn++;
2013-07-03 15:05:31 -07:00
return 1;
2008-03-28 14:15:58 -07:00
}
2013-07-03 15:05:31 -07:00
return 0;
2007-07-15 23:37:22 -07:00
}
sub CHK {
2014-04-03 14:49:19 -07:00
my ($type, $msg) = @_;
if ($check && report("CHECK", $type, $msg)) {
2007-10-18 03:05:08 -07:00
our $clean = 0;
our $cnt_chk++;
2013-07-03 15:05:31 -07:00
return 1;
2007-10-18 03:05:08 -07:00
}
2013-07-03 15:05:31 -07:00
return 0;
2007-07-15 23:37:22 -07:00
}
2008-10-15 22:02:21 -07:00
sub check_absolute_file {
my ($absolute, $herecurr) = @_;
my $file = $absolute;
##print "absolute<$absolute>\n";
# See if any suffix of this path is a path within the tree.
while ($file =~ s@^[^/]*/@@) {
if (-f "$root/$file") {
##print "file<$file>\n";
last;
}
}
if (! -f _) {
return 0;
}
# It is, so see if the prefix is acceptable.
my $prefix = $absolute;
substr($prefix, -length($file)) = '';
##print "prefix<$prefix>\n";
if ($prefix ne ".../") {
2011-07-25 17:13:25 -07:00
WARN("USE_RELATIVE_PATH",
"use relative pathname instead of absolute in changelog text\n" . $herecurr);
2008-10-15 22:02:21 -07:00
}
}
2013-07-03 15:05:31 -07:00
sub trim {
my ($string) = @_;
2013-09-11 14:24:01 -07:00
$string =~ s/^\s+|\s+$//g;
return $string;
}
sub ltrim {
my ($string) = @_;
$string =~ s/^\s+//;
return $string;
}
sub rtrim {
my ($string) = @_;
$string =~ s/\s+$//;
2013-07-03 15:05:31 -07:00
return $string;
}
2013-11-12 15:10:09 -08:00
sub string_find_replace {
my ($string, $find, $replace) = @_;
$string =~ s/$find/$replace/g;
return $string;
}
2013-07-03 15:05:31 -07:00
sub tabify {
my ($leading) = @_;
2020-04-06 20:11:07 -07:00
my $source_indent = $tabsize;
2013-07-03 15:05:31 -07:00
my $max_spaces_before_tab = $source_indent - 1;
my $spaces_to_tab = " " x $source_indent;
#convert leading spaces to tabs
1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g;
#Remove spaces before a tab
1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g;
return "$leading";
}
2012-03-23 15:02:16 -07:00
sub pos_last_openparen {
my ($line) = @_;
my $pos = 0;
my $opens = $line =~ tr/\(/\(/;
my $closes = $line =~ tr/\)/\)/;
my $last_openparen = 0;
if (($opens == 0) || ($closes >= $opens)) {
return -1;
}
my $len = length($line);
for ($pos = 0; $pos < $len; $pos++) {
my $string = substr($line, $pos);
if ($string =~ /^($FuncArg|$balanced_parens)/) {
$pos += length($1) - 1;
} elsif (substr($line, $pos, 1) eq ' ( ') {
$last_openparen = $pos;
} elsif (index($string, ' ( ') == -1) {
last;
}
}
2014-04-03 14:49:32 -07:00
return length(expand_tabs(substr($line, 0, $last_openparen))) + 1;
2012-03-23 15:02:16 -07:00
}
2020-04-06 20:10:58 -07:00
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;
}
2007-06-01 00:46:48 -07:00
sub process {
my $filename = shift;
my $linenr=0;
my $prevline="";
2008-02-08 04:20:54 -08:00
my $prevrawline="";
2007-06-01 00:46:48 -07:00
my $stashline="";
2008-02-08 04:20:54 -08:00
my $stashrawline="";
2007-06-01 00:46:48 -07:00
2007-06-08 13:46:39 -07:00
my $length;
2007-06-01 00:46:48 -07:00
my $indent;
my $previndent=0;
my $stashindent=0;
2007-07-15 23:37:22 -07:00
our $clean = 1;
2007-06-01 00:46:48 -07:00
my $signoff = 0;
2018-08-21 21:57:40 -07:00
my $author = '';
my $authorsignoff = 0;
2020-10-15 20:12:28 -07:00
my $author_sob = '';
2007-06-01 00:46:48 -07:00
my $is_patch = 0;
2018-08-21 21:58:16 -07:00
my $is_binding_patch = -1;
2014-08-06 16:10:35 -07:00
my $in_header_lines = $file ? 0 : 1;
2011-10-31 17:13:12 -07:00
my $in_commit_log = 0; #Scanning lines before patch
2020-04-06 20:11:10 -07:00
my $has_patch_separator = 0; #Found a --- line
2016-08-02 14:04:45 -07:00
my $has_commit_log = 0; #Encountered lines before patch
2018-08-21 21:58:01 -07:00
my $commit_log_lines = 0; #Number of commit log lines
2017-02-24 15:01:28 -08:00
my $commit_log_possible_stack_dump = 0;
2015-04-16 12:44:28 -07:00
my $commit_log_long_line = 0;
2015-06-25 15:03:27 -07:00
my $commit_log_has_diff = 0;
2014-08-06 16:10:59 -07:00
my $reported_maintainer_file = 0;
2012-10-04 17:13:29 -07:00
my $non_utf8_charset = 0;
2014-08-06 16:10:42 -07:00
my $last_blank_line = 0;
2014-12-10 15:52:05 -08:00
my $last_coalesced_string_linenr = -1;
2014-08-06 16:10:42 -07:00
2008-02-08 04:22:03 -08:00
our @report = ();
2007-10-18 03:05:08 -07:00
our $cnt_lines = 0;
our $cnt_error = 0;
our $cnt_warn = 0;
our $cnt_chk = 0;
2007-06-01 00:46:48 -07:00
# Trace the real file/line as we go.
my $realfile = '';
my $realline = 0;
my $realcnt = 0;
my $here = '';
2017-02-24 15:01:28 -08:00
my $context_function; #undef' d unless there 's a known function
2007-06-01 00:46:48 -07:00
my $in_comment = 0;
2008-02-08 04:20:54 -08:00
my $comment_edge = 0;
2007-06-01 00:46:48 -07:00
my $first_line = 0;
2009-01-06 14:41:24 -08:00
my $p1_prefix = '';
2007-06-01 00:46:48 -07:00
2008-02-08 04:22:03 -08:00
my $prev_values = ' E ';
# suppression flags
2008-03-28 14:15:58 -07:00
my %suppress_ifbraces;
2008-10-15 22:02:30 -07:00
my %suppress_whiletrailers;
2009-10-26 16:50:16 -07:00
my %suppress_export;
2012-01-10 15:10:01 -08:00
my $suppress_statement = 0;
2007-06-23 17:16:34 -07:00
2013-09-11 14:23:57 -07:00
my %signatures = ();
2012-12-17 16:02:07 -08:00
2008-02-08 04:20:54 -08:00
# Pre-scan the patch sanitizing the lines.
2007-07-15 23:37:22 -07:00
# Pre-scan the patch looking for any __setup documentation.
2008-02-08 04:20:54 -08:00
#
2007-07-15 23:37:22 -07:00
my @setup_docs = ();
my $setup_docs = 0;
2008-03-28 14:15:58 -07:00
2013-11-12 15:10:06 -08:00
my $camelcase_file_seeded = 0;
2018-04-10 16:33:13 -07:00
my $checklicenseline = 1;
2008-03-28 14:15:58 -07:00
sanitise_line_reset();
2008-02-08 04:20:54 -08:00
my $line;
foreach my $rawline (@rawlines) {
2008-03-28 14:15:58 -07:00
$linenr++;
$line = $rawline;
2008-02-08 04:20:54 -08:00
2013-07-03 15:05:31 -07:00
push(@fixed, $rawline) if ($fix);
2008-03-28 14:15:58 -07:00
if ($rawline=~/^\+\+\+\s+(\S+)/) {
2007-07-15 23:37:22 -07:00
$setup_docs = 0;
2020-06-10 18:41:38 -07:00
if ($1 =~ m@Documentation/admin-guide/kernel-parameters.txt$@) {
2007-07-15 23:37:22 -07:00
$setup_docs = 1;
}
2008-03-28 14:15:58 -07:00
#next;
2007-07-15 23:37:22 -07:00
}
2017-05-08 15:56:02 -07:00
if ($rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
2008-03-28 14:15:58 -07:00
$realline=$1-1;
if (defined $2) {
$realcnt=$3+1;
} else {
$realcnt=1+1;
}
2008-06-05 22:46:01 -07:00
$in_comment = 0;
2008-03-28 14:15:58 -07:00
# Guestimate if this is a continuing comment. Run
# the context looking for a comment "edge". If this
# edge is a close comment then we must be in a comment
# at context start.
my $edge;
2008-10-15 22:02:19 -07:00
my $cnt = $realcnt;
for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
next if (defined $rawlines[$ln - 1] &&
$rawlines[$ln - 1] =~ /^-/);
$cnt--;
#print "RAW<$rawlines[$ln - 1]>\n";
2009-01-06 14:41:16 -08:00
last if (!defined $rawlines[$ln - 1]);
2009-01-06 14:41:20 -08:00
if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
$rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
($edge) = $1;
last;
}
2008-03-28 14:15:58 -07:00
}
if (defined $edge && $edge eq ' */ ') {
$in_comment = 1;
}
# Guestimate if this is a continuing comment. If this
# is the start of a diff block and this line starts
# ' * ' then it is very likely a comment.
if (!defined $edge &&
2009-01-06 14:41:17 -08:00
$rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
2008-03-28 14:15:58 -07:00
{
$in_comment = 1;
}
##print "COMMENT:$in_comment edge<$edge> $rawline\n";
sanitise_line_reset($in_comment);
2008-04-29 00:59:32 -07:00
} elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
2008-03-28 14:15:58 -07:00
# Standardise the strings and chars within the input to
2008-04-29 00:59:32 -07:00
# simplify matching -- only bother with positive lines.
2008-03-28 14:15:58 -07:00
$line = sanitise_line($rawline);
}
push(@lines, $line);
if ($realcnt > 1) {
$realcnt-- if ($line =~ /^(?:\+| |$)/);
} else {
$realcnt = 0;
}
#print "==>$rawline\n";
#print "-->$line\n";
2007-07-15 23:37:22 -07:00
if ($setup_docs && $line =~ /^\+/) {
push(@setup_docs, $line);
}
}
2007-10-18 03:05:08 -07:00
$prefix = '';
2008-03-28 14:15:58 -07:00
$realcnt = 0;
$linenr = 0;
2014-08-06 16:11:03 -07:00
$fixlinenr = -1;
2007-06-01 00:46:48 -07:00
foreach my $line (@lines) {
$linenr++;
2014-08-06 16:11:03 -07:00
$fixlinenr++;
2013-09-11 14:24:03 -07:00
my $sline = $line; #copy of $line
$sline =~ s/$;/ /g; #with comments as spaces
2007-06-01 00:46:48 -07:00
2008-02-08 04:20:54 -08:00
my $rawline = $rawlines[$linenr - 1];
2020-04-06 20:10:58 -07:00
my $raw_comment = get_raw_comment($line, $rawline);
2007-10-18 03:05:08 -07:00
2018-06-07 17:10:58 -07:00
# check if it' s a mode change , rename or start of a patch
if ( ! $ in_commit_log &&
( $ line =~ /^ mode change [ 0 - 7 ] + => [ 0 - 7 ] + \ S +\ s * $ / | |
( $ line =~ /^ rename ( ?: from | to ) \ S +\ s * $ / | |
$ line =~ /^ diff -- git a \/ [ \ w \/\.\ _ \- ] + b \/\ S +\ s * $ / ) ) ) {
$ is_patch = 1 ;
}
2007-06-01 00:46:48 -07:00
# extract the line range in the file after the patch is applied
2015-06-25 15:03:27 -07:00
if ( ! $ in_commit_log &&
2017-05-08 15:56:02 -07:00
$ line =~ /^\@\@ -\ d + ( ?: , \ d + ) ? \+ ( \ d + ) ( , ( \ d + ) ) ? \@\@ ( . * ) / ) {
my $ context = $ 4 ;
2007-06-01 00:46:48 -07:00
$ is_patch = 1 ;
2007-06-08 13:46:39 -07:00
$ first_line = $ linenr + 1 ;
2007-06-01 00:46:48 -07:00
$ realline = $ 1 - 1 ;
if ( defined $ 2 ) {
$ realcnt = $ 3 + 1 ;
} else {
$ realcnt = 1 + 1 ;
}
2008-02-08 04:20:54 -08:00
annotate_reset ( ) ;
2008-02-08 04:22:03 -08:00
$ prev_values = 'E' ;
2008-03-28 14:15:58 -07:00
%suppress_ifbraces = ();
2008-10-15 22:02:30 -07:00
%suppress_whiletrailers = ();
2009-10-26 16:50:16 -07:00
%suppress_export = ();
2012-01-10 15:10:01 -08:00
$ suppress_statement = 0 ;
2017-05-08 15:56:02 -07:00
if ( $ context =~ /\ b ( \ w + ) \ s *\ ( / ) {
$ context_function = $ 1 ;
} else {
undef $ context_function ;
}
2007-06-01 00:46:48 -07:00
next ;
2007-06-08 13:46:39 -07:00
# track the line number as we move through the hunk , note that
# new versions of GNU diff omit the leading space on completely
# blank context lines so we need to count that too .
2008-03-28 14:15:58 -07:00
} elsif ( $ line =~ /^ ( | \+ | $ ) / ) {
2007-06-01 00:46:48 -07:00
$ realline ++ ;
2007-06-23 17:16:44 -07:00
$ realcnt -- if ( $ realcnt ! = 0 ) ;
2007-06-01 00:46:48 -07:00
2007-06-08 13:46:39 -07:00
# Measure the line length and indent .
2008-02-08 04:20:54 -08:00
( $ length , $ indent ) = line_stats ( $ rawline ) ;
2007-06-01 00:46:48 -07:00
# Track the previous line .
( $ prevline , $ stashline ) = ( $ stashline , $ line ) ;
( $ previndent , $ stashindent ) = ( $ stashindent , $ indent ) ;
2008-02-08 04:20:54 -08:00
( $ prevrawline , $ stashrawline ) = ( $ stashrawline , $ rawline ) ;
2008-03-28 14:15:58 -07:00
# warn "line<$line>\n" ;
2007-10-18 03:05:08 -07:00
2007-06-23 17:16:44 -07:00
} elsif ( $ realcnt == 1 ) {
$ realcnt -- ;
2007-06-01 00:46:48 -07:00
}
2009-10-26 16:50:13 -07:00
my $ hunk_line = ( $ realcnt ! = 0 ) ;
2007-10-18 03:05:08 -07:00
$ here = "#$linenr: " if ( ! $ file ) ;
$ here = "#$realline: " if ( $ file ) ;
2008-03-28 14:15:58 -07:00
2014-06-04 16:12:05 -07:00
my $ found_file = 0 ;
2008-03-28 14:15:58 -07:00
# extract the filename as it passes
2010-10-26 14:23:16 -07:00
if ( $ line =~ /^ diff -- git . *? ( \ S + ) $ / ) {
$ realfile = $ 1 ;
2013-11-12 15:10:14 -08:00
$ realfile =~ s @^ ( [ ^/ ] * ) /@@ if ( ! $ file ) ;
2012-01-10 15:09:50 -08:00
$ in_commit_log = 0 ;
2014-06-04 16:12:05 -07:00
$ found_file = 1 ;
2010-10-26 14:23:16 -07:00
} elsif ( $ line =~ /^\+\+\+\ s + ( \ S + ) / ) {
2008-03-28 14:15:58 -07:00
$ realfile = $ 1 ;
2013-11-12 15:10:14 -08:00
$ realfile =~ s @^ ( [ ^/ ] * ) /@@ if ( ! $ file ) ;
2012-01-10 15:09:50 -08:00
$ in_commit_log = 0 ;
2009-01-06 14:41:24 -08:00
$ p1_prefix = $ 1 ;
2009-02-27 14:03:06 -08:00
if ( ! $ file && $ tree && $ p1_prefix ne '' &&
- e "$root/$p1_prefix" ) {
2011-07-25 17:13:25 -07:00
WARN ( "PATCH_PREFIX" ,
"patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n" ) ;
2009-01-06 14:41:24 -08:00
}
2008-03-28 14:15:58 -07:00
2008-10-15 22:02:20 -07:00
if ( $ realfile =~ m @^ include / asm /@ ) {
2011-07-25 17:13:25 -07:00
ERROR ( "MODIFIED_INCLUDE_ASM" ,
"do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n" ) ;
2008-03-28 14:15:58 -07:00
}
2014-06-04 16:12:05 -07:00
$ found_file = 1 ;
}
2015-06-25 15:03:05 -07:00
# make up the handle for any error we report on this line
if ( $ showfile ) {
$ prefix = "$realfile:$realline: "
} elsif ( $ emacs ) {
2015-09-09 15:37:39 -07:00
if ( $ file ) {
$ prefix = "$filename:$realline: " ;
} else {
$ prefix = "$filename:$linenr: " ;
}
2015-06-25 15:03:05 -07:00
}
2014-06-04 16:12:05 -07:00
if ( $ found_file ) {
2016-10-11 13:51:44 -07:00
if ( is_maintained_obsolete ( $ realfile ) ) {
WARN ( "OBSOLETE" ,
"$realfile is marked as 'obsolete' in the MAINTAINERS hierarchy. No unnecessary modifications please.\n" ) ;
}
2015-09-09 15:37:44 -07:00
if ( $ realfile =~ m @^ ( ?: drivers / net / | net / | drivers / staging / ) @ ) {
2014-06-04 16:12:05 -07:00
$ check = 1 ;
} else {
$ check = $ check_orig ;
}
2018-04-10 16:33:13 -07:00
$ checklicenseline = 1 ;
2018-08-21 21:58:16 -07:00
if ( $ realfile ! ~ /^ MAINTAINERS / ) {
my $ last_binding_patch = $ is_binding_patch ;
$ is_binding_patch = ( ) = $ realfile =~ m @^ ( ?: Documentation / devicetree / | include / dt - bindings / ) @ ;
if ( ( $ last_binding_patch ! = - 1 ) &&
( $ last_binding_patch ^ $ is_binding_patch ) ) {
WARN ( "DT_SPLIT_BINDING_PATCH" ,
2020-04-15 16:45:25 +02:00
"DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.rst\n" ) ;
2018-08-21 21:58:16 -07:00
}
}
2008-03-28 14:15:58 -07:00
next ;
}
2007-06-08 13:47:03 -07:00
$ here . = "FILE: $realfile:$realline:" if ( $ realcnt ! = 0 ) ;
2007-06-01 00:46:48 -07:00
2008-02-08 04:20:54 -08:00
my $ hereline = "$here\n$rawline\n" ;
my $ herecurr = "$here\n$rawline\n" ;
my $ hereprev = "$here\n$prevrawline\n$rawline\n" ;
2007-06-01 00:46:48 -07:00
2007-10-18 03:05:08 -07:00
$ cnt_lines ++ if ( $ realcnt ! = 0 ) ;
2018-08-21 21:58:01 -07:00
# Verify the existence of a commit log if appropriate
# 2 is used because a $ signature is counted in $ commit_log_lines
if ( $ in_commit_log ) {
if ( $ line ! ~ /^\ s * $ / ) {
$ commit_log_lines ++ ; # could be a $ signature
}
} elsif ( $ has_commit_log && $ commit_log_lines < 2 ) {
WARN ( "COMMIT_MESSAGE" ,
"Missing commit description - Add an appropriate one\n" ) ;
$ commit_log_lines = 2 ; # warn only once
}
2015-06-25 15:03:27 -07:00
# Check if the commit log has what seems like a diff which can confuse patch
if ( $ in_commit_log && ! $ commit_log_has_diff &&
2020-09-04 16:35:52 -07:00
( ( $ line =~ m @^\ s + diff \ b . * a / ( [ \ w / ] + ) @ &&
$ line =~ m @^\ s + diff \ b . * a / [ \ w / ] +\ s + b / $ 1 \ b @ ) | |
2015-06-25 15:03:27 -07:00
$ line =~ m @^\ s * ( ?:\-\-\-\ s + a / | \+\+\+\ s + b / ) @ | |
$ line =~ m /^\ s *\@\@ \-\ d + , \ d + \+\ d + , \ d + \@\@/ ) ) {
ERROR ( "DIFF_IN_COMMIT_MSG" ,
"Avoid using diff content in the commit message - patch(1) might not work\n" . $ herecurr ) ;
$ commit_log_has_diff = 1 ;
}
2010-10-26 14:23:16 -07:00
# Check for incorrect file permissions
if ( $ line =~ /^ new ( file ) ? mode . * [ 7531 ] \ d { 0 , 2 } $ / ) {
my $ permhere = $ here . "FILE: $realfile\n" ;
2013-04-29 16:18:14 -07:00
if ( $ realfile ! ~ m @ scripts /@ &&
$ realfile ! ~ /\. ( py | pl | awk | sh ) $ / ) {
2011-07-25 17:13:25 -07:00
ERROR ( "EXECUTE_PERMISSIONS" ,
"do not set execute permissions for source files\n" . $ permhere ) ;
2010-10-26 14:23:16 -07:00
}
}
2018-08-21 21:57:40 -07:00
# Check the patch for a From :
if ( decode ( "MIME-Header" , $ line ) =~ /^ From :\ s * ( . * ) / ) {
$ author = $ 1 ;
2020-10-15 20:12:15 -07:00
my $ curline = $ linenr ;
while ( defined ( $ rawlines [ $ curline ] ) && ( $ rawlines [ $ curline ++ ] =~ /^ [ \ t ] \ s * ( . * ) / ) ) {
$ author . = $ 1 ;
}
2018-08-21 21:57:40 -07:00
$ author = encode ( "utf8" , $ author ) if ( $ line =~ /=\? utf - 8 \?/ i ) ;
$ author =~ s / " // g ;
2020-04-06 20:10:48 -07:00
$ author = reformat_email ( $ author ) ;
2018-08-21 21:57:40 -07:00
}
2011-07-25 17:13:23 -07:00
# Check the patch for a signoff :
2020-04-06 20:10:48 -07:00
if ( $ line =~ /^\ s * signed - off - by : \ s * ( . * ) / i ) {
2007-06-08 13:46:39 -07:00
$ signoff ++ ;
2011-10-31 17:13:12 -07:00
$ in_commit_log = 0 ;
2020-10-15 20:12:28 -07:00
if ( $ author ne '' && $ authorsignoff ! = 1 ) {
2020-12-15 20:44:53 -08:00
if ( same_email_addresses ( $ 1 , $ author ) ) {
2020-04-06 20:10:48 -07:00
$ authorsignoff = 1 ;
2020-10-15 20:12:28 -07:00
} else {
my $ ctx = $ 1 ;
my ( $ email_name , $ email_comment , $ email_address , $ comment1 ) = parse_email ( $ ctx ) ;
my ( $ author_name , $ author_comment , $ author_address , $ comment2 ) = parse_email ( $ author ) ;
if ( $ email_address eq $ author_address && $ email_name eq $ author_name ) {
$ author_sob = $ ctx ;
$ authorsignoff = 2 ;
} elsif ( $ email_address eq $ author_address ) {
$ author_sob = $ ctx ;
$ authorsignoff = 3 ;
} elsif ( $ email_name eq $ author_name ) {
$ author_sob = $ ctx ;
$ authorsignoff = 4 ;
my $ address1 = $ email_address ;
my $ address2 = $ author_address ;
if ( $ address1 =~ / ( \ S + ) \+\ S + ( \@.* ) / ) {
$ address1 = "$1$2" ;
}
if ( $ address2 =~ / ( \ S + ) \+\ S + ( \@.* ) / ) {
$ address2 = "$1$2" ;
}
if ( $ address1 eq $ address2 ) {
$ authorsignoff = 5 ;
}
}
2018-08-21 21:57:40 -07:00
}
}
2011-07-25 17:13:23 -07:00
}
2020-04-06 20:11:10 -07:00
# Check for patch separator
if ( $ line =~ /^--- $ / ) {
$ has_patch_separator = 1 ;
$ in_commit_log = 0 ;
}
2014-12-10 15:51:49 -08:00
# 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*\|/) {
$reported_maintainer_file = 1;
}
2011-07-25 17:13:23 -07:00
# Check signature styles
2012-01-10 15:09:50 -08:00
if (!$in_header_lines &&
2012-07-30 14:41:18 -07:00
$line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) {
2011-07-25 17:13:23 -07:00
my $space_before = $1;
my $sign_off = $2;
my $space_after = $3;
my $email = $4;
my $ucfirst_sign_off = ucfirst(lc($sign_off));
2012-07-30 14:41:18 -07:00
if ($sign_off !~ /$signature_tags/) {
2020-12-15 20:45:12 -08:00
my $suggested_signature = find_standard_signature($sign_off);
if ($suggested_signature eq "") {
WARN("BAD_SIGN_OFF",
"Non-standard signature: $sign_off\n" . $herecurr);
} else {
if (WARN("BAD_SIGN_OFF",
"Non-standard signature: ' $ sign_off ' - perhaps ' $ suggested_signature '?\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/$sign_off/$suggested_signature/;
}
}
2012-07-30 14:41:18 -07:00
}
2011-07-25 17:13:23 -07:00
if (defined $space_before && $space_before ne "") {
2013-07-03 15:05:31 -07:00
if (WARN("BAD_SIGN_OFF",
"Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =
2013-07-03 15:05:31 -07:00
"$ucfirst_sign_off $email";
}
2007-06-01 00:46:48 -07:00
}
2011-07-25 17:13:23 -07:00
if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) {
2013-07-03 15:05:31 -07:00
if (WARN("BAD_SIGN_OFF",
"' $ ucfirst_sign_off ' is the preferred signature form\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =
2013-07-03 15:05:31 -07:00
"$ucfirst_sign_off $email";
}
2011-07-25 17:13:23 -07:00
}
if (!defined $space_after || $space_after ne " ") {
2013-07-03 15:05:31 -07:00
if (WARN("BAD_SIGN_OFF",
"Use a single space after $ucfirst_sign_off\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =
2013-07-03 15:05:31 -07:00
"$ucfirst_sign_off $email";
}
2011-07-25 17:13:23 -07:00
}
2020-04-06 20:10:48 -07:00
my ($email_name, $name_comment, $email_address, $comment) = parse_email($email);
2020-10-15 20:12:28 -07:00
my $suggested_email = format_email(($email_name, $name_comment, $email_address, $comment));
2011-07-25 17:13:23 -07:00
if ($suggested_email eq "") {
2011-07-25 17:13:25 -07:00
ERROR("BAD_SIGN_OFF",
"Unrecognized email address: ' $ email '\n" . $herecurr);
2011-07-25 17:13:23 -07:00
} else {
my $dequoted = $suggested_email;
$dequoted =~ s/^"//;
$dequoted =~ s/" </ </;
# Don' t force email to have quotes
# Allow just an angle bracketed address
2020-12-15 20:44:53 -08:00
if ( ! same_email_addresses ( $ email , $ suggested_email ) ) {
if ( WARN ( "BAD_SIGN_OFF" ,
"email address '$email' might be better as '$suggested_email'\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ fixlinenr ] =~ s /\ Q $ email \ E / $ suggested_email / ;
}
}
# Address part shouldn 't have comments
my $stripped_address = $email_address;
$stripped_address =~ s/\([^\(\)]*\)//g;
if ($email_address ne $stripped_address) {
if (WARN("BAD_SIGN_OFF",
"address part of email should not have comments: ' $ email_address '\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\Q$email_address\E/$stripped_address/;
}
}
# Only one name comment should be allowed
my $comment_count = () = $name_comment =~ /\([^\)]+\)/g;
if ($comment_count > 1) {
2011-07-25 17:13:25 -07:00
WARN("BAD_SIGN_OFF",
2020-12-15 20:44:53 -08:00
"Use a single name comment in email: ' $ email '\n" . $herecurr);
}
# stable@vger.kernel.org or stable@kernel.org shouldn' t
2020-12-15 20:44:56 -08:00
# have an email name . In addition comments should strictly
2020-12-15 20:44:53 -08:00
# begin with a #
if ( $ email =~ /^.* stable \@ ( ?: vger \. ) ? kernel \. org / i ) {
if ( ( $ comment ne "" && $ comment ! ~ /^#.+/ ) | |
( $ email_name ne "" ) ) {
my $ cur_name = $ email_name ;
my $ new_comment = $ comment ;
$ cur_name =~ s / [ a - zA - Z \ s \-\ " ] +// g ;
# Remove brackets enclosing comment text
# and # from start of comments to get comment text
$ new_comment =~ s /^\ ( ( . * ) \ ) $ / $ 1 / ;
$ new_comment =~ s /^\ [ ( . * ) \ ] $ / $ 1 / ;
$ new_comment =~ s /^ [ \ s \# ] + | \ s + $ // g ;
$ new_comment = trim ( "$new_comment $cur_name" ) if ( $ cur_name ne $ new_comment ) ;
$ new_comment = " # $new_comment" if ( $ new_comment ne "" ) ;
my $ new_email = "$email_address$new_comment" ;
if ( WARN ( "BAD_STABLE_ADDRESS_STYLE" ,
"Invalid email format for stable: '$email', prefer '$new_email'\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ fixlinenr ] =~ s /\ Q $ email \ E / $ new_email / ;
}
}
} elsif ( $ comment ne "" && $ comment ! ~ /^ ( ?:#.+ | \ ( . +\ ) ) $ / ) {
my $ new_comment = $ comment ;
# Extract comment text from within brackets or
# c89 style /* ... */ comments
$ new_comment =~ s /^\ [ ( . * ) \ ] $ / $ 1 / ;
$ new_comment =~ s /^\/\* ( . * ) \*\/ $ / $ 1 / ;
$ new_comment = trim ( $ new_comment ) ;
$ new_comment =~ s /^ [ ^\ w ] $ // ; # Single lettered comment with non word character is usually a typo
$ new_comment = "($new_comment)" if ( $ new_comment ne "" ) ;
my $ new_email = format_email ( $ email_name , $ name_comment , $ email_address , $ new_comment ) ;
if ( WARN ( "BAD_SIGN_OFF" ,
"Unexpected content after email: '$email', should be: '$new_email'\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ fixlinenr ] =~ s /\ Q $ email \ E / $ new_email / ;
}
2011-07-25 17:13:23 -07:00
}
2007-06-01 00:46:48 -07:00
}
2013-09-11 14:23:57 -07:00
# Check for duplicate signatures
my $ sig_nospace = $ line ;
$ sig_nospace =~ s /\ s // g ;
$ sig_nospace = lc ( $ sig_nospace ) ;
if ( defined $ signatures { $ sig_nospace } ) {
WARN ( "BAD_SIGN_OFF" ,
"Duplicate signature\n" . $ herecurr ) ;
} else {
$ signatures { $ sig_nospace } = 1 ;
}
2019-03-22 14:11:37 -07:00
# Check Co - developed - by : immediately followed by Signed - off - by : with same name and email
if ( $ sign_off =~ /^ co - developed - by : $ / i ) {
if ( $ email eq $ author ) {
WARN ( "BAD_SIGN_OFF" ,
"Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $ rawline ) ;
}
if ( ! defined $ lines [ $ linenr ] ) {
WARN ( "BAD_SIGN_OFF" ,
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $ rawline ) ;
} elsif ( $ rawlines [ $ linenr ] ! ~ /^\ s * signed - off - by : \ s * ( . * ) / i ) {
WARN ( "BAD_SIGN_OFF" ,
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $ rawline . "\n" . $ rawlines [ $ linenr ] ) ;
} elsif ( $ 1 ne $ email ) {
WARN ( "BAD_SIGN_OFF" ,
"Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $ rawline . "\n" . $ rawlines [ $ linenr ] ) ;
}
}
2007-06-01 00:46:48 -07:00
}
2015-02-13 14:39:02 -08:00
# Check email subject for common tools that don 't need to be mentioned
if ($in_header_lines &&
$line =~ /^Subject:.*\b(?:checkpatch|sparse|smatch)\b[^:]/i) {
WARN("EMAIL_SUBJECT",
"A patch subject line should describe the change not the tool that found it\n" . $herecurr);
}
2020-04-06 20:11:10 -07:00
# Check for Gerrit Change-Ids not in any patch context
if ($realfile eq '' && !$has_patch_separator && $line =~ /^\s*change-id:/i) {
2020-12-15 20:44:47 -08:00
if (ERROR("GERRIT_CHANGE_ID",
"Remove Gerrit Change-Id' s before submitting upstream \ n " . $ herecurr ) &&
$ fix ) {
fix_delete_line ( $ fixlinenr , $ rawline ) ;
}
2014-04-03 14:49:31 -07:00
}
2015-11-06 16:31:34 -08:00
# Check if the commit log is in a possible stack dump
if ( $ in_commit_log && ! $ commit_log_possible_stack_dump &&
( $ line =~ /^\ s * ( ?: WARNING : | BUG : ) / | |
$ line =~ /^\ s *\ [ \ s *\ d +\.\ d { 6 , 6 } \ s *\ ] / | |
# timestamp
2019-09-25 16:46:32 -07:00
$ line =~ /^\ s *\ [ \< [ 0 - 9 a - fA - F ] { 8 , } \>\ ] / ) | |
$ line =~ /^ ( ?:\ s +\ w +:\ s + [ 0 - 9 a - fA - F ] + ) { 3 , 3 } / | |
$ line =~ /^\ s *\#\ d +\ s *\ [ [ 0 - 9 a - fA - F ] +\ ] \ s *\ w + at [ 0 - 9 a - fA - F ] +/ ) {
# stack dump address styles
2015-11-06 16:31:34 -08:00
$ commit_log_possible_stack_dump = 1 ;
}
2015-04-16 12:44:28 -07:00
# Check for line lengths > 75 in commit log , warn once
if ( $ in_commit_log && ! $ commit_log_long_line &&
2015-11-06 16:31:34 -08:00
length ( $ line ) > 75 &&
! ( $ line =~ /^\ s * [ a - zA - Z0 - 9 _ \/\. ] +\ s +\ | \ s +\ d +/ | |
# file delta changes
$ line =~ /^\ s * ( ?: [ \ w \.\- ] +\/ ) ++ [ \ w \.\- ] +:/ | |
# filename then :
2020-12-15 20:44:59 -08:00
$ line =~ /^\ s * ( ?: Fixes : | Link : | $ signature_tags ) / i | |
# A Fixes : or Link : line or signature tag line
2015-11-06 16:31:34 -08:00
$ commit_log_possible_stack_dump ) ) {
2015-04-16 12:44:28 -07:00
WARN ( "COMMIT_LOG_LONG_LINE" ,
"Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $ herecurr ) ;
$ commit_log_long_line = 1 ;
}
2015-09-09 15:37:50 -07:00
# Reset possible stack dump if a blank line is found
2015-11-06 16:31:34 -08:00
if ( $ in_commit_log && $ commit_log_possible_stack_dump &&
$ line =~ /^\ s * $ / ) {
$ commit_log_possible_stack_dump = 0 ;
}
2015-09-09 15:37:50 -07:00
2020-12-15 20:45:18 -08:00
# Check for lines starting with a #
if ( $ in_commit_log && $ line =~ /^#/ ) {
if ( WARN ( "COMMIT_COMMENT_SYMBOL" ,
"Commit log lines starting with '#' are dropped by git as comments\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ fixlinenr ] =~ s /^/ / ;
}
}
2015-02-13 14:38:35 -08:00
# Check for git id commit length and improperly formed commit descriptions
2015-11-06 16:31:34 -08:00
if ( $ in_commit_log && ! $ commit_log_possible_stack_dump &&
2020-04-06 20:10:55 -07:00
$ line ! ~ /^\ s * ( ?: Link | Patchwork | http | https | BugLink | base - commit ) :/ i &&
2017-05-08 15:55:54 -07:00
$ line ! ~ /^ This reverts commit [ 0 - 9 a - f ] { 7 , 40 } / &&
2015-09-09 15:37:25 -07:00
( $ line =~ /\ bcommit \ s + [ 0 - 9 a - f ] { 5 , } \ b / i | |
2016-08-02 14:04:36 -07:00
( $ line =~ / ( ?:\ s | ^ ) [ 0 - 9 a - f ] { 12 , 40 } ( ?: [ \ s " '\(\[]|$)/i &&
2015-11-06 16:31:34 -08:00
$line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i &&
$line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) {
2015-09-09 15:37:25 -07:00
my $init_char = "c";
my $orig_commit = "";
2015-02-13 14:38:35 -08:00
my $short = 1;
my $long = 0;
my $case = 1;
my $space = 1;
my $hasdesc = 0;
2015-02-13 14:39:00 -08:00
my $hasparens = 0;
2015-02-13 14:38:35 -08:00
my $id = ' 0123456789 ab ';
my $orig_desc = "commit description";
my $description = "";
2015-09-09 15:37:25 -07:00
if ($line =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) {
$init_char = $1;
$orig_commit = lc($2);
} elsif ($line =~ /\b([0-9a-f]{12,40})\b/i) {
$orig_commit = lc($1);
}
2015-02-13 14:38:35 -08:00
$short = 0 if ($line =~ /\bcommit\s+[0-9a-f]{12,40}/i);
$long = 1 if ($line =~ /\bcommit\s+[0-9a-f]{41,}/i);
$space = 0 if ($line =~ /\bcommit [0-9a-f]/i);
$case = 0 if ($line =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/);
if ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)"\)/i) {
$orig_desc = $1;
2015-02-13 14:39:00 -08:00
$hasparens = 1;
2015-02-13 14:38:35 -08:00
} elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s*$/i &&
defined $rawlines[$linenr] &&
$rawlines[$linenr] =~ /^\s*\("([^"]+)"\)/) {
$orig_desc = $1;
2015-02-13 14:39:00 -08:00
$hasparens = 1;
2015-02-13 14:38:41 -08:00
} elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("[^"]+$/i &&
defined $rawlines[$linenr] &&
$rawlines[$linenr] =~ /^\s*[^"]+"\)/) {
$line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)$/i;
$orig_desc = $1;
$rawlines[$linenr] =~ /^\s*([^"]+)"\)/;
$orig_desc .= " " . $1;
2015-02-13 14:39:00 -08:00
$hasparens = 1;
2015-02-13 14:38:35 -08:00
}
($id, $description) = git_commit_info($orig_commit,
$id, $orig_desc);
2017-07-10 15:52:16 -07:00
if (defined($id) &&
($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens)) {
2015-02-13 14:38:35 -08:00
ERROR("GIT_COMMIT_ID",
"Please use git commit description style ' commit < 12 + chars of sha1 > ( \ "<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $ herecurr ) ;
}
2014-08-06 16:10:57 -07:00
}
2014-08-06 16:10:59 -07:00
# Check for added , moved or deleted files
if ( ! $ reported_maintainer_file && ! $ in_commit_log &&
( $ line =~ /^ ( ?: new | deleted ) file mode \ s *\ d +\ s * $ / | |
$ line =~ /^ rename ( ?: from | to ) [ \ w \/\.\- ] +\ s * $ / | |
( $ line =~ /\ { \ s * ( [ \ w \/\.\- ] * ) \ s *\=\>\ s * ( [ \ w \/\.\- ] * ) \ s *\ } / &&
( defined ( $ 1 ) | | defined ( $ 2 ) ) ) ) ) {
2016-12-12 16:46:37 -08:00
$ is_patch = 1 ;
2014-08-06 16:10:59 -07:00
$ reported_maintainer_file = 1 ;
WARN ( "FILE_PATH_CHANGES" ,
"added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $ herecurr ) ;
}
2019-09-12 15:18:20 +01:00
# Check for adding new DT bindings not in schema format
if ( ! $ in_commit_log &&
( $ line =~ /^ new file mode \ s *\ d +\ s * $ / ) &&
( $ realfile =~ m @^ Documentation / devicetree / bindings /.*\. txt$ @ ) ) {
WARN ( "DT_SCHEMA_BINDING_PATCH" ,
"DT bindings should be in DT schema format. See: Documentation/devicetree/writing-schema.rst\n" ) ;
}
2007-06-08 13:47:06 -07:00
# Check for wrappage within a valid hunk of the file
2007-11-28 16:21:06 -08:00
if ( $ realcnt ! = 0 && $ line ! ~ m { ^ ( ?:\+ | - | | \\ No newline | $ ) } ) {
2011-07-25 17:13:25 -07:00
ERROR ( "CORRUPTED_PATCH" ,
"patch seems to be corrupt (line wrapped?)\n" .
2007-10-18 03:05:08 -07:00
$ herecurr ) if ( ! $ emitted_corrupt ++ ) ;
2007-07-15 23:37:22 -07:00
}
# UTF - 8 regex found at http : // www . w3 . org / International / questions / qa - forms - utf - 8. en . php
if ( ( $ realfile =~ /^ $ / | | $ line =~ /^\+/ ) &&
2008-04-29 00:59:32 -07:00
$ rawline ! ~ m /^ $ UTF8 * $ / ) {
my ( $ utf8_prefix ) = ( $ rawline =~ /^ ( $ UTF8 * ) / ) ;
my $ blank = copy_spacing ( $ rawline ) ;
my $ ptr = substr ( $ blank , 0 , length ( $ utf8_prefix ) ) . "^" ;
my $ hereptr = "$hereline$ptr\n" ;
2011-07-25 17:13:26 -07:00
CHK ( "INVALID_UTF8" ,
"Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $ hereptr ) ;
2007-06-08 13:47:06 -07:00
}
2007-06-01 00:46:48 -07:00
2011-10-31 17:13:12 -07:00
# Check if it 's the start of a commit log
# (not a header line and we haven' t seen the patch filename )
if ( $ in_header_lines && $ realfile =~ /^ $ / &&
2017-05-08 15:55:42 -07:00
! ( $ rawline =~ /^\ s + ( ?:\ S | $ ) / | |
$ rawline =~ /^ ( ?: commit \ b | from \ b | [ \ w - ] +: ) / i ) ) {
2011-10-31 17:13:12 -07:00
$ in_header_lines = 0 ;
$ in_commit_log = 1 ;
2016-08-02 14:04:45 -07:00
$ has_commit_log = 1 ;
2011-10-31 17:13:12 -07:00
}
2012-10-04 17:13:29 -07:00
# Check if there is UTF - 8 in a commit log when a mail header has explicitly
# declined it , i . e defined some charset where it is missing .
if ( $ in_header_lines &&
$ rawline =~ /^ Content - Type :.+ charset = "(.+)" . * $ / &&
$ 1 ! ~ / utf - 8 / i ) {
$ non_utf8_charset = 1 ;
}
if ( $ in_commit_log && $ non_utf8_charset && $ realfile =~ /^ $ / &&
2011-10-31 17:13:12 -07:00
$ rawline =~ / $ NON_ASCII_UTF8 / ) {
2012-10-04 17:13:29 -07:00
WARN ( "UTF8_BEFORE_PATCH" ,
2011-10-31 17:13:12 -07:00
"8-bit UTF-8 used in possible commit log\n" . $ herecurr ) ;
}
2016-12-12 16:46:28 -08:00
# Check for absolute kernel paths in commit message
if ( $ tree && $ in_commit_log ) {
while ( $ line =~ m { ( ?:^ | \ s ) ( /\ S * ) } g ) {
my $ file = $ 1 ;
if ( $ file =~ m { ^ ( . *? ) ( ?::\ d + ) +:? $ } &&
check_absolute_file ( $ 1 , $ herecurr ) ) {
#
} else {
check_absolute_file ( $ file , $ herecurr ) ;
}
}
}
2014-10-13 15:51:57 -07:00
# Check for various typo / spelling mistakes
2015-04-16 12:44:08 -07:00
if ( defined ( $ misspellings ) &&
( $ in_commit_log | | $ line =~ /^ ( ?:\+ | Subject : ) / i ) ) {
2020-12-15 20:45:21 -08:00
while ( $ rawline =~ / ( ?:^ | [ ^\ w \- '`])($misspellings)(?:[^\w\-' ` ] | $ ) / gi ) {
2014-10-13 15:51:57 -07:00
my $ typo = $ 1 ;
2020-12-15 20:45:21 -08:00
my $ blank = copy_spacing ( $ rawline ) ;
my $ ptr = substr ( $ blank , 0 , $ - [ 1 ] ) . "^" x length ( $ typo ) ;
my $ hereptr = "$hereline$ptr\n" ;
2014-10-13 15:51:57 -07:00
my $ typo_fix = $ spelling_fix { lc ( $ typo ) } ;
$ typo_fix = ucfirst ( $ typo_fix ) if ( $ typo =~ /^ [ A - Z ] / ) ;
$ typo_fix = uc ( $ typo_fix ) if ( $ typo =~ /^ [ A - Z ] + $ / ) ;
2017-09-08 16:16:07 -07:00
my $ msg_level = \& WARN ;
$ msg_level = \& CHK if ( $ file ) ;
if ( & { $ msg_level } ( "TYPO_SPELLING" ,
2020-12-15 20:45:21 -08:00
"'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $ hereptr ) &&
2014-10-13 15:51:57 -07:00
$ fix ) {
$ fixed [ $ fixlinenr ] =~ s / ( ^ | [ ^ A - Za - z @ ] ) ( $ typo ) ( $ | [ ^ A - Za - z @ ] ) / $ 1 $ typo_fix$3 / ;
}
}
}
2019-09-25 16:46:38 -07:00
# check for invalid commit id
if ( $ in_commit_log && $ line =~ / ( ^ fixes : | \ bcommit ) \ s + ( [ 0 - 9 a - f ] { 6 , 40 } ) \ b / i ) {
my $ id ;
my $ description ;
( $ id , $ description ) = git_commit_info ( $ 2 , undef , undef ) ;
if ( ! defined ( $ id ) ) {
WARN ( "UNKNOWN_COMMIT_ID" ,
"Unknown commit id '$2', maybe rebased or not pulled?\n" . $ herecurr ) ;
}
}
2020-10-15 20:11:52 -07:00
# check for repeated words separated by a single space
2020-12-15 20:44:24 -08:00
# avoid false positive from list command eg , '-rw-r--r-- 1 root root'
if ( ( $ rawline =~ /^\+/ | | $ in_commit_log ) &&
$ rawline ! ~ / [ bcCdDlMnpPs \?- ] [ rwxsStT - ] { 9 } / ) {
2020-12-15 20:44:20 -08:00
pos ( $ rawline ) = 1 if ( ! $ in_commit_log ) ;
2020-10-15 20:11:52 -07:00
while ( $ rawline =~ /\ b ( $ word_pattern ) ( ?= ( $ word_pattern ) ) / g ) {
my $ first = $ 1 ;
my $ second = $ 2 ;
2020-12-15 20:44:20 -08:00
my $ start_pos = $ - [ 1 ] ;
my $ end_pos = $ + [ 2 ] ;
2020-10-15 20:11:52 -07:00
if ( $ first =~ / ( ?: struct | union | enum ) / ) {
pos ( $ rawline ) += length ( $ first ) + length ( $ second ) + 1 ;
next ;
}
2020-12-15 20:44:20 -08:00
next if ( lc ( $ first ) ne lc ( $ second ) ) ;
2020-10-15 20:11:52 -07:00
next if ( $ first eq 'long' ) ;
2020-12-15 20:44:20 -08:00
# check for character before and after the word matches
my $ start_char = '' ;
my $ end_char = '' ;
$ start_char = substr ( $ rawline , $ start_pos - 1 , 1 ) if ( $ start_pos > ( $ in_commit_log ? 0 : 1 ) ) ;
$ end_char = substr ( $ rawline , $ end_pos , 1 ) if ( $ end_pos < length ( $ rawline ) ) ;
next if ( $ start_char =~ /^\ S $ / ) ;
next if ( index ( " \t.,;?!" , $ end_char ) == - 1 ) ;
2020-12-15 20:44:24 -08:00
# avoid repeating hex occurrences like 'ff ff fe 09 ...'
if ( $ first =~ /\ b [ 0 - 9 a - f ] { 2 , } \ b / i ) {
next if ( ! exists ( $ allow_repeated_words { lc ( $ first ) } ) ) ;
}
2020-10-15 20:11:52 -07:00
if ( WARN ( "REPEATED_WORD" ,
"Possible repeated word: '$first'\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ fixlinenr ] =~ s /\ b$first $ second \ b / $ first / ;
}
}
# if it 's a repeated word on consecutive lines in a comment block
if ($prevline =~ /$;+\s*$/ &&
$prevrawline =~ /($word_pattern)\s*$/) {
my $last_word = $1;
if ($rawline =~ /^\+\s*\*\s*$last_word /) {
if (WARN("REPEATED_WORD",
"Possible repeated word: ' $ last_word '\n" . $hereprev) &&
$fix) {
$fixed[$fixlinenr] =~ s/(\+\s*\*\s*)$last_word /$1/;
}
}
}
}
2008-10-15 22:02:28 -07:00
# ignore non-hunk lines and lines being removed
next if (!$hunk_line || $line =~ /^-/);
2007-06-08 13:47:06 -07:00
2007-06-01 00:46:48 -07:00
#trailing whitespace
2007-10-16 23:29:38 -07:00
if ($line =~ /^\+.*\015/) {
2008-02-08 04:20:54 -08:00
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
2013-09-11 14:23:54 -07:00
if (ERROR("DOS_LINE_ENDINGS",
"DOS line endings\n" . $herevet) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/[\s\015]+$//;
2013-09-11 14:23:54 -07:00
}
2008-02-08 04:20:54 -08:00
} elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
2013-07-03 15:05:31 -07:00
if (ERROR("TRAILING_WHITESPACE",
"trailing whitespace\n" . $herevet) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/\s+$//;
2013-07-03 15:05:31 -07:00
}
2010-10-26 14:23:12 -07:00
$rpt_cleaners = 1;
2007-06-01 00:46:48 -07:00
}
2008-10-15 22:02:27 -07:00
2013-11-12 15:10:12 -08:00
# Check for FSF mailing addresses.
2014-01-23 15:54:50 -08:00
if ($rawline =~ /\bwrite to the Free/i ||
2017-02-24 15:01:38 -08:00
$rawline =~ /\b675\s+Mass\s+Ave/i ||
2014-01-23 15:54:48 -08:00
$rawline =~ /\b59\s+Temple\s+Pl/i ||
$rawline =~ /\b51\s+Franklin\s+St/i) {
2013-11-12 15:10:12 -08:00
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
2017-09-08 16:16:07 -07:00
my $msg_level = \&ERROR;
$msg_level = \&CHK if ($file);
&{$msg_level}("FSF_MAILING_ADDRESS",
"Do not include the paragraph about writing to the Free Software Foundation' s mailing address from the sample GPL notice . The FSF has changed addresses in the past , and may do so again . Linux already includes a copy of the GPL . \ n " . $ herevet )
2013-11-12 15:10:12 -08:00
}
2010-05-24 14:33:29 -07:00
# check for Kconfig help text having a real description
2010-10-26 14:23:15 -07:00
# Only applies when adding the entry originally , after that we do not have
# sufficient context to determine whether it is indeed long enough .
2010-05-24 14:33:29 -07:00
if ( $ realfile =~ / Kconfig / &&
2018-02-16 21:22:54 +01:00
# 'choice' is usually the last thing on the line ( though
# Kconfig supports named choices ) , so use a word boundary
# ( \ b ) rather than a whitespace character ( \ s )
$ line =~ /^\+\ s * ( ?: config | menuconfig | choice ) \ b / ) {
2010-05-24 14:33:29 -07:00
my $ length = 0 ;
2010-10-26 14:23:15 -07:00
my $ cnt = $ realcnt ;
my $ ln = $ linenr + 1 ;
my $ f ;
2012-01-10 15:10:03 -08:00
my $ is_start = 0 ;
2010-10-26 14:23:15 -07:00
my $ is_end = 0 ;
2012-01-10 15:10:03 -08:00
for ( ; $ cnt > 0 && defined $ lines [ $ ln - 1 ] ; $ ln ++ ) {
2010-10-26 14:23:15 -07:00
$ f = $ lines [ $ ln - 1 ] ;
$ cnt -- if ( $ lines [ $ ln - 1 ] ! ~ /^-/ ) ;
$ is_end = $ lines [ $ ln - 1 ] =~ /^\+/ ;
next if ( $ f =~ /^-/ ) ;
2014-08-06 16:10:46 -07:00
last if ( ! $ file && $ f =~ /^\@\@/ ) ;
2012-01-10 15:10:03 -08:00
2018-02-16 21:22:53 +01:00
if ( $ lines [ $ ln - 1 ] =~ /^\+\ s * ( ?: bool | tristate | prompt ) \ s * [ " ']/) {
2012-01-10 15:10:03 -08:00
$is_start = 1;
2020-06-17 12:02:20 +09:00
} elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) {
2012-01-10 15:10:03 -08:00
$length = -1;
}
2010-10-26 14:23:15 -07:00
$f =~ s/^.//;
2010-05-24 14:33:29 -07:00
$f =~ s/#.*//;
$f =~ s/^\s+//;
next if ($f =~ /^$/);
2018-02-16 21:22:54 +01:00
# This only checks context lines in the patch
# and so hopefully shouldn' t trigger false
# positives , even though some of these are
# common words in help texts
if ( $ f =~ /^\ s * ( ?: config | menuconfig | choice | endchoice |
if | endif | menu | endmenu | source ) \ b / x ) {
2010-10-26 14:23:15 -07:00
$ is_end = 1 ;
last ;
}
2010-05-24 14:33:29 -07:00
$ length ++ ;
}
2014-10-13 15:51:48 -07:00
if ( $ is_start && $ is_end && $ length < $ min_conf_desc_length ) {
WARN ( "CONFIG_DESCRIPTION" ,
"please write a paragraph that describes the config symbol fully\n" . $ herecurr ) ;
}
2012-01-10 15:10:03 -08:00
# print "is_start<$is_start> is_end<$is_end> length<$length>\n" ;
2010-05-24 14:33:29 -07:00
}
2020-06-04 16:50:33 -07:00
# check MAINTAINERS entries
if ( $ realfile =~ /^ MAINTAINERS $ / ) {
# check MAINTAINERS entries for the right form
if ( $ rawline =~ /^\+ [ A - Z ] :/ &&
$ rawline ! ~ /^\+ [ A - Z ] :\ t \ S / ) {
if ( WARN ( "MAINTAINERS_STYLE" ,
"MAINTAINERS entries use one tab after TYPE:\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ fixlinenr ] =~ s /^ ( \+ [ A - Z ] ) :\ s */ $ 1 :\ t / ;
}
}
# check MAINTAINERS entries for the right ordering too
my $ preferred_order = 'MRLSWQBCPTFXNK' ;
if ( $ rawline =~ /^\+ [ A - Z ] :/ &&
$ prevrawline =~ /^ [ \+ ] [ A - Z ] :/ ) {
$ rawline =~ /^\+ ( [ A - Z ] ) :\ s * ( . * ) / ;
my $ cur = $ 1 ;
my $ curval = $ 2 ;
$ prevrawline =~ /^ [ \+ ] ( [ A - Z ] ) :\ s * ( . * ) / ;
my $ prev = $ 1 ;
my $ prevval = $ 2 ;
my $ curindex = index ( $ preferred_order , $ cur ) ;
my $ previndex = index ( $ preferred_order , $ prev ) ;
if ( $ curindex < 0 ) {
WARN ( "MAINTAINERS_STYLE" ,
"Unknown MAINTAINERS entry type: '$cur'\n" . $ herecurr ) ;
} else {
if ( $ previndex >= 0 && $ curindex < $ previndex ) {
WARN ( "MAINTAINERS_STYLE" ,
"Misordered MAINTAINERS entry - list '$cur:' before '$prev:'\n" . $ hereprev ) ;
} elsif ( ( ( $ prev eq 'F' && $ cur eq 'F' ) | |
( $ prev eq 'X' && $ cur eq 'X' ) ) &&
( $ prevval cmp $ curval ) > 0 ) {
WARN ( "MAINTAINERS_STYLE" ,
"Misordered MAINTAINERS entry - list file patterns in alphabetic order\n" . $ hereprev ) ;
}
}
2017-07-10 15:52:07 -07:00
}
}
2015-02-13 14:38:29 -08:00
# discourage the use of boolean for type definition attributes of Kconfig options
if ( $ realfile =~ / Kconfig / &&
$ line =~ /^\+\ s *\ bboolean \ b / ) {
WARN ( "CONFIG_TYPE_BOOLEAN" ,
"Use of boolean is deprecated, please use bool instead.\n" . $ herecurr ) ;
}
2011-08-15 01:07:14 -04:00
if ( ( $ realfile =~ / Makefile . */ | | $ realfile =~ / Kbuild . */ ) &&
( $ line =~ /\+ ( EXTRA_ [ A - Z ] + FLAGS ) . */ ) ) {
my $ flag = $ 1 ;
my $ replacement = {
'EXTRA_AFLAGS' => 'asflags-y' ,
'EXTRA_CFLAGS' => 'ccflags-y' ,
'EXTRA_CPPFLAGS' => 'cppflags-y' ,
'EXTRA_LDFLAGS' => 'ldflags-y' ,
} ;
WARN ( "DEPRECATED_VARIABLE" ,
" Use of $ flag is deprecated , please use \ ` $ replacement -> { $ flag } instead . \ n " . $ herecurr ) if ( $ replacement -> { $ flag } ) ;
}
2014-01-23 15:54:51 -08:00
# check for DT compatible documentation
2014-04-03 14:49:26 -07:00
if ( defined $ root &&
( ( $ realfile =~ /\. dtsi ? $ / && $ line =~ /^\+\ s * compatible \ s *=\ s *\ " / ) | |
( $ realfile =~ /\. [ ch ] $ / && $ line =~ /^\+.*\. compatible \ s *=\ s *\ " / ) ) ) {
2014-01-23 15:54:51 -08:00
my @ compats = $ rawline =~ /\ " ( [ a - zA - Z0 - 9 \-\ , \.\+ _ ] + ) \ "/g;
2014-04-03 14:49:27 -07:00
my $dt_path = $root . " / Documentation / devicetree / bindings / ";
2019-05-22 09:55:34 -05:00
my $vp_file = $dt_path . " vendor - prefixes . yaml " ;
2014-04-03 14:49:27 -07:00
2014-01-23 15:54:51 -08:00
foreach my $ compat ( @ compats ) {
my $ compat2 = $ compat ;
2014-06-04 16:12:03 -07:00
$ compat2 =~ s /\ , [ a - zA - Z0 - 9 ] *\-/\ , <\.\*>\-/ ;
my $ compat3 = $ compat ;
$ compat3 =~ s /\ , ( [ a - z ] * ) [ 0 - 9 ] *\-/\ , $ 1 <\.\*>\-/ ;
` grep - Erq "$compat|$compat2|$compat3" $ dt_path ` ;
2014-01-23 15:54:51 -08:00
if ( $ ? >> 8 ) {
WARN ( "UNDOCUMENTED_DT_STRING" ,
"DT compatible string \"$compat\" appears un-documented -- check $dt_path\n" . $ herecurr ) ;
}
2014-04-03 14:49:25 -07:00
next if $ compat ! ~ /^ ( [ a - zA - Z0 - 9 \- ] + ) \ , / ;
my $ vendor = $ 1 ;
2019-05-22 09:55:34 -05:00
` grep - Eq " \\ " \\^\ Q $ vendor \ E , \\.\\*\\ ":" $ vp_file ` ;
2014-01-23 15:54:51 -08:00
if ( $ ? >> 8 ) {
WARN ( "UNDOCUMENTED_DT_STRING" ,
2014-04-03 14:49:27 -07:00
"DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $ herecurr ) ;
2014-01-23 15:54:51 -08:00
}
}
}
2018-04-10 16:33:13 -07:00
# check for using SPDX license tag at beginning of files
if ( $ realline == $ checklicenseline ) {
if ( $ rawline =~ /^ [ \+ ] \ s *\#\ ! \ s *\// ) {
$ checklicenseline = 2 ;
} elsif ( $ rawline =~ /^\+/ ) {
my $ comment = "" ;
if ( $ realfile =~ /\. ( h | s | S ) $ / ) {
$ comment = '/*' ;
} elsif ( $ realfile =~ /\. ( c | dts | dtsi ) $ / ) {
$ comment = '//' ;
2020-04-06 20:10:51 -07:00
} elsif ( ( $ checklicenseline == 2 ) | | $ realfile =~ /\. ( sh | pl | py | awk | tc | yaml ) $ / ) {
2018-04-10 16:33:13 -07:00
$ comment = '#' ;
} elsif ( $ realfile =~ /\. rst$ / ) {
$ comment = '..' ;
}
2019-03-07 16:28:32 -08:00
# check SPDX comment style for . [ chsS ] files
if ( $ realfile =~ /\. [ chsS ] $ / &&
$ rawline =~ / SPDX - License - Identifier :/ &&
2019-09-25 16:46:35 -07:00
$ rawline ! ~ m @^\+\ s *\ Q $ comment \ E \ s *@ ) {
2019-03-07 16:28:32 -08:00
WARN ( "SPDX_LICENSE_TAG" ,
"Improper SPDX comment style for '$realfile', please use '$comment' instead\n" . $ herecurr ) ;
}
2018-04-10 16:33:13 -07:00
if ( $ comment ! ~ /^ $ / &&
2019-09-25 16:46:35 -07:00
$ rawline ! ~ m @^\+\ Q $ comment \ E SPDX - License - Identifier : @ ) {
WARN ( "SPDX_LICENSE_TAG" ,
"Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $ herecurr ) ;
2018-08-21 21:57:47 -07:00
} elsif ( $ rawline =~ / ( SPDX - License - Identifier : . * ) / ) {
2019-09-25 16:46:35 -07:00
my $ spdx_license = $ 1 ;
if ( ! is_SPDX_License_valid ( $ spdx_license ) ) {
WARN ( "SPDX_LICENSE_TAG" ,
"'$spdx_license' is not supported in LICENSES/...\n" . $ herecurr ) ;
}
2020-04-06 20:11:13 -07:00
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 ) / ;
}
}
2018-04-10 16:33:13 -07:00
}
}
}
2020-10-15 20:12:19 -07:00
# check for embedded filenames
if ( $ rawline =~ /^\+.*\ Q $ realfile \ E / ) {
WARN ( "EMBEDDED_FILENAME" ,
"It's generally not useful to have the filename in the file\n" . $ herecurr ) ;
}
2008-10-15 22:02:27 -07:00
# check we are in a valid source file if not then ignore this hunk
2016-12-12 16:46:28 -08:00
next if ( $ realfile ! ~ /\. ( h | c | s | S | sh | dtsi | dts ) $ / ) ;
2008-10-15 22:02:27 -07:00
2019-03-07 16:28:42 -08:00
# check for using SPDX - License - Identifier on the wrong line number
if ( $ realline ! = $ checklicenseline &&
$ rawline =~ /\ bSPDX - License - Identifier :/ &&
substr ( $ line , @- , @+ - @- ) eq "$;" x ( @+ - @- ) ) {
WARN ( "SPDX_LICENSE_TAG" ,
"Misplaced SPDX-License-Identifier tag - use line $checklicenseline instead\n" . $ herecurr ) ;
}
2015-06-25 15:02:57 -07:00
# line length limit ( with some exclusions )
#
# There are a few types of lines that may extend beyond $ max_line_length :
# logging functions like pr_info that end in a string
# lines with a single string
# # defines that are a single string
2018-02-06 15:38:45 -08:00
# lines with an RFC3986 like URL
2015-06-25 15:02:57 -07:00
#
# There are 3 different line length message types :
2017-09-08 16:16:04 -07:00
# LONG_LINE_COMMENT a comment starts before but extends beyond $ max_line_length
2015-06-25 15:02:57 -07:00
# LONG_LINE_STRING a string starts before but extends beyond $ max_line_length
# LONG_LINE all other lines longer than $ max_line_length
#
# if LONG_LINE is ignored , the other 2 types are also ignored
#
2015-07-17 16:24:01 -07:00
if ( $ line =~ /^\+/ && $ length > $ max_line_length ) {
2015-06-25 15:02:57 -07:00
my $ msg_type = "LONG_LINE" ;
# Check the allowed long line types first
# logging functions that end in a string that starts
# before $ max_line_length
if ( $ line =~ /^\+\ s * $ logFunctions \ s *\ ( \ s * ( ?: ( ?: KERN_ \ S +\ s * | [ ^ " ] * ) ) ? ( $ String \ s * ( ?: | , | \ ) \ s * ; ) \ s * ) $ / &&
length ( expand_tabs ( substr ( $ line , 1 , length ( $ line ) - length ( $ 1 ) - 1 ) ) ) <= $ max_line_length ) {
$ msg_type = "" ;
# lines with only strings ( w / possible termination )
# # defines with only strings
} elsif ( $ line =~ /^\+\ s * $ String \ s * ( ?:\ s * | , | \ ) \ s * ; ) \ s * $ / | |
$ line =~ /^\+\ s *#\ s * define \ s +\ w +\ s + $ String $ / ) {
$ msg_type = "" ;
2017-11-17 15:28:44 -08:00
# More special cases
} elsif ( $ line =~ /^\+.*\ bEFI_GUID \ s *\ ( / | |
$ line =~ /^\+\ s * ( ?:\ w + ) ?\ s * DEFINE_PER_CPU / ) {
2016-08-02 14:04:31 -07:00
$ msg_type = "" ;
2018-02-06 15:38:45 -08:00
# URL ( $ rawline is used in case the URL is in a comment )
} elsif ( $ rawline =~ /^\+.*\ b [ a - z ] [ \ w \.\+\- ] *:\/\/\ S +/ i ) {
$ msg_type = "" ;
2015-06-25 15:02:57 -07:00
# Otherwise set the alternate message types
# a comment starts before $ max_line_length
} elsif ( $ line =~ / ( $ ; [ \ s$ ; ] * ) $ / &&
length ( expand_tabs ( substr ( $ line , 1 , length ( $ line ) - length ( $ 1 ) - 1 ) ) ) <= $ max_line_length ) {
$ msg_type = "LONG_LINE_COMMENT"
# a quoted string starts before $ max_line_length
} elsif ( $ sline =~ /\ s * ( $ String ( ?:\ s * ( ?:\\ | , \ s * | \ ) \ s * ; \ s * ) ) ? ) $ / &&
length ( expand_tabs ( substr ( $ line , 1 , length ( $ line ) - length ( $ 1 ) - 1 ) ) ) <= $ max_line_length ) {
$ msg_type = "LONG_LINE_STRING"
}
if ( $ msg_type ne "" &&
( show_type ( "LONG_LINE" ) | | show_type ( $ msg_type ) ) ) {
2020-05-29 16:12:21 -07:00
my $ msg_level = \& WARN ;
$ msg_level = \& CHK if ( $ file ) ;
& { $ msg_level } ( $ msg_type ,
"line length of $length exceeds $max_line_length columns\n" . $ herecurr ) ;
2015-06-25 15:02:57 -07:00
}
2007-06-01 00:46:48 -07:00
}
2007-11-28 16:21:06 -08:00
# check for adding lines without a newline .
if ( $ line =~ /^\+/ && defined $ lines [ $ linenr ] && $ lines [ $ linenr ] =~ /^\\ No newline at end of file / ) {
2020-12-15 20:44:40 -08:00
if ( WARN ( "MISSING_EOF_NEWLINE" ,
"adding a line without newline at end of file\n" . $ herecurr ) &&
$ fix ) {
fix_delete_line ( $ fixlinenr + 1 , "No newline at end of file" ) ;
}
2007-11-28 16:21:06 -08:00
}
2008-10-15 22:02:24 -07:00
# check we are in a valid source file C or perl if not then ignore this hunk
2014-10-13 15:51:46 -07:00
next if ( $ realfile ! ~ /\. ( h | c | pl | dtsi | dts ) $ / ) ;
2007-06-01 00:46:48 -07:00
# at the beginning of a line any tabs must come first and anything
2020-04-06 20:11:07 -07:00
# more than $ tabsize must use tabs .
2008-02-08 04:20:54 -08:00
if ( $ rawline =~ /^\+\ s * \ t \ s *\ S / | |
$ rawline =~ /^\+\ s * \ s */ ) {
my $ herevet = "$here\n" . cat_vet ( $ rawline ) . "\n" ;
2010-10-26 14:23:12 -07:00
$ rpt_cleaners = 1 ;
2013-07-03 15:05:31 -07:00
if ( ERROR ( "CODE_INDENT" ,
"code indent should use tabs where possible\n" . $ herevet ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~ s /^\+ ( [ \ t ] + ) / " \+ " . tabify ( $ 1 ) / e ;
2013-07-03 15:05:31 -07:00
}
2007-06-01 00:46:48 -07:00
}
2010-03-05 13:43:54 -08:00
# check for space before tabs .
if ( $ rawline =~ /^\+/ && $ rawline =~ / \ t / ) {
my $ herevet = "$here\n" . cat_vet ( $ rawline ) . "\n" ;
2013-07-03 15:05:31 -07:00
if ( WARN ( "SPACE_BEFORE_TAB" ,
"please, no space before tabs\n" . $ herevet ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
while ( $ fixed [ $ fixlinenr ] =~
2020-04-06 20:11:07 -07:00
s / ( ^\+.* ) { $ tabsize , $ tabsize } \ t / $ 1 \ t \ t / ) { }
2014-08-06 16:11:03 -07:00
while ( $ fixed [ $ fixlinenr ] =~
2014-01-23 15:54:46 -08:00
s / ( ^\+.* ) +\ t / $ 1 \ t / ) { }
2013-07-03 15:05:31 -07:00
}
2010-03-05 13:43:54 -08:00
}
2018-04-10 16:34:04 -07:00
# check for assignments on the start of a line
if ( $ sline =~ /^\+\ s + ( $ Assignment ) [ ^= ] / ) {
2020-12-15 20:45:06 -08:00
my $ operator = $ 1 ;
if ( CHK ( "ASSIGNMENT_CONTINUATIONS" ,
"Assignment operator '$1' should be on the previous line\n" . $ hereprev ) &&
$ fix && $ prevrawline =~ /^\+/ ) {
# add assignment operator to the previous line , remove from current line
$ fixed [ $ fixlinenr - 1 ] . = " $operator" ;
$ fixed [ $ fixlinenr ] =~ s /\ Q $ operator \ E \ s *// ;
}
2018-04-10 16:34:04 -07:00
}
2010-03-05 13:43:54 -08:00
2012-03-23 15:02:16 -07:00
# check for && or | | at the start of a line
if ( $ rawline =~ /^\+\ s * ( && | \ | \ | ) / ) {
2020-12-15 20:45:09 -08:00
my $ operator = $ 1 ;
if ( CHK ( "LOGICAL_CONTINUATIONS" ,
"Logical continuations should be on the previous line\n" . $ hereprev ) &&
$ fix && $ prevrawline =~ /^\+/ ) {
# insert logical operator at last non - comment , non - whitepsace char on previous line
$ prevline =~ / [ \ s$ ; ] * $ / ;
my $ line_end = substr ( $ prevrawline , $ - [ 0 ] ) ;
$ fixed [ $ fixlinenr - 1 ] =~ s /\ Q $ line_end \ E $ / $ operator$line_end / ;
$ fixed [ $ fixlinenr ] =~ s /\ Q $ operator \ E \ s *// ;
}
2012-03-23 15:02:16 -07:00
}
2016-05-20 17:04:05 -07:00
# check indentation starts on a tab stop
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2018-02-06 15:39:06 -08:00
$ sline =~ /^\+\ t + ( + ) ( ?: $ c90_Keywords \ b | \ { \ s * $ | \ } \ s * ( ?: else \ b | while \ b | \ s * $ ) | $ Declare \ s * $ Ident \ s * [ ; = ] ) / ) {
2016-05-20 17:04:05 -07:00
my $ indent = length ( $ 1 ) ;
2020-04-06 20:11:07 -07:00
if ( $ indent % $tabsize) {
2016-05-20 17:04:05 -07:00
if ( WARN ( "TABSTOP" ,
"Statements should start on a tabstop\n" . $ herecurr ) &&
$ fix ) {
2020-04-06 20:11:07 -07:00
$ fixed [ $ fixlinenr ] =~ s @ ( ^\+\ t + ) +@ $ 1 . "\t" x ( $ indent / $ tabsize ) @ e ;
2016-05-20 17:04:05 -07:00
}
}
}
2012-03-23 15:02:16 -07:00
# check multi - line statement indentation matches previous line
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2017-07-10 15:52:30 -07:00
$ prevline =~ /^\+ ( [ \ t ] * ) ( ( ?: $ c90_Keywords ( ?:\ s + if ) \ s * ) | ( ?: $ Declare \ s * ) ? ( ?: $ Ident | \ ( \ s *\*\ s * $ Ident \ s *\ ) ) \ s * | ( ?:\*\ s * ) * $ Lval \ s *=\ s * $ Ident \ s * ) \ ( . * ( \&\& | \ | \ | | , ) \ s * $ / ) {
2012-03-23 15:02:16 -07:00
$ prevline =~ /^\+ ( \ t * ) ( . * ) $ / ;
my $ oldindent = $ 1 ;
my $ rest = $ 2 ;
my $ pos = pos_last_openparen ( $ rest ) ;
if ( $ pos >= 0 ) {
2012-07-30 14:41:16 -07:00
$ line =~ /^ ( \+ | ) ( [ \ t ] * ) / ;
my $ newindent = $ 2 ;
2012-03-23 15:02:16 -07:00
my $ goodtabindent = $ oldindent .
2020-04-06 20:11:07 -07:00
"\t" x ( $ pos / $ tabsize ) .
" " x ( $ pos % $tabsize);
2012-03-23 15:02:16 -07:00
my $ goodspaceindent = $ oldindent . " " x $ pos ;
if ( $ newindent ne $ goodtabindent &&
$ newindent ne $ goodspaceindent ) {
2013-07-03 15:05:31 -07:00
if ( CHK ( "PARENTHESIS_ALIGNMENT" ,
"Alignment should match open parenthesis\n" . $ hereprev ) &&
$ fix && $ line =~ /^\+/ ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /^\+ [ \ t ] */\+ $ goodtabindent / ;
}
2012-03-23 15:02:16 -07:00
}
}
}
2015-04-16 12:44:05 -07:00
# 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 * $ / ) ) {
2013-07-03 15:05:31 -07:00
if ( CHK ( "SPACING" ,
2014-08-06 16:10:52 -07:00
"No space is necessary after a cast\n" . $ herecurr ) &&
2013-07-03 15:05:31 -07:00
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2014-08-06 16:10:52 -07:00
s / ( \ ( \ s * $ Type \ s *\ ) ) [ \ t ] +/ $ 1 / ;
2013-07-03 15:05:31 -07:00
}
2012-03-23 15:02:19 -07:00
}
2015-09-09 15:37:41 -07:00
# Block comment styles
# Networking with an initial /*
2012-10-04 17:13:35 -07:00
if ($realfile =~ m@^(drivers / net / |net / )@ &&
2013-07-03 15:05:23 -07:00
$prevrawline =~ / ^\+[ \t] * \ / \ * [ \t] * $ / &&
2014-04-03 14:49:20 -07:00
$rawline =~ / ^\+[ \t] * \ */ &&
2020-10-15 20:12:25 -07:00
$ realline > 3 ) { # Do not warn about the initial copyright comment block after SPDX - License - Identifier
2012-10-04 17:13:35 -07:00
WARN ( "NETWORKING_BLOCK_COMMENT_STYLE" ,
"networking block comments don't use an empty /* line, use /* Comment...\n" . $ hereprev ) ;
}
2015-09-09 15:37:41 -07:00
# Block comments use * on subsequent lines
if ( $ prevline =~ / $ ; [ \ t ] * $ / && # ends in comment
$ prevrawline =~ /^\+.*?\/\*/ && # starting /*
2013-07-03 15:05:24 -07:00
$prevrawline !~ / \ * \ / [ \t] * $ / && #no trailing */
2013-09-11 14:23:59 -07:00
$ rawline =~ /^\+/ && # line is new
2013-07-03 15:05:24 -07:00
$ rawline ! ~ /^\+ [ \ t ] *\*/ ) { # no leading *
2015-09-09 15:37:41 -07:00
WARN ( "BLOCK_COMMENT_STYLE" ,
"Block comments use * on subsequent lines\n" . $ hereprev ) ;
2013-07-03 15:05:24 -07:00
}
2015-09-09 15:37:41 -07:00
# Block comments use */ on trailing lines
if ( $ rawline ! ~ m @^\+ [ \ t ] *\*/ [ \ t ] * $ @ && # trailing */
2012-11-08 15:53:29 -08:00
$ rawline ! ~ m @^\+.*/\*.*\*/ [ \ t ] * $ @ && # inline /* ... */
$ rawline ! ~ m @^\+.*\* { 2 , } / [ \ t ] * $ @ && # trailing **/
$ rawline =~ m @^\+ [ \ t ] *.+\*\/ [ \ t ] * $ @ ) { # non blank */
2015-09-09 15:37:41 -07:00
WARN ( "BLOCK_COMMENT_STYLE" ,
"Block comments use a trailing */ on a separate line\n" . $ herecurr ) ;
2012-10-04 17:13:35 -07:00
}
2016-10-11 13:51:50 -07:00
# Block comment * alignment
if ( $ prevline =~ / $ ; [ \ t ] * $ / && # ends in comment
2016-10-11 13:52:05 -07:00
$ line =~ /^\+ [ \ t ] * $ ; / && # leading comment
$ rawline =~ /^\+ [ \ t ] *\*/ && # leading *
( ( $ prevrawline =~ /^\+.*?\/\*/ && # leading /*
2016-10-11 13:51:50 -07:00
$prevrawline !~ / \ * \ / [ \t] * $ / ) || #no trailing */
2016-10-11 13:52:05 -07:00
$ prevrawline =~ /^\+ [ \ t ] *\*/ ) ) { # leading *
my $ oldindent ;
2016-10-11 13:51:50 -07:00
$ prevrawline =~ m @^\+ ( [ \ t ] */? ) \*@ ;
2016-10-11 13:52:05 -07:00
if ( defined ( $ 1 ) ) {
$ oldindent = expand_tabs ( $ 1 ) ;
} else {
$ prevrawline =~ m @^\+ ( . */? ) \*@ ;
$ oldindent = expand_tabs ( $ 1 ) ;
}
2016-10-11 13:51:50 -07:00
$ rawline =~ m @^\+ ( [ \ t ] * ) \*@ ;
my $ newindent = $ 1 ;
$ newindent = expand_tabs ( $ newindent ) ;
2016-10-11 13:52:05 -07:00
if ( length ( $ oldindent ) ne length ( $ newindent ) ) {
2016-10-11 13:51:50 -07:00
WARN ( "BLOCK_COMMENT_STYLE" ,
"Block comments should align the * on each line\n" . $ hereprev ) ;
}
}
2014-08-06 16:10:39 -07:00
# check for missing blank lines after struct / union declarations
# with exceptions for various attributes and macros
if ( $ prevline =~ /^ [ \+ ] } ; ?\ s * $ / &&
$ line =~ /^\+/ &&
! ( $ line =~ /^\+\ s * $ / | |
$ line =~ /^\+\ s * EXPORT_SYMBOL / | |
$ line =~ /^\+\ s * MODULE_ / i | |
$ line =~ /^\+\ s *\#\ s * ( ?: end | elif | else ) / | |
$ line =~ /^\+ [ a - z_ ] * init / | |
$ line =~ /^\+\ s * ( ?: static \ s + ) ? [ A - Z_ ] * ATTR / | |
$ line =~ /^\+\ s * DECLARE / | |
2017-11-17 15:28:55 -08:00
$ line =~ /^\+\ s * builtin_ [ \ w_ ] * driver / | |
2014-08-06 16:10:39 -07:00
$ line =~ /^\+\ s * _ _ setup / ) ) {
2014-08-06 16:11:05 -07:00
if ( CHK ( "LINE_SPACING" ,
"Please use a blank line after function/struct/union/enum declarations\n" . $ hereprev ) &&
$ fix ) {
2014-08-06 16:11:07 -07:00
fix_insert_line ( $ fixlinenr , " \+ " ) ;
2014-08-06 16:11:05 -07:00
}
2014-08-06 16:10:39 -07:00
}
2014-08-06 16:10:42 -07:00
# check for multiple consecutive blank lines
if ( $ prevline =~ /^ [ \+ ] \ s * $ / &&
$ line =~ /^\+\ s * $ / &&
$ last_blank_line ! = ( $ linenr - 1 ) ) {
2014-08-06 16:11:05 -07:00
if ( CHK ( "LINE_SPACING" ,
"Please don't use multiple blank lines\n" . $ hereprev ) &&
$ fix ) {
2014-08-06 16:11:07 -07:00
fix_delete_line ( $ fixlinenr , $ rawline ) ;
2014-08-06 16:11:05 -07:00
}
2014-08-06 16:10:42 -07:00
$ last_blank_line = $ linenr ;
}
2014-04-03 14:49:28 -07:00
# check for missing blank lines after declarations
2014-06-04 16:12:04 -07:00
if ( $ sline =~ /^\+\ s +\ S / && # Not at char 1
# actual declarations
( $ prevline =~ /^\+\ s + $ Declare \ s * $ Ident \ s * [ = , ; :\ [ ] / | |
2014-08-06 16:10:33 -07:00
# function pointer declarations
$ prevline =~ /^\+\ s + $ Declare \ s *\ ( \ s *\*\ s * $ Ident \ s *\ ) \ s * [ = , ; :\ [ \ ( ] / | |
2014-06-04 16:12:04 -07:00
# foo bar ; where foo is some local typedef or # define
$ prevline =~ /^\+\ s + $ Ident ( ?:\ s + | \ s *\*\ s * ) $ Ident \ s * [ = , ; \ [ ] / | |
# known declaration macros
$ prevline =~ /^\+\ s + $ declaration_macros / ) &&
# for "else if" which can look like "$Ident $Ident"
! ( $ prevline =~ /^\+\ s + $ c90_Keywords \ b / | |
# other possible extensions of declaration lines
$ prevline =~ / ( ?: $ Compare | $ Assignment | $ Operators ) \ s * $ / | |
# not starting a section or a macro " \ " extended line
$ prevline =~ / ( ?:\ { \ s * | \\ ) $ / ) &&
# looks like a declaration
! ( $ sline =~ /^\+\ s + $ Declare \ s * $ Ident \ s * [ = , ; :\ [ ] / | |
2014-08-06 16:10:33 -07:00
# function pointer declarations
$ sline =~ /^\+\ s + $ Declare \ s *\ ( \ s *\*\ s * $ Ident \ s *\ ) \ s * [ = , ; :\ [ \ ( ] / | |
2014-06-04 16:12:04 -07:00
# foo bar ; where foo is some local typedef or # define
$ sline =~ /^\+\ s + $ Ident ( ?:\ s + | \ s *\*\ s * ) $ Ident \ s * [ = , ; \ [ ] / | |
# known declaration macros
$ sline =~ /^\+\ s + $ declaration_macros / | |
# start of struct or union or enum
2018-09-04 15:46:06 -07:00
$ sline =~ /^\+\ s + ( ?: static \ s + ) ? ( ?: const \ s + ) ? ( ?: union | struct | enum | typedef ) \ b / | |
2014-06-04 16:12:04 -07:00
# start or end of block or continuation of declaration
$ sline =~ /^\+\ s + ( ?: $ | [ \ { \ } \.\#\ " \?\:\ ( \ [ ] ) / | |
# bitfield continuation
$ sline =~ /^\+\ s + $ Ident \ s *:\ s *\ d +\ s * [ , ; ] / | |
# other possible extensions of declaration lines
$ sline =~ /^\+\ s +\ ( ?\ s * ( ?: $ Compare | $ Assignment | $ Operators ) / ) &&
# indentation of previous and current line are the same
( ( $ prevline =~ /\+ ( \ s + ) \ S / ) && $ sline =~ /^\+ $ 1 \ S / ) ) {
2014-08-06 16:11:05 -07:00
if ( WARN ( "LINE_SPACING" ,
"Missing a blank line after declarations\n" . $ hereprev ) &&
$ fix ) {
2014-08-06 16:11:07 -07:00
fix_insert_line ( $ fixlinenr , " \+ " ) ;
2014-08-06 16:11:05 -07:00
}
2014-04-03 14:49:28 -07:00
}
2010-08-09 17:20:59 -07:00
# check for spaces at the beginning of a line .
2010-10-26 14:23:11 -07:00
# Exceptions :
# 1 ) within comments
# 2 ) indented preprocessor commands
# 3 ) hanging labels
2013-07-03 15:05:31 -07:00
if ( $ rawline =~ /^\+ / && $ line ! ~ /^\+ * ( ?: $ ; | # | $ Ident : ) / ) {
2010-08-09 17:20:59 -07:00
my $ herevet = "$here\n" . cat_vet ( $ rawline ) . "\n" ;
2013-07-03 15:05:31 -07:00
if ( WARN ( "LEADING_SPACE" ,
"please, no spaces at the start of a line\n" . $ herevet ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~ s /^\+ ( [ \ t ] + ) / " \+ " . tabify ( $ 1 ) / e ;
2013-07-03 15:05:31 -07:00
}
2010-08-09 17:20:59 -07:00
}
2008-10-15 22:02:24 -07:00
# check we are in a valid C source file if not then ignore this hunk
next if ( $ realfile ! ~ /\. ( h | c ) $ / ) ;
2017-11-17 15:28:52 -08:00
# check for unusual line ending [ or (
if ( $ line =~ /^\+.* ( [ \ [ \ ( ] ) \ s * $ / ) {
CHK ( "OPEN_ENDED_LINE" ,
"Lines should not end with a '$1'\n" . $ herecurr ) ;
}
2017-05-08 15:55:39 -07:00
# check if this appears to be the start function declaration , save the name
if ( $ sline =~ /^\+\ { \ s * $ / &&
$ prevline =~ /^\+ ( ?: ( ?: ( ?: $ Storage | $ Inline ) \ s * ) *\ s * $ Type \ s * ) ? ( $ Ident ) \ ( / ) {
$ context_function = $ 1 ;
}
# check if this appears to be the end of function declaration
if ( $ sline =~ /^\+\ } \ s * $ / ) {
undef $ context_function ;
}
2014-08-06 16:10:29 -07:00
# check indentation of any line with a bare else
2014-10-13 15:51:59 -07:00
# ( but not if it is a multiple line "if (foo) return bar; else return baz;" )
2014-08-06 16:10:29 -07:00
# if the previous line is a break or return and is indented 1 tab more . . .
if ( $ sline =~ /^\+ ( [ \ t ] + ) ( ?: } [ \ t ] * ) ? else ( ?: [ \ t ] * { ) ?\ s * $ / ) {
my $ tabs = length ( $ 1 ) + 1 ;
2014-10-13 15:51:59 -07:00
if ( $ prevline =~ /^\+\ t { $ tabs , $ tabs } break \ b / | |
( $ prevline =~ /^\+\ t { $ tabs , $ tabs } return \ b / &&
defined $ lines [ $ linenr ] &&
$ lines [ $ linenr ] ! ~ /^ [ \+ ] \ t { $ tabs , $ tabs } return / ) ) {
2014-08-06 16:10:29 -07:00
WARN ( "UNNECESSARY_ELSE" ,
"else is not generally useful after a break or return\n" . $ hereprev ) ;
}
}
2014-08-06 16:11:01 -07:00
# check indentation of a line with a break ;
2020-12-15 20:44:33 -08:00
# if the previous line is a goto , return or break
# and is indented the same # of tabs
2014-08-06 16:11:01 -07:00
if ( $ sline =~ /^\+ ( [ \ t ] + ) break \ s * ; \ s * $ / ) {
my $ tabs = $ 1 ;
2020-12-15 20:44:33 -08:00
if ( $ prevline =~ /^\+ $ tabs ( goto | return | break ) \ b / ) {
if ( WARN ( "UNNECESSARY_BREAK" ,
"break is not useful after a $1\n" . $ hereprev ) &&
$ fix ) {
fix_delete_line ( $ fixlinenr , $ rawline ) ;
}
2014-08-06 16:11:01 -07:00
}
}
2008-02-08 04:20:54 -08:00
# check for RCS / CVS revision markers
2008-03-04 14:28:20 -08:00
if ( $ rawline =~ /^\+.*\ $ ( Revision | Log | Id ) ( ?:\ $ | ) / ) {
2011-07-25 17:13:25 -07:00
WARN ( "CVS_KEYWORD" ,
"CVS style keyword markers, these will _not_ be updated\n" . $ herecurr ) ;
2008-02-08 04:20:54 -08:00
}
2007-08-10 13:01:03 -07:00
2013-02-21 16:44:14 -08:00
# check for old HOTPLUG _ _ dev < foo > section markings
if ( $ line =~ /\ b ( _ _ dev ( init | exit ) ( data | const | ) ) \ b / ) {
WARN ( "HOTPLUG_SECTION" ,
"Using $1 is unnecessary\n" . $ herecurr ) ;
}
2007-10-16 23:29:38 -07:00
# Check for potential 'bare' types
2009-10-26 16:50:16 -07:00
my ( $ stat , $ cond , $ line_nr_next , $ remain_next , $ off_next ,
$ realline_next ) ;
2012-01-10 15:10:01 -08:00
# print "LINE<$line>\n" ;
2017-07-10 15:52:13 -07:00
if ( $ linenr > $ suppress_statement &&
2013-09-11 14:24:03 -07:00
$ realcnt && $ sline =~ /.\ s *\ S / ) {
2008-10-15 22:02:30 -07:00
( $ stat , $ cond , $ line_nr_next , $ remain_next , $ off_next ) =
2008-07-23 21:29:03 -07:00
ctx_statement_block ( $ linenr , $ realcnt , 0 ) ;
2008-04-29 00:59:32 -07:00
$ stat =~ s /\ n . /\ n / g ;
$ cond =~ s /\ n . /\ n / g ;
2012-01-10 15:10:01 -08:00
# print "linenr<$linenr> <$stat>\n" ;
# If this statement has no statement boundaries within
# it there is no point in retrying a statement scan
# until we hit end of it .
my $ frag = $ stat ; $ frag =~ s / ; +\ s * $ // ;
if ( $ frag ! ~ / ( ?: { | ; ) / ) {
# print "skip<$line_nr_next>\n" ;
$ suppress_statement = $ line_nr_next ;
}
2012-01-10 15:09:54 -08:00
2009-10-26 16:50:16 -07:00
# Find the real next line .
$ realline_next = $ line_nr_next ;
if ( defined $ realline_next &&
( ! defined $ lines [ $ realline_next - 1 ] | |
substr ( $ lines [ $ realline_next - 1 ] , $ off_next ) =~ /^\ s * $ / ) ) {
$ realline_next ++ ;
}
2008-04-29 00:59:32 -07:00
my $ s = $ stat ;
$ s =~ s / { . * $ // s ;
2008-03-04 14:28:20 -08:00
2008-02-08 04:20:54 -08:00
# Ignore goto labels .
2008-04-29 00:59:32 -07:00
if ( $ s =~ / $ Ident :\* $ / s ) {
2008-02-08 04:20:54 -08:00
# Ignore functions being called
2008-04-29 00:59:32 -07:00
} elsif ( $ s =~ /^.\ s * $ Ident \ s *\ ( / s ) {
2008-02-08 04:20:54 -08:00
2009-09-21 17:04:34 -07:00
} elsif ( $ s =~ /^.\ s * else \ b / s ) {
2008-06-05 22:46:01 -07:00
# declarations always start with types
2008-07-23 21:29:09 -07:00
} elsif ( $ prev_values eq 'E' && $ s =~ /^.\ s * ( ?: $ Storage \ s + ) ? ( ?: $ Inline \ s + ) ? ( ?: const \ s + ) ? ( ( ?:\ s * $ Ident ) +? ) \ b ( ?:\ s + $ Sparse ) ?\ s *\**\ s * ( ?: $ Ident | \ ( \* [ ^\ ) ] *\ ) ) ( ?:\ s * $ Modifier ) ?\ s * ( ?: ; | = | , | \ ( ) / s ) {
2008-06-05 22:46:01 -07:00
my $ type = $ 1 ;
$ type =~ s /\ s +/ / g ;
possible ( $ type , "A:" . $ s ) ;
2007-11-28 16:21:06 -08:00
# definitions in global scope can only start with types
2008-10-15 22:02:30 -07:00
} elsif ( $ s =~ /^. ( ?: $ Storage \ s + ) ? ( ?: $ Inline \ s + ) ? ( ?: const \ s + ) ? ( $ Ident ) \ b \ s * ( ? ! : ) / s ) {
2008-06-05 22:46:01 -07:00
possible ( $ 1 , "B:" . $ s ) ;
2008-02-08 04:20:54 -08:00
}
2007-11-28 16:21:06 -08:00
# any ( foo . . . * ) is a pointer cast , and foo is a type
2009-01-06 14:41:21 -08:00
while ( $ s =~ /\ ( ( $ Ident ) ( ?:\ s + $ Sparse ) * [ \ s \* ] +\ s *\ ) / sg ) {
2008-06-05 22:46:01 -07:00
possible ( $ 1 , "C:" . $ s ) ;
2007-10-16 23:29:38 -07:00
}
2007-11-28 16:21:06 -08:00
# Check for any sort of function declaration .
# int foo ( something bar , other baz ) ;
# void ( * store_gdt ) ( x86_descr_ptr * ) ;
2008-04-29 00:59:32 -07:00
if ( $ prev_values eq 'E' && $ s =~ /^ ( . ( ?: typedef \ s * ) ? ( ?: ( ?: $ Storage | $ Inline ) \ s * ) *\ s * $ Type \ s * ( ?:\ b$Ident | \ ( \*\ s * $ Ident \ ) ) \ s * ) \ ( / s ) {
2007-11-28 16:21:06 -08:00
my ( $ name_len ) = length ( $ 1 ) ;
2008-03-04 14:28:20 -08:00
my $ ctx = $ s ;
2008-03-28 14:15:58 -07:00
substr ( $ ctx , 0 , $ name_len + 1 , '' ) ;
2007-11-28 16:21:06 -08:00
$ ctx =~ s /\ ) [ ^\ ) ] * $ // ;
2008-03-04 14:28:20 -08:00
2007-11-28 16:21:06 -08:00
for my $ arg ( split ( /\ s * , \ s */ , $ ctx ) ) {
2008-06-05 22:46:01 -07:00
if ( $ arg =~ /^ ( ?: const \ s + ) ? ( $ Ident ) ( ?:\ s + $ Sparse ) *\ s *\**\ s * ( :?\ b$Ident ) ? $ / s | | $ arg =~ /^ ( $ Ident ) $ / s ) {
2007-11-28 16:21:06 -08:00
2008-06-05 22:46:01 -07:00
possible ( $ 1 , "D:" . $ s ) ;
2007-11-28 16:21:06 -08:00
}
}
}
2007-10-16 23:29:38 -07:00
}
2007-06-23 17:16:34 -07:00
#
# Checks which may be anchored in the context .
#
# Check for switch ( ) and associated case and default
# statements should be at the same indent .
2007-06-08 13:47:06 -07:00
if ( $ line =~/\ bswitch \ s *\ ( . *\ ) / ) {
my $ err = '' ;
my $ sep = '' ;
my @ ctx = ctx_block_outer ( $ linenr , $ realcnt ) ;
shift ( @ ctx ) ;
for my $ ctx ( @ ctx ) {
my ( $ clen , $ cindent ) = line_stats ( $ ctx ) ;
if ( $ ctx =~ /^\+\ s * ( case \ s + | default : ) / &&
$ indent ! = $ cindent ) {
$ err . = "$sep$ctx\n" ;
$ sep = '' ;
} else {
$ sep = "[...]\n" ;
}
}
if ( $ err ne '' ) {
2011-07-25 17:13:25 -07:00
ERROR ( "SWITCH_CASE_INDENT_LEVEL" ,
"switch and case should be at the same indent\n$hereline$err" ) ;
2007-07-15 23:37:22 -07:00
}
}
# if / while / etc brace do not go on next line , unless defining a do while loop ,
# or if that brace on the next line is for something else
2014-08-06 16:11:16 -07:00
if ( $ line =~ / ( . * ) \ b ( ( ?: if | while | for | switch | ( ?: [ a - z_ ] + | ) for_each [ a - z_ ] + ) \ s *\ ( | do \ b | else \ b ) / && $ line ! ~ /^.\ s *\#/ ) {
2008-03-28 14:15:58 -07:00
my $ pre_ctx = "$1$2" ;
2007-10-16 23:29:38 -07:00
my ( $ level , @ ctx ) = ctx_statement_level ( $ linenr , $ realcnt , 0 ) ;
2012-02-03 15:20:39 -08:00
if ( $ line =~ /^\+\ t { 6 , } / ) {
WARN ( "DEEP_INDENTATION" ,
"Too many leading tabs - consider code refactoring\n" . $ herecurr ) ;
}
2007-07-15 23:37:22 -07:00
my $ ctx_cnt = $ realcnt - $ # ctx - 1 ;
my $ ctx = join ( "\n" , @ ctx ) ;
2008-07-23 21:29:01 -07:00
my $ ctx_ln = $ linenr ;
my $ ctx_skip = $ realcnt ;
2007-07-15 23:37:22 -07:00
2008-07-23 21:29:01 -07:00
while ( $ ctx_skip > $ ctx_cnt | | ( $ ctx_skip == $ ctx_cnt &&
defined $ lines [ $ ctx_ln - 1 ] &&
$ lines [ $ ctx_ln - 1 ] =~ /^-/ ) ) {
## print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n" ;
$ ctx_skip -- if ( ! defined $ lines [ $ ctx_ln - 1 ] | | $ lines [ $ ctx_ln - 1 ] ! ~ /^-/ ) ;
2008-03-28 14:15:58 -07:00
$ ctx_ln ++ ;
}
2008-07-23 21:29:01 -07:00
2008-07-23 21:29:03 -07:00
# print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n" ;
# print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n" ;
2008-03-28 14:15:58 -07:00
2014-08-06 16:11:05 -07:00
if ( $ ctx ! ~ / { \ s */ && defined ( $ lines [ $ ctx_ln - 1 ] ) && $ lines [ $ ctx_ln - 1 ] =~ /^\+\ s * { / ) {
2011-07-25 17:13:25 -07:00
ERROR ( "OPEN_BRACE" ,
"that open brace { should be on the previous line\n" .
2010-10-26 14:23:19 -07:00
"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n" ) ;
2007-06-08 13:47:06 -07:00
}
2008-03-28 14:15:58 -07:00
if ( $ level == 0 && $ pre_ctx ! ~ / } \ s * while \ s *\ ( $ / &&
$ ctx =~ /\ ) \ s *\ ; \ s * $ / &&
defined $ lines [ $ ctx_ln - 1 ] )
{
2007-10-16 23:29:38 -07:00
my ( $ nlength , $ nindent ) = line_stats ( $ lines [ $ ctx_ln - 1 ] ) ;
if ( $ nindent > $ indent ) {
2011-07-25 17:13:25 -07:00
WARN ( "TRAILING_SEMICOLON" ,
"trailing semicolon indicates no statements, indent implies otherwise\n" .
2010-10-26 14:23:19 -07:00
"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n" ) ;
2007-10-16 23:29:38 -07:00
}
}
2007-06-08 13:47:06 -07:00
}
2008-10-15 22:02:21 -07:00
# Check relative indent for conditionals and blocks .
2017-05-08 15:56:05 -07:00
if ( $ line =~ /\ b ( ?: ( ?: if | while | for | ( ?: [ a - z_ ] + | ) for_each [ a - z_ ] + ) \ s *\ ( | ( ?: do | else ) \ b ) / && $ line ! ~ /^.\ s *#/ && $ line ! ~ /\ } \ s * while \ s */ ) {
2012-01-10 15:10:01 -08:00
( $ stat , $ cond , $ line_nr_next , $ remain_next , $ off_next ) =
ctx_statement_block ( $ linenr , $ realcnt , 0 )
if ( ! defined $ stat ) ;
2008-10-15 22:02:21 -07:00
my ( $ s , $ c ) = ( $ stat , $ cond ) ;
substr ( $ s , 0 , length ( $ c ) , '' ) ;
2015-09-09 15:37:30 -07:00
# remove inline comments
$ s =~ s / $ ; / / g ;
$ c =~ s / $ ; / / g ;
2008-10-15 22:02:21 -07:00
# Find out how long the conditional actually is .
2008-10-15 22:02:27 -07:00
my @ newlines = ( $ c =~ /\ n / gs ) ;
my $ cond_lines = 1 + $ # newlines ;
2008-10-15 22:02:21 -07:00
2015-09-09 15:37:30 -07:00
# Make sure we remove the line prefixes as we have
# none on the first line , and are going to readd them
# where necessary .
$ s =~ s /\ n . /\ n / gs ;
while ( $ s =~ /\ n \ s +\\\ n / ) {
$ cond_lines += $ s =~ s /\ n \ s +\\\ n /\ n / g ;
}
2008-10-15 22:02:21 -07:00
# We want to check the first line inside the block
# starting at the end of the conditional , so remove :
# 1 ) any blank line termination
# 2 ) any opening brace { on end of the line
# 3 ) any do ( . . . ) {
my $ continuation = 0 ;
my $ check = 0 ;
$ s =~ s /^.*\ bdo \ b // ;
$ s =~ s /^\ s * { // ;
if ( $ s =~ s /^\ s *\\// ) {
$ continuation = 1 ;
}
2008-10-15 22:02:22 -07:00
if ( $ s =~ s /^\ s *?\ n // ) {
2008-10-15 22:02:21 -07:00
$ check = 1 ;
$ cond_lines ++ ;
}
# Also ignore a loop construct at the end of a
# preprocessor statement .
if ( ( $ prevline =~ /^.\ s *#\ s * define \ s / | |
$ prevline =~ /\\\ s * $ / ) && $ continuation == 0 ) {
$ check = 0 ;
}
2008-10-15 22:02:22 -07:00
my $ cond_ptr = - 1 ;
2008-10-15 22:02:35 -07:00
$ continuation = 0 ;
2008-10-15 22:02:22 -07:00
while ( $ cond_ptr ! = $ cond_lines ) {
$ cond_ptr = $ cond_lines ;
2008-10-15 22:02:21 -07:00
2008-10-15 22:02:32 -07:00
# If we see an # else /# elif then the code
# is not linear .
if ( $ s =~ /^\ s *\#\ s * ( ?: else | elif ) / ) {
$ check = 0 ;
}
2008-10-15 22:02:22 -07:00
# Ignore :
# 1 ) blank lines , they should be at 0 ,
# 2 ) preprocessor lines , and
# 3 ) labels .
2008-10-15 22:02:35 -07:00
if ( $ continuation | |
$ s =~ /^\ s *?\ n / | |
2008-10-15 22:02:22 -07:00
$ s =~ /^\ s *#\ s *?/ | |
$ s =~ /^\ s * $ Ident \ s *:/ ) {
2008-10-15 22:02:35 -07:00
$ continuation = ( $ s =~ /^.*?\\\ n / ) ? 1 : 0 ;
2009-09-21 17:04:36 -07:00
if ( $ s =~ s /^.*?\ n // ) {
$ cond_lines ++ ;
}
2008-10-15 22:02:22 -07:00
}
2008-10-15 22:02:21 -07:00
}
my ( undef , $ sindent ) = line_stats ( "+" . $ s ) ;
my $ stat_real = raw_line ( $ linenr , $ cond_lines ) ;
# Check if either of these lines are modified , else
# this is not this patch 's fault.
if (!defined($stat_real) ||
$stat !~ /^\+/ && $stat_real !~ /^\+/) {
$check = 0;
}
if (defined($stat_real) && $cond_lines > 1) {
$stat_real = "[...]\n$stat_real";
}
2008-10-15 22:02:22 -07:00
#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";
2008-10-15 22:02:21 -07:00
2015-09-09 15:37:30 -07:00
if ($check && $s ne '' &&
2020-04-06 20:11:07 -07:00
(($sindent % $tabsize) != 0 ||
2015-09-09 15:37:30 -07:00
($sindent < $indent) ||
2017-05-08 15:56:05 -07:00
($sindent == $indent &&
($s !~ /^\s*(?:\}|\{|else\b)/)) ||
2020-04-06 20:11:07 -07:00
($sindent > $indent + $tabsize))) {
2011-07-25 17:13:25 -07:00
WARN("SUSPECT_CODE_INDENT",
"suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
2008-10-15 22:02:21 -07:00
}
}
2007-10-18 03:05:08 -07:00
# Track the ' values ' across context and added lines.
my $opline = $line; $opline =~ s/^./ /;
2008-07-23 21:29:10 -07:00
my ($curr_values, $curr_vars) =
annotate_values($opline . "\n", $prev_values);
2007-10-18 03:05:08 -07:00
$curr_values = $prev_values . $curr_values;
2008-02-08 04:20:54 -08:00
if ($dbg_values) {
my $outline = $opline; $outline =~ s/\t/ /g;
2008-03-04 14:28:20 -08:00
print "$linenr > .$outline\n";
print "$linenr > $curr_values\n";
2008-07-23 21:29:10 -07:00
print "$linenr > $curr_vars\n";
2008-02-08 04:20:54 -08:00
}
2007-10-18 03:05:08 -07:00
$prev_values = substr($curr_values, -1);
2007-06-08 13:47:06 -07:00
#ignore lines not being added
2013-07-03 15:05:31 -07:00
next if ($line =~ /^[^\+]/);
2007-06-08 13:47:06 -07:00
2020-10-15 20:12:09 -07:00
# check for self assignments used to avoid compiler warnings
# e.g.: int foo = foo, *bar = NULL;
# struct foo bar = *(&(bar));
if ($line =~ /^\+\s*(?:$Declare)?([A-Za-z_][A-Za-z\d_]*)\s*=/) {
my $var = $1;
if ($line =~ /^\+\s*(?:$Declare)?$var\s*=\s*(?:$var|\*\s*\(?\s*&\s*\(?\s*$var\s*\)?\s*\)?)\s*[;,]/) {
WARN("SELF_ASSIGNMENT",
"Do not use self-assignments to avoid compiler warnings\n" . $herecurr);
}
}
2016-12-12 16:46:31 -08:00
# check for dereferences that span multiple lines
if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ &&
$line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) {
$prevline =~ /($Lval\s*(?:\.|->))\s*$/;
my $ref = $1;
$line =~ /^.\s*($Lval)/;
$ref .= $1;
$ref =~ s/\s//g;
WARN("MULTILINE_DEREFERENCE",
"Avoid multiple line dereference - prefer ' $ ref '\n" . $hereprev);
}
2016-03-15 14:58:03 -07:00
# check for declarations of signed or unsigned without int
2016-08-02 14:04:42 -07:00
while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) {
2016-03-15 14:58:03 -07:00
my $type = $1;
my $var = $2;
2016-03-15 14:58:06 -07:00
$var = "" if (!defined $var);
if ($type =~ /^(?:(?:$Storage|$Inline|$Attribute)\s+)*((?:un)?signed)((?:\s*\*)*)\s*$/) {
2016-03-15 14:58:03 -07:00
my $sign = $1;
my $pointer = $2;
$pointer = "" if (!defined $pointer);
if (WARN("UNSPECIFIED_INT",
"Prefer ' " . trim($sign) . " int " . rtrim($pointer) . " ' to bare use of ' $ sign " . rtrim($pointer) . " '\n" . $herecurr) &&
$fix) {
my $decl = trim($sign) . " int ";
2016-03-15 14:58:06 -07:00
my $comp_pointer = $pointer;
$comp_pointer =~ s/\s//g;
$decl .= $comp_pointer;
$decl = rtrim($decl) if ($var eq "");
$fixed[$fixlinenr] =~ s@\b$sign\s*\Q$pointer\E\s*$var\b@$decl$var@;
2016-03-15 14:58:03 -07:00
}
}
}
2007-06-23 17:16:34 -07:00
# TEST: allow direct testing of the type matcher.
2008-07-23 21:29:06 -07:00
if ($dbg_type) {
if ($line =~ /^.\s*$Declare\s*$/) {
2011-07-25 17:13:25 -07:00
ERROR("TEST_TYPE",
"TEST: is type\n" . $herecurr);
2008-07-23 21:29:06 -07:00
} elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
2011-07-25 17:13:25 -07:00
ERROR("TEST_NOT_TYPE",
"TEST: is not type ($1 is)\n". $herecurr);
2008-07-23 21:29:06 -07:00
}
2007-06-23 17:16:34 -07:00
next;
}
2008-10-15 22:02:17 -07:00
# TEST: allow direct testing of the attribute matcher.
if ($dbg_attr) {
2009-02-27 14:03:08 -08:00
if ($line =~ /^.\s*$Modifier\s*$/) {
2011-07-25 17:13:25 -07:00
ERROR("TEST_ATTR",
"TEST: is attr\n" . $herecurr);
2009-02-27 14:03:08 -08:00
} elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
2011-07-25 17:13:25 -07:00
ERROR("TEST_NOT_ATTR",
"TEST: is not attr ($1 is)\n". $herecurr);
2008-10-15 22:02:17 -07:00
}
next;
}
2007-06-23 17:16:34 -07:00
2007-07-19 01:48:34 -07:00
# check for initialisation to aggregates open brace on the next line
2009-10-26 16:50:15 -07:00
if ($line =~ /^.\s*{/ &&
$prevline =~ /(?:^|[^=])=\s*$/) {
2014-08-06 16:11:05 -07:00
if (ERROR("OPEN_BRACE",
"that open brace { should be on the previous line\n" . $hereprev) &&
2014-08-06 16:11:07 -07:00
$fix && $prevline =~ /^\+/ && $line =~ /^\+/) {
fix_delete_line($fixlinenr - 1, $prevrawline);
fix_delete_line($fixlinenr, $rawline);
2014-08-06 16:11:05 -07:00
my $fixedline = $prevrawline;
$fixedline =~ s/\s*=\s*$/ = {/;
2014-08-06 16:11:07 -07:00
fix_insert_line($fixlinenr, $fixedline);
2014-08-06 16:11:05 -07:00
$fixedline = $line;
2017-07-10 15:52:21 -07:00
$fixedline =~ s/^(.\s*)\{\s*/$1/;
2014-08-06 16:11:07 -07:00
fix_insert_line($fixlinenr, $fixedline);
2014-08-06 16:11:05 -07:00
}
2007-07-19 01:48:34 -07:00
}
2007-06-23 17:16:34 -07:00
#
# Checks which are anchored on the added line.
#
# check for malformed paths in #include statements (uses RAW line)
2008-06-05 22:46:01 -07:00
if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
2007-06-23 17:16:34 -07:00
my $path = $1;
if ($path =~ m{//}) {
2011-07-25 17:13:25 -07:00
ERROR("MALFORMED_INCLUDE",
2012-12-20 15:05:37 -08:00
"malformed #include filename\n" . $herecurr);
}
if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) {
ERROR("UAPI_INCLUDE",
"No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr);
2007-06-23 17:16:34 -07:00
}
}
2007-06-08 13:47:06 -07:00
# no C99 // comments
if ($line =~ m{//}) {
2013-07-03 15:05:31 -07:00
if (ERROR("C99_COMMENTS",
"do not use C99 // comments\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
my $line = $fixed[$fixlinenr];
2013-07-03 15:05:31 -07:00
if ($line =~ /\/\/(.*)$/) {
my $comment = trim($1);
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s@\/\/(.*)$@/\* $comment \*/@;
2013-07-03 15:05:31 -07:00
}
}
2007-06-08 13:47:06 -07:00
}
# Remove C99 comments.
2007-06-01 00:46:48 -07:00
$line =~ s@//.*@@;
2007-10-18 03:05:08 -07:00
$opline =~ s@//.*@@;
2007-06-01 00:46:48 -07:00
2009-10-26 16:50:16 -07:00
# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
# the whole statement.
#print "APW <$lines[$realline_next - 1]>\n";
if (defined $realline_next &&
exists $lines[$realline_next - 1] &&
!defined $suppress_export{$realline_next} &&
($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
$lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
2010-10-26 14:23:18 -07:00
# Handle definitions which produce identifiers with
# a prefix:
# XXX(foo);
# EXPORT_SYMBOL(something_foo);
2007-06-23 17:16:34 -07:00
my $name = $1;
2012-01-10 15:10:04 -08:00
if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
2010-10-26 14:23:18 -07:00
$name =~ /^${Ident}_$2/) {
#print "FOO C name<$name>\n";
$suppress_export{$realline_next} = 1;
} elsif ($stat !~ /(?:
2009-10-26 16:50:16 -07:00
\n.}\s*$|
2008-10-15 22:02:34 -07:00
^.DEFINE_$Ident\(\Q$name\E\)|
^.DECLARE_$Ident\(\Q$name\E\)|
^.LIST_HEAD\(\Q$name\E\)|
2009-10-26 16:50:16 -07:00
^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
\b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
2008-10-15 22:02:34 -07:00
)/x) {
2009-10-26 16:50:16 -07:00
#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
$suppress_export{$realline_next} = 2;
} else {
$suppress_export{$realline_next} = 1;
2007-06-01 00:46:48 -07:00
}
}
2009-10-26 16:50:16 -07:00
if (!defined $suppress_export{$linenr} &&
$prevline =~ /^.\s*$/ &&
($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
$line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
#print "FOO B <$lines[$linenr - 1]>\n";
$suppress_export{$linenr} = 2;
}
if (defined $suppress_export{$linenr} &&
$suppress_export{$linenr} == 2) {
2011-07-25 17:13:25 -07:00
WARN("EXPORT_SYMBOL",
"EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
2009-10-26 16:50:16 -07:00
}
2007-06-01 00:46:48 -07:00
2010-08-09 17:21:00 -07:00
# check for global initialisers.
2015-11-06 16:31:37 -08:00
if ($line =~ /^\+$Type\s*$Ident(?:\s+$Modifier)*\s*=\s*($zero_initializer)\s*;/) {
2013-09-11 14:23:54 -07:00
if (ERROR("GLOBAL_INITIALISERS",
2015-11-06 16:31:37 -08:00
"do not initialise globals to $1\n" . $herecurr) &&
2013-09-11 14:23:54 -07:00
$fix) {
2015-11-06 16:31:37 -08:00
$fixed[$fixlinenr] =~ s/(^.$Type\s*$Ident(?:\s+$Modifier)*)\s*=\s*$zero_initializer\s*;/$1;/;
2013-09-11 14:23:54 -07:00
}
2007-07-19 01:48:34 -07:00
}
2007-06-23 17:16:34 -07:00
# check for static initialisers.
2015-11-06 16:31:37 -08:00
if ($line =~ /^\+.*\bstatic\s.*=\s*($zero_initializer)\s*;/) {
2013-09-11 14:23:54 -07:00
if (ERROR("INITIALISED_STATIC",
2015-11-06 16:31:37 -08:00
"do not initialise statics to $1\n" .
2013-09-11 14:23:54 -07:00
$herecurr) &&
$fix) {
2015-11-06 16:31:37 -08:00
$fixed[$fixlinenr] =~ s/(\bstatic\s.*?)\s*=\s*$zero_initializer\s*;/$1;/;
2013-09-11 14:23:54 -07:00
}
2007-06-01 00:46:48 -07:00
}
2014-08-06 16:11:22 -07:00
# check for misordered declarations of char/short/int/long with signed/unsigned
while ($sline =~ m{(\b$TypeMisordered\b)}g) {
my $tmp = trim($1);
WARN("MISORDERED_TYPE",
"type ' $ tmp ' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr);
}
2018-08-21 21:58:12 -07:00
# check for unnecessary <signed> int declarations of short/long/long long
while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) {
my $type = trim($1);
next if ($type !~ /\bint\b/);
next if ($type !~ /\b(?:short|long\s+long|long)\b/);
my $new_type = $type;
$new_type =~ s/\b\s*int\s*\b/ /;
$new_type =~ s/\b\s*(?:un)?signed\b\s*/ /;
$new_type =~ s/^const\s+//;
$new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/);
$new_type = "const $new_type" if ($type =~ /^const\b/);
$new_type =~ s/\s+/ /g;
$new_type = trim($new_type);
if (WARN("UNNECESSARY_INT",
"Prefer ' $ new_type ' over ' $ type ' as the int is unnecessary\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/;
}
}
2010-10-26 14:23:20 -07:00
# check for static const char * arrays.
if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
2011-07-25 17:13:25 -07:00
WARN("STATIC_CONST_CHAR_ARRAY",
"static const char * array should probably be static const char * const\n" .
2010-10-26 14:23:20 -07:00
$herecurr);
2019-01-03 15:26:59 -08:00
}
# check for initialized const char arrays that should be static const
if ($line =~ /^\+\s*const\s+(char|unsigned\s+char|_*u8|(?:[us]_)?int8_t)\s+\w+\s*\[\s*(?:\w+\s*)?\]\s*=\s*"/) {
if (WARN("STATIC_CONST_CHAR_ARRAY",
"const array should probably be static const\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/(^.\s*)const\b/${1}static const/;
}
}
2010-10-26 14:23:20 -07:00
# check for static char foo[] = "bar" declarations.
if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) {
2011-07-25 17:13:25 -07:00
WARN("STATIC_CONST_CHAR_ARRAY",
"static char array declaration should probably be static const char\n" .
2010-10-26 14:23:20 -07:00
$herecurr);
2019-01-03 15:26:59 -08:00
}
2010-10-26 14:23:20 -07:00
2015-04-16 12:44:22 -07:00
# 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);
}
}
2020-12-15 20:44:30 -08:00
# check for const static or static <non ptr type> const declarations
# prefer ' static const < foo > ' over ' const static < foo > ' and ' static < foo > const '
if ($sline =~ /^\+\s*const\s+static\s+($Type)\b/ ||
$sline =~ /^\+\s*static\s+($BasicType)\s+const\b/) {
if (WARN("STATIC_CONST",
"Move const after static - use ' static const $ 1 '\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bconst\s+static\b/static const/;
$fixed[$fixlinenr] =~ s/\bstatic\s+($BasicType)\s+const\b/static const $1/;
}
}
2014-04-03 14:49:18 -07:00
# 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",
"char * array declaration might be better as static const\n" .
$herecurr);
}
2015-04-16 12:44:36 -07:00
# 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)/;
}
}
}
2014-01-27 17:07:18 -08:00
# check for function declarations without arguments like "int foo()"
2020-04-06 20:11:17 -07:00
if ($line =~ /(\b$Type\s*$Ident)\s*\(\s*\)/) {
2014-01-27 17:07:18 -08:00
if (ERROR("FUNCTION_WITHOUT_ARGS",
"Bad function definition - $1() should probably be $1(void)\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/;
2014-01-27 17:07:18 -08:00
}
}
2007-06-23 17:16:34 -07:00
# check for new typedefs, only function parameters and sparse annotations
# make sense.
if ($line =~ /\btypedef\s/ &&
2009-01-06 14:41:26 -08:00
$line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
2008-06-05 22:46:01 -07:00
$line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
2008-10-15 22:02:32 -07:00
$line !~ /\b$typeTypedefs\b/ &&
2016-12-11 06:29:58 +02:00
$line !~ /\b__bitwise\b/) {
2011-07-25 17:13:25 -07:00
WARN("NEW_TYPEDEFS",
"do not add new typedefs\n" . $herecurr);
2007-06-01 00:46:48 -07:00
}
# * goes on variable not on type
2009-01-06 14:41:21 -08:00
# (char*[ const])
2012-01-10 15:10:15 -08:00
while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) {
#print "AA<$1>\n";
2013-07-03 15:05:31 -07:00
my ($ident, $from, $to) = ($1, $2, $2);
2007-06-23 17:16:44 -07:00
2009-01-06 14:41:21 -08:00
# Should start with a space.
$to =~ s/^(\S)/ $1/;
# Should not end with a space.
$to =~ s/\s+$//;
# ' * 's should not have spaces between.
2009-01-15 13:51:05 -08:00
while ($to =~ s/\*\s+\*/\*\*/) {
2009-01-06 14:41:21 -08:00
}
2007-06-23 17:16:44 -07:00
2013-07-03 15:05:31 -07:00
## print "1: from<$from> to<$to> ident<$ident>\n";
2009-01-06 14:41:21 -08:00
if ($from ne $to) {
2013-07-03 15:05:31 -07:00
if (ERROR("POINTER_LOCATION",
"\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr) &&
$fix) {
my $sub_from = $ident;
my $sub_to = $ident;
$sub_to =~ s/\Q$from\E/$to/;
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~
2013-07-03 15:05:31 -07:00
s@\Q$sub_from\E@$sub_to@;
}
2009-01-06 14:41:21 -08:00
}
2012-01-10 15:10:15 -08:00
}
while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) {
#print "BB<$1>\n";
2013-07-03 15:05:31 -07:00
my ($match, $from, $to, $ident) = ($1, $2, $2, $3);
2007-06-23 17:16:44 -07:00
2009-01-06 14:41:21 -08:00
# Should start with a space.
$to =~ s/^(\S)/ $1/;
# Should not end with a space.
$to =~ s/\s+$//;
# ' * 's should not have spaces between.
2009-01-15 13:51:05 -08:00
while ($to =~ s/\*\s+\*/\*\*/) {
2009-01-06 14:41:21 -08:00
}
# Modifiers should have spaces.
$to =~ s/(\b$Modifier$)/$1 /;
2013-07-03 15:05:31 -07:00
## print "2: from<$from> to<$to> ident<$ident>\n";
2009-02-27 14:03:08 -08:00
if ($from ne $to && $ident !~ /^$Modifier$/) {
2013-07-03 15:05:31 -07:00
if (ERROR("POINTER_LOCATION",
"\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr) &&
$fix) {
my $sub_from = $match;
my $sub_to = $match;
$sub_to =~ s/\Q$from\E/$to/;
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~
2013-07-03 15:05:31 -07:00
s@\Q$sub_from\E@$sub_to@;
}
2009-01-06 14:41:21 -08:00
}
2007-06-01 00:46:48 -07:00
}
2015-09-09 15:37:27 -07:00
# avoid BUG() or BUG_ON()
if ($line =~ /\b(?:BUG|BUG_ON)\b/) {
2017-09-08 16:16:07 -07:00
my $msg_level = \&WARN;
$msg_level = \&CHK if ($file);
&{$msg_level}("AVOID_BUG",
"Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr);
2015-09-09 15:37:27 -07:00
}
2007-06-01 00:46:48 -07:00
2015-09-09 15:37:27 -07:00
# avoid LINUX_VERSION_CODE
2007-11-28 16:21:06 -08:00
if ($line =~ /\bLINUX_VERSION_CODE\b/) {
2011-07-25 17:13:25 -07:00
WARN("LINUX_VERSION_CODE",
"LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
2007-11-28 16:21:06 -08:00
}
2011-06-15 15:08:17 -07:00
# check for uses of printk_ratelimit
if ($line =~ /\bprintk_ratelimit\s*\(/) {
2011-07-25 17:13:25 -07:00
WARN("PRINTK_RATELIMITED",
2015-02-13 14:38:54 -08:00
"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
2011-06-15 15:08:17 -07:00
}
2017-11-17 15:28:41 -08:00
# printk should use KERN_* levels
if ($line =~ /\bprintk\s*\(\s*(?!KERN_[A-Z]+\b)/) {
WARN("PRINTK_WITHOUT_KERN_LEVEL",
"printk() should include KERN_<LEVEL> facility level\n" . $herecurr);
2007-06-01 00:46:48 -07:00
}
2020-12-15 20:45:24 -08:00
# prefer variants of (subsystem|netdev|dev|pr)_<level> to printk(KERN_<LEVEL>
if ($line =~ /\b(printk(_once|_ratelimited)?)\s*\(\s*KERN_([A-Z]+)/) {
my $printk = $1;
my $modifier = $2;
my $orig = $3;
$modifier = "" if (!defined($modifier));
2012-05-31 16:26:09 -07:00
my $level = lc($orig);
$level = "warn" if ($level eq "warning");
2012-10-04 17:13:32 -07:00
my $level2 = $level;
$level2 = "dbg" if ($level eq "debug");
2020-12-15 20:45:24 -08:00
$level .= $modifier;
$level2 .= $modifier;
2012-05-31 16:26:09 -07:00
WARN("PREFER_PR_LEVEL",
2020-12-15 20:45:24 -08:00
"Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to $printk(KERN_$orig ...\n" . $herecurr);
2012-05-31 16:26:09 -07:00
}
2020-12-15 20:45:24 -08:00
# prefer dev_<level> to dev_printk(KERN_<LEVEL>
2013-02-21 16:44:13 -08:00
if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) {
my $orig = $1;
my $level = lc($orig);
$level = "warn" if ($level eq "warning");
$level = "dbg" if ($level eq "debug");
WARN("PREFER_DEV_LEVEL",
"Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr);
}
2020-10-15 20:12:02 -07:00
# trace_printk should not be used in production code.
if ($line =~ /\b(trace_printk|trace_puts|ftrace_vprintk)\s*\(/) {
WARN("TRACE_PRINTK",
"Do not use $1() in production code (this can be ignored if built only with a debug config option)\n" . $herecurr);
}
2015-04-16 12:44:44 -07:00
# 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);
}
2020-05-11 10:08:07 -07:00
# ENOTSUPP is not a standard error code and should be avoided in new patches.
# Folks usually mean EOPNOTSUPP (also called ENOTSUP), when they type ENOTSUPP.
# Similarly to ENOSYS warning a small number of false positives is expected.
if (!$file && $line =~ /\bENOTSUPP\b/) {
if (WARN("ENOTSUPP",
"ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bENOTSUPP\b/EOPNOTSUPP/;
}
}
2007-06-23 17:16:34 -07:00
# function brace can' t be on same line , except for # defines of do while ,
# or if closed on same line
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2018-02-06 15:39:09 -08:00
$ sline =~ / $ Type \ s * $ Ident \ s * $ balanced_parens \ s *\ { / &&
$ sline ! ~ /\#\ s * define \ b . * do \ s *\ { / &&
$ sline ! ~ / } / ) {
2014-08-06 16:11:12 -07:00
if ( ERROR ( "OPEN_BRACE" ,
2018-02-06 15:39:09 -08:00
"open brace '{' following function definitions go on the next line\n" . $ herecurr ) &&
2014-08-06 16:11:12 -07:00
$ fix ) {
fix_delete_line ( $ fixlinenr , $ rawline ) ;
my $ fixed_line = $ rawline ;
2020-12-15 20:45:02 -08:00
$ fixed_line =~ / ( ^..* $ Type \ s * $ Ident \ ( . *\ ) \ s * ) \ { ( . * ) $ / ;
2014-08-06 16:11:12 -07:00
my $ line1 = $ 1 ;
my $ line2 = $ 2 ;
fix_insert_line ( $ fixlinenr , ltrim ( $ line1 ) ) ;
fix_insert_line ( $ fixlinenr , " \+ { ");
if ($line2 !~ /^\s*$/) {
fix_insert_line($fixlinenr, " \+\ t " . trim($line2));
}
}
2007-06-01 00:46:48 -07:00
}
2007-06-23 17:16:34 -07:00
2007-11-28 16:21:06 -08:00
# open braces for enum, union and struct go on the same line.
if ($line =~ /^.\s*{/ &&
$prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
2014-08-06 16:11:12 -07:00
if (ERROR(" OPEN_BRACE ",
" open brace '{' following $ 1 go on the same line \ n " . $ hereprev ) &&
$ fix && $ prevline =~ /^\+/ && $ line =~ /^\+/ ) {
fix_delete_line ( $ fixlinenr - 1 , $ prevrawline ) ;
fix_delete_line ( $ fixlinenr , $ rawline ) ;
my $ fixedline = rtrim ( $ prevrawline ) . " {" ;
fix_insert_line ( $ fixlinenr , $ fixedline ) ;
$ fixedline = $ rawline ;
2017-07-10 15:52:21 -07:00
$ fixedline =~ s /^ ( . \ s * ) \ { \ s */ $ 1 \ t / ;
2014-08-06 16:11:12 -07:00
if ( $ fixedline ! ~ /^\+\ s * $ / ) {
fix_insert_line ( $ fixlinenr , $ fixedline ) ;
}
}
2007-11-28 16:21:06 -08:00
}
2010-10-26 14:23:15 -07:00
# missing space after union , struct or enum definition
2013-07-03 15:05:31 -07:00
if ( $ line =~ /^.\ s * ( ?: typedef \ s + ) ? ( enum | union | struct ) ( ?:\ s + $ Ident ) { 1 , 2 } [ =\ { ] / ) {
if ( WARN ( "SPACING" ,
"missing space after $1 definition\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /^ ( . \ s * ( ?: typedef \ s + ) ? ( ?: enum | union | struct ) ( ?:\ s + $ Ident ) { 1 , 2 } ) ( [ =\ { ] ) / $ 1 $ 2 / ;
}
2010-10-26 14:23:15 -07:00
}
2014-01-23 15:54:49 -08:00
# Function pointer declarations
# check spacing between type , funcptr , and args
# canonical declaration is "type (*funcptr)(args...)"
2014-04-03 14:49:12 -07:00
if ( $ line =~ /^.\ s * ( $ Declare ) \ ( ( \ s * ) \* ( \ s * ) ( $ Ident ) ( \ s * ) \ ) ( \ s * ) \ ( / ) {
2014-01-23 15:54:49 -08:00
my $ declare = $ 1 ;
my $ pre_pointer_space = $ 2 ;
my $ post_pointer_space = $ 3 ;
my $ funcname = $ 4 ;
my $ post_funcname_space = $ 5 ;
my $ pre_args_space = $ 6 ;
2014-04-03 14:49:12 -07:00
# the $ Declare variable will capture all spaces after the type
# so check it for a missing trailing missing space but pointer return types
# don 't need a space so don' t warn for those .
my $ post_declare_space = "" ;
if ( $ declare =~ / ( \ s + ) $ / ) {
$ post_declare_space = $ 1 ;
$ declare = rtrim ( $ declare ) ;
}
if ( $ declare ! ~ /\* $ / && $ post_declare_space =~ /^ $ / ) {
2014-01-23 15:54:49 -08:00
WARN ( "SPACING" ,
"missing space after return type\n" . $ herecurr ) ;
2014-04-03 14:49:12 -07:00
$ post_declare_space = " " ;
2014-01-23 15:54:49 -08:00
}
# unnecessary space "type (*funcptr)(args...)"
2014-04-03 14:49:12 -07:00
# This test is not currently implemented because these declarations are
# equivalent to
# int foo ( int bar , . . . )
# and this is form shouldn 't/doesn' t generate a checkpatch warning .
#
# elsif ( $ declare =~ /\ s { 2 , } $ / ) {
# WARN ( "SPACING" ,
# "Multiple spaces after return type\n" . $ herecurr ) ;
# }
2014-01-23 15:54:49 -08:00
# unnecessary space "type ( *funcptr)(args...)"
if ( defined $ pre_pointer_space &&
$ pre_pointer_space =~ /^\ s / ) {
WARN ( "SPACING" ,
"Unnecessary space after function pointer open parenthesis\n" . $ herecurr ) ;
}
# unnecessary space "type (* funcptr)(args...)"
if ( defined $ post_pointer_space &&
$ post_pointer_space =~ /^\ s / ) {
WARN ( "SPACING" ,
"Unnecessary space before function pointer name\n" . $ herecurr ) ;
}
# unnecessary space "type (*funcptr )(args...)"
if ( defined $ post_funcname_space &&
$ post_funcname_space =~ /^\ s / ) {
WARN ( "SPACING" ,
"Unnecessary space after function pointer name\n" . $ herecurr ) ;
}
# unnecessary space "type (*funcptr) (args...)"
if ( defined $ pre_args_space &&
$ pre_args_space =~ /^\ s / ) {
WARN ( "SPACING" ,
"Unnecessary space before function pointer arguments\n" . $ herecurr ) ;
}
if ( show_type ( "SPACING" ) && $ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2014-04-03 14:49:12 -07:00
s /^ ( . \ s * ) $ Declare \ s *\ ( \ s *\*\ s * $ Ident \ s *\ ) \ s *\ ( / $ 1 . $ declare . $ post_declare_space . '(*' . $ funcname . ')(' / ex ;
2014-01-23 15:54:49 -08:00
}
}
2008-07-23 21:29:02 -07:00
# check for spacing round square brackets ; allowed :
# 1. with a type on the left -- int [ ] a ;
2008-10-15 22:02:15 -07:00
# 2. at the beginning of a line for slice initialisers -- [ 0. . .10 ] = 5 ,
# 3. inside a curly brace -- = { [ 0. . .10 ] = 5 }
2008-07-23 21:29:02 -07:00
while ( $ line =~ / ( . *?\ s ) \ [ / g ) {
my ( $ where , $ prefix ) = ( $ - [ 1 ] , $ 1 ) ;
if ( $ prefix ! ~ / $ Type \ s + $ / &&
2008-10-15 22:02:15 -07:00
( $ where ! = 0 | | $ prefix ! ~ /^.\ s + $ / ) &&
2018-04-10 16:34:14 -07:00
$ prefix ! ~ / [ { , : ] \ s + $ / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "BRACKET_SPACE" ,
"space prohibited before open square bracket '['\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /^ ( \+.*? ) \ s +\ [ / $ 1 \ [ / ;
}
2008-07-23 21:29:02 -07:00
}
}
2007-07-19 01:48:34 -07:00
# check for spaces between functions and their parentheses .
2007-10-18 03:05:08 -07:00
while ( $ line =~ / ( $ Ident ) \ s +\ ( / g ) {
2008-02-08 04:20:54 -08:00
my $ name = $ 1 ;
2008-03-28 14:15:58 -07:00
my $ ctx_before = substr ( $ line , 0 , $ - [ 1 ] ) ;
my $ ctx = "$ctx_before$name" ;
2008-02-08 04:20:54 -08:00
# Ignore those directives where spaces _ are_ permitted .
2008-03-28 14:15:58 -07:00
if ( $ name =~ /^ ( ?:
if | for | while | switch | return | case |
volatile | _ _ volatile__ |
_ _ attribute__ | format | _ _ extension__ |
asm | _ _ asm__ ) $ / x )
{
2008-02-08 04:20:54 -08:00
# 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 .
2008-06-05 22:46:01 -07:00
} elsif ( $ ctx_before =~ /^.\ s *\#\ s * define \ s * $ / ) {
2008-03-28 14:15:58 -07:00
# cpp # elif statement condition may start with a (
2008-06-05 22:46:01 -07:00
} elsif ( $ ctx =~ /^.\ s *\#\ s * elif \ s * $ / ) {
2008-02-08 04:20:54 -08:00
# If this whole things ends with a type its most
# likely a typedef for a function .
2008-03-28 14:15:58 -07:00
} elsif ( $ ctx =~ / $ Type $ / ) {
2008-02-08 04:20:54 -08:00
} else {
2013-07-03 15:05:31 -07:00
if ( WARN ( "SPACING" ,
"space prohibited between function name and open parenthesis '('\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /\ b$name \ s +\ ( / $ name \ ( / ;
}
2007-10-18 03:05:08 -07:00
}
2007-07-19 01:48:34 -07:00
}
2012-05-31 16:26:09 -07:00
2007-06-23 17:16:34 -07:00
# Check operator spacing .
2007-06-01 00:46:48 -07:00
if ( ! ( $ line =~/\#\ s * include / ) ) {
2013-07-03 15:05:31 -07:00
my $ fixed_line = "" ;
my $ line_fixed = 0 ;
2007-10-16 23:29:38 -07:00
my $ ops = qr {
<<= | >>= | <= | >= | == | ! = |
\+= | -= | \*= | \/= | %=|\^=|\|=|&=|
=> | -> | << | >> | < | > | = | ! | ~ |
2008-07-23 21:29:10 -07:00
&& | \ | \ | | , | \^ | \+\+ | -- | & | \ | | \+ | - | \* | \/ | %|
2013-11-12 15:10:05 -08:00
\?: | \? | :
2007-10-16 23:29:38 -07:00
} x ;
2008-03-04 14:28:20 -08:00
my @ elements = split ( / ( $ ops | ; ) / , $ opline ) ;
2013-07-03 15:05:31 -07:00
## print ( "element count: <" . $ # elements . ">\n" ) ;
## foreach my $ el ( @ elements ) {
## print ( "el: <$el>\n" ) ;
## }
my @ fix_elements = ( ) ;
2007-06-08 13:47:06 -07:00
my $ off = 0 ;
2007-10-18 03:05:08 -07:00
2013-07-03 15:05:31 -07:00
foreach my $ el ( @ elements ) {
push ( @ fix_elements , substr ( $ rawline , $ off , length ( $ el ) ) ) ;
$ off += length ( $ el ) ;
}
$ off = 0 ;
2007-10-18 03:05:08 -07:00
my $ blank = copy_spacing ( $ opline ) ;
2013-09-11 14:24:01 -07:00
my $ last_after = - 1 ;
2007-10-18 03:05:08 -07:00
2007-06-01 00:46:48 -07:00
for ( my $ n = 0 ; $ n < $ # elements ; $ n += 2 ) {
2013-07-03 15:05:31 -07:00
my $ good = $ fix_elements [ $ n ] . $ fix_elements [ $ n + 1 ] ;
## print ( "n: <$n> good: <$good>\n" ) ;
2007-06-08 13:46:39 -07:00
$ off += length ( $ elements [ $ n ] ) ;
2011-03-30 22:57:33 -03:00
# Pick up the preceding and succeeding characters .
2008-03-28 14:15:58 -07:00
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" ;
2007-06-08 13:46:39 -07:00
my $ a = '' ;
$ a = 'V' if ( $ elements [ $ n ] ne '' ) ;
$ a = 'W' if ( $ elements [ $ n ] =~ /\ s$ / ) ;
2008-03-04 14:28:20 -08:00
$ a = 'C' if ( $ elements [ $ n ] =~ / $ ; $ / ) ;
2007-06-08 13:46:39 -07:00
$ a = 'B' if ( $ elements [ $ n ] =~ / ( \ [ | \ ( ) $ / ) ;
$ a = 'O' if ( $ elements [ $ n ] eq '' ) ;
2008-03-28 14:15:58 -07:00
$ a = 'E' if ( $ ca =~ /^\ s * $ / ) ;
2007-06-08 13:46:39 -07:00
2007-06-01 00:46:48 -07:00
my $ op = $ elements [ $ n + 1 ] ;
2007-06-08 13:46:39 -07:00
my $ c = '' ;
2007-06-01 00:46:48 -07:00
if ( defined $ elements [ $ n + 2 ] ) {
2007-06-08 13:46:39 -07:00
$ c = 'V' if ( $ elements [ $ n + 2 ] ne '' ) ;
$ c = 'W' if ( $ elements [ $ n + 2 ] =~ /^\ s / ) ;
2008-03-04 14:28:20 -08:00
$ c = 'C' if ( $ elements [ $ n + 2 ] =~ /^ $ ; / ) ;
2007-06-08 13:46:39 -07:00
$ c = 'B' if ( $ elements [ $ n + 2 ] =~ /^ ( \ ) | \ ] | ; ) / ) ;
$ c = 'O' if ( $ elements [ $ n + 2 ] eq '' ) ;
2009-01-06 14:41:27 -08:00
$ c = 'E' if ( $ elements [ $ n + 2 ] =~ /^\ s *\\ $ / ) ;
2007-06-08 13:46:39 -07:00
} else {
$ c = 'E' ;
2007-06-01 00:46:48 -07:00
}
2007-06-08 13:46:39 -07:00
my $ ctx = "${a}x${c}" ;
my $ at = "(ctx:$ctx)" ;
2007-10-18 03:05:08 -07:00
my $ ptr = substr ( $ blank , 0 , $ off ) . "^" ;
2007-07-15 23:37:22 -07:00
my $ hereptr = "$hereline$ptr\n" ;
2007-06-01 00:46:48 -07:00
2008-07-23 21:29:10 -07:00
# Pull out the value of this operator .
2007-10-18 03:05:08 -07:00
my $ op_type = substr ( $ curr_values , $ off + 1 , 1 ) ;
2007-06-01 00:46:48 -07:00
2008-07-23 21:29:10 -07:00
# Get the full operator variant .
my $ opv = $ op . substr ( $ curr_vars , $ off , 1 ) ;
2008-02-08 04:22:03 -08:00
# Ignore operators passed as parameters .
if ( $ op_type ne 'V' &&
2015-04-16 12:44:39 -07:00
$ ca =~ /\ s$ / && $ cc =~ /^\ s * [ , \ ) ] / ) {
2008-02-08 04:22:03 -08:00
2008-03-04 14:28:20 -08:00
# # Ignore comments
# } elsif ( $ op =~ /^ $ ; + $ / ) {
2008-02-08 04:22:03 -08:00
2007-06-23 17:16:44 -07:00
# ; should have either the end of line or a space or \ after it
2008-02-08 04:22:03 -08:00
} elsif ( $ op eq ';' ) {
2008-03-04 14:28:20 -08:00
if ( $ ctx ! ~ /. x [ WEBC ] / &&
$ cc ! ~ /^\\/ && $ cc ! ~ /^ ; / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space required after that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = $ fix_elements [ $ n ] . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
2013-07-03 15:05:31 -07:00
$ line_fixed = 1 ;
}
2007-06-23 17:16:44 -07:00
}
# // is a comment
} elsif ( $ op eq '//' ) {
2007-06-01 00:46:48 -07:00
2014-04-03 14:49:33 -07:00
# : when part of a bitfield
} elsif ( $ opv eq ':B' ) {
# skip the bitfield test for now
2008-07-23 21:29:10 -07:00
# No spaces for :
# ->
2014-04-03 14:49:33 -07:00
} elsif ( $ op eq '->' ) {
2007-06-08 13:46:39 -07:00
if ( $ ctx =~ / Wx . | . xW / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"spaces prohibited around that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = rtrim ( $ fix_elements [ $ n ] ) . trim ( $ fix_elements [ $ n + 1 ] ) ;
2013-07-03 15:05:31 -07:00
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s /^\ s +// ;
}
2013-09-11 14:24:01 -07:00
$ line_fixed = 1 ;
2013-07-03 15:05:31 -07:00
}
2007-06-01 00:46:48 -07:00
}
2014-12-10 15:51:32 -08:00
# , must not have a space before and must have a space on the right .
2007-06-01 00:46:48 -07:00
} elsif ( $ op eq ',' ) {
2014-12-10 15:51:32 -08:00
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 ;
}
}
2008-03-04 14:28:20 -08:00
if ( $ ctx ! ~ /. x [ WEC ] / && $ cc ! ~ /^ } / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space required after that '$op' $at\n" . $ hereptr ) ) {
$ line_fixed = 1 ;
2013-09-11 14:24:01 -07:00
$ last_after = $ n ;
2014-12-10 15:51:32 -08:00
$ 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 . = " " ;
2013-07-03 15:05:31 -07:00
}
2007-06-01 00:46:48 -07:00
}
2007-10-16 23:29:38 -07:00
# '*' as part of a type definition -- reported already .
2008-07-23 21:29:10 -07:00
} elsif ( $ opv eq '*_' ) {
2007-10-16 23:29:38 -07:00
# 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 '~' | |
2008-07-23 21:29:10 -07:00
$ opv eq '*U' | | $ opv eq '-U' | |
2008-10-15 22:02:16 -07:00
$ opv eq '&U' | | $ opv eq '&&U' ) {
2008-03-04 14:28:20 -08:00
if ( $ ctx ! ~ / [ WEBC ] x . / && $ ca ! ~ / ( ?:\ ) | ! | ~ | \* | - | \& | \ | | \+\+ | \-\- | \ { ) $ / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space required before that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
if ( $ n ! = $ last_after + 2 ) {
$ good = $ fix_elements [ $ n ] . " " . ltrim ( $ fix_elements [ $ n + 1 ] ) ;
$ line_fixed = 1 ;
}
2013-07-03 15:05:31 -07:00
}
2007-06-01 00:46:48 -07:00
}
2009-02-27 14:03:07 -08:00
if ( $ op eq '*' && $ cc =~/\ s * $ Modifier \ b / ) {
2008-04-29 00:59:32 -07:00
# A unary '*' may be const
} elsif ( $ ctx =~ /. xW / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited after that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = $ fix_elements [ $ n ] . rtrim ( $ fix_elements [ $ n + 1 ] ) ;
2013-07-03 15:05:31 -07:00
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s /^\ s +// ;
}
2013-09-11 14:24:01 -07:00
$ line_fixed = 1 ;
2013-07-03 15:05:31 -07:00
}
2007-06-01 00:46:48 -07:00
}
# unary ++ and unary -- are allowed no space on one side .
} elsif ( $ op eq '++' or $ op eq '--' ) {
2008-03-28 14:15:58 -07:00
if ( $ ctx ! ~ / [ WEOBC ] x [ ^ W ] / && $ ctx ! ~ / [ ^ W ] x [ WOBEC ] / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space required one side of that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = $ fix_elements [ $ n ] . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
2013-07-03 15:05:31 -07:00
$ line_fixed = 1 ;
}
2007-06-01 00:46:48 -07:00
}
2008-03-28 14:15:58 -07:00
if ( $ ctx =~ / Wx [ BE ] / | |
( $ ctx =~ / Wx . / && $ cc =~ /^ ; / ) ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited before that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = rtrim ( $ fix_elements [ $ n ] ) . trim ( $ fix_elements [ $ n + 1 ] ) ;
2013-07-03 15:05:31 -07:00
$ line_fixed = 1 ;
}
2007-06-23 17:16:34 -07:00
}
2008-03-28 14:15:58 -07:00
if ( $ ctx =~ / ExW / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited after that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = $ fix_elements [ $ n ] . trim ( $ fix_elements [ $ n + 1 ] ) ;
2013-07-03 15:05:31 -07:00
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s /^\ s +// ;
}
2013-09-11 14:24:01 -07:00
$ line_fixed = 1 ;
2013-07-03 15:05:31 -07:00
}
2008-03-28 14:15:58 -07:00
}
2007-06-01 00:46:48 -07:00
# << and >> may either have or not have spaces both sides
2007-10-16 23:29:38 -07:00
} elsif ( $ op eq '<<' or $ op eq '>>' or
$ op eq '&' or $ op eq '^' or $ op eq '|' or
$ op eq '+' or $ op eq '-' or
2008-02-08 04:20:54 -08:00
$ op eq '*' or $ op eq '/' or
$ op eq '%' )
2007-06-01 00:46:48 -07:00
{
2015-02-13 14:38:57 -08:00
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 / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"need consistent spacing around '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = rtrim ( $ fix_elements [ $ n ] ) . " " . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s /^\ s +// ;
}
2013-07-03 15:05:31 -07:00
$ line_fixed = 1 ;
}
2007-06-01 00:46:48 -07:00
}
2008-07-23 21:29:10 -07:00
# 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 . / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited before that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = rtrim ( $ fix_elements [ $ n ] ) . trim ( $ fix_elements [ $ n + 1 ] ) ;
2013-07-03 15:05:31 -07:00
$ line_fixed = 1 ;
}
2008-07-23 21:29:10 -07:00
}
2007-06-01 00:46:48 -07:00
# All the others need spaces both sides .
2008-03-04 14:28:20 -08:00
} elsif ( $ ctx ! ~ / [ EWC ] x [ CWE ] / ) {
2008-07-23 21:29:10 -07:00
my $ ok = 0 ;
2007-08-10 13:01:03 -07:00
# Ignore email addresses < foo @ bar >
2008-07-23 21:29:10 -07:00
if ( ( $ op eq '<' &&
$ cc =~ /^\ S +\@\ S +>/ ) | |
( $ op eq '>' &&
$ ca =~ /<\ S +\@\ S + $ / ) )
{
2020-04-06 20:11:01 -07:00
$ ok = 1 ;
2008-07-23 21:29:10 -07:00
}
2015-04-16 12:44:53 -07:00
# for asm volatile statements
# ignore a colon with another
# colon immediately before or after
if ( ( $ op eq ':' ) &&
( $ ca =~ /: $ / | | $ cc =~ /^:/ ) ) {
$ ok = 1 ;
}
2013-11-12 15:10:05 -08:00
# messages are ERROR , but ?: are CHK
2008-07-23 21:29:10 -07:00
if ( $ ok == 0 ) {
2017-09-08 16:16:07 -07:00
my $ msg_level = \& ERROR ;
$ msg_level = \& CHK if ( ( $ op eq '?:' | | $ op eq '?' | | $ op eq ':' ) && $ ctx =~ / VxV / ) ;
2013-11-12 15:10:05 -08:00
2017-09-08 16:16:07 -07:00
if ( & { $ msg_level } ( "SPACING" ,
"spaces required around that '$op' $at\n" . $ hereptr ) ) {
2013-09-11 14:24:01 -07:00
$ good = rtrim ( $ fix_elements [ $ n ] ) . " " . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s /^\ s +// ;
}
2013-07-03 15:05:31 -07:00
$ line_fixed = 1 ;
}
2007-08-10 13:01:03 -07:00
}
2007-06-01 00:46:48 -07:00
}
2007-06-08 13:46:39 -07:00
$ off += length ( $ elements [ $ n + 1 ] ) ;
2013-07-03 15:05:31 -07:00
## print ( "n: <$n> GOOD: <$good>\n" ) ;
$ fixed_line = $ fixed_line . $ good ;
2007-06-01 00:46:48 -07:00
}
2013-07-03 15:05:31 -07:00
if ( ( $ # elements % 2) == 0) {
$ fixed_line = $ fixed_line . $ fix_elements [ $ # elements ] ;
}
2014-08-06 16:11:03 -07:00
if ( $ fix && $ line_fixed && $ fixed_line ne $ fixed [ $ fixlinenr ] ) {
$ fixed [ $ fixlinenr ] = $ fixed_line ;
2013-07-03 15:05:31 -07:00
}
2007-06-01 00:46:48 -07:00
}
2013-07-03 15:05:32 -07:00
# check for whitespace before a non - naked semicolon
2014-01-23 15:54:41 -08:00
if ( $ line =~ /^\+.*\ S \ s + ; \ s * $ / ) {
2013-07-03 15:05:32 -07:00
if ( WARN ( "SPACING" ,
"space prohibited before semicolon\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
1 while $ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:32 -07:00
s /^ ( \+.*\ S ) \ s + ; / $ 1 ; / ;
}
}
2007-07-19 01:48:34 -07:00
# check for multiple assignments
if ( $ line =~ /^.\ s * $ Lval \ s *=\ s * $ Lval \ s *= ( ? ! = ) / ) {
2011-07-25 17:13:25 -07:00
CHK ( "MULTIPLE_ASSIGNMENTS" ,
"multiple assignments should be avoided\n" . $ herecurr ) ;
2007-07-19 01:48:34 -07:00
}
2007-08-10 13:01:03 -07:00
## # 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
2020-12-15 20:44:56 -08:00
## # falsely report the parameters of functions .
2007-08-10 13:01:03 -07:00
## my $ ln = $ line ;
## while ( $ ln =~ s /\ ( [ ^\ ( \ ) ] *\ ) // g ) {
## }
## if ( $ ln =~ / , / ) {
2011-07-25 17:13:25 -07:00
## WARN ( "MULTIPLE_DECLARATION" ,
## "declaring multiple variables together should be avoided\n" . $ herecurr ) ;
2007-08-10 13:01:03 -07:00
## }
## }
2007-07-19 01:48:34 -07:00
2007-06-01 00:46:48 -07:00
# need space before brace following if , while , etc
2016-03-15 14:58:09 -07:00
if ( ( $ line =~ /\ ( . *\ ) \ { / && $ line ! ~ /\ ( $ Type \ ) \ { / ) | |
2018-08-21 21:58:08 -07:00
$ line =~ /\ b ( ?: else | do ) \ { / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space required before the open brace '{'\n" . $ herecurr ) &&
$ fix ) {
2018-08-21 21:58:08 -07:00
$ fixed [ $ fixlinenr ] =~ s /^ ( \+.* ( ?: do | else | \ ) ) ) \ { / $ 1 { / ;
2013-07-03 15:05:31 -07:00
}
2007-07-15 23:37:22 -07:00
}
2013-07-03 15:05:28 -07:00
## # check for blank lines before declarations
## if ( $ line =~ /^.\ t + $ Type \ s + $ Ident ( ?:\ s *=.* ) ? ; / &&
## $ prevrawline =~ /^.\ s * $ / ) {
## WARN ( "SPACING" ,
## "No blank lines before declarations\n" . $ hereprev ) ;
## }
##
2007-07-15 23:37:22 -07:00
# closing brace should have a space following it when it has anything
# on the line
2019-09-25 16:46:47 -07:00
if ( $ line =~ / } ( ? ! ( ?: , | ; | \ ) | \ } ) ) \ S / ) {
2013-09-11 14:23:54 -07:00
if ( ERROR ( "SPACING" ,
"space required after that close brace '}'\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-09-11 14:23:54 -07:00
s / } ( ( ? ! ( ?: , | ; | \ ) ) ) \ S ) / } $ 1 / ;
}
2007-06-01 00:46:48 -07:00
}
2007-08-10 13:01:03 -07:00
# check spacing on square brackets
if ( $ line =~ /\ [ \ s / && $ line ! ~ /\ [ \ s * $ / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited after that open square bracket '['\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /\ [ \ s +/\ [ / ;
}
2007-08-10 13:01:03 -07:00
}
if ( $ line =~ /\ s \ ] / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited before that close square bracket ']'\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /\ s +\ ] /\ ] / ;
}
2007-08-10 13:01:03 -07:00
}
2008-06-05 22:46:01 -07:00
# check spacing on parentheses
2007-10-16 23:29:38 -07:00
if ( $ line =~ /\ ( \ s / && $ line ! ~ /\ ( \ s * ( ?:\\ ) ? $ / &&
$ line ! ~ / for \ s *\ ( \ s + ; / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited after that open parenthesis '('\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /\ ( \ s +/\ ( / ;
}
2007-08-10 13:01:03 -07:00
}
2008-02-08 04:22:03 -08:00
if ( $ line =~ / ( \ s + ) \ ) / && $ line ! ~ /^.\ s *\ ) / &&
2008-06-05 22:46:01 -07:00
$ line ! ~ / for \ s *\ ( . * ; \ s +\ ) / &&
$ line ! ~ /:\ s +\ ) / ) {
2013-07-03 15:05:31 -07:00
if ( ERROR ( "SPACING" ,
"space prohibited before that close parenthesis ')'\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~
2013-07-03 15:05:31 -07:00
s /\ s +\ ) /\ ) / ;
}
2007-08-10 13:01:03 -07:00
}
2014-08-06 16:10:48 -07:00
# 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 ) {
2014-12-10 15:51:51 -08:00
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 / ;
}
}
2014-08-06 16:10:48 -07:00
2017-09-08 16:16:01 -07:00
# check for unnecessary parentheses around comparisons in if uses
2018-02-06 15:39:03 -08:00
# when ! drivers / staging or command - line uses -- strict
if ( ( $ realfile ! ~ m @^ ( ?: drivers / staging / ) @ | | $ check_orig ) &&
2018-08-21 21:57:33 -07:00
$ perl_version_ok && defined ( $ stat ) &&
2017-09-08 16:16:01 -07:00
$ stat =~ / ( ^.\ s * if \ s * ( $ balanced_parens ) ) / ) {
my $ if_stat = $ 1 ;
my $ test = substr ( $ 2 , 1 , - 1 ) ;
my $ herectx ;
while ( $ test =~ / ( ?:^ | [ ^\ w \&\ ! \~ ] ) +\ s *\ ( \ s * ( [ \&\ ! \~ ] ?\ s * $ Lval \ s * ( ?: $ Compare \ s * $ FuncArg ) ? ) \ s *\ ) / g ) {
my $ match = $ 1 ;
# avoid parentheses around potential macro args
next if ( $ match =~ /^\ s *\ w +\ s * $ / ) ;
if ( ! defined ( $ herectx ) ) {
$ herectx = $ here . "\n" ;
my $ cnt = statement_rawlines ( $ if_stat ) ;
for ( my $ n = 0 ; $ n < $ cnt ; $ n ++ ) {
my $ rl = raw_line ( $ linenr , $ n ) ;
$ herectx . = $ rl . "\n" ;
last if $ rl =~ /^ [ \+ ] . *\ { / ;
}
}
CHK ( "UNNECESSARY_PARENTHESES" ,
"Unnecessary parentheses around '$match'\n" . $ herectx ) ;
}
}
2007-06-01 00:46:48 -07:00
# goto labels aren 't indented, allow a single space however
2007-06-08 13:46:39 -07:00
if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
2007-06-01 00:46:48 -07:00
!($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
2013-07-03 15:05:31 -07:00
if (WARN("INDENTED_LABEL",
"labels should not be indented\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~
2013-07-03 15:05:31 -07:00
s/^(.)\s+/$1/;
}
2007-06-01 00:46:48 -07:00
}
2020-10-15 20:11:56 -07:00
# check if a statement with a comma should be two statements like:
# foo = bar(), /* comma should be semicolon */
# bar = baz();
if (defined($stat) &&
$stat =~ /^\+\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*,\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*;\s*$/) {
my $cnt = statement_rawlines($stat);
my $herectx = get_stat_here($linenr, $cnt, $here);
WARN("SUSPECT_COMMA_SEMICOLON",
"Possible comma where semicolon could be used\n" . $herectx);
}
2014-04-03 14:49:21 -07:00
# return is not a function
2013-11-12 15:10:13 -08:00
if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
2008-06-05 22:46:01 -07:00
my $spacing = $1;
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2014-04-03 14:49:21 -07:00
$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);
}
2008-06-05 22:46:01 -07:00
} elsif ($spacing !~ /\s+/) {
2011-07-25 17:13:25 -07:00
ERROR("SPACING",
"space required before the open parenthesis ' ( '\n" . $herecurr);
2008-06-05 22:46:01 -07:00
}
}
2013-11-12 15:10:13 -08:00
2014-06-23 13:22:07 -07:00
# 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*:/) {
2014-06-04 16:12:09 -07:00
WARN("RETURN_VOID",
2014-06-23 13:22:07 -07:00
"void function return statements are not generally useful\n" . $hereprev);
}
2014-06-04 16:12:09 -07:00
2014-01-23 15:54:47 -08:00
# if statements using unnecessary parentheses - ie: if ((foo == bar))
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2014-01-23 15:54:47 -08:00
$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);
}
}
2015-09-09 15:37:58 -07:00
# 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"
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2015-09-09 15:37:58 -07:00
$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;
2016-05-20 17:04:02 -07:00
if ($lead !~ /(?:$Operators|\.)\s*$/ &&
2015-09-09 15:37:58 -07:00
$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)/;
}
}
2015-04-16 12:44:19 -07:00
# Return of what appears to be an errno should normally be negative
if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) {
2010-10-26 14:23:14 -07:00
my $name = $1;
if ($name ne ' EOF ' && $name ne ' ERROR ') {
2011-07-25 17:13:25 -07:00
WARN("USE_NEGATIVE_ERRNO",
2015-04-16 12:44:19 -07:00
"return of an errno should typically be negative (ie: return -$1)\n" . $herecurr);
2010-10-26 14:23:14 -07:00
}
}
2008-06-05 22:46:01 -07:00
2007-06-01 00:46:48 -07:00
# Need a space before open parenthesis after if, while etc
2013-07-03 15:05:31 -07:00
if ($line =~ /\b(if|while|for|switch)\(/) {
if (ERROR("SPACING",
"space required before the open parenthesis ' ( '\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~
2013-07-03 15:05:31 -07:00
s/\b(if|while|for|switch)\(/$1 \(/;
}
2007-06-01 00:46:48 -07:00
}
2008-07-23 21:29:03 -07:00
# Check for illegal assignment in if conditional -- and check for trailing
# statements after the conditional.
2008-10-15 22:02:30 -07:00
if ($line =~ /do\s*(?!{)/) {
2012-01-10 15:10:01 -08:00
($stat, $cond, $line_nr_next, $remain_next, $off_next) =
ctx_statement_block($linenr, $realcnt, 0)
if (!defined $stat);
2008-10-15 22:02:30 -07:00
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} &&
2013-11-21 14:31:57 -08:00
defined($stat) && defined($cond) &&
2008-10-15 22:02:30 -07:00
$line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
2008-04-29 00:59:32 -07:00
my ($s, $c) = ($stat, $cond);
2007-11-28 16:21:06 -08:00
2009-01-06 14:41:29 -08:00
if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
2020-08-11 18:35:10 -07:00
if (ERROR("ASSIGN_IN_IF",
"do not use assignment in if condition\n" . $herecurr) &&
$fix && $perl_version_ok) {
if ($rawline =~ /^\+(\s+)if\s*\(\s*(\!)?\s*\(\s*(($Lval)\s*=\s*$LvalOrFunc)\s*\)\s*(?:($Compare)\s*($FuncArg))?\s*\)\s*(\{)?\s*$/) {
my $space = $1;
my $not = $2;
my $statement = $3;
my $assigned = $4;
my $test = $8;
my $against = $9;
my $brace = $15;
fix_delete_line($fixlinenr, $rawline);
fix_insert_line($fixlinenr, "$space$statement;");
my $newline = "${space}if (";
$newline .= ' ! ' if defined($not);
$newline .= ' ( ' if (defined $not && defined($test) && defined($against));
$newline .= "$assigned";
$newline .= " $test $against" if (defined($test) && defined($against));
$newline .= ' ) ' if (defined $not && defined($test) && defined($against));
$newline .= ' ) ';
$newline .= " {" if (defined($brace));
fix_insert_line($fixlinenr + 1, $newline);
}
}
2007-11-28 16:21:06 -08:00
}
# Find out what is on the end of the line after the
# conditional.
2008-03-28 14:15:58 -07:00
substr($s, 0, length($c), '');
2007-11-28 16:21:06 -08:00
$s =~ s/\n.*//g;
2020-04-06 20:11:01 -07:00
$s =~ s/$;//g; # Remove any comments
2008-07-23 21:29:03 -07:00
if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
$c !~ /}\s*while\s*/)
2008-03-28 14:15:58 -07:00
{
2008-10-15 22:02:34 -07:00
# Find out how long the conditional actually is.
my @newlines = ($c =~ /\n/gs);
my $cond_lines = 1 + $#newlines;
2010-03-05 13:43:50 -08:00
my $stat_real = '';
2008-10-15 22:02:34 -07:00
2010-03-05 13:43:50 -08:00
$stat_real = raw_line($linenr, $cond_lines)
. "\n" if ($cond_lines);
2008-10-15 22:02:34 -07:00
if (defined($stat_real) && $cond_lines > 1) {
$stat_real = "[...]\n$stat_real";
}
2011-07-25 17:13:25 -07:00
ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" . $herecurr . $stat_real);
2007-11-28 16:21:06 -08:00
}
}
2008-02-08 04:22:03 -08:00
# Check for bitwise tests written as boolean
if ($line =~ /
(?:
(?:\[|\(|\&\&|\|\|)
\s*0[xX][0-9]+\s*
(?:\&\&|\|\|)
|
(?:\&\&|\|\|)
\s*0[xX][0-9]+\s*
(?:\&\&|\|\||\)|\])
)/x)
{
2011-07-25 17:13:25 -07:00
WARN("HEXADECIMAL_BOOLEAN_TEST",
"boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
2008-02-08 04:22:03 -08:00
}
2007-11-28 16:21:06 -08:00
# if and else should not have general statements after it
2008-02-08 04:22:03 -08:00
if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
my $s = $1;
2020-04-06 20:11:01 -07:00
$s =~ s/$;//g; # Remove any comments
2008-02-08 04:22:03 -08:00
if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
2011-07-25 17:13:25 -07:00
ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" . $herecurr);
2008-02-08 04:22:03 -08:00
}
2007-06-01 00:46:48 -07:00
}
2009-01-15 13:51:06 -08:00
# if should not continue a brace
if ($line =~ /}\s*if\b/) {
2011-07-25 17:13:25 -07:00
ERROR("TRAILING_STATEMENTS",
2014-08-06 16:10:37 -07:00
"trailing statements should be on next line (or did you mean ' else if '?)\n" .
2009-01-15 13:51:06 -08:00
$herecurr);
}
2008-10-15 22:02:25 -07:00
# case and default should not have general statements after them
if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
$line !~ /\G(?:
2008-10-15 22:02:36 -07:00
(?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
2008-10-15 22:02:25 -07:00
\s*return\s+
)/xg)
{
2011-07-25 17:13:25 -07:00
ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" . $herecurr);
2008-10-15 22:02:25 -07:00
}
2007-06-01 00:46:48 -07:00
# Check for }<nl>else {, these must be at the same
# indent level to be relevant to each other.
2014-08-06 16:11:14 -07:00
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);
}
2007-06-01 00:46:48 -07:00
}
2014-08-06 16:11:14 -07:00
if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ &&
$previndent == $indent) {
2008-02-08 04:20:54 -08:00
my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
# Find out what is on the end of the line after the
# conditional.
2008-03-28 14:15:58 -07:00
substr($s, 0, length($c), '');
2008-02-08 04:20:54 -08:00
$s =~ s/\n.*//g;
if ($s =~ /^\s*;/) {
2014-08-06 16:11:14 -07:00
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);
}
2008-02-08 04:20:54 -08:00
}
}
2013-07-03 15:05:20 -07:00
#Specific variable tests
2012-12-17 16:02:07 -08:00
while ($line =~ m{($Constant|$Lval)}g) {
my $var = $1;
2013-07-03 15:05:20 -07:00
#CamelCase
2013-07-03 15:05:22 -07:00
if ($var !~ /^$Constant$/ &&
2013-07-03 15:05:20 -07:00
$var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
2020-12-15 20:44:27 -08:00
#Ignore some autogenerated defines and enum values
$var !~ /^(?:[A-Z]+_){1,5}[A-Z]{1,3}[a-z]/ &&
2013-07-03 15:05:33 -07:00
#Ignore Page<foo> variants
2013-07-03 15:05:22 -07:00
$var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
2019-12-04 16:52:06 -08:00
#Ignore SI style variants like nS, mV and dB
#(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE)
$var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ &&
2014-12-10 15:51:54 -08:00
#Ignore some three character SI units explicitly, like MiB and KHz
$var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) {
2013-09-11 14:23:55 -07:00
while ($var =~ m{($Ident)}g) {
my $word = $1;
next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/);
2013-11-12 15:10:06 -08:00
if ($check) {
seed_camelcase_includes();
if (!$file && !$camelcase_file_seeded) {
seed_camelcase_file($realfile);
$camelcase_file_seeded = 1;
}
}
2013-09-11 14:23:55 -07:00
if (!defined $camelcase{$word}) {
$camelcase{$word} = 1;
CHK("CAMELCASE",
"Avoid CamelCase: <$word>\n" . $herecurr);
}
2013-07-03 15:05:34 -07:00
}
2012-12-17 16:02:07 -08:00
}
}
2007-06-01 00:46:48 -07:00
#no spaces allowed after \ in define
2013-09-11 14:23:54 -07:00
if ($line =~ /\#\s*define.*\\\s+$/) {
if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
"Whitespace after \\ makes next lines useless\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/\s+$//;
2013-09-11 14:23:54 -07:00
}
2007-06-01 00:46:48 -07:00
}
2015-04-16 12:44:25 -07:00
# warn if <asm/foo.h> is #included and <linux/foo.h> is available and includes
# itself <asm/foo.h> (uses RAW line)
2008-06-05 22:46:01 -07:00
if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
2008-10-15 22:02:20 -07:00
my $file = "$1.h";
my $checkfile = "include/linux/$file";
if (-f "$root/$checkfile" &&
$realfile ne $checkfile &&
2010-08-09 17:20:57 -07:00
$1 !~ /$allowed_asm_includes/)
2008-06-05 22:46:01 -07:00
{
2015-04-16 12:44:25 -07:00
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);
}
2008-10-15 22:02:20 -07:00
}
2007-06-01 00:46:48 -07:00
}
}
2007-06-23 17:16:34 -07:00
# 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
2008-03-04 14:28:20 -08:00
# in a known good container
2008-07-23 21:29:07 -07:00
if ($realfile !~ m@/vmlinux.lds.h$@ &&
$line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
2007-06-23 17:16:44 -07:00
my $ln = $linenr;
my $cnt = $realcnt;
2008-06-05 22:46:01 -07:00
my ($off, $dstat, $dcond, $rest);
my $ctx = '';
2014-10-13 15:51:55 -07:00
my $has_flow_statement = 0;
my $has_arg_concat = 0;
2008-06-05 22:46:01 -07:00
($dstat, $dcond, $ln, $cnt, $off) =
2012-01-10 15:09:54 -08:00
ctx_statement_block($linenr, $realcnt, 0);
$ctx = $dstat;
2008-06-05 22:46:01 -07:00
#print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
2008-07-23 21:29:00 -07:00
#print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
2008-06-05 22:46:01 -07:00
2014-10-13 15:51:55 -07:00
$has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/);
2016-01-20 14:59:18 -08:00
$has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/);
2014-10-13 15:51:55 -07:00
2016-10-11 13:52:08 -07:00
$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;
2018-08-21 21:57:43 -07:00
$define_args =~ s/\\\+?//g;
2016-10-11 13:52:08 -07:00
@def_args = split(",", $define_args);
}
2008-07-23 21:29:11 -07:00
$dstat =~ s/$;//g;
2008-06-05 22:46:01 -07:00
$dstat =~ s/\\\n.//g;
$dstat =~ s/^\s*//s;
$dstat =~ s/\s*$//s;
# Flatten any parentheses and braces
2020-10-15 20:12:22 -07:00
while ($dstat =~ s/\([^\(\)]*\)/1u/ ||
$dstat =~ s/\{[^\{\}]*\}/1u/ ||
$dstat =~ s/.\[[^\[\]]*\]/1u/)
2008-10-15 22:02:33 -07:00
{
2007-07-15 23:37:22 -07:00
}
2007-06-23 17:16:44 -07:00
2020-04-06 20:11:01 -07:00
# Flatten any obvious string concatenation.
2015-06-25 15:02:54 -07:00
while ($dstat =~ s/($String)\s*$Ident/$1/ ||
$dstat =~ s/$Ident\s*($String)/$1/)
2012-03-23 15:02:18 -07:00
{
}
2016-03-15 14:58:01 -07:00
# Make asm volatile uses seem like a generic function
$dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g;
2008-06-05 22:46:01 -07:00
my $exceptions = qr{
$Declare|
module_param_named|
2012-10-04 17:13:38 -07:00
MODULE_PARM_DESC|
2008-06-05 22:46:01 -07:00
DECLARE_PER_CPU|
DEFINE_PER_CPU|
2009-01-06 14:41:18 -08:00
__typeof__\(|
2010-03-05 13:43:52 -08:00
union|
struct|
2009-09-21 17:04:38 -07:00
\.$Ident\s*=\s*|
2016-01-20 14:59:21 -08:00
^\"|\"$|
^\[
2008-06-05 22:46:01 -07:00
}x;
2010-10-26 14:23:18 -07:00
#print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
2016-10-11 13:52:08 -07:00
$ctx =~ s/\n*$//;
my $stmt_cnt = statement_rawlines($ctx);
2018-04-10 16:33:27 -07:00
my $herectx = get_stat_here($linenr, $stmt_cnt, $here);
2016-10-11 13:52:08 -07:00
2012-01-10 15:09:54 -08:00
if ($dstat ne '' &&
$dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(),
$dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo();
2013-07-03 15:05:27 -07:00
$dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz
2014-08-06 16:10:31 -07:00
$dstat !~ /^' X '$/ && $dstat !~ /^' XX '$/ && # character constants
2012-01-10 15:09:54 -08:00
$dstat !~ /$exceptions/ &&
$dstat !~ /^\.$Ident\s*=/ && # .foo =
2013-04-17 15:58:26 -07:00
$dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo
2012-01-10 15:10:06 -08:00
$dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
2020-10-15 20:12:22 -07:00
$dstat !~ /^while\s*$Constant\s*$Constant\s*$/ && # while (...) {...}
2012-01-10 15:09:54 -08:00
$dstat !~ /^for\s*$Constant$/ && # for (...)
$dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar()
$dstat !~ /^do\s*{/ && # do {...
2015-09-09 15:37:52 -07:00
$dstat !~ /^\(\{/ && # ({...
2013-09-11 14:24:00 -07:00
$ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/)
2012-01-10 15:09:54 -08:00
{
2017-05-08 15:55:48 -07:00
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 =~ /;/) {
2012-01-10 15:09:54 -08:00
ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
"Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
} else {
2011-07-25 17:13:25 -07:00
ERROR("COMPLEX_MACRO",
2014-10-13 15:51:40 -07:00
"Macros with complex values should be enclosed in parentheses\n" . "$herectx");
2007-06-23 17:16:44 -07:00
}
2016-10-11 13:52:08 -07:00
}
2016-10-11 13:52:14 -07:00
# 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);
2016-10-11 13:52:08 -07:00
# check if any macro arguments are reused (ignore ' . . . ' and ' type ')
foreach my $arg (@def_args) {
next if ($arg =~ /\.\.\./);
2016-10-11 13:52:11 -07:00
next if ($arg =~ /^type$/i);
2017-07-10 15:52:27 -07:00
my $tmp_stmt = $define_stmt;
2019-09-25 16:46:41 -07:00
$tmp_stmt =~ s/\b(sizeof|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
2017-07-10 15:52:27 -07:00
$tmp_stmt =~ s/\#+\s*$arg\b//g;
$tmp_stmt =~ s/\b$arg\s*\#\#//g;
2018-05-25 14:48:04 -07:00
my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g;
2016-10-11 13:52:08 -07:00
if ($use_cnt > 1) {
CHK("MACRO_ARG_REUSE",
"Macro argument reuse ' $ arg ' - possible side-effects?\n" . "$herectx");
2016-10-11 13:52:11 -07:00
}
# check if any macro arguments may have other precedence issues
2017-07-10 15:52:27 -07:00
if ($tmp_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m &&
2016-10-11 13:52:11 -07:00
((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");
2016-10-11 13:52:08 -07:00
}
2007-06-23 17:16:34 -07:00
}
2012-12-17 16:01:47 -08:00
2014-10-13 15:51:55 -07:00
# 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 $cnt = statement_rawlines($ctx);
2018-04-10 16:33:27 -07:00
my $herectx = get_stat_here($linenr, $cnt, $here);
2014-10-13 15:51:55 -07:00
WARN("MACRO_WITH_FLOW_CONTROL",
"Macros with flow control statements should be avoided\n" . "$herectx");
}
2012-12-17 16:01:56 -08:00
# check for line continuations outside of #defines, preprocessor #, and asm
2012-12-17 16:01:47 -08:00
} else {
if ($prevline !~ /^..*\\$/ &&
2012-12-17 16:01:56 -08:00
$line !~ /^\+\s*\#.*\\$/ && # preprocessor
$line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm
2012-12-17 16:01:47 -08:00
$line =~ /^\+.*\\$/) {
WARN("LINE_CONTINUATIONS",
"Avoid unnecessary line continuations\n" . $herecurr);
}
2007-06-01 00:46:48 -07:00
}
2012-07-30 14:41:24 -07:00
# 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
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2012-07-30 14:41:24 -07:00
$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;
2015-02-13 14:38:32 -08:00
$dstat =~ s/$;/ /g;
2012-07-30 14:41:24 -07:00
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);
2018-04-10 16:33:27 -07:00
my $herectx = get_stat_here($linenr, $cnt, $here);
2012-07-30 14:41:24 -07:00
2012-08-21 16:15:53 -07:00
if (($stmts =~ tr/;/;/) == 1 &&
$stmts !~ /^\s*(if|while|for|switch)\b/) {
2012-07-30 14:41:24 -07:00
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");
}
2014-06-04 16:12:06 -07:00
} elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) {
$ctx =~ s/\n*$//;
my $cnt = statement_rawlines($ctx);
2018-04-10 16:33:27 -07:00
my $herectx = get_stat_here($linenr, $cnt, $here);
2014-06-04 16:12:06 -07:00
WARN("TRAILING_SEMICOLON",
"macros should not use a trailing semicolon\n" . "$herectx");
2012-07-30 14:41:24 -07:00
}
}
2007-07-19 01:48:34 -07:00
# check for redundant bracing round if etc
2008-02-08 04:22:03 -08:00
if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
my ($level, $endln, @chunks) =
2008-03-04 14:28:20 -08:00
ctx_statement_full($linenr, $realcnt, 1);
2008-02-08 04:22:03 -08:00
#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
2008-03-04 14:28:20 -08:00
#print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
if ($#chunks > 0 && $level == 0) {
2012-03-23 15:02:19 -07:00
my @allowed = ();
my $allow = 0;
2008-02-08 04:22:03 -08:00
my $seen = 0;
2008-03-28 14:15:58 -07:00
my $herectx = $here . "\n";
2008-03-04 14:28:20 -08:00
my $ln = $linenr - 1;
2008-02-08 04:22:03 -08:00
for my $chunk (@chunks) {
my ($cond, $block) = @{$chunk};
2008-03-28 14:15:58 -07:00
# If the condition carries leading newlines, then count those as offsets.
my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
my $offset = statement_rawlines($whitespace) - 1;
2012-03-23 15:02:19 -07:00
$allowed[$allow] = 0;
2008-03-28 14:15:58 -07:00
#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";
2008-03-04 14:28:20 -08:00
$ln += statement_rawlines($block) - 1;
2008-03-28 14:15:58 -07:00
substr($block, 0, length($cond), '');
2008-02-08 04:22:03 -08:00
$seen++ if ($block =~ /^\s*{/);
2012-03-23 15:02:19 -07:00
#print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n";
2008-03-04 14:28:20 -08:00
if (statement_lines($cond) > 1) {
#print "APW: ALLOWED: cond<$cond>\n";
2012-03-23 15:02:19 -07:00
$allowed[$allow] = 1;
2008-02-08 04:22:03 -08:00
}
if ($block =~/\b(?:if|for|while)\b/) {
2008-03-04 14:28:20 -08:00
#print "APW: ALLOWED: block<$block>\n";
2012-03-23 15:02:19 -07:00
$allowed[$allow] = 1;
2008-02-08 04:22:03 -08:00
}
2008-03-04 14:28:20 -08:00
if (statement_block_size($block) > 1) {
#print "APW: ALLOWED: lines block<$block>\n";
2012-03-23 15:02:19 -07:00
$allowed[$allow] = 1;
2008-02-08 04:22:03 -08:00
}
2012-03-23 15:02:19 -07:00
$allow++;
2008-02-08 04:22:03 -08:00
}
2012-03-23 15:02:19 -07:00
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);
}
2008-02-08 04:22:03 -08:00
}
}
}
2008-03-28 14:15:58 -07:00
if (!defined $suppress_ifbraces{$linenr - 1} &&
2008-02-08 04:22:03 -08:00
$line =~ /\b(if|while|for|else)\b/) {
2008-03-04 14:28:20 -08:00
my $allowed = 0;
2007-07-19 01:48:34 -07:00
2008-03-04 14:28:20 -08:00
# Check the pre-context.
if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
#print "APW: ALLOWED: pre<$1>\n";
$allowed = 1;
}
2008-03-28 14:15:58 -07:00
my ($level, $endln, @chunks) =
ctx_statement_full($linenr, $realcnt, $-[0]);
2008-03-04 14:28:20 -08:00
# Check the condition.
my ($cond, $block) = @{$chunks[0]};
2008-03-28 14:15:58 -07:00
#print "CHECKING<$linenr> cond<$cond> block<$block>\n";
2008-03-04 14:28:20 -08:00
if (defined $cond) {
2008-03-28 14:15:58 -07:00
substr($block, 0, length($cond), '');
2008-03-04 14:28:20 -08:00
}
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) {
2008-03-28 14:15:58 -07:00
substr($block, 0, length($cond), '');
2007-07-19 01:48:34 -07:00
}
2008-03-04 14:28:20 -08:00
if ($block =~ /^\s*\{/) {
#print "APW: ALLOWED: chunk-1 block<$block>\n";
$allowed = 1;
}
}
if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
2008-10-15 22:02:23 -07:00
my $cnt = statement_rawlines($block);
2018-04-10 16:33:27 -07:00
my $herectx = get_stat_here($linenr, $cnt, $here);
2008-03-04 14:28:20 -08:00
2011-07-25 17:13:25 -07:00
WARN("BRACES",
"braces {} are not necessary for single statement blocks\n" . $herectx);
2007-07-19 01:48:34 -07:00
}
}
2017-02-24 15:01:41 -08:00
# check for single line unbalanced braces
2017-02-24 15:01:43 -08:00
if ($sline =~ /^.\s*\}\s*else\s*$/ ||
$sline =~ /^.\s*else\s*\{\s*$/) {
2017-02-24 15:01:41 -08:00
CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr);
}
2012-12-17 16:01:59 -08:00
# check for unnecessary blank lines around braces
2013-07-03 15:05:29 -07:00
if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) {
2015-02-13 14:38:46 -08:00
if (CHK("BRACES",
"Blank lines aren' t necessary before a close brace '}' \ n " . $ hereprev ) &&
$ fix && $ prevrawline =~ /^\+/ ) {
fix_delete_line ( $ fixlinenr - 1 , $ prevrawline ) ;
}
2012-12-17 16:01:59 -08:00
}
2013-07-03 15:05:29 -07:00
if ( ( $ rawline =~ /^.\ s * $ / && $ prevline =~ /^..* { \ s * $ / ) ) {
2015-02-13 14:38:46 -08:00
if ( CHK ( "BRACES" ,
"Blank lines aren't necessary after an open brace '{'\n" . $ hereprev ) &&
$ fix ) {
fix_delete_line ( $ fixlinenr , $ rawline ) ;
}
2012-12-17 16:01:59 -08:00
}
2007-06-08 13:46:39 -07:00
# no volatiles please
2007-10-18 03:05:08 -07:00
my $ asm_volatile = qr { \ b ( _ _ asm__ | asm ) \ s + ( _ _ volatile__ | volatile ) \ b } ;
if ( $ line =~ /\ bvolatile \ b / && $ line ! ~ / $ asm_volatile / ) {
2011-07-25 17:13:25 -07:00
WARN ( "VOLATILE" ,
2016-10-18 10:12:27 -02:00
"Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst\n" . $ herecurr ) ;
2007-06-08 13:46:39 -07:00
}
2014-12-10 15:52:05 -08:00
# 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
2015-06-25 15:02:54 -07:00
if ( $ line =~ /^\+\ s * $ String / &&
2014-12-10 15:52:05 -08:00
$ prevline =~ / " \ s * $ / &&
$ prevrawline ! ~ / ( ?:\\ ( ?: [ ntr ] | [ 0 - 7 ] { 1 , 3 } | x [ 0 - 9 a - 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 ) ;
}
2017-05-08 15:55:51 -07:00
# 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
2017-02-24 15:01:28 -08:00
if ( $ line =~ /^\+.* $ String / &&
defined ( $ context_function ) &&
2017-05-08 15:55:51 -07:00
get_quoted_string ( $ line , $ rawline ) =~ /\ b$context_function \ b / &&
length ( get_quoted_string ( $ line , $ rawline ) ) ! = ( length ( $ context_function ) + 2 ) ) {
2017-02-24 15:01:28 -08:00
WARN ( "EMBEDDED_FUNCTION_NAME" ,
2017-05-08 15:55:51 -07:00
"Prefer using '\"%s...\", __func__' to using '$context_function', this function's name, in a string\n" . $ herecurr ) ;
2017-02-24 15:01:28 -08:00
}
2014-12-10 15:52:05 -08:00
# 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 / ;
}
}
2014-10-13 15:51:51 -07:00
# concatenated string without spaces between elements
2018-08-21 21:57:29 -07:00
if ( $ line =~ / $ String [ A - Za - z0 - 9 _ ] / | | $ line =~ / [ A - Za - z0 - 9 _ ] $ String / ) {
if ( CHK ( "CONCATENATED_STRING" ,
"Concatenated strings should use spaces between elements\n" . $ herecurr ) &&
$ fix ) {
while ( $ line =~ / ( $ String ) / g ) {
my $ extracted_string = substr ( $ rawline , $ - [ 0 ] , $ + [ 0 ] - $ - [ 0 ] ) ;
$ fixed [ $ fixlinenr ] =~ s /\ Q $ extracted_string \ E ( [ A - Za - z0 - 9 _ ] ) / $ extracted_string $ 1 / ;
$ fixed [ $ fixlinenr ] =~ s / ( [ A - Za - z0 - 9 _ ] ) \ Q $ extracted_string \ E / $ 1 $ extracted_string / ;
}
}
2014-10-13 15:51:51 -07:00
}
2014-12-10 15:51:59 -08:00
# uncoalesced string fragments
2015-06-25 15:02:54 -07:00
if ( $ line =~ / $ String \ s * "/) {
2018-08-21 21:57:29 -07:00
if (WARN(" STRING_FRAGMENTS ",
" Consecutive strings are generally better as a single string \ n " . $herecurr) &&
$fix) {
while ($line =~ /($String)(?=\s*" ) / g ) {
my $ extracted_string = substr ( $ rawline , $ - [ 0 ] , $ + [ 0 ] - $ - [ 0 ] ) ;
$ fixed [ $ fixlinenr ] =~ s /\ Q $ extracted_string \ E \ s * "/substr($extracted_string, 0, -1)/e;
}
}
2014-12-10 15:51:59 -08:00
}
2017-02-27 14:30:05 -08:00
# 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;
2014-12-10 15:52:05 -08:00
while ($line =~ /(?:^|" ) ( [ X \ t ] * ) ( ?: " | $ ) / g ) {
2017-02-27 14:30:05 -08:00
my $ string = substr ( $ rawline , $ - [ 1 ] , $ + [ 1 ] - $ - [ 1 ] ) ;
2014-12-10 15:52:05 -08:00
$ string =~ s / %%/__/g;
2017-02-27 14:30:05 -08:00
# check for %L
if ( $ show_L && $ string =~ / %[\*\d\.\$]*L([diouxX])/) {
2014-12-10 15:52:05 -08:00
WARN ( "PRINTF_L" ,
2017-02-27 14:30:05 -08:00
" \ %L$1 is non-standard C, use %ll$1\n" . $herecurr);
$ show_L = 0 ;
2014-12-10 15:52:05 -08:00
}
2017-02-27 14:30:05 -08:00
# 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 0 x < decimal >
if ( $ string =~ / 0 x %[\*\d\.\$\Llzth]*[diou]/) {
ERROR ( "PRINTF_0XDECIMAL" ,
2015-09-09 15:37:47 -07:00
"Prefixing 0x with decimal output is defective\n" . $ herecurr ) ;
}
2014-12-10 15:52:05 -08:00
}
# check for line continuations in quoted strings with odd counts of "
2018-02-06 15:38:52 -08:00
if ( $ rawline =~ /\\ $ / && $ sline =~ tr / "/" / % 2) {
2014-12-10 15:52:05 -08:00
WARN ( "LINE_CONTINUATIONS" ,
"Avoid line continuations in quoted strings\n" . $ herecurr ) ;
}
2007-06-08 13:47:06 -07:00
# warn about # if 0
2008-06-05 22:46:01 -07:00
if ( $ line =~ /^.\ s *\#\ s * if \ s + 0 \ b / ) {
2018-08-21 21:57:57 -07:00
WARN ( "IF_0" ,
"Consider removing the code enclosed by this #if 0 and its #endif\n" . $ herecurr ) ;
}
# warn about # if 1
if ( $ line =~ /^.\ s *\#\ s * if \ s + 1 \ b / ) {
WARN ( "IF_1" ,
"Consider removing the #if 1 and its #endif\n" . $ herecurr ) ;
2007-06-08 13:46:39 -07:00
}
2012-12-17 16:01:52 -08:00
# check for needless "if (<foo>) fn(<foo>)" uses
if ( $ prevline =~ /\ bif \ s *\ ( \ s * ( $ Lval ) \ s *\ ) / ) {
2015-09-09 15:37:36 -07:00
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 / ;
}
}
2008-07-23 21:29:04 -07:00
}
}
2007-07-19 01:48:34 -07:00
2014-08-06 16:10:27 -07:00
# 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" ) ;
2019-03-07 16:28:35 -08:00
if ( $ s =~ / ( ?:^ | \ n ) [ \+ ] \ s * ( ?: $ Type \ s * ) ?\ Q $ testval \ E \ s *=\ s * ( ?:\ ( [ ^\ ) ] *\ ) \ s * ) ?\ s * $ allocFunctions \ s *\ ( / &&
$ s ! ~ /\ b__GFP_NOWARN \ b / ) {
2014-08-06 16:10:27 -07:00
WARN ( "OOM_MESSAGE" ,
"Possible unnecessary 'out of memory' message\n" . $ hereprev ) ;
}
}
2014-10-13 15:52:01 -07:00
# check for logging functions with KERN_ < LEVEL >
2015-02-13 14:38:26 -08:00
if ( $ line ! ~ / printk ( ?: _ ratelimited | _ once ) ?\ s *\ ( / &&
2014-10-13 15:52:01 -07:00
$ 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 *// ;
}
}
2017-02-24 15:01:31 -08:00
# 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 ) ;
}
2020-12-15 20:45:15 -08:00
# check for unnecessary use of %h[xudi] and %hh[xudi] in logging functions
if ( defined $ stat &&
$ line =~ /\ b$logFunctions \ s *\ ( / &&
index ( $ stat , '"' ) >= 0 ) {
my $ lc = $ stat =~ tr @\ n @@ ;
$ lc = $ lc + $ linenr ;
my $ stat_real = get_stat_real ( $ linenr , $ lc ) ;
pos ( $ stat_real ) = index ( $ stat_real , '"' ) ;
while ( $ stat_real =~ / [ ^\ " %]*(%[\#\d\.\*\-]*(h+)[idux])/g) {
my $ pspec = $ 1 ;
my $ h = $ 2 ;
my $ lineoff = substr ( $ stat_real , 0 , $ - [ 1 ] ) =~ tr @\ n @@ ;
if ( WARN ( "UNNECESSARY_MODIFIER" ,
"Integer promotion: Using '$h' in '$pspec' is unnecessary\n" . "$here\n$stat_real\n" ) &&
$ fix && $ fixed [ $ fixlinenr + $ lineoff ] =~ /^\+/ ) {
my $ nspec = $ pspec ;
$ nspec =~ s / h // g ;
$ fixed [ $ fixlinenr + $ lineoff ] =~ s /\ Q $ pspec \ E / $ nspec / ;
}
}
}
2014-12-10 15:51:46 -08:00
# check for mask then right shift without a parentheses
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2014-12-10 15:51:46 -08:00
$ 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 ) ;
}
2014-12-10 15:52:02 -08:00
# check for pointer comparisons to NULL
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok ) {
2014-12-10 15:52:02 -08:00
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 / ;
}
}
}
2013-09-11 14:24:05 -07:00
# 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 ) {
2014-08-06 16:11:03 -07:00
$ 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;
2013-09-11 14:24:05 -07:00
}
}
}
2013-11-12 15:10:10 -08:00
# 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) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~
2013-11-12 15:10:10 -08:00
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 ) {
2014-08-06 16:11:03 -07:00
my $ lead = $ fixed [ $ fixlinenr ] =~
2013-11-12 15:10:10 -08:00
/ ( ^\+\ s * ( ?: static \ s + ) ) / ;
$ lead = rtrim ( $ 1 ) ;
$ lead = "$lead " if ( $ lead ! ~ /^\+ $ / ) ;
$ lead = "${lead}const " ;
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~ s / ( ^\+\ s * ( ?: static \ s + ) ) / $ lead / ;
2013-11-12 15:10:10 -08:00
}
}
2015-04-16 12:44:42 -07:00
# 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 // ;
}
}
2014-04-03 14:49:14 -07:00
# 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) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/\b$constant_func\b/$func/g;
2014-04-03 14:49:14 -07:00
}
}
2010-08-09 17:21:01 -07:00
# prefer usleep_range over udelay
2013-02-21 16:44:19 -08:00
if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
2014-04-03 14:49:11 -07:00
my $delay = $1;
2010-08-09 17:21:01 -07:00
# ignore udelay' s < 10 , however
2014-04-03 14:49:11 -07:00
if ( ! ( $ delay < 10 ) ) {
2011-07-25 17:13:25 -07:00
CHK ( "USLEEP_RANGE" ,
2019-06-12 14:53:00 -03:00
"usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst\n" . $ herecurr ) ;
2014-04-03 14:49:11 -07:00
}
if ( $ delay > 2000 ) {
WARN ( "LONG_UDELAY" ,
"long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $ herecurr ) ;
2010-08-09 17:21:01 -07:00
}
}
2010-08-09 17:21:02 -07:00
# warn about unexpectedly long msleep 's
if ($line =~ /\bmsleep\s*\((\d+)\);/) {
if ($1 < 20) {
2011-07-25 17:13:25 -07:00
WARN("MSLEEP",
2019-06-12 14:53:00 -03:00
"msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst\n" . $herecurr);
2010-08-09 17:21:02 -07:00
}
}
2013-07-03 15:05:25 -07:00
# 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);
}
2013-07-03 15:05:26 -07:00
# 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);
}
2007-06-08 13:47:06 -07:00
# warn about #ifdefs in C files
2008-06-05 22:46:01 -07:00
# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
2007-06-08 13:47:06 -07:00
# print "#ifdef in C files should be avoided\n";
# print "$herecurr";
# $clean = 0;
# }
2007-08-10 13:01:03 -07:00
# warn about spacing in #ifdefs
2008-06-05 22:46:01 -07:00
if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
2013-07-03 15:05:31 -07:00
if (ERROR("SPACING",
"exactly one space required after that #$1\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~
2013-07-03 15:05:31 -07:00
s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /;
}
2007-08-10 13:01:03 -07:00
}
2007-06-08 13:46:39 -07:00
# check for spinlock_t definitions without a comment.
2008-04-29 00:59:32 -07:00
if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
$line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
2007-06-08 13:46:39 -07:00
my $which = $1;
if (!ctx_has_comment($first_line, $linenr)) {
2011-07-25 17:13:25 -07:00
CHK("UNCOMMENTED_DEFINITION",
"$1 definition without comment\n" . $herecurr);
2007-06-08 13:46:39 -07:00
}
}
# check for memory barriers without a comment.
2016-01-04 09:39:01 +02:00
my $barriers = qr{
mb|
rmb|
2019-11-07 14:49:00 +00:00
wmb
2016-01-04 09:39:01 +02:00
}x;
my $barrier_stems = qr{
mb__before_atomic|
mb__after_atomic|
store_release|
load_acquire|
store_mb|
(?:$barriers)
}x;
my $all_barriers = qr{
(?:$barriers)|
2016-01-04 10:00:10 +02:00
smp_(?:$barrier_stems)|
virt_(?:$barrier_stems)
2016-01-04 09:39:01 +02:00
}x;
if ($line =~ /\b(?:$all_barriers)\s*\(/) {
2007-06-08 13:46:39 -07:00
if (!ctx_has_comment($first_line, $linenr)) {
2013-11-12 15:10:11 -08:00
WARN("MEMORY_BARRIER",
"memory barrier without comment\n" . $herecurr);
2007-06-08 13:46:39 -07:00
}
}
2015-07-02 11:55:40 -07:00
2016-01-04 09:54:51 +02:00
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 ) ;
}
2015-06-25 15:02:46 -07:00
# 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 ) ;
}
}
2015-07-02 11:55:40 -07:00
2020-04-01 12:17:14 +02:00
# check for data_race without a comment .
if ( $ line =~ /\ bdata_race \ s *\ ( / ) {
if ( ! ctx_has_comment ( $ first_line , $ linenr ) ) {
WARN ( "DATA_RACE" ,
"data_race without comment\n" . $ herecurr ) ;
}
}
2007-06-08 13:46:39 -07:00
# check of hardware specific defines
2008-06-05 22:46:01 -07:00
if ( $ line =~ m @^.\ s *\#\ s * if . *\ b ( _ _ i386__ | _ _ powerpc64__ | _ _ sun__ | _ _ s390x__ ) \ b @ && $ realfile ! ~ m @ include / asm -@ ) {
2011-07-25 17:13:25 -07:00
CHK ( "ARCH_DEFINES" ,
"architecture specific defines should be avoided\n" . $ herecurr ) ;
2007-06-01 00:46:48 -07:00
}
2007-06-23 17:16:34 -07:00
2017-07-12 14:37:02 -07:00
# check that the storage class is not after a type
if ( $ line =~ /\ b ( $ Type ) \ s + ( $ Storage ) \ b / ) {
2011-07-25 17:13:25 -07:00
WARN ( "STORAGE_CLASS" ,
2017-07-12 14:37:02 -07:00
"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 ) ;
2010-05-24 14:33:30 -07:00
}
2007-07-15 23:37:22 -07:00
# check the location of the inline attribute , that it is between
# storage class and type .
2007-10-16 23:29:38 -07:00
if ( $ line =~ /\ b$Type \ s + $ Inline \ b / | |
$ line =~ /\ b$Inline \ s + $ Storage \ b / ) {
2011-07-25 17:13:25 -07:00
ERROR ( "INLINE_LOCATION" ,
"inline keyword should sit between storage class and type\n" . $ herecurr ) ;
2007-07-15 23:37:22 -07:00
}
2007-11-28 16:21:06 -08:00
# Check for _ _ inline__ and _ _ inline , prefer inline
2013-11-12 15:10:14 -08:00
if ( $ realfile ! ~ m @\ binclude / uapi /@ &&
$ line =~ /\ b ( _ _ inline__ | _ _ inline ) \ b / ) {
2013-09-11 14:23:54 -07:00
if ( WARN ( "INLINE" ,
"plain inline is preferred over $1\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~ s /\ b ( _ _ inline__ | _ _ inline ) \ b / inline / ;
2013-09-11 14:23:54 -07:00
}
2007-11-28 16:21:06 -08:00
}
2020-12-15 20:44:36 -08:00
# Check for compiler attributes
2013-11-12 15:10:14 -08:00
if ( $ realfile ! ~ m @\ binclude / uapi /@ &&
2020-12-15 20:44:36 -08:00
$ rawline =~ /\ b__attribute__ \ s *\ ( \ s * ( $ balanced_parens ) \ s *\ ) / ) {
my $ attr = $ 1 ;
$ attr =~ s /\ s *\ ( \ s * ( . * ) \ ) \ s */ $ 1 / ;
2011-01-12 17:00:00 -08:00
2020-12-15 20:44:36 -08:00
my %attr_list = (
2020-12-15 20:44:50 -08:00
"alias" => "__alias" ,
2020-12-15 20:44:36 -08:00
"aligned" => "__aligned" ,
"always_inline" => "__always_inline" ,
"assume_aligned" => "__assume_aligned" ,
"cold" => "__cold" ,
"const" => "__attribute_const__" ,
"copy" => "__copy" ,
"designated_init" => "__designated_init" ,
"externally_visible" => "__visible" ,
"format" => "printf|scanf" ,
"gnu_inline" => "__gnu_inline" ,
"malloc" => "__malloc" ,
"mode" => "__mode" ,
"no_caller_saved_registers" => "__no_caller_saved_registers" ,
"noclone" => "__noclone" ,
"noinline" => "noinline" ,
"nonstring" => "__nonstring" ,
"noreturn" => "__noreturn" ,
"packed" => "__packed" ,
"pure" => "__pure" ,
2020-12-15 20:44:43 -08:00
"section" => "__section" ,
2020-12-15 20:44:50 -08:00
"used" => "__used" ,
"weak" => "__weak"
2020-12-15 20:44:36 -08:00
) ;
2011-07-25 17:13:24 -07:00
2020-12-15 20:44:36 -08:00
while ( $ attr =~ /\ s * ( \ w + ) \ s * ( $ { balanced_parens } ) ?/ g ) {
2020-12-15 20:44:43 -08:00
my $ orig_attr = $ 1 ;
2020-12-15 20:44:36 -08:00
my $ params = '' ;
$ params = $ 2 if defined ( $ 2 ) ;
2020-12-15 20:44:43 -08:00
my $ curr_attr = $ orig_attr ;
2020-12-15 20:44:36 -08:00
$ curr_attr =~ s /^ [ \ s_ ] + | [ \ s_ ] + $ // g ;
if ( exists ( $ attr_list { $ curr_attr } ) ) {
2020-12-15 20:44:43 -08:00
my $ new = $ attr_list { $ curr_attr } ;
2020-12-15 20:44:36 -08:00
if ( $ curr_attr eq "format" && $ params ) {
$ params =~ /^\ s *\ ( \ s * ( \ w + ) \ s * , \ s * ( . * ) / ;
2020-12-15 20:44:43 -08:00
$ new = " _ _ $ 1 \ ( $ 2 ";
2020-12-15 20:44:36 -08:00
} else {
2020-12-15 20:44:43 -08:00
$new = " $ new$params ";
}
if (WARN(" PREFER_DEFINED_ATTRIBUTE_MACRO ",
" Prefer $ new over _ _ attribute__ ( ( $ orig_attr$params ) ) \ n " . $herecurr) &&
$fix) {
my $remove = " \ Q $ orig_attr \ E " . '\s*' . " \ Q $ params \ E " . '(?:\s*,\s*)?' ;
$ fixed [ $ fixlinenr ] =~ s / $ remove // ;
$ fixed [ $ fixlinenr ] =~ s /\ b__attribute__ / $ new _ _ attribute__ / ;
$ fixed [ $ fixlinenr ] =~ s /\ } \ Q $ new \ E / } $ new / ;
$ fixed [ $ fixlinenr ] =~ s / _ _ attribute__ \ s *\ ( \ s *\ ( \ s *\ ) \ s *\ ) // ;
2020-12-15 20:44:36 -08:00
}
}
}
# Check for _ _ attribute__ unused , prefer _ _ always_unused or _ _ maybe_unused
if ( $ attr =~ /^ _ * unused / ) {
WARN ( "PREFER_DEFINED_ATTRIBUTE_MACRO" ,
"__always_unused or __maybe_unused is preferred over __attribute__((__unused__))\n" . $ herecurr ) ;
2013-09-11 14:23:54 -07:00
}
2012-03-23 15:02:16 -07:00
}
2014-12-10 15:51:35 -08:00
# Check for _ _ attribute__ weak , or _ _ weak declarations ( may have link issues )
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2014-12-10 15:51:35 -08:00
$ 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 ) ;
}
2016-12-12 16:46:34 -08:00
# check for c99 types like uint8_t used outside of uapi / and tools /
2015-06-25 15:02:49 -07:00
if ( $ realfile ! ~ m @\ binclude / uapi /@ &&
2016-12-12 16:46:34 -08:00
$ realfile ! ~ m @\ btools /@ &&
2015-06-25 15:02:49 -07:00
$ 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 / ;
}
}
}
2016-01-20 14:59:15 -08:00
# 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 / ;
}
}
2010-03-05 13:43:48 -08:00
# check for sizeof ( & )
if ( $ line =~ /\ bsizeof \ s *\ ( \ s *\&/ ) {
2011-07-25 17:13:25 -07:00
WARN ( "SIZEOF_ADDRESS" ,
"sizeof(& should be avoided\n" . $ herecurr ) ;
2010-03-05 13:43:48 -08:00
}
2012-07-30 14:41:22 -07:00
# check for sizeof without parenthesis
if ( $ line =~ /\ bsizeof \ s + ( ( ?:\*\ s * | ) $ Lval | $ Type ( ?:\ s + $ Lval | ) ) / ) {
2013-09-11 14:23:54 -07:00
if ( WARN ( "SIZEOF_PARENTHESIS" ,
"sizeof $1 should be sizeof($1)\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~ s /\ bsizeof \ s + ( ( ?:\*\ s * | ) $ Lval | $ Type ( ?:\ s + $ Lval | ) ) / "sizeof(" . trim ( $ 1 ) . ")" / ex ;
2013-09-11 14:23:54 -07:00
}
2012-07-30 14:41:22 -07:00
}
2012-12-17 16:02:00 -08:00
# 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 ) ;
}
2013-04-29 16:18:13 -07:00
# check for seq_printf uses that could be seq_puts
2013-11-12 15:10:07 -08:00
if ( $ sline =~ /\ bseq_printf \ s *\ ( . * " \ s *\ ) \ s * ; \ s * $ / ) {
2013-04-29 16:18:13 -07:00
my $ fmt = get_quoted_string ( $ line , $ rawline ) ;
2015-02-13 14:38:49 -08:00
$ fmt =~ s / %%//g;
if ( $ fmt ! ~ / %/) {
2013-09-11 14:23:54 -07:00
if ( WARN ( "PREFER_SEQ_PUTS" ,
"Prefer seq_puts to seq_printf\n" . $ herecurr ) &&
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~ s /\ bseq_printf \ b / seq_puts / ;
2013-09-11 14:23:54 -07:00
}
2013-04-29 16:18:13 -07:00
}
}
2018-04-10 16:33:34 -07:00
# check for vsprintf extension %p<foo> misuses
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2017-05-08 15:55:36 -07:00
defined $ stat &&
$ stat =~ /^\+ ( ? ! [ ^\ { ] *\ { \ s * ) . *\ b ( \ w + ) \ s *\ ( . * $ String \ s * , / s &&
$ 1 ! ~ /^ _ * volatile_ * $ / ) {
2018-04-10 16:33:31 -07:00
my $ stat_real ;
2017-05-08 15:55:36 -07:00
my $ lc = $ stat =~ tr @\ n @@ ;
$ lc = $ lc + $ linenr ;
for ( my $ count = $ linenr ; $ count <= $ lc ; $ count ++ ) {
2018-07-13 16:59:23 -07:00
my $ specifier ;
my $ extension ;
2019-10-03 15:32:18 +03:00
my $ qualifier ;
2018-07-13 16:59:23 -07:00
my $ bad_specifier = "" ;
2017-05-08 15:55:36 -07:00
my $ fmt = get_quoted_string ( $ lines [ $ count - 1 ] , raw_line ( $ count , 0 ) ) ;
$ fmt =~ s / %%//g;
2018-04-10 16:33:20 -07:00
2019-10-03 15:32:18 +03:00
while ( $ fmt =~ / ( \ %[\*\d\.]*p(\w)(\w*))/g) {
2018-04-10 16:33:31 -07:00
$ specifier = $ 1 ;
$ extension = $ 2 ;
2019-10-03 15:32:18 +03:00
$ qualifier = $ 3 ;
2019-11-26 19:45:12 -08:00
if ( $ extension ! ~ / [ SsBKRraEehMmIiUDdgVCbGNOxtf ] / | |
2019-10-03 15:32:18 +03:00
( $ extension eq "f" &&
defined $ qualifier && $ qualifier ! ~ /^ w / ) ) {
2018-04-10 16:33:31 -07:00
$ bad_specifier = $ specifier ;
last ;
}
if ( $ extension eq "x" && ! defined ( $ stat_real ) ) {
if ( ! defined ( $ stat_real ) ) {
$ stat_real = get_stat_real ( $ linenr , $ lc ) ;
}
WARN ( "VSPRINTF_SPECIFIER_PX" ,
" Using vsprintf specifier '\%px' potentially exposes the kernel memory layout , if you don 't really need the address please consider using ' \ %p'.\n" . "$here\n$stat_real\n");
}
}
if ( $ bad_specifier ne "" ) {
my $ stat_real = get_stat_real ( $ linenr , $ lc ) ;
my $ ext_type = "Invalid" ;
my $ use = "" ;
if ( $ bad_specifier =~ / p [ Ff ] / ) {
$ use = " - use %pS instead" ;
$ use =~ s / pS / ps / if ( $ bad_specifier =~ / pf / ) ;
}
WARN ( "VSPRINTF_POINTER_EXTENSION" ,
"$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n" ) ;
}
2017-05-08 15:55:36 -07:00
}
}
2012-01-10 15:09:57 -08:00
# Check for misused memsets
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2012-03-23 15:02:16 -07:00
defined $ stat &&
2015-06-25 15:03:16 -07:00
$ stat =~ /^\+ ( ?:.*? ) \ bmemset \ s *\ ( \ s * $ FuncArg \ s * , \ s * $ FuncArg \ s *\ , \ s * $ FuncArg \ s *\ ) / ) {
2012-01-10 15:09:58 -08:00
my $ ms_addr = $ 2 ;
2012-03-23 15:02:16 -07:00
my $ ms_val = $ 7 ;
my $ ms_size = $ 12 ;
2012-01-10 15:09:57 -08:00
if ( $ ms_size =~ /^ ( 0 x | ) 0 $ / i ) {
ERROR ( "MEMSET" ,
2012-01-10 15:09:58 -08:00
"memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n" ) ;
2012-01-10 15:09:57 -08:00
} elsif ( $ ms_size =~ /^ ( 0 x | ) 1 $ / i ) {
WARN ( "MEMSET" ,
2012-01-10 15:09:58 -08:00
"single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n" ) ;
}
}
2014-01-23 15:54:52 -08:00
# Check for memcpy ( foo , bar , ETH_ALEN ) that could be ether_addr_copy ( foo , bar )
2018-08-21 21:57:33 -07:00
# if ( $ perl_version_ok &&
2016-10-11 13:51:53 -07:00
# 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 ) / ;
# }
# }
2014-01-23 15:54:52 -08:00
2015-06-25 15:03:13 -07:00
# Check for memcmp ( foo , bar , ETH_ALEN ) that could be ether_addr_equal * ( foo , bar )
2018-08-21 21:57:33 -07:00
# if ( $ perl_version_ok &&
2016-10-11 13:51:53 -07:00
# 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" )
# }
2015-06-25 15:03:13 -07:00
2015-06-25 15:03:19 -07:00
# 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
2018-08-21 21:57:33 -07:00
# if ( $ perl_version_ok &&
2016-10-11 13:51:53 -07:00
# defined $ stat &&
# $ stat =~ /^\+ ( ?:.*? ) \ bmemset \ s *\ ( \ s * $ FuncArg \ s * , \ s * $ FuncArg \ s *\ , \ s * ETH_ALEN \ s *\ ) / ) {
#
# my $ ms_val = $ 7 ;
#
# if ( $ ms_val =~ /^ ( ?: 0 x | ) 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 ) / ;
# }
# }
# }
2015-06-25 15:03:19 -07:00
2020-12-29 15:14:31 -08:00
# strlcpy uses that should likely be strscpy
if ( $ line =~ /\ bstrlcpy \ s *\ ( / ) {
WARN ( "STRLCPY" ,
" Prefer strscpy over strlcpy - see : https : // lore . kernel . org / r / CAHk -= wgfRnXz0W3D37d01q3JFkr_i_uTL = V6A6G1oUZcprmknw \@ mail . gmail . com /\ n " . $ herecurr ) ;
}
2012-01-10 15:09:58 -08:00
# typecasts on min / max could be min_t / max_t
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2012-03-23 15:02:16 -07:00
defined $ stat &&
2012-01-10 15:09:58 -08:00
$ stat =~ /^\+ ( ?:.*? ) \ b ( min | max ) \ s *\ ( \ s * $ FuncArg \ s * , \ s * $ FuncArg \ s *\ ) / ) {
2012-03-23 15:02:16 -07:00
if ( defined $ 2 | | defined $ 7 ) {
2012-01-10 15:09:58 -08:00
my $ call = $ 1 ;
my $ cast1 = deparenthesize ( $ 2 ) ;
my $ arg1 = $ 3 ;
2012-03-23 15:02:16 -07:00
my $ cast2 = deparenthesize ( $ 7 ) ;
my $ arg2 = $ 8 ;
2012-01-10 15:09:58 -08:00
my $ cast ;
2012-03-23 15:02:16 -07:00
if ( $ cast1 ne "" && $ cast2 ne "" && $ cast1 ne $ cast2 ) {
2012-01-10 15:09:58 -08:00
$ 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" ) ;
2012-01-10 15:09:57 -08:00
}
}
2012-07-30 14:41:20 -07:00
# check usleep_range arguments
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2012-07-30 14:41:20 -07:00
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" ,
2019-06-12 14:53:00 -03:00
"usleep_range should not use min == max args; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n" ) ;
2012-07-30 14:41:20 -07:00
} elsif ( $ min =~ /^\ d + $ / && $ max =~ /^\ d + $ / &&
$ min > $ max ) {
WARN ( "USLEEP_RANGE" ,
2019-06-12 14:53:00 -03:00
"usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n" ) ;
2012-07-30 14:41:20 -07:00
}
}
2013-11-12 15:10:15 -08:00
# check for naked sscanf
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2013-11-12 15:10:15 -08:00
defined $ stat &&
2014-04-03 14:49:16 -07:00
$ line =~ /\ bsscanf \ b / &&
2013-11-12 15:10:15 -08:00
( $ 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 ;
2018-04-10 16:33:20 -07:00
my $ stat_real = get_stat_real ( $ linenr , $ lc ) ;
2013-11-12 15:10:15 -08:00
WARN ( "NAKED_SSCANF" ,
"unchecked sscanf return value\n" . "$here\n$stat_real\n" ) ;
}
2014-06-04 16:12:08 -07:00
# check for simple sscanf that should be kstrto < foo >
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2014-06-04 16:12:08 -07:00
defined $ stat &&
$ line =~ /\ bsscanf \ b / ) {
my $ lc = $ stat =~ tr @\ n @@ ;
$ lc = $ lc + $ linenr ;
2018-04-10 16:33:20 -07:00
my $ stat_real = get_stat_real ( $ linenr , $ lc ) ;
2014-06-04 16:12:08 -07:00
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" ) ;
}
}
}
2013-09-11 14:23:58 -07:00
# check for new externs in . h files .
if ( $ realfile =~ /\. h$ / &&
$ line =~ /^\+\ s * ( extern \ s + ) $ Type \ s * $ Ident \ s *\ ( / s ) {
2013-09-24 15:27:46 -07:00
if ( CHK ( "AVOID_EXTERNS" ,
"extern prototypes should be avoided in .h files\n" . $ herecurr ) &&
2013-09-11 14:23:58 -07:00
$ fix ) {
2014-08-06 16:11:03 -07:00
$ fixed [ $ fixlinenr ] =~ s / ( . * ) \ bextern \ b \ s * ( . * ) / $ 1 $ 2 / ;
2013-09-11 14:23:58 -07:00
}
}
2007-07-15 23:37:22 -07:00
# check for new externs in . c files .
2008-04-29 00:59:32 -07:00
if ( $ realfile =~ /\. c$ / && defined $ stat &&
2008-06-05 22:46:01 -07:00
$ stat =~ /^.\ s * ( ?: extern \ s + ) ? $ Type \ s + ( $ Ident ) ( \ s * ) \ ( / s )
2008-04-29 00:59:32 -07:00
{
2008-06-05 22:46:01 -07:00
my $ function_name = $ 1 ;
my $ paren_space = $ 2 ;
2008-04-29 00:59:32 -07:00
my $ s = $ stat ;
if ( defined $ cond ) {
substr ( $ s , 0 , length ( $ cond ) , '' ) ;
}
2020-06-03 14:18:09 -07:00
if ( $ s =~ /^\ s * ; / )
2008-06-05 22:46:01 -07:00
{
2011-07-25 17:13:25 -07:00
WARN ( "AVOID_EXTERNS" ,
"externs should be avoided in .c files\n" . $ herecurr ) ;
2008-04-29 00:59:32 -07:00
}
if ( $ paren_space =~ /\ n / ) {
2011-07-25 17:13:25 -07:00
WARN ( "FUNCTION_ARGUMENTS" ,
"arguments for function declarations should follow identifier\n" . $ herecurr ) ;
2008-04-29 00:59:32 -07:00
}
2008-04-29 00:59:33 -07:00
} elsif ( $ realfile =~ /\. c$ / && defined $ stat &&
$ stat =~ /^.\ s * extern \ s +/ )
{
2011-07-25 17:13:25 -07:00
WARN ( "AVOID_EXTERNS" ,
"externs should be avoided in .c files\n" . $ herecurr ) ;
2007-07-15 23:37:22 -07:00
}
2017-07-10 15:52:19 -07:00
# check for function declarations that have arguments without identifier names
if ( defined $ stat &&
2020-06-03 14:18:09 -07:00
$ stat =~ /^.\ s * ( ?: extern \ s + ) ? $ Type \ s * ( ?: $ Ident | \ ( \ s *\*\ s * $ Ident \ s *\ ) ) \ s *\ ( \ s * ( [ ^ { ] + ) \ s *\ ) \ s * ; / s &&
$ 1 ne "void" ) {
my $ args = trim ( $ 1 ) ;
2016-10-11 13:52:16 -07:00
while ( $ args =~ m /\ s * ( $ Type \ s * ( ?: $ Ident | \ ( \ s *\*\ s * $ Ident ?\ s *\ ) \ s * $ balanced_parens ) ? ) / g ) {
my $ arg = trim ( $ 1 ) ;
2020-06-03 14:18:09 -07:00
if ( $ arg =~ /^ $ Type $ / && $ arg ! ~ / enum \ s + $ Ident $ / ) {
2016-10-11 13:52:16 -07:00
WARN ( "FUNCTION_ARGUMENTS" ,
"function definition argument '$arg' should also have an identifier name\n" . $ herecurr ) ;
}
}
}
2017-07-10 15:52:19 -07:00
# check for function definitions
2018-08-21 21:57:33 -07:00
if ( $ perl_version_ok &&
2017-07-10 15:52:19 -07:00
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 ) ;
}
}
2007-07-15 23:37:22 -07:00
# checks for new _ _ setup 's
if ($rawline =~ /\b__setup\("([^"]*)"/) {
my $name = $1;
if (!grep(/$name/, @setup_docs)) {
2011-07-25 17:13:25 -07:00
CHK("UNDOCUMENTED_SETUP",
2020-06-10 18:41:38 -07:00
"__setup appears un-documented -- check Documentation/admin-guide/kernel-parameters.txt\n" . $herecurr);
2007-07-15 23:37:22 -07:00
}
2007-06-23 17:16:34 -07:00
}
2007-10-16 23:29:38 -07:00
2019-03-07 16:28:35 -08:00
# check for pointless casting of alloc functions
if ($line =~ /\*\s*\)\s*$allocFunctions\b/) {
2011-07-25 17:13:25 -07:00
WARN("UNNECESSARY_CASTS",
"unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
2007-10-16 23:29:38 -07:00
}
2008-02-08 04:22:03 -08:00
2013-07-03 15:05:21 -07:00
# alloc style
# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2019-03-07 16:28:35 -08:00
$line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k|v)[mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
2013-07-03 15:05:21 -07:00
CHK("ALLOC_SIZEOF_STRUCT",
"Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
}
2014-06-04 16:12:07 -07:00
# check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2017-05-08 15:55:57 -07:00
defined $stat &&
$stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
2014-06-04 16:12:07 -07:00
my $oldfunc = $3;
my $a1 = $4;
my $a2 = $10;
my $newfunc = "kmalloc_array";
$newfunc = "kcalloc" if ($oldfunc eq "kzalloc");
2014-08-06 16:10:55 -07:00
my $r1 = $a1;
my $r2 = $a2;
if ($a1 =~ /^sizeof\s*\S/) {
$r1 = $a2;
$r2 = $a1;
}
if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ &&
!($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) {
2017-05-08 15:55:57 -07:00
my $cnt = statement_rawlines($stat);
2018-04-10 16:33:27 -07:00
my $herectx = get_stat_here($linenr, $cnt, $here);
2014-06-04 16:12:07 -07:00
if (WARN("ALLOC_WITH_MULTIPLY",
2017-05-08 15:55:57 -07:00
"Prefer $newfunc over $oldfunc with multiply\n" . $herectx) &&
$cnt == 1 &&
2014-06-04 16:12:07 -07:00
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ' , ' . trim($r2)/e;
2014-06-04 16:12:07 -07:00
}
}
}
2013-04-29 16:18:12 -07:00
# check for krealloc arg reuse
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2018-08-21 21:57:50 -07:00
$line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ &&
$1 eq $3) {
2013-04-29 16:18:12 -07:00
WARN("KREALLOC_ARG_REUSE",
"Reusing the krealloc arg is almost always a bug\n" . $herecurr);
}
2013-02-21 16:44:18 -08:00
# check for alloc argument mismatch
if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) {
WARN("ALLOC_ARRAY_ARGS",
"$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
}
2011-01-12 16:59:56 -08:00
# check for multiple semicolons
if ($line =~ /;\s*;\s*$/) {
2013-09-11 14:23:54 -07:00
if (WARN("ONE_SEMICOLON",
"Statements terminations use 1 semicolon\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/(\s*;\s*){2,}$/;/g;
2013-09-11 14:23:54 -07:00
}
2012-12-17 16:02:01 -08:00
}
2016-08-02 14:04:39 -07:00
# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi
if ($realfile !~ m@^include/uapi/@ &&
$line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
2014-12-10 15:51:57 -08:00
my $ull = "";
$ull = "_ULL" if (defined($1) && $1 =~ /ll/i);
if (CHK("BIT_MACRO",
"Prefer using the BIT$ull macro\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\(?\s*1\s*[ulUL]*\s*<<\s*(\d+|$Ident)\s*\)?/BIT${ull}($1)/;
}
}
2020-08-11 18:35:07 -07:00
# check for IS_ENABLED() without CONFIG_<FOO> ($rawline for comments too)
2020-10-15 20:11:49 -07:00
if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/ && $1 !~ /^${CONFIG_}/) {
2020-08-11 18:35:07 -07:00
WARN("IS_ENABLED_CONFIG",
2020-10-15 20:11:49 -07:00
"IS_ENABLED($1) is normally used as IS_ENABLED(${CONFIG_}$1)\n" . $herecurr);
2020-08-11 18:35:07 -07:00
}
2016-05-20 17:04:00 -07:00
# check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE
2020-10-15 20:11:49 -07:00
if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(${CONFIG_}[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) {
2016-05-20 17:04:00 -07:00
my $config = $1;
if (WARN("PREFER_IS_ENABLED",
2020-10-15 20:11:49 -07:00
"Prefer IS_ENABLED(<FOO>) to ${CONFIG_}<FOO> || ${CONFIG_}<FOO>_MODULE\n" . $herecurr) &&
2016-05-20 17:04:00 -07:00
$fix) {
$fixed[$fixlinenr] = "\+#if IS_ENABLED($config)";
}
}
2020-04-06 20:10:58 -07:00
# 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;
}
}
}
2012-12-17 16:02:01 -08:00
# check for switch/default statements without a break;
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2012-12-17 16:02:01 -08:00
defined $stat &&
$stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) {
my $cnt = statement_rawlines($stat);
2018-04-10 16:33:27 -07:00
my $herectx = get_stat_here($linenr, $cnt, $here);
2012-12-17 16:02:01 -08:00
WARN("DEFAULT_NO_BREAK",
"switch default: should use break\n" . $herectx);
2011-01-12 16:59:56 -08:00
}
2008-02-08 04:22:03 -08:00
# check for gcc specific __FUNCTION__
2013-09-11 14:23:54 -07:00
if ($line =~ /\b__FUNCTION__\b/) {
if (WARN("USE_FUNC",
"__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr) &&
$fix) {
2014-08-06 16:11:03 -07:00
$fixed[$fixlinenr] =~ s/\b__FUNCTION__\b/__func__/g;
2013-09-11 14:23:54 -07:00
}
2008-02-08 04:22:03 -08:00
}
2008-03-28 14:15:58 -07:00
2015-02-13 14:38:18 -08:00
# check for uses of __DATE__, __TIME__, __TIMESTAMP__
while ($line =~ /\b(__(?:DATE|TIME|TIMESTAMP)__)\b/g) {
ERROR("DATE_TIME",
"Use of the ' $ 1 ' macro makes the build non-deterministic\n" . $herecurr);
}
2012-03-23 15:02:20 -07:00
# check for use of yield()
if ($line =~ /\byield\s*\(\s*\)/) {
WARN("YIELD",
"Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr);
}
2013-07-03 15:05:30 -07:00
# check for comparisons against true and false
if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) {
my $lead = $1;
my $arg = $2;
my $test = $3;
my $otype = $4;
my $trail = $5;
my $op = "!";
($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i);
my $type = lc($otype);
if ($type =~ /^(?:true|false)$/) {
if (("$test" eq "==" && "$type" eq "true") ||
("$test" eq "!=" && "$type" eq "false")) {
$op = "";
}
CHK("BOOL_COMPARISON",
"Using comparison to $otype is error prone\n" . $herecurr);
## maybe suggesting a correct construct would better
## "Using comparison to $otype is error prone. Perhaps use ' $ { lead } $ { op } $ { arg } $ { trail } '\n" . $herecurr);
}
}
2010-09-07 14:34:01 +00:00
# check for semaphores initialized locked
if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
2011-07-25 17:13:25 -07:00
WARN("CONSIDER_COMPLETION",
"consider using a completion\n" . $herecurr);
2008-03-28 14:15:58 -07:00
}
2012-03-23 15:02:20 -07:00
2011-10-31 17:13:10 -07:00
# recommend kstrto* over simple_strto* and strict_strto*
if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) {
2011-07-25 17:13:25 -07:00
WARN("CONSIDER_KSTRTO",
2011-10-31 17:13:10 -07:00
"$1 is obsolete, use k$3 instead\n" . $herecurr);
2008-03-28 14:15:58 -07:00
}
2012-03-23 15:02:20 -07:00
2014-06-04 16:12:10 -07:00
# check for __initcall(), use device_initcall() explicitly or more appropriate function please
2008-07-23 21:28:57 -07:00
if ($line =~ /^.\s*__initcall\s*\(/) {
2011-07-25 17:13:25 -07:00
WARN("USE_DEVICE_INITCALL",
2014-06-04 16:12:10 -07:00
"please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr);
2008-07-23 21:28:57 -07:00
}
2012-03-23 15:02:20 -07:00
2018-11-11 10:49:10 -08:00
# check for spin_is_locked(), suggest lockdep instead
if ($line =~ /\bspin_is_locked\(/) {
WARN("USE_LOCKDEP",
"Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr);
}
2018-09-07 15:26:18 -07:00
# check for deprecated apis
if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) {
my $deprecated_api = $1;
my $new_api = $deprecated_apis{$deprecated_api};
WARN("DEPRECATED_API",
"Deprecated use of ' $ deprecated_api ', prefer ' $ new_api ' instead\n" . $herecurr);
}
2015-02-13 14:39:05 -08:00
# check for various structs that are normally const (ops, kgdb, device_tree)
2017-05-08 15:55:45 -07:00
# and avoid what seem like struct definitions ' struct foo { '
2020-08-11 18:35:13 -07:00
if (defined($const_structs) &&
$line !~ /\bconst\b/ &&
2017-05-08 15:55:45 -07:00
$line =~ /\bstruct\s+($const_structs)\b(?!\s*\{)/) {
2011-07-25 17:13:25 -07:00
WARN("CONST_STRUCT",
2017-05-08 15:55:45 -07:00
"struct $1 should normally be const\n" . $herecurr);
2009-01-06 14:41:29 -08:00
}
2008-03-28 14:15:58 -07:00
# use of NR_CPUS is usually wrong
# ignore definitions of NR_CPUS and usage to define arrays as likely right
if ($line =~ /\bNR_CPUS\b/ &&
2008-06-05 22:46:01 -07:00
$line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
$line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
2008-04-29 00:59:32 -07:00
$line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
$line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
$line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
2008-03-28 14:15:58 -07:00
{
2011-07-25 17:13:25 -07:00
WARN("NR_CPUS",
"usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
2008-03-28 14:15:58 -07:00
}
2008-04-29 00:59:33 -07:00
2013-11-12 15:10:09 -08:00
# Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong.
if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) {
ERROR("DEFINE_ARCH_HAS",
"#define of ' $ 1 ' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr);
}
2015-02-13 14:38:38 -08:00
# likely/unlikely comparisons similar to "(likely(foo) > 0)"
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2015-02-13 14:38:38 -08:00
$line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) {
WARN("LIKELY_MISUSE",
"Using $1 should generally have parentheses around the comparison\n" . $herecurr);
}
2019-09-25 16:49:25 -07:00
# nested likely/unlikely calls
if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) {
WARN("LIKELY_MISUSE",
"nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr);
}
2009-01-06 14:41:16 -08:00
# whine mightly about in_atomic
if ($line =~ /\bin_atomic\s*\(/) {
if ($realfile =~ m@^drivers/@) {
2011-07-25 17:13:25 -07:00
ERROR("IN_ATOMIC",
"do not use in_atomic in drivers\n" . $herecurr);
2009-02-27 14:03:05 -08:00
} elsif ($realfile !~ m@^kernel/@) {
2011-07-25 17:13:25 -07:00
WARN("IN_ATOMIC",
"use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
2009-01-06 14:41:16 -08:00
}
}
2010-03-19 01:37:42 +01:00
2016-10-07 17:43:51 +02:00
# check for mutex_trylock_recursive usage
if ($line =~ /mutex_trylock_recursive/) {
ERROR("LOCKING",
"recursive locking is bad, do not use this ever.\n" . $herecurr);
}
2010-03-19 01:37:42 +01:00
# check for lockdep_set_novalidate_class
if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
$line =~ /__lockdep_no_validate__\s*\)/ ) {
if ($realfile !~ m@^kernel/lockdep@ &&
$realfile !~ m@^include/linux/lockdep@ &&
$realfile !~ m@^drivers/base/core@) {
2011-07-25 17:13:25 -07:00
ERROR("LOCKDEP",
"lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr);
2010-03-19 01:37:42 +01:00
}
}
2011-01-12 16:59:59 -08:00
2015-04-16 12:44:16 -07:00
if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ ||
$line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) {
2011-07-25 17:13:25 -07:00
WARN("EXPORTED_WORLD_WRITABLE",
"Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
2011-01-12 16:59:59 -08:00
}
2014-04-03 14:49:13 -07:00
2018-02-06 15:38:55 -08:00
# check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO>
# and whether or not function naming is typical and if
# DEVICE_ATTR permissions uses are unusual too
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2018-02-06 15:38:55 -08:00
defined $stat &&
$stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) {
my $var = $1;
my $perms = $2;
my $show = $3;
my $store = $4;
my $octal_perms = perms_to_octal($perms);
if ($show =~ /^${var}_show$/ &&
$store =~ /^${var}_store$/ &&
$octal_perms eq "0644") {
if (WARN("DEVICE_ATTR_RW",
"Use DEVICE_ATTR_RW\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*$store\s*\)/DEVICE_ATTR_RW(${var})/;
}
} elsif ($show =~ /^${var}_show$/ &&
$store =~ /^NULL$/ &&
$octal_perms eq "0444") {
if (WARN("DEVICE_ATTR_RO",
"Use DEVICE_ATTR_RO\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*NULL\s*\)/DEVICE_ATTR_RO(${var})/;
}
} elsif ($show =~ /^NULL$/ &&
$store =~ /^${var}_store$/ &&
$octal_perms eq "0200") {
if (WARN("DEVICE_ATTR_WO",
"Use DEVICE_ATTR_WO\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*NULL\s*,\s*$store\s*\)/DEVICE_ATTR_WO(${var})/;
}
} elsif ($octal_perms eq "0644" ||
$octal_perms eq "0444" ||
$octal_perms eq "0200") {
my $newshow = "$show";
$newshow = "${var}_show" if ($show ne "NULL" && $show ne "${var}_show");
my $newstore = $store;
$newstore = "${var}_store" if ($store ne "NULL" && $store ne "${var}_store");
my $rename = "";
if ($show ne $newshow) {
$rename .= " ' $ show ' to ' $ newshow '";
}
if ($store ne $newstore) {
$rename .= " ' $ store ' to ' $ newstore '";
}
WARN("DEVICE_ATTR_FUNCTIONS",
"Consider renaming function(s)$rename\n" . $herecurr);
} else {
WARN("DEVICE_ATTR_PERMS",
"DEVICE_ATTR unusual permissions ' $ perms ' used\n" . $herecurr);
}
}
2014-04-03 14:49:24 -07:00
# Mode permission misuses where it seems decimal should be octal
# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop
2018-02-06 15:38:49 -08:00
# o Ignore module_param*(...) uses with a decimal 0 permission as that has a
# specific definition of not visible in sysfs.
# o Ignore proc_create*(...) uses with a decimal 0 permission as that means
# use the default permissions
2018-08-21 21:57:33 -07:00
if ($perl_version_ok &&
2016-10-11 13:52:19 -07:00
defined $stat &&
2014-04-03 14:49:24 -07:00
$line =~ /$mode_perms_search/) {
foreach my $entry (@mode_permission_funcs) {
my $func = $entry->[0];
my $arg_pos = $entry->[1];
2014-04-03 14:49:13 -07:00
2016-10-11 13:52:19 -07:00
my $lc = $stat =~ tr@\n@@;
$lc = $lc + $linenr;
2018-04-10 16:33:20 -07:00
my $stat_real = get_stat_real($linenr, $lc);
2016-10-11 13:52:19 -07:00
2014-04-03 14:49:24 -07:00
my $skip_args = "";
if ($arg_pos > 1) {
$arg_pos--;
$skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}";
}
2016-10-11 13:51:47 -07:00
my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]";
2016-10-11 13:52:19 -07:00
if ($stat =~ /$test/) {
2014-04-03 14:49:24 -07:00
my $val = $1;
$val = $6 if ($skip_args ne "");
2018-02-06 15:38:49 -08:00
if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") &&
(($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
($val =~ /^$Octal$/ && length($val) ne 4))) {
2014-04-03 14:49:24 -07:00
ERROR("NON_OCTAL_PERMISSIONS",
2016-10-11 13:52:19 -07:00
"Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real);
2016-10-11 13:51:47 -07:00
}
if ($val =~ /^$Octal$/ && (oct($val) & 02)) {
2015-02-13 14:38:21 -08:00
ERROR("EXPORTED_WORLD_WRITABLE",
2016-10-11 13:52:19 -07:00
"Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real);
2016-10-11 13:51:47 -07:00
}
2014-04-03 14:49:13 -07:00
}
}
}
2015-06-25 15:03:24 -07:00
2016-10-11 13:52:19 -07:00
# check for uses of S_<PERMS> that could be octal for readability
2018-04-10 16:33:53 -07:00
while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) {
2018-02-06 15:38:55 -08:00
my $oval = $1;
my $octal = perms_to_octal($oval);
2016-10-11 13:52:19 -07:00
if (WARN("SYMBOLIC_PERMS",
"Symbolic permissions ' $ oval ' are not preferred. Consider using octal permissions ' $ octal '.\n" . $herecurr) &&
$fix) {
2018-02-06 15:38:55 -08:00
$fixed[$fixlinenr] =~ s/\Q$oval\E/$octal/;
2016-10-11 13:52:19 -07:00
}
}
2015-06-25 15:03:24 -07:00
# validate content of MODULE_LICENSE against list from include/linux/module.h
if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) {
my $extracted_string = get_quoted_string($line, $rawline);
my $valid_licenses = qr{
GPL|
GPL\ v2|
GPL\ and\ additional\ rights|
Dual\ BSD/GPL|
Dual\ MIT/GPL|
Dual\ MPL/GPL|
Proprietary
}x;
if ($extracted_string !~ /^"(?:$valid_licenses)"$/x) {
WARN("MODULE_LICENSE",
"unknown module license " . $extracted_string . "\n" . $herecurr);
}
}
2019-07-16 16:27:48 -07:00
# check for sysctl duplicate constants
if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) {
WARN("DUPLICATED_SYSCTL_CONST",
"duplicated sysctl range checking value ' $ 1 ', consider using the shared one in include/linux/sysctl.h\n" . $herecurr);
}
2008-02-08 04:22:03 -08:00
}
# If we have no input at all, then there is nothing to report on
# so just keep quiet.
if ($#rawlines == -1) {
exit(0);
2007-06-01 00:46:48 -07:00
}
2007-11-28 16:21:06 -08:00
# In mailback mode only produce a report in the negative, for
# things that appear to be patches.
if ($mailback && ($clean == 1 || !$is_patch)) {
exit(0);
}
2020-12-15 20:44:56 -08:00
# This is not a patch, and we are in ' no - patch ' mode so
2007-11-28 16:21:06 -08:00
# just keep quiet.
if (!$chk_patch && !$is_patch) {
exit(0);
}
2017-10-03 16:16:51 -07:00
if (!$is_patch && $filename !~ /cover-letter\.patch$/) {
2011-07-25 17:13:25 -07:00
ERROR("NOT_UNIFIED_DIFF",
"Does not appear to be a unified-diff format patch\n");
2007-06-01 00:46:48 -07:00
}
2018-08-21 21:57:40 -07:00
if ($is_patch && $has_commit_log && $chk_signoff) {
if ($signoff == 0) {
ERROR("MISSING_SIGN_OFF",
"Missing Signed-off-by: line(s)\n");
2020-10-15 20:12:28 -07:00
} elsif ($authorsignoff != 1) {
# authorsignoff values:
# 0 -> missing sign off
# 1 -> sign off identical
# 2 -> names and addresses match, comments mismatch
# 3 -> addresses match, names different
# 4 -> names match, addresses different
# 5 -> names match, addresses excluding subaddress details (refer RFC 5233) match
my $sob_msg = "' From : $ author ' != ' Signed - off - by : $ author_sob '";
if ($authorsignoff == 0) {
ERROR("NO_AUTHOR_SIGN_OFF",
"Missing Signed-off-by: line by nominal patch author ' $ author '\n");
} elsif ($authorsignoff == 2) {
CHK("FROM_SIGN_OFF_MISMATCH",
"From:/Signed-off-by: email comments mismatch: $sob_msg\n");
} elsif ($authorsignoff == 3) {
WARN("FROM_SIGN_OFF_MISMATCH",
"From:/Signed-off-by: email name mismatch: $sob_msg\n");
} elsif ($authorsignoff == 4) {
WARN("FROM_SIGN_OFF_MISMATCH",
"From:/Signed-off-by: email address mismatch: $sob_msg\n");
} elsif ($authorsignoff == 5) {
WARN("FROM_SIGN_OFF_MISMATCH",
"From:/Signed-off-by: email subaddress mismatch: $sob_msg\n");
}
2018-08-21 21:57:40 -07:00
}
2007-06-01 00:46:48 -07:00
}
2007-11-28 16:21:06 -08:00
print report_dump();
2008-02-08 04:22:03 -08:00
if ($summary && !($clean == 1 && $quiet == 1)) {
print "$filename " if ($summary_file);
2007-11-28 16:21:06 -08:00
print "total: $cnt_error errors, $cnt_warn warnings, " .
(($check)? "$cnt_chk checks, " : "") .
"$cnt_lines lines checked\n";
2007-07-19 01:48:34 -07:00
}
2007-11-28 16:21:06 -08:00
2010-10-26 14:23:12 -07:00
if ($quiet == 0) {
2016-05-20 17:04:11 -07:00
# If there were any defects found and not already fixing them
if (!$clean and !$fix) {
print << "EOM"
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
EOM
}
2010-10-26 14:23:12 -07:00
# If there were whitespace errors which cleanpatch can fix
# then suggest that.
if ($rpt_cleaners) {
2011-03-22 16:34:43 -07:00
$rpt_cleaners = 0;
2015-06-25 15:03:00 -07:00
print << "EOM"
NOTE: Whitespace errors detected.
You may wish to use scripts/cleanpatch or scripts/cleanfile
EOM
2010-10-26 14:23:12 -07:00
}
}
2014-08-06 16:11:05 -07:00
if ($clean == 0 && $fix &&
("@rawlines" ne "@fixed" ||
$#fixed_inserted >= 0 || $#fixed_deleted >= 0)) {
2014-01-23 15:54:44 -08:00
my $newfile = $filename;
$newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace);
2013-07-03 15:05:31 -07:00
my $linecount = 0;
my $f;
2014-08-06 16:11:05 -07:00
@fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted);
2013-07-03 15:05:31 -07:00
open($f, ' > ', $newfile)
or die "$P: Can' t open $ newfile for write \ n " ;
foreach my $ fixed_line ( @ fixed ) {
$ linecount ++ ;
if ( $ file ) {
if ( $ linecount > 3 ) {
$ fixed_line =~ s /^\+// ;
2014-08-06 16:11:05 -07:00
print $ f $ fixed_line . "\n" ;
2013-07-03 15:05:31 -07:00
}
} else {
print $ f $ fixed_line . "\n" ;
}
}
close ( $ f ) ;
if ( ! $ quiet ) {
print << "EOM" ;
2015-06-25 15:03:00 -07:00
2013-07-03 15:05:31 -07:00
Wrote EXPERIMENTAL -- fix correction ( s ) to '$newfile'
Do _ NOT_ trust the results written to this file .
Do _ NOT_ submit these changes without inspecting them for correctness .
This EXPERIMENTAL file is simply a convenience to help rewrite patches .
No warranties , expressed or implied . . .
EOM
}
}
2015-06-25 15:03:00 -07:00
if ( $ quiet == 0 ) {
print "\n" ;
if ( $ clean == 1 ) {
print "$vname has no obvious style problems and is ready for submission.\n" ;
} else {
print "$vname has style problems, please review.\n" ;
}
2007-06-01 00:46:48 -07:00
}
return $ clean ;
}