aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/checkkconfigsymbols.py
diff options
context:
space:
mode:
authorValentin Rothberg <valentinrothberg@gmail.com>2014-11-08 14:56:35 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-08 23:50:43 -0500
commitcc641d5529965fbd01edbdf289951fb95d3de1b8 (patch)
tree7c6f8e6e0fc0a297fadba41032263eba17d6a2a1 /scripts/checkkconfigsymbols.py
parent184901a06a366d40386e07307bcadc9eeaabbd39 (diff)
checkkconfigsymbols.py: improve detection of defects
This patch improves the detection of defects by updating the regular expression to find Kconfig identifiers in the source code, and fixes some cases of false positives. The following changes are made: - improve regex to find Kconfig identifiers in the source - exclude .log files from analysis - improve filtering of false positives (e.g, CONFIG_XXX) - change output format from (feature:\tlist) to (feature\tlist) Signed-off-by: Valentin Rothberg <valentinrothberg@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'scripts/checkkconfigsymbols.py')
-rw-r--r--scripts/checkkconfigsymbols.py57
1 files changed, 27 insertions, 30 deletions
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py
index f9440891d048..e9cc689033fe 100644
--- a/scripts/checkkconfigsymbols.py
+++ b/scripts/checkkconfigsymbols.py
@@ -1,36 +1,31 @@
1#!/usr/bin/env python 1#!/usr/bin/env python
2 2
3"""Find Kconfig identifieres that are referenced but not defined.""" 3"""Find Kconfig identifiers that are referenced but not defined."""
4 4
5# Copyright (C) 2014 Valentin Rothberg <valentinrothberg@gmail.com> 5# (c) 2014 Valentin Rothberg <valentinrothberg@gmail.com>
6# Copyright (C) 2014 Stefan Hengelein <stefan.hengelein@fau.de> 6# (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de>
7# 7#
8# This program is free software; you can redistribute it and/or modify it 8# Licensed under the terms of the GNU GPL License version 2
9# under the terms and conditions of the GNU General Public License,
10# version 2, as published by the Free Software Foundation.
11#
12# This program is distributed in the hope it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15# more details.
16 9
17 10
18import os 11import os
19import re 12import re
20from subprocess import Popen, PIPE, STDOUT 13from subprocess import Popen, PIPE, STDOUT
21 14
22# REGEX EXPRESSIONS 15
16# regex expressions
23OPERATORS = r"&|\(|\)|\||\!" 17OPERATORS = r"&|\(|\)|\||\!"
24FEATURE = r"\w*[A-Z]{1}\w*" 18FEATURE = r"(?:\w*[A-Z0-9]\w*){2,}"
25CONFIG_DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*" 19DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*"
26EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+" 20EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+"
27STMT = r"^\s*(?:if|select|depends\s+on)\s+" + EXPR 21STMT = r"^\s*(?:if|select|depends\s+on)\s+" + EXPR
22SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")"
28 23
29# REGEX OBJECTS 24# regex objects
30REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$") 25REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$")
31REGEX_FEATURE = re.compile(r"(" + FEATURE + r")") 26REGEX_FEATURE = re.compile(r"(" + FEATURE + r")")
32REGEX_SOURCE_FEATURE = re.compile(r"(?:D|\W|\b)+CONFIG_(" + FEATURE + r")") 27REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE)
33REGEX_KCONFIG_DEF = re.compile(CONFIG_DEF) 28REGEX_KCONFIG_DEF = re.compile(DEF)
34REGEX_KCONFIG_EXPR = re.compile(EXPR) 29REGEX_KCONFIG_EXPR = re.compile(EXPR)
35REGEX_KCONFIG_STMT = re.compile(STMT) 30REGEX_KCONFIG_STMT = re.compile(STMT)
36REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$") 31REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$")
@@ -42,7 +37,7 @@ def main():
42 source_files = [] 37 source_files = []
43 kconfig_files = [] 38 kconfig_files = []
44 defined_features = set() 39 defined_features = set()
45 referenced_features = dict() 40 referenced_features = dict() # {feature: [files]}
46 41
47 # use 'git ls-files' to get the worklist 42 # use 'git ls-files' to get the worklist
48 pop = Popen("git ls-files", stdout=PIPE, stderr=STDOUT, shell=True) 43 pop = Popen("git ls-files", stdout=PIPE, stderr=STDOUT, shell=True)
@@ -52,12 +47,12 @@ def main():
52 47
53 for gitfile in stdout.rsplit("\n"): 48 for gitfile in stdout.rsplit("\n"):
54 if ".git" in gitfile or "ChangeLog" in gitfile or \ 49 if ".git" in gitfile or "ChangeLog" in gitfile or \
55 os.path.isdir(gitfile): 50 ".log" in gitfile or os.path.isdir(gitfile):
56 continue 51 continue
57 if REGEX_FILE_KCONFIG.match(gitfile): 52 if REGEX_FILE_KCONFIG.match(gitfile):
58 kconfig_files.append(gitfile) 53 kconfig_files.append(gitfile)
59 else: 54 else:
60 # All non-Kconfig files are checked for consistency 55 # all non-Kconfig files are checked for consistency
61 source_files.append(gitfile) 56 source_files.append(gitfile)
62 57
63 for sfile in source_files: 58 for sfile in source_files:
@@ -68,15 +63,17 @@ def main():
68 63
69 print "Undefined symbol used\tFile list" 64 print "Undefined symbol used\tFile list"
70 for feature in sorted(referenced_features): 65 for feature in sorted(referenced_features):
66 # filter some false positives
67 if feature == "FOO" or feature == "BAR" or \
68 feature == "FOO_BAR" or feature == "XXX":
69 continue
71 if feature not in defined_features: 70 if feature not in defined_features:
72 if feature.endswith("_MODULE"): 71 if feature.endswith("_MODULE"):
73 # Avoid false positives for kernel modules 72 # avoid false positives for kernel modules
74 if feature[:-len("_MODULE")] in defined_features: 73 if feature[:-len("_MODULE")] in defined_features:
75 continue 74 continue
76 if "FOO" in feature or "BAR" in feature:
77 continue
78 files = referenced_features.get(feature) 75 files = referenced_features.get(feature)
79 print "%s:\t%s" % (feature, ", ".join(files)) 76 print "%s\t%s" % (feature, ", ".join(files))
80 77
81 78
82def parse_source_file(sfile, referenced_features): 79def parse_source_file(sfile, referenced_features):
@@ -92,9 +89,9 @@ def parse_source_file(sfile, referenced_features):
92 for feature in features: 89 for feature in features:
93 if not REGEX_FILTER_FEATURES.search(feature): 90 if not REGEX_FILTER_FEATURES.search(feature):
94 continue 91 continue
95 paths = referenced_features.get(feature, set()) 92 sfiles = referenced_features.get(feature, set())
96 paths.add(sfile) 93 sfiles.add(sfile)
97 referenced_features[feature] = paths 94 referenced_features[feature] = sfiles
98 95
99 96
100def get_features_in_line(line): 97def get_features_in_line(line):
@@ -113,7 +110,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
113 for i in range(len(lines)): 110 for i in range(len(lines)):
114 line = lines[i] 111 line = lines[i]
115 line = line.strip('\n') 112 line = line.strip('\n')
116 line = line.split("#")[0] # Ignore Kconfig comments 113 line = line.split("#")[0] # ignore comments
117 114
118 if REGEX_KCONFIG_DEF.match(line): 115 if REGEX_KCONFIG_DEF.match(line):
119 feature_def = REGEX_KCONFIG_DEF.findall(line) 116 feature_def = REGEX_KCONFIG_DEF.findall(line)
@@ -122,11 +119,11 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
122 elif REGEX_KCONFIG_HELP.match(line): 119 elif REGEX_KCONFIG_HELP.match(line):
123 skip = True 120 skip = True
124 elif skip: 121 elif skip:
125 # Ignore content of help messages 122 # ignore content of help messages
126 pass 123 pass
127 elif REGEX_KCONFIG_STMT.match(line): 124 elif REGEX_KCONFIG_STMT.match(line):
128 features = get_features_in_line(line) 125 features = get_features_in_line(line)
129 # Multi-line statements 126 # multi-line statements
130 while line.endswith("\\"): 127 while line.endswith("\\"):
131 i += 1 128 i += 1
132 line = lines[i] 129 line = lines[i]