From 9f3d71d8785bc1573bd82a9210106a7146f03b44 Mon Sep 17 00:00:00 2001 From: Sourcery AI <> Date: Mon, 4 Dec 2023 15:25:40 +0000 Subject: [PATCH] 'Refactored by Sourcery' --- benchmarks/thirdparty/benchmark/mingw.py | 23 +- .../thirdparty/benchmark/tools/compare.py | 16 +- .../benchmark/tools/compare_bench.py | 5 +- .../benchmark/tools/gbench/report.py | 7 +- .../thirdparty/benchmark/tools/gbench/util.py | 13 +- .../thirdparty/benchmark/tools/strip_asm.py | 26 +- doc/scripts/send_to_wandbox.py | 6 +- third_party/amalgamate/amalgamate.py | 11 +- third_party/cpplint/cpplint.py | 393 +++++++++--------- 9 files changed, 238 insertions(+), 262 deletions(-) diff --git a/benchmarks/thirdparty/benchmark/mingw.py b/benchmarks/thirdparty/benchmark/mingw.py index 706ad559db..656346b5e8 100755 --- a/benchmarks/thirdparty/benchmark/mingw.py +++ b/benchmarks/thirdparty/benchmark/mingw.py @@ -69,7 +69,7 @@ def repository(urls = urls, log = EmptyLogger()): socket.close() for entry in repo.split('\n')[:-1]: value = entry.split('|') - version = tuple([int(n) for n in value[0].strip().split('.')]) + version = tuple(int(n) for n in value[0].strip().split('.')) version = versions.setdefault(version, {}) arch = value[1].strip() if arch == 'x32': @@ -117,7 +117,7 @@ def unpack(archive, location, log = EmptyLogger()): ''' sevenzip = find_7zip(log) log.info('unpacking %s', os.path.basename(archive)) - cmd = [sevenzip, 'x', archive, '-o' + location, '-y'] + cmd = [sevenzip, 'x', archive, f'-o{location}', '-y'] log.debug(' - %r', cmd) with open(os.devnull, 'w') as devnull: subprocess.check_call(cmd, stdout = devnull) @@ -137,8 +137,7 @@ def download(url, location, log = EmptyLogger()): content = stream.getheader('Content-Disposition') or '' except AttributeError: content = stream.headers.getheader('Content-Disposition') or '' - matches = re_content.match(content) - if matches: + if matches := re_content.match(content): filename = matches.group(2) else: parsed = parse.urlparse(stream.geturl()) @@ -147,18 +146,16 @@ def download(url, location, log = EmptyLogger()): try: os.makedirs(location) except OSError as e: - if e.errno == errno.EEXIST and os.path.isdir(location): - pass - else: + if e.errno != errno.EEXIST or not os.path.isdir(location): raise archive = os.path.join(location, filename) with open(archive, 'wb') as out: while True: - buf = stream.read(1024) - if not buf: + if buf := stream.read(1024): + out.write(buf) + else: break - out.write(buf) unpack(archive, location, log = log) os.remove(archive) @@ -166,7 +163,7 @@ def download(url, location, log = EmptyLogger()): if not os.path.exists(possible): possible = os.path.join(location, 'mingw32') if not os.path.exists(possible): - raise ValueError('Failed to find unpacked MinGW: ' + possible) + raise ValueError(f'Failed to find unpacked MinGW: {possible}') return possible def root(location = None, arch = None, version = None, threading = None, @@ -204,7 +201,7 @@ def root(location = None, arch = None, version = None, threading = None, exceptions = 'sjlj' else: exceptions = keys[0] - if revision == None: + if revision is None: revision = max(versions[version][arch][threading][exceptions].keys()) if not location: location = os.path.join(tempfile.gettempdir(), 'mingw-builds') @@ -234,7 +231,7 @@ def root(location = None, arch = None, version = None, threading = None, elif arch == 'i686': root_dir = os.path.join(location, slug, 'mingw32') else: - raise ValueError('Unknown MinGW arch: ' + arch) + raise ValueError(f'Unknown MinGW arch: {arch}') # Download if needed if not os.path.exists(root_dir): diff --git a/benchmarks/thirdparty/benchmark/tools/compare.py b/benchmarks/thirdparty/benchmark/tools/compare.py index f0a4455f5f..b4c279ef07 100755 --- a/benchmarks/thirdparty/benchmark/tools/compare.py +++ b/benchmarks/thirdparty/benchmark/tools/compare.py @@ -152,7 +152,7 @@ def main(): # NOTE: if test_baseline == test_contender, you are analyzing the stdev - description = 'Comparing %s to %s' % (test_baseline, test_contender) + description = f'Comparing {test_baseline} to {test_contender}' elif args.mode == 'filters': test_baseline = args.test[0].name test_contender = args.test[0].name @@ -162,8 +162,7 @@ def main(): # NOTE: if filter_baseline == filter_contender, you are analyzing the # stdev - description = 'Comparing %s to %s (from %s)' % ( - filter_baseline, filter_contender, args.test[0].name) + description = f'Comparing {filter_baseline} to {filter_contender} (from {args.test[0].name})' elif args.mode == 'benchmarksfiltered': test_baseline = args.test_baseline[0].name test_contender = args.test_contender[0].name @@ -173,11 +172,10 @@ def main(): # NOTE: if test_baseline == test_contender and # filter_baseline == filter_contender, you are analyzing the stdev - description = 'Comparing %s (from %s) to %s (from %s)' % ( - filter_baseline, test_baseline, filter_contender, test_contender) + description = f'Comparing {filter_baseline} (from {test_baseline}) to {filter_contender} (from {test_contender})' else: # should never happen - print("Unrecognized mode of operation: '%s'" % args.mode) + print(f"Unrecognized mode of operation: '{args.mode}'") parser.print_help() exit(1) @@ -187,8 +185,8 @@ def main(): options_contender = [] if filter_baseline and filter_contender: - options_baseline = ['--benchmark_filter=%s' % filter_baseline] - options_contender = ['--benchmark_filter=%s' % filter_contender] + options_baseline = [f'--benchmark_filter={filter_baseline}'] + options_contender = [f'--benchmark_filter={filter_contender}'] # Run the benchmarks and report the results json1 = json1_orig = gbench.util.run_or_load_benchmark( @@ -198,7 +196,7 @@ def main(): # Now, filter the benchmarks so that the difference report can work if filter_baseline and filter_contender: - replacement = '[%s vs. %s]' % (filter_baseline, filter_contender) + replacement = f'[{filter_baseline} vs. {filter_contender}]' json1 = gbench.report.filter_benchmark( json1_orig, filter_baseline, replacement) json2 = gbench.report.filter_benchmark( diff --git a/benchmarks/thirdparty/benchmark/tools/compare_bench.py b/benchmarks/thirdparty/benchmark/tools/compare_bench.py index 7bbf0d0157..de6903ebba 100755 --- a/benchmarks/thirdparty/benchmark/tools/compare_bench.py +++ b/benchmarks/thirdparty/benchmark/tools/compare_bench.py @@ -49,8 +49,7 @@ def main(): test2 = args.test2[0] if unknown_args: # should never happen - print("Unrecognized positional argument arguments: '%s'" - % unknown_args) + print(f"Unrecognized positional argument arguments: '{unknown_args}'") exit(1) benchmark_options = args.benchmark_options check_inputs(test1, test2, benchmark_options) @@ -58,7 +57,7 @@ def main(): json1 = gbench.util.run_or_load_benchmark(test1, benchmark_options) json2 = gbench.util.run_or_load_benchmark(test2, benchmark_options) output_lines = gbench.report.generate_difference_report(json1, json2) - print('Comparing %s to %s' % (test1, test2)) + print(f'Comparing {test1} to {test2}') for ln in output_lines: print(ln) diff --git a/benchmarks/thirdparty/benchmark/tools/gbench/report.py b/benchmarks/thirdparty/benchmark/tools/gbench/report.py index 0c090981a8..dfb5e8397c 100755 --- a/benchmarks/thirdparty/benchmark/tools/gbench/report.py +++ b/benchmarks/thirdparty/benchmark/tools/gbench/report.py @@ -61,9 +61,9 @@ def calculate_change(old_val, new_val): """ Return a float representing the decimal change between old_val and new_val. """ - if old_val == 0 and new_val == 0: - return 0.0 if old_val == 0: + if new_val == 0: + return 0.0 return float(new_val - old_val) / (float(old_val + new_val) / 2) return float(new_val - old_val) / abs(old_val) @@ -73,8 +73,7 @@ def filter_benchmark(json_orig, family, replacement=""): Apply a filter to the json, and only leave the 'family' of benchmarks. """ regex = re.compile(family) - filtered = {} - filtered['benchmarks'] = [] + filtered = {'benchmarks': []} for be in json_orig['benchmarks']: if not regex.search(be['name']): continue diff --git a/benchmarks/thirdparty/benchmark/tools/gbench/util.py b/benchmarks/thirdparty/benchmark/tools/gbench/util.py index 07c2377275..af9ca130fa 100755 --- a/benchmarks/thirdparty/benchmark/tools/gbench/util.py +++ b/benchmarks/thirdparty/benchmark/tools/gbench/util.py @@ -60,15 +60,15 @@ def classify_input_file(filename): ftype = IT_Invalid err_msg = None if not os.path.exists(filename): - err_msg = "'%s' does not exist" % filename + err_msg = f"'{filename}' does not exist" elif not os.path.isfile(filename): - err_msg = "'%s' does not name a file" % filename + err_msg = f"'{filename}' does not name a file" elif is_executable_file(filename): ftype = IT_Executable elif is_json_file(filename): ftype = IT_JSON else: - err_msg = "'%s' does not name a valid benchmark executable or JSON file" % filename + err_msg = f"'{filename}' does not name a valid benchmark executable or JSON file" return ftype, err_msg @@ -80,7 +80,7 @@ def check_input_file(filename): """ ftype, msg = classify_input_file(filename) if ftype == IT_Invalid: - print("Invalid input file: %s" % msg) + print(f"Invalid input file: {msg}") sys.exit(1) return ftype @@ -128,11 +128,10 @@ def run_benchmark(exe_name, benchmark_flags): is_temp_output = True thandle, output_name = tempfile.mkstemp() os.close(thandle) - benchmark_flags = list(benchmark_flags) + \ - ['--benchmark_out=%s' % output_name] + benchmark_flags = (list(benchmark_flags) + [f'--benchmark_out={output_name}']) cmd = [exe_name] + benchmark_flags - print("RUNNING: %s" % ' '.join(cmd)) + print(f"RUNNING: {' '.join(cmd)}") exitCode = subprocess.call(cmd) if exitCode != 0: print('TEST FAILED...') diff --git a/benchmarks/thirdparty/benchmark/tools/strip_asm.py b/benchmarks/thirdparty/benchmark/tools/strip_asm.py index 9030550b43..91a7b1a9c7 100755 --- a/benchmarks/thirdparty/benchmark/tools/strip_asm.py +++ b/benchmarks/thirdparty/benchmark/tools/strip_asm.py @@ -13,9 +13,8 @@ def find_used_labels(asm): found = set() label_re = re.compile("\s*j[a-z]+\s+\.L([a-zA-Z0-9][a-zA-Z0-9_]*)") for l in asm.splitlines(): - m = label_re.match(l) - if m: - found.add('.L%s' % m.group(1)) + if m := label_re.match(l): + found.add(f'.L{m.group(1)}') return found @@ -23,10 +22,9 @@ def normalize_labels(asm): decls = set() label_decl = re.compile("^[.]{0,1}L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)") for l in asm.splitlines(): - m = label_decl.match(l) - if m: + if m := label_decl.match(l): decls.add(m.group(0)) - if len(decls) == 0: + if not decls: return asm needs_dot = next(iter(decls))[0] != '.' if not needs_dot: @@ -103,16 +101,10 @@ def process_asm(asm): for l in asm.splitlines(): # Remove Mach-O attribute l = l.replace('@GOTPCREL', '') - add_line = True - for reg in discard_regexes: - if reg.match(l) is not None: - add_line = False - break - for reg in keep_regexes: - if reg.match(l) is not None: - add_line = True - break - if add_line: + if add_line := next( + (True for reg in keep_regexes if reg.match(l) is not None), + all(reg.match(l) is None for reg in discard_regexes), + ): if fn_label_def.match(l) and len(new_contents) != 0: new_contents += '\n' l = process_identifiers(l) @@ -133,7 +125,7 @@ def main(): input = args.input[0] output = args.out[0] if not os.path.isfile(input): - print(("ERROR: input file '%s' does not exist") % input) + print(f"ERROR: input file '{input}' does not exist") sys.exit(1) contents = None with open(input, 'r') as f: diff --git a/doc/scripts/send_to_wandbox.py b/doc/scripts/send_to_wandbox.py index 1126566940..0ef8245eb7 100755 --- a/doc/scripts/send_to_wandbox.py +++ b/doc/scripts/send_to_wandbox.py @@ -28,10 +28,8 @@ def strip_comments(text): def replacer(match): s = match.group(0) - if s.startswith('/'): - return " " # note: a space and not an empty string - else: - return s + return " " if s.startswith('/') else s + pattern = re.compile( r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE diff --git a/third_party/amalgamate/amalgamate.py b/third_party/amalgamate/amalgamate.py index f01b43b760..653d95851a 100755 --- a/third_party/amalgamate/amalgamate.py +++ b/third_party/amalgamate/amalgamate.py @@ -105,11 +105,9 @@ def generate(self): def _is_within(match, matches): - for m in matches: - if match.start() > m.start() and \ - match.end() < m.end(): - return True - return False + return any( + match.start() > m.start() and match.end() < m.end() for m in matches + ) class TranslationUnit(object): @@ -134,8 +132,7 @@ class TranslationUnit(object): # Search for pattern in self.content, add the match to # contexts if found and update the index accordingly. def _search_content(self, index, pattern, contexts): - match = pattern.search(self.content, index) - if match: + if match := pattern.search(self.content, index): contexts.append(match) return match.end() return index + 2 diff --git a/third_party/cpplint/cpplint.py b/third_party/cpplint/cpplint.py index 81bc98b7ac..83ec8e4037 100755 --- a/third_party/cpplint/cpplint.py +++ b/third_party/cpplint/cpplint.py @@ -41,6 +41,7 @@ same line, but it is far from perfect (in either direction). """ + import codecs import copy import getopt @@ -557,16 +558,16 @@ for op, replacement in [('==', 'EQ'), ('!=', 'NE'), ('>=', 'GE'), ('>', 'GT'), ('<=', 'LE'), ('<', 'LT')]: - _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement - _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement - _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement - _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement + _CHECK_REPLACEMENT['DCHECK'][op] = f'DCHECK_{replacement}' + _CHECK_REPLACEMENT['CHECK'][op] = f'CHECK_{replacement}' + _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = f'EXPECT_{replacement}' + _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = f'ASSERT_{replacement}' for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), ('>=', 'LT'), ('>', 'LE'), ('<=', 'GT'), ('<', 'GE')]: - _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement - _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement + _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = f'EXPECT_{inv_replacement}' + _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = f'ASSERT_{inv_replacement}' # Alternative tokens and their replacements. For full list, see section 2.5 # Alternative tokens [lex.digraph] in the C++ standard. @@ -671,14 +672,11 @@ iteritems = dict.items def unicode_escape_decode(x): - if sys.version_info < (3,): - return codecs.unicode_escape_decode(x)[0] - else: - return x + return codecs.unicode_escape_decode(x)[0] if sys.version_info < (3,) else x # Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc. # This is set by --headers flag. -_hpp_headers = set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh']) +_hpp_headers = {'h', 'hh', 'hpp', 'hxx', 'h++', 'cuh'} # {str, bool}: a map from error categories to booleans which indicate if the # category should be suppressed for every line. @@ -703,7 +701,7 @@ def GetHeaderExtensions(): # This is set by --extensions flag def GetAllExtensions(): if not _valid_extensions: - return GetHeaderExtensions().union(set(['c', 'cc', 'cpp', 'cxx', 'c++', 'cu'])) + return GetHeaderExtensions().union({'c', 'cc', 'cpp', 'cxx', 'c++', 'cu'}) return _valid_extensions def GetNonHeaderExtensions(): @@ -724,23 +722,24 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error): linenum: int, the number of the current line. error: function, an error handler. """ - matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line) - if matched: - if matched.group(1): - suppressed_line = linenum + 1 - else: - suppressed_line = linenum - category = matched.group(2) - if category in (None, '(*)'): # => "suppress all" - _error_suppressions.setdefault(None, set()).add(suppressed_line) - else: - if category.startswith('(') and category.endswith(')'): - category = category[1:-1] - if category in _ERROR_CATEGORIES: - _error_suppressions.setdefault(category, set()).add(suppressed_line) - elif category not in _LEGACY_ERROR_CATEGORIES: - error(filename, linenum, 'readability/nolint', 5, - 'Unknown NOLINT error category: %s' % category) + if not (matched := Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)): + return + suppressed_line = linenum + 1 if matched.group(1) else linenum + category = matched.group(2) + if category in (None, '(*)'): # => "suppress all" + _error_suppressions.setdefault(None, set()).add(suppressed_line) + elif category.startswith('(') and category.endswith(')'): + category = category[1:-1] + if category in _ERROR_CATEGORIES: + _error_suppressions.setdefault(category, set()).add(suppressed_line) + elif category not in _LEGACY_ERROR_CATEGORIES: + error( + filename, + linenum, + 'readability/nolint', + 5, + f'Unknown NOLINT error category: {category}', + ) def ProcessGlobalSuppresions(lines): @@ -933,10 +932,8 @@ def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): # # If previous line was a blank line, assume that the headers are # intentionally sorted the way they are. - if (self._last_header > header_path and - Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])): - return False - return True + return self._last_header <= header_path or not Match( + r'^\s*#\s*include\b', clean_lines.elided[linenum - 1]) def CheckNextIncludeOrder(self, header_type): """Returns a non-empty error message if the next header is out of order. @@ -952,9 +949,7 @@ def CheckNextIncludeOrder(self, header_type): error message describing what's wrong. """ - error_message = ('Found %s after %s' % - (self._TYPE_NAMES[header_type], - self._SECTION_NAMES[self._section])) + error_message = f'Found {self._TYPE_NAMES[header_type]} after {self._SECTION_NAMES[self._section]}' last_section = self._section @@ -1059,8 +1054,7 @@ def SetFilters(self, filters): def AddFilters(self, filters): """ Adds more filters to the existing list of error-message filters. """ for filt in filters.split(','): - clean_filt = filt.strip() - if clean_filt: + if clean_filt := filt.strip(): self.filters.append(clean_filt) for filt in self.filters: if not (filt.startswith('+') or filt.startswith('-')): @@ -1275,8 +1269,7 @@ def Check(self, error, filename, linenum): if self.lines_in_function > trigger: error_level = int(math.log(self.lines_in_function / base_trigger, 2)) # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... - if error_level > 5: - error_level = 5 + error_level = min(error_level, 5) error(filename, linenum, 'readability/fn_size', error_level, 'Small and focused functions are preferred:' ' %s has %d non-comment lines' @@ -1391,7 +1384,7 @@ def Extension(self): def NoExtension(self): """File has no source file extension.""" - return '/'.join(self.Split()[0:2]) + return '/'.join(self.Split()[:2]) def IsSource(self): """File has a source file extension.""" @@ -1420,10 +1413,7 @@ def _ShouldPrintError(category, confidence, linenum): is_filtered = False else: assert False # should have been checked for in SetFilter. - if is_filtered: - return False - - return True + return not is_filtered def Error(filename, linenum, category, confidence, message): @@ -1532,7 +1522,7 @@ def CleanseRawStrings(raw_lines): # line and resume copying the original lines, and also insert # a "" on the last line. leading_space = Match(r'^(\s*)\S', line) - line = leading_space.group(1) + '""' + line[end + len(delimiter):] + line = f'{leading_space.group(1)}""{line[end + len(delimiter):]}' delimiter = None else: # Haven't found the end yet, append a blank line. @@ -1556,17 +1546,16 @@ def CleanseRawStrings(raw_lines): if (matched and not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//', matched.group(1))): - delimiter = ')' + matched.group(2) + '"' + delimiter = f'){matched.group(2)}"' end = matched.group(3).find(delimiter) if end >= 0: # Raw string ended on same line - line = (matched.group(1) + '""' + - matched.group(3)[end + len(delimiter):]) + line = f'{matched.group(1)}""{matched.group(3)[end + len(delimiter):]}' delimiter = None else: # Start of a multi-line raw string - line = matched.group(1) + '""' + line = f'{matched.group(1)}""' else: break @@ -1700,34 +1689,26 @@ def _CollapseStrings(elided): # Collapse double quoted strings second_quote = tail.find('"') if second_quote >= 0: - collapsed += head + '""' + collapsed += f'{head}""' elided = tail[second_quote + 1:] else: # Unmatched double quote, don't bother processing the rest # of the line since this is probably a multiline string. collapsed += elided break + elif Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head): + match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', f"'{tail}") + collapsed += head + match_literal.group(1).replace("'", '') + elided = match_literal.group(2) else: - # Found single quote, check nearby text to eliminate digit separators. - # - # There is no special handling for floating point here, because - # the integer/fractional/exponent parts would all be parsed - # correctly as long as there are digits on both sides of the - # separator. So we are fine as long as we don't see something - # like "0.'3" (gcc 4.9.0 will not allow this literal). - if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head): - match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail) - collapsed += head + match_literal.group(1).replace("'", '') - elided = match_literal.group(2) + second_quote = tail.find('\'') + if second_quote >= 0: + collapsed += f"{head}''" + elided = tail[second_quote + 1:] else: - second_quote = tail.find('\'') - if second_quote >= 0: - collapsed += head + "''" - elided = tail[second_quote + 1:] - else: - # Unmatched single quote - collapsed += elided - break + # Unmatched single quote + collapsed += elided + break return collapsed @@ -1758,7 +1739,7 @@ def FindEndOfExpressionInLine(line, startpos, stack): stack.pop() if not stack: return (-1, None) - elif i > 0 and Search(r'\boperator\s*$', line[0:i]): + elif i > 0 and Search(r'\boperator\s*$', line[:i]): # operator<, don't add to stack continue else: @@ -1773,21 +1754,20 @@ def FindEndOfExpressionInLine(line, startpos, stack): stack.pop() if not stack: return (-1, None) - if ((stack[-1] == '(' and char == ')') or - (stack[-1] == '[' and char == ']') or - (stack[-1] == '{' and char == '}')): - stack.pop() - if not stack: - return (i + 1, None) - else: + if ((stack[-1] != '(' or char != ')') + and (stack[-1] != '[' or char != ']') + and (stack[-1] != '{' or char != '}')): # Mismatched parentheses return (-1, None) + stack.pop() + if not stack: + return (i + 1, None) elif char == '>': # Found potential end of template argument list. # Ignore "->" and operator functions - if (i > 0 and - (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))): + if i > 0 and (line[i - 1] == '-' + or Search(r'\boperator\s*$', line[:i - 1])): continue # Pop the stack if there is a matching '<'. Otherwise, ignore @@ -1880,10 +1860,8 @@ def FindStartOfExpressionInLine(line, endpos, stack): # Found potential end of template argument list. # # Ignore it if it's a "->" or ">=" or "operator>" - if (i > 0 and - (line[i - 1] == '-' or - Match(r'\s>=\s', line[i - 1:]) or - Search(r'\boperator\s*$', line[0:i]))): + if i > 0 and (line[i - 1] == '-' or Match(r'\s>=\s', line[i - 1:]) + or Search(r'\boperator\s*$', line[:i])): i -= 1 else: stack.append('>') @@ -1892,13 +1870,10 @@ def FindStartOfExpressionInLine(line, endpos, stack): if i > 0 and line[i - 1] == '<': # Left shift operator i -= 1 - else: - # If there is a matching '>', we can pop the expression stack. - # Otherwise, ignore this '<' since it must be an operator. - if stack and stack[-1] == '>': - stack.pop() - if not stack: - return (i, None) + elif stack and stack[-1] == '>': + stack.pop() + if not stack: + return (i, None) elif char in '([{': # Found start of expression. # @@ -1908,15 +1883,14 @@ def FindStartOfExpressionInLine(line, endpos, stack): stack.pop() if not stack: return (-1, None) - if ((char == '(' and stack[-1] == ')') or - (char == '[' and stack[-1] == ']') or - (char == '{' and stack[-1] == '}')): - stack.pop() - if not stack: - return (i, None) - else: + if ((char != '(' or stack[-1] != ')') + and (char != '[' or stack[-1] != ']') + and (char != '{' or stack[-1] != '}')): # Mismatched parentheses return (-1, None) + stack.pop() + if not stack: + return (i, None) elif char == ';': # Found something that look like end of statements. If we are currently # expecting a '<', the matching '>' must have been an operator, since @@ -1991,11 +1965,7 @@ def GetIndentLevel(line): Returns: An integer count of leading spaces, possibly zero. """ - indent = Match(r'^( *)\S', line) - if indent: - return len(indent.group(1)) - else: - return 0 + return len(indent.group(1)) if (indent := Match(r'^( *)\S', line)) else 0 def PathSplitToList(path): """Returns the path split into a list by the separator. @@ -2057,10 +2027,7 @@ def FixupPathFromRoot(): def StripListPrefix(lst, prefix): # f(['x', 'y'], ['w, z']) -> None (not a valid prefix) - if lst[:len(prefix)] != prefix: - return None - # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd'] - return lst[(len(prefix)):] + return None if lst[:len(prefix)] != prefix else lst[(len(prefix)):] # root behavior: # --root=subdir , lstrips subdir from the header guard @@ -2149,32 +2116,42 @@ def CheckForHeaderGuard(filename, clean_lines, error): endif_linenum = linenum if not ifndef or not define or ifndef != define: - error(filename, 0, 'build/header_guard', 5, - 'No #ifndef header guard found, suggested CPP variable is: %s' % - cppvar) + error( + filename, + 0, + 'build/header_guard', + 5, + f'No #ifndef header guard found, suggested CPP variable is: {cppvar}', + ) return # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ # for backward compatibility. if ifndef != cppvar: - error_level = 0 - if ifndef != cppvar + '_': - error_level = 5 - + error_level = 5 if ifndef != f'{cppvar}_' else 0 ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum, error) - error(filename, ifndef_linenum, 'build/header_guard', error_level, - '#ifndef header guard has wrong style, please use: %s' % cppvar) + error( + filename, + ifndef_linenum, + 'build/header_guard', + error_level, + f'#ifndef header guard has wrong style, please use: {cppvar}', + ) # Check for "//" comments on endif line. ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum, error) - match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif) - if match: + if match := Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif): if match.group(1) == '_': # Issue low severity warning for deprecated double trailing underscore - error(filename, endif_linenum, 'build/header_guard', 0, - '#endif line should be "#endif // %s"' % cppvar) + error( + filename, + endif_linenum, + 'build/header_guard', + 0, + f'#endif line should be "#endif // {cppvar}"', + ) return # Didn't find the corresponding "//" comment. If this file does not @@ -2188,17 +2165,26 @@ def CheckForHeaderGuard(filename, clean_lines, error): break if no_single_line_comments: - match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif) - if match: + if match := Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif): if match.group(1) == '_': # Low severity warning for double trailing underscore - error(filename, endif_linenum, 'build/header_guard', 0, - '#endif line should be "#endif /* %s */"' % cppvar) + error( + filename, + endif_linenum, + 'build/header_guard', + 0, + f'#endif line should be "#endif /* {cppvar} */"', + ) return # Didn't find anything - error(filename, endif_linenum, 'build/header_guard', 5, - '#endif line should be "#endif // %s"' % cppvar) + error( + filename, + endif_linenum, + 'build/header_guard', + 5, + f'#endif line should be "#endif // {cppvar}"', + ) def CheckHeaderFileIncluded(filename, include_state, error): @@ -2210,8 +2196,8 @@ def CheckHeaderFileIncluded(filename, include_state, error): return for ext in GetHeaderExtensions(): - basefilename = filename[0:len(filename) - len(fileinfo.Extension())] - headerfile = basefilename + '.' + ext + basefilename = filename[:len(filename) - len(fileinfo.Extension())] + headerfile = f'{basefilename}.{ext}' if not os.path.exists(headerfile): continue headername = FileInfo(headerfile).RepositoryName() @@ -2223,9 +2209,13 @@ def CheckHeaderFileIncluded(filename, include_state, error): if not first_include: first_include = f[1] - error(filename, first_include, 'build/include', 5, - '%s should include its header file %s' % (fileinfo.RepositoryName(), - headername)) + error( + filename, + first_include, + 'build/include', + 5, + f'{fileinfo.RepositoryName()} should include its header file {headername}', + ) def CheckForBadCharacters(filename, lines, error): @@ -2359,10 +2349,13 @@ def CheckPosixThreading(filename, clean_lines, linenum, error): # Additional pattern matching check to confirm that this is the # function we are looking for if Search(pattern, line): - error(filename, linenum, 'runtime/threadsafe_fn', 2, - 'Consider using ' + multithread_safe_func + - '...) instead of ' + single_thread_func + - '...) for improved thread safety.') + error( + filename, + linenum, + 'runtime/threadsafe_fn', + 2, + f'Consider using {multithread_safe_func}...) instead of {single_thread_func}...) for improved thread safety.', + ) def CheckVlogArguments(filename, clean_lines, linenum, error): @@ -2415,10 +2408,7 @@ def IsMacroDefinition(clean_lines, linenum): if Search(r'^#define', clean_lines[linenum]): return True - if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]): - return True - - return False + return bool(linenum > 0 and Search(r'\\$', clean_lines[linenum - 1])) def IsForwardClassDeclaration(clean_lines, linenum): @@ -2525,14 +2515,19 @@ def CheckEnd(self, filename, clean_lines, linenum, error): # the class. seen_last_thing_in_class = False for i in xrange(linenum - 1, self.starting_linenum, -1): - match = Search( + if match := Search( r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' + self.name + r'\)', - clean_lines.elided[i]) - if match: + clean_lines.elided[i], + ): if seen_last_thing_in_class: - error(filename, i, 'readability/constructors', 3, - match.group(1) + ' should be the last thing in the class') + error( + filename, + i, + 'readability/constructors', + 3, + f'{match.group(1)} should be the last thing in the class', + ) break if not Match(r'^\s*$', clean_lines.elided[i]): @@ -2543,12 +2538,14 @@ def CheckEnd(self, filename, clean_lines, linenum, error): # This means we will not check single-line class definitions. indent = Match(r'^( *)\}', clean_lines.elided[linenum]) if indent and len(indent.group(1)) != self.class_indent: - if self.is_struct: - parent = 'struct ' + self.name - else: - parent = 'class ' + self.name - error(filename, linenum, 'whitespace/indent', 3, - 'Closing brace should be aligned with beginning of %s' % parent) + parent = f'struct {self.name}' if self.is_struct else f'class {self.name}' + error( + filename, + linenum, + 'whitespace/indent', + 3, + f'Closing brace should be aligned with beginning of {parent}', + ) class _NamespaceInfo(_BlockInfo): @@ -2595,21 +2592,23 @@ def CheckEnd(self, filename, clean_lines, linenum, error): if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) + r'[\*/\.\\\s]*$'), line): + error( + filename, + linenum, + 'readability/namespace', + 5, + f'Namespace should be terminated with "// namespace {self.name}"', + ) + elif not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): + # If "// namespace anonymous" or "// anonymous namespace (more text)", + # mention "// anonymous namespace" as an acceptable form + if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line): error(filename, linenum, 'readability/namespace', 5, - 'Namespace should be terminated with "// namespace %s"' % - self.name) - else: - # Anonymous namespace - if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): - # If "// namespace anonymous" or "// anonymous namespace (more text)", - # mention "// anonymous namespace" as an acceptable form - if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line): - error(filename, linenum, 'readability/namespace', 5, - 'Anonymous namespace should be terminated with "// namespace"' - ' or "// anonymous namespace"') - else: - error(filename, linenum, 'readability/namespace', 5, - 'Anonymous namespace should be terminated with "// namespace"') + 'Anonymous namespace should be terminated with "// namespace"' + ' or "// anonymous namespace"') + else: + error(filename, linenum, 'readability/namespace', 5, + 'Anonymous namespace should be terminated with "// namespace"') class _PreprocessorInfo(object): @@ -2782,9 +2781,6 @@ def UpdatePreprocessor(self, line): # Restore the stack to how it was before the #if self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) - else: - # TODO(unknown): unexpected #else, issue warning? - pass elif Match(r'^\s*#\s*endif\b', line): # End of #if or #else blocks. if self.pp_stack: @@ -2797,9 +2793,6 @@ def UpdatePreprocessor(self, line): self.stack = self.pp_stack[-1].stack_before_else # Drop the corresponding #if self.pp_stack.pop() - else: - # TODO(unknown): unexpected #endif, issue warning? - pass # TODO(unknown): Update() is too long, but we will refactor later. def Update(self, filename, clean_lines, linenum, error): @@ -2818,11 +2811,7 @@ def Update(self, filename, clean_lines, linenum, error): # The stack is always pushed/popped and not modified in place, so # we can just do a shallow copy instead of copy.deepcopy. Using # deepcopy would slow down cpplint by ~28%. - if self.stack: - self.previous_stack_top = self.stack[-1] - else: - self.previous_stack_top = None - + self.previous_stack_top = self.stack[-1] if self.stack else None # Update pp_stack self.UpdatePreprocessor(line) @@ -2904,11 +2893,11 @@ def Update(self, filename, clean_lines, linenum, error): # Update access control if we are inside a class/struct if self.stack and isinstance(self.stack[-1], _ClassInfo): classinfo = self.stack[-1] - access_match = Match( + if access_match := Match( r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?' r':(?:[^:]|$)', - line) - if access_match: + line, + ): classinfo.access = access_match.group(2) # Check that access keywords are indented +1 space. Skip this @@ -2917,15 +2906,17 @@ def Update(self, filename, clean_lines, linenum, error): if (len(indent) != classinfo.class_indent + 1 and Match(r'^\s*$', indent)): if classinfo.is_struct: - parent = 'struct ' + classinfo.name + parent = f'struct {classinfo.name}' else: - parent = 'class ' + classinfo.name - slots = '' - if access_match.group(3): - slots = access_match.group(3) - error(filename, linenum, 'whitespace/indent', 3, - '%s%s: should be indented +1 space inside %s' % ( - access_match.group(2), slots, parent)) + parent = f'class {classinfo.name}' + slots = access_match.group(3) if access_match.group(3) else '' + error( + filename, + linenum, + 'whitespace/indent', + 3, + f'{access_match.group(2)}{slots}: should be indented +1 space inside {parent}', + ) # Consume braces or semicolons from what's left of the line while True: @@ -2948,7 +2939,7 @@ def Update(self, filename, clean_lines, linenum, error): if _MATCH_ASM.match(line): self.stack[-1].inline_asm = _BLOCK_ASM - elif token == ';' or token == ')': + elif token in [';', ')']: # If we haven't seen an opening brace yet, but we already saw # a semicolon, this is probably a forward declaration. Pop # the stack for these. @@ -2959,11 +2950,9 @@ def Update(self, filename, clean_lines, linenum, error): # Also pop these stack for these. if not self.SeenOpenBrace(): self.stack.pop() - else: # token == '}' - # Perform end of block checks and pop the stack. - if self.stack: - self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) - self.stack.pop() + elif self.stack: + self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) + self.stack.pop() line = matched.group(2) def InnermostClass(self): @@ -2991,13 +2980,21 @@ def CheckCompletedBlocks(self, filename, error): # cpplint_unittest.py for an example of this. for obj in self.stack: if isinstance(obj, _ClassInfo): - error(filename, obj.starting_linenum, 'build/class', 5, - 'Failed to find complete declaration of class %s' % - obj.name) + error( + filename, + obj.starting_linenum, + 'build/class', + 5, + f'Failed to find complete declaration of class {obj.name}', + ) elif isinstance(obj, _NamespaceInfo): - error(filename, obj.starting_linenum, 'build/namespaces', 5, - 'Failed to find complete declaration of namespace %s' % - obj.name) + error( + filename, + obj.starting_linenum, + 'build/namespaces', + 5, + f'Failed to find complete declaration of namespace {obj.name}', + ) def CheckForNonStandardConstructs(filename, clean_lines, linenum,