xref: /linux/scripts/kconfig/kconfig-sym-check.pl (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
1*f58316a4SAndrew Jones#!/usr/bin/env perl
2*f58316a4SAndrew Jones# SPDX-License-Identifier: GPL-2.0
3*f58316a4SAndrew Jones
4*f58316a4SAndrew Jonesuse warnings;
5*f58316a4SAndrew Jonesuse strict;
6*f58316a4SAndrew Jones
7*f58316a4SAndrew Jonesmy $srctree = shift @ARGV;
8*f58316a4SAndrew Jonesunless (defined $srctree) {
9*f58316a4SAndrew Jones	$srctree = `git rev-parse --show-toplevel 2>/dev/null`;
10*f58316a4SAndrew Jones	chomp $srctree;
11*f58316a4SAndrew Jones	my $msg = "Usage: $0 <srctree> [excludes file]\n";
12*f58316a4SAndrew Jones	$msg .= "Please provide <srctree>.";
13*f58316a4SAndrew Jones	$msg .= " Is it '$srctree'?" if $srctree;
14*f58316a4SAndrew Jones	$msg .= "\n";
15*f58316a4SAndrew Jones	die $msg;
16*f58316a4SAndrew Jones}
17*f58316a4SAndrew Jonesmy $kconfig_sym_check_excludes = defined $ARGV[0] ? $ARGV[0] : undef;
18*f58316a4SAndrew Jones
19*f58316a4SAndrew Jonessub indent_depth {
20*f58316a4SAndrew Jones	my ($ws) = @_;
21*f58316a4SAndrew Jones	my $col = 0;
22*f58316a4SAndrew Jones	for my $c (split //, $ws) {
23*f58316a4SAndrew Jones		$col = $c eq "\t" ? int($col / 8) * 8 + 8 : $col + 1;
24*f58316a4SAndrew Jones	}
25*f58316a4SAndrew Jones	return $col;
26*f58316a4SAndrew Jones}
27*f58316a4SAndrew Jones
28*f58316a4SAndrew Jonesmy @files = `git -C \Q$srctree\E ls-files '*Kconfig*' 2>/dev/null`;
29*f58316a4SAndrew Jonesif (@files) {
30*f58316a4SAndrew Jones	chomp @files;
31*f58316a4SAndrew Jones	@files = map { "$srctree/$_" } @files;
32*f58316a4SAndrew Jones} else {
33*f58316a4SAndrew Jones	@files = `find \Q$srctree\E -name '*Kconfig*'`;
34*f58316a4SAndrew Jones	chomp @files;
35*f58316a4SAndrew Jones}
36*f58316a4SAndrew Jones
37*f58316a4SAndrew Jones@files = grep { !m{/scripts/kconfig/tests/} } @files;
38*f58316a4SAndrew Jones
39*f58316a4SAndrew Jonesmy %configs = ();
40*f58316a4SAndrew Jonesmy %refs = ();
41*f58316a4SAndrew Jones
42*f58316a4SAndrew Jonesforeach my $file (@files) {
43*f58316a4SAndrew Jones	open F, $file or die "Cannot open $file: $!";
44*f58316a4SAndrew Jones
45*f58316a4SAndrew Jones	my $help = 0;
46*f58316a4SAndrew Jones	my $help_level;
47*f58316a4SAndrew Jones	my $level;
48*f58316a4SAndrew Jones
49*f58316a4SAndrew Jones	while (<F>) {
50*f58316a4SAndrew Jones		chomp;
51*f58316a4SAndrew Jones
52*f58316a4SAndrew Jones		while (/\\\s*$/) {
53*f58316a4SAndrew Jones			s/\\\s*$/ /;
54*f58316a4SAndrew Jones			my $cont = <F> // last;
55*f58316a4SAndrew Jones			chomp $cont;
56*f58316a4SAndrew Jones			$_ .= $cont;
57*f58316a4SAndrew Jones		}
58*f58316a4SAndrew Jones
59*f58316a4SAndrew Jones		next if /^\s*$/;
60*f58316a4SAndrew Jones		next if /^\s*#/;
61*f58316a4SAndrew Jones
62*f58316a4SAndrew Jones		/^(\s*)/;
63*f58316a4SAndrew Jones		$level = indent_depth($1);
64*f58316a4SAndrew Jones
65*f58316a4SAndrew Jones		if ($help && $level < $help_level) {
66*f58316a4SAndrew Jones			$help = 0;
67*f58316a4SAndrew Jones		}
68*f58316a4SAndrew Jones
69*f58316a4SAndrew Jones		next if ($help);
70*f58316a4SAndrew Jones
71*f58316a4SAndrew Jones		if (/^\s*(help|\-\-\-help\-\-\-)$/) {
72*f58316a4SAndrew Jones			$help = 1;
73*f58316a4SAndrew Jones			my $next;
74*f58316a4SAndrew Jones			while (defined($next = <F>)) {
75*f58316a4SAndrew Jones				last unless $next =~ /^\s*(?:#.*)?$/;
76*f58316a4SAndrew Jones			}
77*f58316a4SAndrew Jones			last unless defined $next;
78*f58316a4SAndrew Jones			$next =~ /^(\s*)/;
79*f58316a4SAndrew Jones			if (indent_depth($1) >= $level) {
80*f58316a4SAndrew Jones				$help_level = indent_depth($1);
81*f58316a4SAndrew Jones			} else {
82*f58316a4SAndrew Jones				$help = 0;
83*f58316a4SAndrew Jones			}
84*f58316a4SAndrew Jones			$_ = $next;
85*f58316a4SAndrew Jones			redo;
86*f58316a4SAndrew Jones		}
87*f58316a4SAndrew Jones
88*f58316a4SAndrew Jones		if (/^\s*(config|menuconfig)\s+([a-zA-Z0-9_]+)\s*(#.*)?$/) {
89*f58316a4SAndrew Jones			$configs{$2}++;
90*f58316a4SAndrew Jones			next;
91*f58316a4SAndrew Jones		}
92*f58316a4SAndrew Jones
93*f58316a4SAndrew Jones		if (/^\s*(default|def_bool|def_tristate|select|depends\s+on|imply|visible\s+if|range|if|bool|tristate|int|hex|string|prompt)\s+(.+)\s*$/) {
94*f58316a4SAndrew Jones			my $s = $2;
95*f58316a4SAndrew Jones			$s =~ s/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'//g;
96*f58316a4SAndrew Jones			$s =~ s/#.*//;
97*f58316a4SAndrew Jones			$s =~ s/\$\((?:[^()]*|\((?:[^()]*|\([^()]*\))*\))*\)//g;
98*f58316a4SAndrew Jones			$s =~ s/%%[^%]*%%//g;
99*f58316a4SAndrew Jones			my @syms = split /[^a-zA-Z0-9_]+/, $s;
100*f58316a4SAndrew Jones			map {
101*f58316a4SAndrew Jones				$refs{$_}++ if (/[a-zA-Z]/ && $_ ne "if" && $_ ne "y" && $_ ne "n" && $_ ne "m" && !/^0[xX][0-9a-fA-F]+$/);
102*f58316a4SAndrew Jones			} @syms
103*f58316a4SAndrew Jones		}
104*f58316a4SAndrew Jones	}
105*f58316a4SAndrew Jones
106*f58316a4SAndrew Jones	close F;
107*f58316a4SAndrew Jones}
108*f58316a4SAndrew Jones
109*f58316a4SAndrew Jonesmy %known_syms = ();
110*f58316a4SAndrew Jonesif (defined $kconfig_sym_check_excludes) {
111*f58316a4SAndrew Jones	my $file = $kconfig_sym_check_excludes;
112*f58316a4SAndrew Jones	open(F, "<", $file) or die "Cannot open $file: $!";
113*f58316a4SAndrew Jones	while (<F>) {
114*f58316a4SAndrew Jones		chomp;
115*f58316a4SAndrew Jones		next if /^\s*$/;
116*f58316a4SAndrew Jones		next if /^\s*#/;
117*f58316a4SAndrew Jones		$known_syms{$1}++ if (/^\s*([a-zA-Z0-9_]+)\s*(#.*)?$/);
118*f58316a4SAndrew Jones	}
119*f58316a4SAndrew Jones}
120*f58316a4SAndrew Jones
121*f58316a4SAndrew Jonesmy $ret = 0;
122*f58316a4SAndrew Jonesforeach my $k (sort keys %refs) {
123*f58316a4SAndrew Jones	next if (exists $configs{$k} || exists $known_syms{$k});
124*f58316a4SAndrew Jones
125*f58316a4SAndrew Jones	print "$k";
126*f58316a4SAndrew Jones	print " - warning: '$k' is probably not what you want; Kconfig tristate literals are always lowercase ('n', 'y', 'm')" if ($k eq "N" || $k eq "Y" || $k eq "M");
127*f58316a4SAndrew Jones	print "\n";
128*f58316a4SAndrew Jones
129*f58316a4SAndrew Jones	$ret = 1;
130*f58316a4SAndrew Jones}
131*f58316a4SAndrew Jones
132*f58316a4SAndrew Jonesexit $ret;
133