Messages in this thread Patch in this message | | | Subject | Re: [PATCH] checkpatch: Add test for possible misuse of IS_ENABLED() without CONFIG_ | From | Joe Perches <> | Date | Fri, 05 Jun 2020 18:58:52 -0700 |
| |
On Fri, 2020-06-05 at 17:32 -0700, Andrew Morton wrote: > On Fri, 05 Jun 2020 11:24:43 -0700 Joe Perches <joe@perches.com> wrote: > > > IS_ENABLED is almost always used with CONFIG_<FOO> defines. > > > > Add a test to verify that the #define being tested starts with CONFIG_. > > Yay. > > I wonder if there's a simple way of testing whether the CONFIG_ thing > can *ever* be enabled. So detect if someone does > > if (IS_ENABLED(CONFIG_BLOCKK))
No, not really. There's no simple way to do that. It's doable, but it's not at all simple.
I think it would require something similar to the checkpatch seed_camelcase_includes function to look for all current config symbols and verify whatever CONFIG_<DEFINE> against that list.
$ git grep -P -oh "^\s*config\s+\w+" -- '*/Kconfig*' | \ sed -r -e 's/^\s+//' -e 's/\s+/ /g' | \ sort | uniq -cym
Right now that takes ~1.5 seconds with my laptop against an uncached git tree, and ~0.25 seconds cached.
Without a git tree it takes 20+ seconds.
Anyway, maybe this.
It only does the time consuming lookup when it finds a IS_ENABLED line.
--- scripts/checkpatch.pl | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+)
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 5f00df2c3f59..aabb01cf1e6c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -47,6 +47,7 @@ my $gitroot = $ENV{'GIT_DIR'}; $gitroot = ".git" if !defined($gitroot); my %debug; my %camelcase = (); +my %Kconfig_syms = (); my %use_type = (); my @use = (); my %ignore_type = (); @@ -911,6 +912,90 @@ sub is_SPDX_License_valid { return 1; } +sub seed_Kconfig_file { + my ($file) = @_; + + return if (!(-f $file)); + + local $/; + + open(my $Kconfig_file, '<', "$file") + or warn "$P: Can't read '$file' $!\n"; + my $text = <$Kconfig_file>; + close($Kconfig_file); + + my @lines = split('\n', $text); + + foreach my $line (@lines) { + next if ($line !~ /^\s*config\s+(\w+)/); + $Kconfig_syms{$1} = 1; + } +} + +my $Kconfig_symbols_seeded = 0; +sub seed_Kconfig_symbols { + return if ($Kconfig_symbols_seeded); + + my $files; + my @Kconfig_files = (); + my $Kconfig_syms_cache = ""; + + $Kconfig_symbols_seeded = 1; + + if (-e "$gitroot") { + my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`; + chomp $git_last_include_commit; + $Kconfig_syms_cache = ".checkpatch-Kconfig_syms.git.$git_last_include_commit"; + } else { + my $last_mod_date = 0; + $files = `find $root/ -name "Kconfig*"`; + @Kconfig_files = split('\n', $files); + foreach my $file (@Kconfig_files) { + my $date = POSIX::strftime("%Y%m%d%H%M", + localtime((stat $file)[9])); + $last_mod_date = $date if ($last_mod_date < $date); + } + $Kconfig_syms_cache = ".checkpatch-Kconfig_syms.date.$last_mod_date"; + } + + if ($Kconfig_syms_cache ne "" && -f $Kconfig_syms_cache) { + open(my $Kconfig_syms_file, '<', "$Kconfig_syms_cache") + or warn "$P: Can't read '$Kconfig_syms_cache' $!\n"; + while (<$Kconfig_syms_file>) { + chomp; + $Kconfig_syms{$_} = 1; + } + close($Kconfig_syms_file); + + return; + } + + if (-e "$gitroot") { + my @syms = `${git_command} grep -P -oh '^\\s*config\\s+\\w+' -- '*/Kconfig*'`; + s/^\s+// for @syms; + s/config\s+// for @syms; + s/\n$// for @syms; + @syms = sort(uniq(@syms)); + foreach my $sym (@syms) { + $Kconfig_syms{$sym} = 1; + } + } else { + foreach my $file (@Kconfig_files) { + seed_Kconfig_file($file); + } + } + + if ($Kconfig_syms_cache ne "") { + unlink glob ".checkpatch-Kconfig_syms.*"; + open(my $Kconfig_syms_file, '>', "$Kconfig_syms_cache") + or warn "$P: Can't write '$Kconfig_syms_cache' $!\n"; + foreach (sort { lc($a) cmp lc($b) } keys(%Kconfig_syms)) { + print $Kconfig_syms_file ("$_\n"); + } + close($Kconfig_syms_file); + } +} + my $camelcase_seeded = 0; sub seed_camelcase_includes { return if ($camelcase_seeded); @@ -6480,6 +6565,22 @@ sub process { } } +# check for IS_ENABLED() used without CONFIG_<FOO> ($rawline for comment use) +# or if the CONFIG_<FOO> symbol is not a known Kconfig entry + if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/) { + my $sym = $1; + seed_Kconfig_symbols(); + if ($sym !~ /^CONFIG_/) { + WARN("IS_ENABLED_CONFIG", + "IS_ENABLED($sym) is normally used as IS_ENABLED(CONFIG_$1)\n" . $herecurr); + } + if (!exists($Kconfig_syms{$sym})) { + WARN("IS_ENABLED_CONFIG", + "'$sym' is not a known Kconfig config entry in the current kernel sources\n" . $herecurr); + + } + } + # check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(CONFIG_[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) { my $config = $1;
| |