Skip to content

Commit ef2c326

Browse files
authored
Fix #13843: htmlreport: support cert/misra report types (danmar#7590)
1 parent 291c053 commit ef2c326

File tree

1 file changed

+73
-18
lines changed

1 file changed

+73
-18
lines changed

htmlreport/cppcheck-htmlreport

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ label.checkBtn > input {
139139
140140
table.summaryTable td { padding: 0 5px 0 5px; }
141141
142-
.statHeader, .severityHeader {
142+
.statHeader, .severityHeader, .classificationHeader {
143143
font-weight: bold;
144144
}
145145
@@ -201,7 +201,7 @@ table.summaryTable td { padding: 0 5px 0 5px; }
201201
padding-right: 6px;
202202
}
203203
204-
.id-filtered, .severity-filtered, .file-filtered, .tool-filtered, .text-filtered {
204+
.id-filtered, .severity-filtered, .classification-filtered, .file-filtered, .tool-filtered, .text-filtered {
205205
visibility: collapse;
206206
}
207207
"""
@@ -278,7 +278,18 @@ HTML_HEAD = """
278278
279279
updateFileRows();
280280
}
281+
282+
function toggleClassification(cb) {
283+
cb.parentElement.classList.toggle("unchecked", !cb.checked);
284+
var elements = document.querySelectorAll(".class_" + cb.id);
285+
286+
for (var i = 0, len = elements.length; i < len; i++) {
287+
elements[i].classList.toggle("classification-filtered", !cb.checked);
288+
}
281289
290+
updateFileRows();
291+
}
292+
282293
function toggleTool(cb) {
283294
cb.parentElement.classList.toggle("unchecked", !cb.checked);
284295
@@ -340,7 +351,7 @@ HTML_HEAD = """
340351
var elements = document.querySelectorAll(".fileEntry");
341352
342353
for (var i = 0, len = elements.length; i < len; i++) {
343-
var visible = elements[i].querySelector(".issue:not(.id-filtered):not(.severity-filtered):not(.tool-filtered):not(.text-filtered)");
354+
var visible = elements[i].querySelector(".issue:not(.id-filtered):not(.severity-filtered):not(.classification-filtered):not(.tool-filtered):not(.text-filtered)");
344355
elements[i].classList.toggle("file-filtered", !visible);
345356
}
346357
}
@@ -399,20 +410,27 @@ def html_escape(text):
399410

400411
def filter_button(enabled_filters, id, function):
401412
enabled = enabled_filters.get(id, False)
413+
if not id:
414+
id = 'None'
402415
return '\n <label class="checkBtn%s"><input type="checkbox" onclick="%s(this)" id="%s"%s/>%s</label>'\
403416
% (' disabled' if not enabled else '', function, id, 'checked' if enabled else 'disabled', id)
404417

405418
def filter_bar(enabled):
419+
severity_bar = ''.join([filter_button(enabled, severity, 'toggleSeverity') for severity in ['error', 'warning', 'portability', 'performance', 'style', 'information']]) + '\n | '
420+
classification_bar = ''.join([filter_button(enabled, _class, 'toggleClassification') for _class in ['Mandatory', 'Required', 'Advisory', 'Document', 'Disapplied', 'L1','L2','L3','']]) + '\n | '
421+
if "checked/>" not in severity_bar:
422+
severity_bar = ''
423+
if "checked/>" not in classification_bar:
424+
classification_bar = ''
406425
return ''.join([
407426
' <div id="filters">\n'
408-
,''.join([filter_button(enabled, severity, 'toggleSeverity') for severity in ['error', 'warning', 'portability', 'performance', 'style', 'information']])
409-
,'\n | '
427+
,severity_bar
428+
, classification_bar
410429
,''.join([filter_button(enabled, tool, 'toggleTool') for tool in ['cppcheck', 'clang-tidy']])
411430
,'\n | '
412431
,'\n <label class="severityHeader">File: <input type="search" oninput="filterFile(this.value)"/></label>'
413432
,'\n <label class="severityHeader">Filter: <input type="search" oninput="filterText(this.value)"/></label>'
414433
,'\n </div>\n'])
415-
416434
def git_blame(errors, path, file, blame_options):
417435
last_line= errors[-1]['line']
418436
if last_line == 0:
@@ -471,14 +489,20 @@ def blame_lookup(blame_data, line):
471489
return next((data for start, end, data in blame_data if line >= start and line < end), {})
472490

473491

474-
def tr_str(td_th, line, id, cwe, severity, message, timestamp, author, author_mail, date, add_author, tr_class=None, htmlfile=None, message_class=None):
492+
def tr_str(td_th, line, id, cwe, severity, classification, guideline, message, timestamp, author, author_mail, date, add_author, tr_class=None, htmlfile=None, message_class=None):
475493
ret = ''
494+
items = [id, cwe]
495+
if severity:
496+
items.append(severity)
497+
if classification:
498+
items.extend([classification, guideline])
476499
if htmlfile:
477500
ret += '<%s><a href="%s#line-%d">%d</a></%s>' % (td_th, htmlfile, line, line, td_th)
478-
for item in (id, cwe, severity):
501+
for item in items:
479502
ret += '<%s>%s</%s>' % (td_th, item, td_th)
480503
else:
481-
for item in (line, id, cwe, severity):
504+
items.insert(0,line)
505+
for item in items:
482506
ret += '<%s>%s</%s>' % (td_th, item, td_th)
483507
if message_class:
484508
message_attribute = ' class="%s"' % message_class
@@ -561,6 +585,7 @@ class CppCheckHandler(XmlContentHandler):
561585
self.version = '1'
562586
self.versionCppcheck = ''
563587
self.timestamp = ''
588+
self.report_type = False
564589

565590
def startElement(self, name, attributes):
566591
if name == 'results':
@@ -574,7 +599,10 @@ class CppCheckHandler(XmlContentHandler):
574599
def handleVersion1(self, name, attributes):
575600
if name != 'error':
576601
return
577-
602+
att_class = attributes.get('classification', '')
603+
att_guide = attributes.get('guideline', '')
604+
if att_class and not self.report_type:
605+
self.report_type = True
578606
self.errors.append({
579607
'file': attributes.get('file', ''),
580608
'line': int(attributes.get('line', 0)),
@@ -584,6 +612,8 @@ class CppCheckHandler(XmlContentHandler):
584612
}],
585613
'id': attributes['id'],
586614
'severity': attributes['severity'],
615+
'classification': att_class,
616+
'guideline': att_guide,
587617
'timestamp': self.timestamp,
588618
'msg': attributes['msg']
589619
})
@@ -592,12 +622,18 @@ class CppCheckHandler(XmlContentHandler):
592622
if name == 'cppcheck':
593623
self.versionCppcheck = attributes['version']
594624
if name == 'error':
625+
att_class = attributes.get('classification', '')
626+
att_guide = attributes.get('guideline', '')
627+
if att_class and not self.report_type:
628+
self.report_type = True
595629
error = {
596630
'locations': [],
597631
'file': '',
598632
'line': 0,
599633
'id': attributes['id'],
634+
'classification': att_class,
600635
'severity': attributes['severity'],
636+
'guideline': att_guide,
601637
'timestamp': self.timestamp,
602638
'msg': attributes['msg'],
603639
'verbose': attributes.get('verbose')
@@ -623,7 +659,6 @@ class CppCheckHandler(XmlContentHandler):
623659
'line': line,
624660
'info': attributes.get('info')
625661
})
626-
627662
def main() -> None:
628663
# Configure all the options this little utility is using.
629664
parser = argparse.ArgumentParser()
@@ -751,6 +786,8 @@ def main() -> None:
751786
if location.get('info'):
752787
newError['msg'] = location['info']
753788
newError['severity'] = 'information'
789+
newError['classification'] = ''
790+
newError['guideline'] = ''
754791
del newError['verbose']
755792

756793
errors.append(newError)
@@ -832,7 +869,12 @@ def main() -> None:
832869
for filename, data in sorted(files.items()):
833870
for error in data['errors']:
834871
stats.append(error['id']) # get the stats
835-
filter_enabled[error['severity']] = True
872+
if contentHandler.report_type:
873+
filter_enabled[error['severity']] = False
874+
filter_enabled[error['classification']] = True
875+
else:
876+
filter_enabled[error['severity']] = True
877+
filter_enabled[error['classification']] = False
836878
filter_enabled['clang-tidy' if error['id'].startswith('clang-tidy-') else 'cppcheck'] = True
837879
stats_count += 1
838880

@@ -877,9 +919,15 @@ def main() -> None:
877919
output_file.write(HTML_MENU_END.replace("content", "content_index", 1))
878920

879921
output_file.write('\n <table class=\"summaryTable\">')
880-
output_file.write(
881-
'\n %s' %
882-
tr_str('th', 'Line', 'Id', 'CWE', 'Severity', 'Message', 'Timestamp', 'Author', 'Author mail', 'Date (DD/MM/YYYY)', add_author=add_author_information))
922+
if contentHandler.report_type:
923+
output_file.write(
924+
'\n %s' %
925+
tr_str('th', 'Line', 'Id', 'CWE', '', 'Classification', 'Guideline', 'Message', 'Timestamp',
926+
'Author', 'Author mail', 'Date (DD/MM/YYYY)', add_author=add_author_information))
927+
else:
928+
output_file.write(
929+
'\n %s' %
930+
tr_str('th', 'Line', 'Id', 'CWE', 'Severity', '', '', 'Message', 'Timestamp', 'Author', 'Author mail', 'Date (DD/MM/YYYY)', add_author=add_author_information))
883931

884932
for filename, data in sorted(files.items()):
885933
file_error = filename in decode_errors or filename.endswith('*')
@@ -916,13 +964,20 @@ def main() -> None:
916964
message_class = error['severity']
917965

918966
line = error["line"] if is_file else ""
919-
967+
_severity = error.get('severity', '')
968+
_classification = error.get('classification', '')
969+
_guideline = error.get('guideline', '')
970+
if contentHandler.report_type:
971+
_severity = ''
972+
if not _classification:
973+
_classification = 'None'
974+
_guideline = 'None'
920975
output_file.write(
921976
'\n %s' %
922-
tr_str('td', line, error["id"], cwe_url, error["severity"], error["msg"], error["timestamp"],
977+
tr_str('td', line, error["id"], cwe_url, _severity, _classification, _guideline, error["msg"], error["timestamp"],
923978
git_blame_dict.get('author', 'Unknown'), git_blame_dict.get('author-mail', '---'),
924979
git_blame_dict.get('author-time', '---'),
925-
tr_class=to_css_selector(error["id"]) + ' sev_' + error["severity"] + ' issue',
980+
tr_class=to_css_selector(error["id"]) + ' sev_' + _severity +' class_' + _classification + ' issue',
926981
message_class=message_class,
927982
add_author=add_author_information,
928983
htmlfile=htmlfile))

0 commit comments

Comments
 (0)