utils: checkstyle.py: Show location of coding style issue within line

The issue checkers display the line number and line content of each
offending line, but don't show the location of the issue within a line.
Improve checkstyle by adding a marker that points to the exact location.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2024-05-31 14:24:24 +03:00
parent 4a7c9ce467
commit aad5837d70

View file

@ -556,8 +556,9 @@ class StyleChecker(metaclass=ClassRegistry):
class StyleIssue(object): class StyleIssue(object):
def __init__(self, line_number, line, msg): def __init__(self, line_number, position, line, msg):
self.line_number = line_number self.line_number = line_number
self.position = position
self.line = line self.line = line
self.msg = msg self.msg = msg
@ -584,7 +585,7 @@ class HexValueChecker(StyleChecker):
if value == value.lower(): if value == value.lower():
continue continue
issues.append(StyleIssue(line_number, line, issues.append(StyleIssue(line_number, match.span(0), line,
f'Use lowercase hex constant {value.lower()}')) f'Use lowercase hex constant {value.lower()}'))
return issues return issues
@ -623,7 +624,7 @@ class IncludeChecker(StyleChecker):
header_type = 'C compatibility' header_type = 'C compatibility'
header = header[1:] + '.h' header = header[1:] + '.h'
issues.append(StyleIssue(line_number, line, issues.append(StyleIssue(line_number, match.span(1), line,
f'{header_type} header <{header}> is preferred')) f'{header_type} header <{header}> is preferred'))
return issues return issues
@ -641,10 +642,12 @@ class LogCategoryChecker(StyleChecker):
issues = [] issues = []
for line_number in line_numbers: for line_number in line_numbers:
line = self.__content[line_number-1] line = self.__content[line_number-1]
if not LogCategoryChecker.log_regex.search(line): match = LogCategoryChecker.log_regex.search(line)
if not match:
continue continue
issues.append(StyleIssue(line_number, line, 'LOG() should use categories')) issues.append(StyleIssue(line_number, match.span(1), line,
'LOG() should use categories'))
return issues return issues
@ -660,8 +663,10 @@ class MesonChecker(StyleChecker):
issues = [] issues = []
for line_number in line_numbers: for line_number in line_numbers:
line = self.__content[line_number-1] line = self.__content[line_number-1]
if line.find('\t') != -1: pos = line.find('\t')
issues.append(StyleIssue(line_number, line, 'meson.build should use spaces for indentation')) if pos != -1:
issues.append(StyleIssue(line_number, [pos, pos], line,
'meson.build should use spaces for indentation'))
return issues return issues
@ -681,7 +686,7 @@ class Pep8Checker(StyleChecker):
ret = subprocess.run(['pycodestyle', '--ignore=E501', '-'], ret = subprocess.run(['pycodestyle', '--ignore=E501', '-'],
input=data, stdout=subprocess.PIPE) input=data, stdout=subprocess.PIPE)
except FileNotFoundError: except FileNotFoundError:
issues.append(StyleIssue(0, None, 'Please install pycodestyle to validate python additions')) issues.append(StyleIssue(0, None, None, 'Please install pycodestyle to validate python additions'))
return issues return issues
results = ret.stdout.decode('utf-8').splitlines() results = ret.stdout.decode('utf-8').splitlines()
@ -693,7 +698,7 @@ class Pep8Checker(StyleChecker):
if line_number in line_numbers: if line_number in line_numbers:
line = self.__content[line_number - 1] line = self.__content[line_number - 1]
issues.append(StyleIssue(line_number, line, msg)) issues.append(StyleIssue(line_number, None, line, msg))
return issues return issues
@ -714,7 +719,7 @@ class ShellChecker(StyleChecker):
ret = subprocess.run(['shellcheck', '-Cnever', '-'], ret = subprocess.run(['shellcheck', '-Cnever', '-'],
input=data, stdout=subprocess.PIPE) input=data, stdout=subprocess.PIPE)
except FileNotFoundError: except FileNotFoundError:
issues.append(StyleIssue(0, None, 'Please install shellcheck to validate shell script additions')) issues.append(StyleIssue(0, None, None, 'Please install shellcheck to validate shell script additions'))
return issues return issues
results = ret.stdout.decode('utf-8').splitlines() results = ret.stdout.decode('utf-8').splitlines()
@ -727,11 +732,8 @@ class ShellChecker(StyleChecker):
line = results[nr + 1] line = results[nr + 1]
msg = results[nr + 2] msg = results[nr + 2]
# Determined, but not yet used
position = msg.find('^') + 1
if line_number in line_numbers: if line_number in line_numbers:
issues.append(StyleIssue(line_number, line, msg)) issues.append(StyleIssue(line_number, None, line, msg))
return issues return issues
@ -973,6 +975,16 @@ def check_file(top_level, commit, filename, checkers):
print('%s+%s%s' % (Colours.fg(Colours.Yellow), issue.line.rstrip(), print('%s+%s%s' % (Colours.fg(Colours.Yellow), issue.line.rstrip(),
Colours.reset())) Colours.reset()))
if issue.position is not None:
# Align the position marker by using the original line with
# all characters except for tabs replaced with spaces. This
# ensures proper alignment regardless of how the code is
# indented.
start = issue.position[0]
prefix = ''.join([c if c == '\t' else ' ' for c in issue.line[:start]])
length = issue.position[1] - start - 1
print(' ' + prefix + '^' + '~' * length)
return len(formatted_diff) + len(issues) return len(formatted_diff) + len(issues)