Skip to content

Commit 46544fa

Browse files
FDniel97bruntib
authored andcommitted
Introduce gcc warnings as checkers
Gcc has its own checkers that can be enabled as warnings: -Wanalyzer-<checker_name>. However, all other warnings can be considered as checkers. Until this patch the -Wanalyzer-<checker_name> checkers could have been enabled in CodeChecker as --enable gcc-<checker_name>. This patch makes it possible to enable all other warnings as checkers: --enable gcc-<warnings_name>. The problem is that both gcc static analyzers and gcc warning names have the following transformation in CodeChecker: -Wanalyzer-<name> -> gcc-<name> -W<name> -> gcc-<name> Theoretically it's possible to generate the inverse transformation, because static analyzer names and warning names are disjoint. But we decided to preserve all original names for the checkers: -Wanalyzer-<name> -> gcc-analyzer-<name> -W<name> -> gcc-<name> This is a backward incompatible change.
1 parent 5600268 commit 46544fa

8 files changed

Lines changed: 582 additions & 77 deletions

File tree

analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

2323
from .config_handler import GccConfigHandler
2424
from .result_handler import GccResultHandler, \
25-
actual_name_to_codechecker_name, codechecker_name_to_actual_name_disabled
25+
actual_name_to_codechecker_name, \
26+
codechecker_name_to_actual_name, codechecker_name_to_actual_name_disabled
2627

2728
LOG = get_logger('analyzer.gcc')
2829

@@ -77,6 +78,9 @@ def construct_analyzer_cmd(self, result_handler):
7778
# than startswith and a hardcoded slicing
7879
analyzer_cmd.append(
7980
codechecker_name_to_actual_name_disabled(checker_name))
81+
else:
82+
analyzer_cmd.append(
83+
codechecker_name_to_actual_name(checker_name))
8084

8185
compile_lang = self.buildaction.lang
8286
if not has_flag('-x', analyzer_cmd):
@@ -106,17 +110,27 @@ def get_analyzer_checkers(cls):
106110
try:
107111
output = subprocess.check_output(command, env=environ)
108112

113+
context = analyzer_context.get_context()
114+
115+
blacklisted_checkers = context.checker_labels.checkers_by_labels(
116+
["blacklist:true"], cls.ANALYZER_NAME)
117+
109118
# Still contains the help message we need to remove.
110119
for entry in output.decode().split('\n'):
111120
warning_name, _, description = entry.strip().partition(' ')
112-
# GCC Static Analyzer names start with -Wanalyzer.
113-
if warning_name.startswith('-Wanalyzer'):
114-
# Rename the checkers interally (similarly to how we
115-
# support cppcheck)
116-
renamed_checker_name = \
117-
actual_name_to_codechecker_name(warning_name)
118-
checker_list.append(
119-
(renamed_checker_name, description.strip()))
121+
# We filter out the unwanted checkers
122+
if not warning_name.startswith('-W') or '=' in warning_name \
123+
or warning_name == '-W' \
124+
or actual_name_to_codechecker_name(warning_name) \
125+
in blacklisted_checkers:
126+
continue
127+
# GCC Static Analyzer names and warning names start with -W.
128+
# Rename the checkers interally
129+
# (similarly to how we support cppcheck)
130+
renamed_checker_name = \
131+
actual_name_to_codechecker_name(warning_name)
132+
checker_list.append(
133+
(renamed_checker_name, description.strip()))
120134
return checker_list
121135
except (subprocess.CalledProcessError) as e:
122136
LOG.error(e.stderr)

analyzer/codechecker_analyzer/analyzers/gcc/result_handler.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,18 @@
2929

3030

3131
def actual_name_to_codechecker_name(actual_name: str):
32-
assert actual_name.startswith('-Wanalyzer')
33-
return actual_name.replace("-Wanalyzer", "gcc")
32+
assert actual_name.startswith('-W')
33+
return actual_name.replace("-W", "gcc-")
3434

3535

3636
def codechecker_name_to_actual_name(codechecker_name: str):
3737
assert codechecker_name.startswith('gcc')
38-
return codechecker_name.replace("gcc", "-Wanalyzer")
38+
return codechecker_name.replace("gcc-", "-W")
3939

4040

4141
def codechecker_name_to_actual_name_disabled(codechecker_name: str):
4242
assert codechecker_name.startswith('gcc')
43-
return codechecker_name.replace("gcc", "-Wno-analyzer")
43+
return codechecker_name.replace("gcc-", "-Wno-")
4444

4545

4646
class GccResultHandler(ResultHandler):

analyzer/tests/functional/analyze/test_analyze.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,105 @@ def test_disable_all_checkers(self):
13421342
# Checkers of all 3 analyzers are disabled.
13431343
self.assertEqual(out.count("No checkers enabled for"), 5)
13441344

1345+
def test_analyzer_gcc_warnings(self):
1346+
build_json = os.path.join(self.test_workspace, "build.json")
1347+
source_file = os.path.join(self.test_dir, "compiler_warning.c")
1348+
1349+
build_log = [{"directory": self.test_workspace,
1350+
"command": "gcc -c " + source_file, "file": source_file}]
1351+
1352+
with open(build_json, 'w',
1353+
encoding="utf-8", errors="ignore") as outfile:
1354+
json.dump(build_log, outfile)
1355+
1356+
analyze_cmd = [self._codechecker_cmd, "analyze", build_json,
1357+
"--analyzers", "gcc",
1358+
"-o", self.report_dir,
1359+
"--disable-all",
1360+
"--verbose", "debug_analyzer"]
1361+
1362+
process = subprocess.Popen(
1363+
analyze_cmd,
1364+
stdout=subprocess.PIPE,
1365+
stderr=subprocess.PIPE,
1366+
cwd=self.test_dir,
1367+
encoding="utf-8",
1368+
errors="ignore")
1369+
out, _ = process.communicate()
1370+
self.assertEqual(out.count("No checkers enabled for gcc"), 1)
1371+
1372+
analyze_cmd = [self._codechecker_cmd, "analyze", build_json,
1373+
"--analyzers", "gcc",
1374+
"-o", self.report_dir,
1375+
"--enable", "gcc-div-by-zero",
1376+
"--verbose", "debug_analyzer"]
1377+
1378+
process = subprocess.Popen(
1379+
analyze_cmd,
1380+
stdout=subprocess.PIPE,
1381+
stderr=subprocess.PIPE,
1382+
cwd=self.test_dir,
1383+
encoding="utf-8",
1384+
errors="ignore")
1385+
out, _ = process.communicate()
1386+
self.assertEqual(out.count("gcc: 1"), 1)
1387+
self.assertEqual(out.count("Wdiv-by-zero"), 2)
1388+
1389+
analyze_cmd = [self._codechecker_cmd, "analyze", build_json,
1390+
"--analyzers", "gcc",
1391+
"-o", self.report_dir,
1392+
"--enable", "gcc-analyzer-out-of-bounds",
1393+
"--verbose", "debug_analyzer"]
1394+
1395+
process = subprocess.Popen(
1396+
analyze_cmd,
1397+
stdout=subprocess.PIPE,
1398+
stderr=subprocess.PIPE,
1399+
cwd=self.test_dir,
1400+
encoding="utf-8",
1401+
errors="ignore")
1402+
out, _ = process.communicate()
1403+
self.assertEqual(out.count("gcc: 1"), 1)
1404+
self.assertEqual(out.count("Wanalyzer-out-of-bounds"), 2)
1405+
1406+
analyze_cmd = [self._codechecker_cmd, "analyze", build_json,
1407+
"--analyzers", "gcc",
1408+
"-o", self.report_dir,
1409+
"--enable", "gcc-comment",
1410+
"--verbose", "debug_analyzer"]
1411+
1412+
process = subprocess.Popen(
1413+
analyze_cmd,
1414+
stdout=subprocess.PIPE,
1415+
stderr=subprocess.PIPE,
1416+
cwd=self.test_dir,
1417+
encoding="utf-8",
1418+
errors="ignore")
1419+
out, _ = process.communicate()
1420+
self.assertEqual(out.count("gcc: 1"), 1)
1421+
self.assertEqual(out.count("Wcomment"), 2)
1422+
1423+
analyze_cmd = [self._codechecker_cmd, "analyze", build_json,
1424+
"--analyzers", "gcc",
1425+
"-o", self.report_dir,
1426+
"--enable-all",
1427+
"--disable", "gcc-div-by-zero",
1428+
"--disable", "gcc-analyzer-out-of-bounds",
1429+
"--disable", "gcc-comment",
1430+
"--verbose", "debug_analyzer"]
1431+
1432+
process = subprocess.Popen(
1433+
analyze_cmd,
1434+
stdout=subprocess.PIPE,
1435+
stderr=subprocess.PIPE,
1436+
cwd=self.test_dir,
1437+
encoding="utf-8",
1438+
errors="ignore")
1439+
out, _ = process.communicate()
1440+
self.assertEqual(out.count("Wno-div-by-zero"), 2)
1441+
self.assertEqual(out.count("Wno-analyzer-out-of-bounds"), 2)
1442+
self.assertEqual(out.count("Wno-comment"), 2)
1443+
13451444
def test_analyzer_and_checker_config(self):
13461445
"""Test analyzer configuration through command line flags."""
13471446
build_json = os.path.join(self.test_workspace, "build_success.json")

analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple.output

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ CHECK#CodeChecker check --build "make gcc_simple" --output $OUTPUT$ --quiet --an
1818
[] - To store results use the "CodeChecker store" command.
1919
[] - See --help and the user guide for further options about parsing and storing the reports.
2020
[] - ----=================----
21-
[HIGH] gcc_simple.cpp:5:3: double-‘free’ of ‘i’ [gcc-double-free]
21+
[HIGH] gcc_simple.cpp:5:3: double-‘free’ of ‘i’ [gcc-analyzer-double-free]
2222
free(i);
2323
^
2424

@@ -34,11 +34,11 @@ Found 1 defect(s) in gcc_simple.cpp
3434
----=================----
3535

3636
----==== Checker Statistics ====----
37-
┌─────────────────┬──────────┬───────────────────┐
38-
│ Checker name │ Severity │ Number of reports │
39-
├─────────────────┼──────────┼───────────────────┤
40-
│ gcc-double-free │ HIGH │ 1 │
41-
└─────────────────┴──────────┴───────────────────┘
37+
┌──────────────────────────┬──────────┬───────────────────┐
38+
│ Checker name │ Severity │ Number of reports │
39+
├──────────────────────────┼──────────┼───────────────────┤
40+
│ gcc-analyzer-double-free │ HIGH │ 1 │
41+
└──────────────────────────┴──────────┴───────────────────┘
4242
----=================----
4343

4444
----==== File Statistics ====----

analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple_checker_disable.output

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
NORMAL#CodeChecker log --output $LOGFILE$ --build "make gcc_simple" --quiet
2-
NORMAL#CodeChecker analyze $LOGFILE$ --output $OUTPUT$ --analyzers gcc --enable=extreme -d gcc-double-free
2+
NORMAL#CodeChecker analyze $LOGFILE$ --output $OUTPUT$ --analyzers gcc --enable=extreme -d gcc-analyzer-double-free
33
NORMAL#CodeChecker parse $OUTPUT$
4-
CHECK#CodeChecker check --build "make gcc_simple" --output $OUTPUT$ --quiet --analyzers gcc --enable=extreme -d gcc-double-free
4+
CHECK#CodeChecker check --build "make gcc_simple" --output $OUTPUT$ --quiet --analyzers gcc --enable=extreme -d gcc-analyzer-double-free
55
-----------------------------------------------
66
[] - Starting build...
77
[] - Using CodeChecker ld-logger.

analyzer/tests/functional/cmdline/test_cmdline.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ def test_checkers_guideline(self):
212212
'MallocSizeof',
213213
'clang-diagnostic-format-overflow',
214214
'overflow-non-kprintf',
215-
'gcc-allocation-size',
216-
'gcc-out-of-bounds']))
215+
'gcc-analyzer-allocation-size',
216+
'gcc-analyzer-out-of-bounds']))
217217

218218
checkers_cmd = [env.codechecker_cmd(), 'checkers', '--guideline']
219219
_, out, _ = run_cmd(checkers_cmd)

analyzer/tests/unit/test_checker_handling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ def create_analyzer_cppcheck(args, workspace):
796796

797797

798798
class MockCppcheckCheckerLabels:
799-
def checkers_by_labels(self, labels):
799+
def checkers_by_labels(self, labels, _=None):
800800
if labels[0] == 'profile:default':
801801
return [
802802
'cppcheck-argumentSize',

0 commit comments

Comments
 (0)