Re: [PATCH] checkpatch: Add test for possible misuse of IS_ENABLED() without CONFIG_

From: Joe Perches
Date: Sat Jun 06 2020 - 05:50:54 EST


Might s well post one that works

Interdiff similar to:

+ if ($sym !~ /^CONFIG_/) {
+ WARN("IS_ENABLED_CONFIG",
+ "IS_ENABLED($sym) is normally used as IS_ENABLED(CONFIG_$1)\n" . $herecurr);
++ } else {
++ $sym =~ s/^CONFIG_//;
+ }
+ if (!exists($Kconfig_syms{$sym})) {
+ WARN("IS_ENABLED_CONFIG",
-+ "'$sym' is not a known Kconfig config entry in the current kernel sources\n" . $herecurr);
-+
++ "'config $sym' is not a known Kconfig config entry in the current kernel sources\n" . $herecurr);
+ }
+ }
+
---
scripts/checkpatch.pl | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 5f00df2c3f59..02814c689676 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,23 @@ 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);
+ } else {
+ $sym =~ s/^CONFIG_//;
+ }
+ if (!exists($Kconfig_syms{$sym})) {
+ WARN("IS_ENABLED_CONFIG",
+ "'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;