Skip to content

Commit

Permalink
Add bug path length column to Bug overview
Browse files Browse the repository at this point in the history
Add bug path length column to `Bug overview` table to indicate how long the
report path is.
  • Loading branch information
csordasmarton committed Jan 9, 2018
1 parent d81536c commit 487f800
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 19 deletions.
4 changes: 3 additions & 1 deletion api/v6/report_server.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ enum SortType {
CHECKER_NAME,
SEVERITY,
REVIEW_STATUS,
DETECTION_STATUS
DETECTION_STATUS,
BUG_PATH_LENGTH,
}


Expand Down Expand Up @@ -161,6 +162,7 @@ struct ReportData {
12: DetectionStatus detectionStatus, // State of the bug (see the enum constant values).
13: string detectedAt, // Detection date of the report.
14: string fixedAt // Date when the report was fixed.
15: i64 bugPathLength, // Length of the bug path.
}
typedef list<ReportData> ReportDataList

Expand Down
46 changes: 34 additions & 12 deletions libcodechecker/server/api/report_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ def get_sort_map(sort_types, is_unique=False):
sort_type_map = {
SortType.FILENAME: [(File.filepath, 'filepath'),
(Report.line, 'line')],
SortType.BUG_PATH_LENGTH: [('bug_path_length', 'bug_path_length')],
SortType.CHECKER_NAME: [(Report.checker_id, 'checker_id')],
SortType.SEVERITY: [(Report.severity, 'severity')],
SortType.REVIEW_STATUS: [(ReviewStatus.status, 'rw_status')],
Expand Down Expand Up @@ -782,17 +783,26 @@ def getRunResults(self, run_ids, limit, offset, sort_types,
filter_expression = process_report_filter_v2(session,
report_filter)

path_len_q = session.query(BugPathEvent.report_id,
func.count(BugPathEvent.report_id)
.label('path_length')) \
.group_by(BugPathEvent.report_id) \
.subquery()

is_unique = report_filter is not None and report_filter.isUnique
if is_unique:
sort_types, sort_type_map, order_type_map = \
get_sort_map(sort_types, True)

selects = [func.max(Report.id).label('id')]
selects = [func.max(Report.id).label('id'),
func.max(path_len_q.c.path_length)
.label('bug_path_length')]
for sort in sort_types:
sorttypes = sort_type_map.get(sort.type)
for sorttype in sorttypes:
selects.append(func.max(sorttype[0])
.label(sorttype[1]))
if sorttype[0] != 'bug_path_length':
selects.append(func.max(sorttype[0])
.label(sorttype[1]))

unique_reports = session.query(*selects)
unique_reports = filter_report_filter(unique_reports,
Expand All @@ -801,10 +811,15 @@ def getRunResults(self, run_ids, limit, offset, sort_types,
cmp_data,
diff_hashes)
unique_reports = unique_reports \
.group_by(Report.bug_id).subquery()
.outerjoin(path_len_q,
path_len_q.c.report_id == Report.id) \
.group_by(Report.bug_id) \
.subquery()

# Sort the results
sorted_reports = session.query(unique_reports.c.id)
sorted_reports = \
session.query(unique_reports.c.id,
unique_reports.c.bug_path_length)

sorted_reports = sort_results_query(sorted_reports,
sort_types,
Expand All @@ -819,7 +834,8 @@ def getRunResults(self, run_ids, limit, offset, sort_types,
Report.checker_message, Report.checker_id,
Report.severity, Report.detected_at,
Report.fixed_at, ReviewStatus,
File.filename, File.filepath) \
File.filename, File.filepath,
sorted_reports.c.bug_path_length) \
.outerjoin(File, Report.file_id == File.id) \
.outerjoin(ReviewStatus,
ReviewStatus.bug_hash == Report.bug_id) \
Expand All @@ -835,8 +851,8 @@ def getRunResults(self, run_ids, limit, offset, sort_types,
order_type_map)

for report_id, bug_id, checker_msg, checker, severity, \
detected_at, fixed_at, status, filename, path in \
q:
detected_at, fixed_at, status, filename, path, \
bug_path_len in q:
review_data = create_review_data(status)

results.append(
Expand All @@ -847,18 +863,23 @@ def getRunResults(self, run_ids, limit, offset, sort_types,
severity=severity,
reviewData=review_data,
detectedAt=str(detected_at),
fixedAt=str(fixed_at)))
fixedAt=str(fixed_at),
bugPathLength=bug_path_len))
else:
q = session.query(Report.run_id, Report.id, Report.file_id,
Report.line, Report.column,
Report.detection_status, Report.bug_id,
Report.checker_message, Report.checker_id,
Report.severity, Report.detected_at,
Report.fixed_at, ReviewStatus,
File.filepath) \
File.filepath,
path_len_q.c.path_length
.label('bug_path_length')) \
.outerjoin(File, Report.file_id == File.id) \
.outerjoin(ReviewStatus,
ReviewStatus.bug_hash == Report.bug_id) \
.outerjoin(path_len_q,
path_len_q.c.report_id == Report.id) \
.filter(filter_expression)

if run_ids:
Expand All @@ -877,7 +898,7 @@ def getRunResults(self, run_ids, limit, offset, sort_types,

for run_id, report_id, file_id, line, column, d_status, \
bug_id, checker_msg, checker, severity, detected_at,\
fixed_at, r_status, path \
fixed_at, r_status, path, bug_path_len \
in q:

review_data = create_review_data(r_status)
Expand All @@ -896,7 +917,8 @@ def getRunResults(self, run_ids, limit, offset, sort_types,
detectionStatus=detection_status_enum(
d_status),
detectedAt=str(detected_at),
fixedAt=str(fixed_at)))
fixedAt=str(fixed_at),
bugPathLength=bug_path_len))

return results

Expand Down
2 changes: 1 addition & 1 deletion libcodechecker/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# This dict object stores for each MAJOR version (key) the largest MINOR
# version (value) supported by the build.
SUPPORTED_VERSIONS = {
6: 5
6: 6
}

# This value is automatically generated to represent the highest version
Expand Down
42 changes: 42 additions & 0 deletions tests/functional/report_viewer_api/test_get_run_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ def setUp(self):

self._runid = test_runs[0].runId

def __check_bug_path_order(self, run_results, order):
"""
Checks the bug path length order of the run results.
:param run_results: Run results.
:param order: If it is a negative value, it checks that bug path length
of the results order is descending otherwise ascending.
"""
prev = None
for res in run_results:
self.assertGreater(res.bugPathLength, 0)

if not prev:
prev = res
continue
if order == Order.ASC:
self.assertGreaterEqual(res.bugPathLength, prev.bugPathLength)
else:
self.assertLessEqual(res.bugPathLength, prev.bugPathLength)

def test_get_run_results_no_filter(self):
""" Get all the run results without any filtering. """
runid = self._runid
Expand Down Expand Up @@ -219,3 +238,26 @@ def test_get_run_results_sorted2(self):
(bug1.line <=
bug2.line) or
(bug1.checkerId <= bug2.checkerId))

def test_bug_path_length(self):
runid = self._runid
sortMode1 = SortMode(SortType.BUG_PATH_LENGTH, Order.ASC)
sortMode2 = SortMode(SortType.BUG_PATH_LENGTH, Order.DESC)
simple_filter = ReportFilter()
unique_filter = ReportFilter(isUnique=True)

run_results = self._cc_client.getRunResults([runid],
100,
0,
[sortMode1],
simple_filter,
None)
self.__check_bug_path_order(run_results, Order.ASC)

run_results = self._cc_client.getRunResults([runid],
100,
0,
[sortMode2],
unique_filter,
None)
self.__check_bug_path_order(run_results, Order.DESC)
27 changes: 23 additions & 4 deletions www/scripts/codecheckerviewer/ListOfBugs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
define([
'dojo/_base/declare',
'dojo/dom-construct',
'dojo/dom-style',
'dojo/Deferred',
'dojo/data/ObjectStore',
'dojo/store/api/Store',
Expand All @@ -21,9 +22,9 @@ define([
'codechecker/RunHistory',
'codechecker/hashHelper',
'codechecker/util'],
function (declare, dom, Deferred, ObjectStore, Store, QueryResults, topic,
BorderContainer, TabContainer, Tooltip, DataGrid, BugViewer, BugFilterView,
RunHistory, hashHelper, util) {
function (declare, dom, style, Deferred, ObjectStore, Store, QueryResults,
topic, BorderContainer, TabContainer, Tooltip, DataGrid, BugViewer,
BugFilterView, RunHistory, hashHelper, util) {

function getRunData(runIds, runNames) {
var runFilter = new CC_OBJECTS.RunFilter();
Expand Down Expand Up @@ -183,6 +184,8 @@ function (declare, dom, Deferred, ObjectStore, Store, QueryResults, topic,
? CC_OBJECTS.SortType.DETECTION_STATUS
: sort.attribute === 'reviewStatus'
? CC_OBJECTS.SortType.REVIEW_STATUS
: sort.attribute === 'bugPathLength'
? CC_OBJECTS.SortType.BUG_PATH_LENGTH
: CC_OBJECTS.SortType.SEVERITY;
sortMode.ord
= sort.descending
Expand Down Expand Up @@ -239,6 +242,20 @@ function (declare, dom, Deferred, ObjectStore, Store, QueryResults, topic,
return '<span class="link">' + checkerId + '</span>';
}

function bugPathLengthFormatter(length) {
var d = dom.create('span', { innerHTML : length, class : 'length' });

// This value says that bug path length with this value and above are
// difficult to understand. The background color of these bug path lengths
// will be red.
var bugPathLengthLimit = 20;
var blendColor = util.generateRedGreenGradientColor(length,
bugPathLengthLimit, 0.5);
style.set(d, 'background-color', blendColor);

return d.outerHTML;
}

var ListOfBugsGrid = declare(DataGrid, {
constructor : function () {
var width = (100 / 5).toString() + '%';
Expand All @@ -248,6 +265,7 @@ function (declare, dom, Deferred, ObjectStore, Store, QueryResults, topic,
{ name : 'Message', field : 'checkerMsg', width : '100%', formatter : checkerMessageFormatter },
{ name : 'Checker name', field : 'checkerId', width : '50%', formatter: checkerNameFormatter },
{ name : 'Severity', field : 'severity', cellClasses : 'severity', width : '15%', formatter : severityFormatter },
{ name : 'Bug path length', field : 'bugPathLength', cellClasses : 'bug-path-length', width : '15%', formatter : bugPathLengthFormatter },
{ name : 'Review status', field : 'reviewStatus', cellClasses : 'review-status', width : '15%', formatter : reviewStatusFormatter },
{ name : 'Review comment', cellClasses : 'review-comment-message compact', field : 'reviewComment', width : '50%' },
{ name : 'Detection status', field : 'detectionStatus', cellClasses : 'detection-status', width : '15%', formatter : detectionStatusFormatter }
Expand All @@ -270,8 +288,9 @@ function (declare, dom, Deferred, ObjectStore, Store, QueryResults, topic,
canSort : function (inSortInfo) {
var cell = this.getCell(Math.abs(inSortInfo) - 1);

return cell.field === 'file' ||
return cell.field === 'bugPathLength' ||
cell.field === 'checkerId' ||
cell.field === 'file' ||
cell.field === 'severity' ||
cell.field === 'reviewStatus' ||
cell.field === 'detectionStatus';
Expand Down
8 changes: 8 additions & 0 deletions www/scripts/codecheckerviewer/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ function (locale, dom, style, json) {
return dojo.blendColors(baseColour, new dojo.Color(blendColour), ratio);
},

generateRedGreenGradientColor : function (value, max, opacity) {
var red = (255 * value) / max;
var green = (255 * (max - value)) / max;
var blue = 0;
return 'rgba(' + parseInt(red) + ',' + parseInt(green) + ',' + blue
+ ',' + opacity + ')';
},

/**
* Converts the given number of seconds into a more human-readable
* 'hh:mm:ss' format.
Expand Down
2 changes: 1 addition & 1 deletion www/scripts/version.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CC_API_VERSION = '6.5';
CC_API_VERSION = '6.6';
9 changes: 9 additions & 0 deletions www/style/codecheckerviewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -1304,3 +1304,12 @@ span[class*="severity-"] {
color: #357ea7;
border: 1px solid #cad2da;
}

.bug-path-length {
position: relative;
}

.bug-path-length .length {
display: block;
text-align: center;
}

0 comments on commit 487f800

Please sign in to comment.