A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
check-style-clang-format.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3# Copyright (c) 2022 Eduardo Nuno Almeida.
4#
5# SPDX-License-Identifier: GPL-2.0-only
6#
7# Author: Eduardo Nuno Almeida <enmsa@outlook.pt> [INESC TEC and FEUP, Portugal]
8
9"""
10Check and apply the ns-3 coding style recursively to all files in the PATH arguments.
11
12The coding style is defined with the clang-format tool, whose definitions are in
13the ".clang-format" file. This script performs the following checks / fixes:
14- Check / apply clang-format. Respects clang-format guards.
15- Check / fix local #include headers with "ns3/" prefix. Respects clang-format guards.
16- Check / trim trailing whitespace. Always checked.
17- Check / replace tabs with spaces. Respects clang-format guards.
18- Check / fix SPDX licenses rather than GPL text. Respects clang-format guards.
19
20This script can be applied to all text files in a given path or to individual files.
21
22NOTE: The formatting check requires clang-format (version >= 14) to be found on the path.
23The remaining checks do not depend on clang-format and can be executed by disabling clang-format
24checking with the "--no-formatting" option.
25"""
26
27import argparse
28import concurrent.futures
29import itertools
30import os
31import re
32import shutil
33import subprocess
34import sys
35from typing import Callable, Dict, List, Tuple
36
37###########################################################
38# PARAMETERS
39###########################################################
40CLANG_FORMAT_VERSIONS = [
41 17,
42 16,
43 15,
44 14,
45]
46
47FORMAT_GUARD_ON = [
48 "// clang-format on",
49 "# cmake-format: on",
50 "# fmt: on",
51]
52
53FORMAT_GUARD_OFF = [
54 "// clang-format off",
55 "# cmake-format: off",
56 "# fmt: off",
57]
58
59DIRECTORIES_TO_SKIP = [
60 "__pycache__",
61 ".git",
62 ".venv",
63 "bindings",
64 "build",
65 "cmake-cache",
66 "testpy-output",
67 "venv",
68]
69
70# List of files entirely copied from elsewhere that should not be checked,
71# in order to optimize the performance of this script
72FILES_TO_SKIP = [
73 "valgrind.h",
74]
75
76# List of checks
77CHECKS = [
78 "include_prefixes",
79 "whitespace",
80 "tabs",
81 "license",
82 "formatting",
83]
84
85# Files to check
86FILES_TO_CHECK: Dict[str, List[str]] = {c: [] for c in CHECKS}
87
88FILES_TO_CHECK["tabs"] = [
89 ".clang-format",
90 ".clang-tidy",
91 ".codespellrc",
92 "CMakeLists.txt",
93 "codespell-ignored-lines",
94 "codespell-ignored-words",
95 "ns3",
96]
97
98FILES_TO_CHECK["whitespace"] = FILES_TO_CHECK["tabs"] + [
99 "Makefile",
100]
101
102# File extensions to check
103FILE_EXTENSIONS_TO_CHECK: Dict[str, List[str]] = {c: [] for c in CHECKS}
104
105FILE_EXTENSIONS_TO_CHECK["formatting"] = [
106 ".c",
107 ".cc",
108 ".h",
109]
110
111FILE_EXTENSIONS_TO_CHECK["include_prefixes"] = FILE_EXTENSIONS_TO_CHECK["formatting"]
112
113FILE_EXTENSIONS_TO_CHECK["tabs"] = [
114 ".c",
115 ".cc",
116 ".cmake",
117 ".css",
118 ".h",
119 ".html",
120 ".js",
121 ".json",
122 ".m",
123 ".md",
124 ".pl",
125 ".py",
126 ".rst",
127 ".sh",
128 ".toml",
129 ".yml",
130]
131
132FILE_EXTENSIONS_TO_CHECK["whitespace"] = FILE_EXTENSIONS_TO_CHECK["tabs"] + [
133 ".click",
134 ".cfg",
135 ".conf",
136 ".dot",
137 ".gnuplot",
138 ".gp",
139 ".mob",
140 ".ns_params",
141 ".ns_movements",
142 ".params",
143 ".plt",
144 ".seqdiag",
145 ".txt",
146]
147
148FILE_EXTENSIONS_TO_CHECK["license"] = [
149 ".c",
150 ".cc",
151 ".cmake",
152 ".h",
153 ".py",
154]
155
156# Other check parameters
157TAB_SIZE = 4
158
159
160###########################################################
161# AUXILIARY FUNCTIONS
162###########################################################
163def should_analyze_directory(dirpath: str) -> bool:
164 """
165 Check whether a directory should be analyzed.
166
167 @param dirpath Directory path.
168 @return Whether the directory should be analyzed.
169 """
170
171 _, directory = os.path.split(dirpath)
172
173 return directory not in DIRECTORIES_TO_SKIP
174
175
177 path: str,
178 files_to_check: List[str],
179 file_extensions_to_check: List[str],
180) -> bool:
181 """
182 Check whether a file should be analyzed.
183
184 @param path Path to the file.
185 @param files_to_check List of files that shall be checked.
186 @param file_extensions_to_check List of file extensions that shall be checked.
187 @return Whether the file should be analyzed.
188 """
189
190 filename = os.path.split(path)[1]
191
192 if filename in FILES_TO_SKIP:
193 return False
194
195 extension = os.path.splitext(filename)[1]
196
197 return filename in files_to_check or extension in file_extensions_to_check
198
199
201 paths: List[str],
202) -> Dict[str, List[str]]:
203 """
204 Find all files to be checked in a given list of paths.
205
206 @param paths List of paths to the files to check.
207 @return Dictionary of checks and corresponding list of files to check.
208 Example: {
209 "formatting": list_of_files_to_check_formatting,
210 ...,
211 }
212 """
213
214 # Get list of files found in the given path
215 files_found: List[str] = []
216
217 for path in paths:
218 abs_path = os.path.abspath(os.path.expanduser(path))
219
220 if os.path.isfile(abs_path):
221 files_found.append(path)
222
223 elif os.path.isdir(abs_path):
224 for dirpath, dirnames, filenames in os.walk(path, topdown=True):
225 if not should_analyze_directory(dirpath):
226 # Remove directory and its subdirectories
227 dirnames[:] = []
228 continue
229
230 files_found.extend([os.path.join(dirpath, f) for f in filenames])
231
232 else:
233 raise ValueError(f"{path} is not a valid file nor a directory")
234
235 files_found.sort()
236
237 # Check which files should be checked
238 files_to_check: Dict[str, List[str]] = {c: [] for c in CHECKS}
239
240 for f in files_found:
241 for check in CHECKS:
242 if should_analyze_file(f, FILES_TO_CHECK[check], FILE_EXTENSIONS_TO_CHECK[check]):
243 files_to_check[check].append(f)
244
245 return files_to_check
246
247
249 """
250 Find the path to one of the supported versions of clang-format.
251 If no supported version of clang-format is found, raise an exception.
252
253 @return Path to clang-format.
254 """
255
256 # Find exact version
257 for version in CLANG_FORMAT_VERSIONS:
258 clang_format_path = shutil.which(f"clang-format-{version}")
259
260 if clang_format_path:
261 return clang_format_path
262
263 # Find default version and check if it is supported
264 clang_format_path = shutil.which("clang-format")
265
266 if clang_format_path:
267 process = subprocess.run(
268 [clang_format_path, "--version"],
269 capture_output=True,
270 text=True,
271 check=True,
272 )
273
274 clang_format_version = process.stdout.strip()
275 version_regex = re.findall(r"\b(\d+)(\.\d+){0,2}\b", clang_format_version)
276
277 if version_regex:
278 major_version = int(version_regex[0][0])
279
280 if major_version in CLANG_FORMAT_VERSIONS:
281 return clang_format_path
282
283 # No supported version of clang-format found
284 raise RuntimeError(
285 f"Could not find any supported version of clang-format installed on this system. "
286 f"List of supported versions: {CLANG_FORMAT_VERSIONS}. "
287 + (f"Found clang-format {major_version}." if version_regex else "")
288 )
289
290
291###########################################################
292# CHECK STYLE MAIN FUNCTIONS
293###########################################################
295 paths: List[str],
296 checks_enabled: Dict[str, bool],
297 fix: bool,
298 verbose: bool,
299 n_jobs: int = 1,
300) -> bool:
301 """
302 Check / fix the coding style of a list of files.
303
304 @param paths List of paths to the files to check.
305 @param checks_enabled Dictionary of checks indicating whether to enable each of them.
306 @param fix Whether to fix (True) or just check (False) the file.
307 @param verbose Show the lines that are not compliant with the style.
308 @param n_jobs Number of parallel jobs.
309 @return Whether all files are compliant with all enabled style checks.
310 """
311
312 files_to_check = find_files_to_check_style(paths)
313 checks_successful = {c: True for c in CHECKS}
314
315 style_check_strs = {
316 "include_prefixes": '#include headers from the same module with the "ns3/" prefix',
317 "whitespace": "trailing whitespace",
318 "tabs": "tabs",
319 "license": "GPL license text instead of SPDX license",
320 "formatting": "bad code formatting",
321 }
322
323 check_style_file_functions_kwargs = {
324 "include_prefixes": {
325 "function": check_manually_file,
326 "kwargs": {
327 "respect_clang_format_guards": True,
328 "check_style_line_function": check_include_prefixes_line,
329 },
330 },
331 "whitespace": {
332 "function": check_manually_file,
333 "kwargs": {
334 "respect_clang_format_guards": False,
335 "check_style_line_function": check_whitespace_line,
336 },
337 },
338 "tabs": {
339 "function": check_manually_file,
340 "kwargs": {
341 "respect_clang_format_guards": True,
342 "check_style_line_function": check_tabs_line,
343 },
344 },
345 "license": {
346 "function": check_manually_file,
347 "kwargs": {
348 "respect_clang_format_guards": True,
349 "check_style_line_function": check_licenses_line,
350 },
351 },
352 "formatting": {
353 "function": check_formatting_file,
354 "kwargs": {}, # The formatting keywords are added below
355 },
356 }
357
358 if checks_enabled["formatting"]:
359 check_style_file_functions_kwargs["formatting"]["kwargs"] = {
360 "clang_format_path": find_clang_format_path(),
361 }
362
363 n_checks_enabled = sum(checks_enabled.values())
364 n_check = 0
365
366 for check in CHECKS:
367 if checks_enabled[check]:
368 checks_successful[check] = check_style_files(
369 style_check_strs[check],
370 check_style_file_functions_kwargs[check]["function"],
371 files_to_check[check],
372 fix,
373 verbose,
374 n_jobs,
375 **check_style_file_functions_kwargs[check]["kwargs"],
376 )
377
378 n_check += 1
379
380 if n_check < n_checks_enabled:
381 print("")
382
383 return all(checks_successful.values())
384
385
387 style_check_str: str,
388 check_style_file_function: Callable[..., Tuple[str, bool, List[str]]],
389 filenames: List[str],
390 fix: bool,
391 verbose: bool,
392 n_jobs: int,
393 **kwargs,
394) -> bool:
395 """
396 Check / fix style of a list of files.
397
398 @param style_check_str Description of the check to be performed.
399 @param check_style_file_function Function used to check the file.
400 @param filename Name of the file to be checked.
401 @param fix Whether to fix (True) or just check (False) the file (True).
402 @param verbose Show the lines that are not compliant with the style.
403 @param n_jobs Number of parallel jobs.
404 @param kwargs Additional keyword arguments to the check_style_file_function.
405 @return Whether all files are compliant with the style.
406 """
407
408 # Check files
409 non_compliant_files: List[str] = []
410 files_verbose_infos: Dict[str, List[str]] = {}
411
412 with concurrent.futures.ProcessPoolExecutor(n_jobs) as executor:
413 non_compliant_files_results = executor.map(
414 check_style_file_function,
415 filenames,
416 itertools.repeat(fix),
417 itertools.repeat(verbose),
418 *[arg if isinstance(arg, list) else itertools.repeat(arg) for arg in kwargs.values()],
419 )
420
421 for filename, is_file_compliant, verbose_infos in non_compliant_files_results:
422 if not is_file_compliant:
423 non_compliant_files.append(filename)
424
425 if verbose:
426 files_verbose_infos[filename] = verbose_infos
427
428 # Output results
429 if not non_compliant_files:
430 print(f"- No files detected with {style_check_str}")
431 return True
432
433 else:
434 n_non_compliant_files = len(non_compliant_files)
435
436 if fix:
437 print(f"- Fixed {style_check_str} in the files ({n_non_compliant_files}):")
438 else:
439 print(f"- Detected {style_check_str} in the files ({n_non_compliant_files}):")
440
441 for f in non_compliant_files:
442 if verbose:
443 print(*[f" {l}" for l in files_verbose_infos[f]], sep="\n")
444 else:
445 print(f" - {f}")
446
447 # If all files were fixed, there are no more non-compliant files
448 return fix
449
450
451###########################################################
452# CHECK STYLE FUNCTIONS
453###########################################################
455 filename: str,
456 fix: bool,
457 verbose: bool,
458 clang_format_path: str,
459) -> Tuple[str, bool, List[str]]:
460 """
461 Check / fix the coding style of a file with clang-format.
462
463 @param filename Name of the file to be checked.
464 @param fix Whether to fix (True) or just check (False) the style of the file.
465 @param verbose Show the lines that are not compliant with the style.
466 @param clang_format_path Path to clang-format.
467 @return Tuple [Filename,
468 Whether the file is compliant with the style (before the check),
469 Verbose information].
470 """
471
472 verbose_infos: List[str] = []
473
474 # Check if the file is well formatted
475 process = subprocess.run(
476 [
477 clang_format_path,
478 filename,
479 "-style=file",
480 "--dry-run",
481 "--Werror",
482 # Optimization: In non-verbose mode, only one error is needed to check that the file is not compliant
483 f"--ferror-limit={0 if verbose else 1}",
484 ],
485 check=False,
486 capture_output=True,
487 text=True,
488 )
489
490 is_file_compliant = process.returncode == 0
491
492 if verbose:
493 verbose_infos = process.stderr.splitlines()
494
495 # Fix file
496 if fix and not is_file_compliant:
497 process = subprocess.run(
498 [
499 clang_format_path,
500 filename,
501 "-style=file",
502 "-i",
503 ],
504 check=False,
505 stdout=subprocess.DEVNULL,
506 stderr=subprocess.DEVNULL,
507 )
508
509 return (filename, is_file_compliant, verbose_infos)
510
511
513 filename: str,
514 fix: bool,
515 verbose: bool,
516 respect_clang_format_guards: bool,
517 check_style_line_function: Callable[[str, str, int], Tuple[bool, str, List[str]]],
518) -> Tuple[str, bool, List[str]]:
519 """
520 Check / fix a file manually using a function to check / fix each line.
521
522 @param filename Name of the file to be checked.
523 @param fix Whether to fix (True) or just check (False) the style of the file.
524 @param verbose Show the lines that are not compliant with the style.
525 @param respect_clang_format_guards Whether to respect clang-format guards.
526 @param check_style_line_function Function used to check each line.
527 @return Tuple [Filename,
528 Whether the file is compliant with the style (before the check),
529 Verbose information].
530 """
531
532 is_file_compliant = True
533 verbose_infos: List[str] = []
534 clang_format_enabled = True
535
536 with open(filename, "r", encoding="utf-8") as f:
537 file_lines = f.readlines()
538
539 for i, line in enumerate(file_lines):
540 # Check clang-format guards
541 if respect_clang_format_guards:
542 line_stripped = line.strip()
543
544 if line_stripped in FORMAT_GUARD_ON:
545 clang_format_enabled = True
546 elif line_stripped in FORMAT_GUARD_OFF:
547 clang_format_enabled = False
548
549 if not clang_format_enabled and line_stripped not in (
550 FORMAT_GUARD_ON + FORMAT_GUARD_OFF
551 ):
552 continue
553
554 # Check if the line is compliant with the style and fix it
555 (is_line_compliant, line_fixed, line_verbose_infos) = check_style_line_function(
556 line, filename, i
557 )
558
559 if not is_line_compliant:
560 is_file_compliant = False
561 file_lines[i] = line_fixed
562 verbose_infos.extend(line_verbose_infos)
563
564 # Optimization: If running in non-verbose check mode, only one error is needed to check that the file is not compliant
565 if not fix and not verbose:
566 break
567
568 # Update file with the fixed lines
569 if fix and not is_file_compliant:
570 with open(filename, "w", encoding="utf-8") as f:
571 f.writelines(file_lines)
572
573 return (filename, is_file_compliant, verbose_infos)
574
575
577 line: str,
578 filename: str,
579 line_number: int,
580) -> Tuple[bool, str, List[str]]:
581 """
582 Check / fix #include headers from the same module with the "ns3/" prefix in a line.
583
584 @param line The line to check.
585 @param filename Name of the file to be checked.
586 @param line_number The number of the line checked.
587 @return Tuple [Whether the line is compliant with the style (before the check),
588 Fixed line,
589 Verbose information].
590 """
591
592 is_line_compliant = True
593 line_fixed = line
594 verbose_infos: List[str] = []
595
596 # Check if the line is an #include and extract its header file
597 line_stripped = line.strip()
598 header_file = re.findall(r'^#include ["<]ns3/(.*\.h)[">]', line_stripped)
599
600 if header_file:
601 # Check if the header file belongs to the same module and remove the "ns3/" prefix
602 header_file = header_file[0]
603 parent_path = os.path.split(filename)[0]
604
605 if os.path.exists(os.path.join(parent_path, header_file)):
606 is_line_compliant = False
607 line_fixed = (
608 line_stripped.replace(f"ns3/{header_file}", header_file)
609 .replace("<", '"')
610 .replace(">", '"')
611 + "\n"
612 )
613
614 header_index = len('#include "')
615
616 verbose_infos.extend(
617 [
618 f'{filename}:{line_number + 1}:{header_index + 1}: error: #include headers from the same module with the "ns3/" prefix detected',
619 f" {line_stripped}",
620 f' {"":{header_index}}^',
621 ]
622 )
623
624 return (is_line_compliant, line_fixed, verbose_infos)
625
626
628 line: str,
629 filename: str,
630 line_number: int,
631) -> Tuple[bool, str, List[str]]:
632 """
633 Check / fix whitespace in a line.
634
635 @param line The line to check.
636 @param filename Name of the file to be checked.
637 @param line_number The number of the line checked.
638 @return Tuple [Whether the line is compliant with the style (before the check),
639 Fixed line,
640 Verbose information].
641 """
642
643 is_line_compliant = True
644 line_fixed = line.rstrip() + "\n"
645 verbose_infos: List[str] = []
646
647 if line_fixed != line:
648 is_line_compliant = False
649 line_fixed_stripped_expanded = line_fixed.rstrip().expandtabs(TAB_SIZE)
650
651 verbose_infos = [
652 f"{filename}:{line_number + 1}:{len(line_fixed_stripped_expanded) + 1}: error: Trailing whitespace detected",
653 f" {line_fixed_stripped_expanded}",
654 f' {"":{len(line_fixed_stripped_expanded)}}^',
655 ]
656
657 return (is_line_compliant, line_fixed, verbose_infos)
658
659
661 line: str,
662 filename: str,
663 line_number: int,
664) -> Tuple[bool, str, List[str]]:
665 """
666 Check / fix tabs in a line.
667
668 @param line The line to check.
669 @param filename Name of the file to be checked.
670 @param line_number The number of the line checked.
671 @return Tuple [Whether the line is compliant with the style (before the check),
672 Fixed line,
673 Verbose information].
674 """
675
676 is_line_compliant = True
677 line_fixed = line
678 verbose_infos: List[str] = []
679
680 tab_index = line.find("\t")
681
682 if tab_index != -1:
683 is_line_compliant = False
684 line_fixed = line.expandtabs(TAB_SIZE)
685
686 verbose_infos = [
687 f"{filename}:{line_number + 1}:{tab_index + 1}: error: Tab detected",
688 f" {line.rstrip()}",
689 f' {"":{tab_index}}^',
690 ]
691
692 return (is_line_compliant, line_fixed, verbose_infos)
693
694
696 line: str,
697 filename: str,
698 line_number: int,
699) -> Tuple[bool, str, List[str]]:
700 """
701 Check / fix SPDX licenses rather than GPL text in a line.
702
703 @param line The line to check.
704 @param filename Name of the file to be checked.
705 @param line_number The number of the line checked.
706 @return Tuple [Whether the line is compliant with the style (before the check),
707 Fixed line,
708 Verbose information].
709 """
710
711 # fmt: off
712 GPL_LICENSE_LINES = [
713 "This program is free software; you can redistribute it and/or modify",
714 "it under the terms of the GNU General Public License version 2 as",
715 "published by the Free Software Foundation;",
716 "This program is distributed in the hope that it will be useful,",
717 "but WITHOUT ANY WARRANTY; without even the implied warranty of",
718 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
719 "GNU General Public License for more details.",
720 "You should have received a copy of the GNU General Public License",
721 "along with this program; if not, write to the Free Software",
722 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA",
723 ]
724 # fmt: on
725
726 SPDX_LICENSE = "SPDX-License-Identifier: GPL-2.0-only"
727
728 is_line_compliant = True
729 line_fixed = line
730 verbose_infos: List[str] = []
731
732 # Check if the line is a GPL license text
733 line_stripped = line.strip()
734 line_stripped_no_leading_comments = line_stripped.strip("*#/").strip()
735
736 if line_stripped_no_leading_comments in GPL_LICENSE_LINES:
737 is_line_compliant = False
738 col_index = 0
739
740 # Replace GPL text with SPDX license.
741 # Replace the first line of the GPL text with SPDX.
742 # Delete the remaining GPL text lines.
743 if line_stripped_no_leading_comments == GPL_LICENSE_LINES[0]:
744 line_fixed = line.replace(line_stripped_no_leading_comments, SPDX_LICENSE)
745 else:
746 line_fixed = ""
747
748 verbose_infos.extend(
749 [
750 f"{filename}:{line_number + 1}:{col_index}: error: GPL license text detected instead of SPDX license",
751 f" {line_stripped}",
752 f' {"":{col_index}}^',
753 ]
754 )
755
756 return (is_line_compliant, line_fixed, verbose_infos)
757
758
759###########################################################
760# MAIN
761###########################################################
762if __name__ == "__main__":
763 parser = argparse.ArgumentParser(
764 description="Check and apply the ns-3 coding style recursively to all files in the given PATHs. "
765 "The script checks the formatting of the files using clang-format and"
766 " other coding style rules manually (see script arguments). "
767 "All checks respect clang-format guards, except trailing whitespace, which is always checked. "
768 'When used in "check mode" (default), the script runs all checks in all files. '
769 "If it detects non-formatted files, they will be printed and this process exits with a non-zero code. "
770 'When used in "fix mode", this script automatically fixes the files and exits with 0 code.'
771 )
772
773 parser.add_argument(
774 "paths",
775 action="store",
776 type=str,
777 nargs="+",
778 help="List of paths to the files to check",
779 )
780
781 parser.add_argument(
782 "--no-include-prefixes",
783 action="store_true",
784 help='Do not check / fix #include headers from the same module with the "ns3/" prefix (respects clang-format guards)',
785 )
786
787 parser.add_argument(
788 "--no-whitespace",
789 action="store_true",
790 help="Do not check / fix trailing whitespace",
791 )
792
793 parser.add_argument(
794 "--no-tabs",
795 action="store_true",
796 help="Do not check / fix tabs (respects clang-format guards)",
797 )
798
799 parser.add_argument(
800 "--no-licenses",
801 action="store_true",
802 help="Do not check / fix SPDX licenses rather than GPL text (respects clang-format guards)",
803 )
804
805 parser.add_argument(
806 "--no-formatting",
807 action="store_true",
808 help="Do not check / fix code formatting (respects clang-format guards)",
809 )
810
811 parser.add_argument(
812 "--fix",
813 action="store_true",
814 help="Fix coding style issues detected in the files",
815 )
816
817 parser.add_argument(
818 "-v",
819 "--verbose",
820 action="store_true",
821 help="Show the lines that are not well-formatted",
822 )
823
824 parser.add_argument(
825 "-j",
826 "--jobs",
827 type=int,
828 default=max(1, os.cpu_count() - 1),
829 help="Number of parallel jobs",
830 )
831
832 args = parser.parse_args()
833
834 try:
835 all_checks_successful = check_style_clang_format(
836 paths=args.paths,
837 checks_enabled={
838 "include_prefixes": not args.no_include_prefixes,
839 "whitespace": not args.no_whitespace,
840 "tabs": not args.no_tabs,
841 "license": not args.no_licenses,
842 "formatting": not args.no_formatting,
843 },
844 fix=args.fix,
845 verbose=args.verbose,
846 n_jobs=args.jobs,
847 )
848
849 except Exception as e:
850 print("ERROR:", e)
851 sys.exit(1)
852
853 if not all_checks_successful:
854 if args.verbose:
855 print(
856 "",
857 "Notes to fix the above formatting issues:",
858 ' - To fix the formatting of specific files, run this script with the flag "--fix":',
859 " $ ./utils/check-style-clang-format.py --fix path [path ...]",
860 " - To fix the formatting of all files modified by this branch, run this script in the following way:",
861 " $ git diff --name-only master | xargs ./utils/check-style-clang-format.py --fix",
862 sep="\n",
863 )
864
865 sys.exit(1)
Tuple[bool, str, List[str]] check_whitespace_line(str line, str filename, int line_number)
Tuple[str, bool, List[str]] check_formatting_file(str filename, bool fix, bool verbose, str clang_format_path)
CHECK STYLE FUNCTIONS.
Dict[str, List[str]] find_files_to_check_style(List[str] paths)
bool check_style_clang_format(List[str] paths, Dict[str, bool] checks_enabled, bool fix, bool verbose, int n_jobs=1)
CHECK STYLE MAIN FUNCTIONS.
Tuple[str, bool, List[str]] check_manually_file(str filename, bool fix, bool verbose, bool respect_clang_format_guards, Callable[[str, str, int], Tuple[bool, str, List[str]]] check_style_line_function)
bool check_style_files(str style_check_str, Callable[..., Tuple[str, bool, List[str]]] check_style_file_function, List[str] filenames, bool fix, bool verbose, int n_jobs, **kwargs)
Tuple[bool, str, List[str]] check_include_prefixes_line(str line, str filename, int line_number)
bool should_analyze_file(str path, List[str] files_to_check, List[str] file_extensions_to_check)
Tuple[bool, str, List[str]] check_tabs_line(str line, str filename, int line_number)
bool should_analyze_directory(str dirpath)
AUXILIARY FUNCTIONS.
Tuple[bool, str, List[str]] check_licenses_line(str line, str filename, int line_number)