4 This produces a structured normalized report json file based on warnings generated by another tool.
5 Currently implemented is clang-tidy warnings.
10 from collections
import namedtuple
11 from itertools
import groupby
14 from fnmatch
import fnmatch
17 from dataclasses
import dataclass
18 from pathlib
import Path
20 from item
import Item, ItemCollection
27 r"(?P<file>[/.\-+\w]+):(?P<line>\d+):(?P<col>\d+): (?P<sev>.*?):(?P<msg>[\s\S]*)\[(?P<code>.*)\]\n(?P<info>[\s\S]*)",
31 lines = itemstr.split(
"\n")
34 path=Path(m.group(
"file")),
35 line=int(m.group(
"line")),
36 col=int(m.group(
"col")),
38 message=m.group(
"msg").strip() +
"\n" +
"\n".
join(lines[1:]),
40 severity=m.group(
"sev"),
47 print(
"Failed parsing clang-tidy item:")
58 itemstr = re.sub(
r"Enabled checks:\n[\S\s]+?\n\n",
"", itemstr)
59 itemstr = re.sub(
r"clang-tidy-\d\.\d.*\n?",
"", itemstr)
60 itemstr = re.sub(
r"clang-apply-.*",
"", itemstr)
61 itemstr = re.sub(
r".*-header-filter.*",
"", itemstr)
67 re.finditer(
r"([\w/.\-+]+):(\d+):(\d+): (?:(?:warning)|(?:error)):", itemstr)
73 item = itemstr[prevstart:start]
75 if idx + 1 == len(matches):
76 item = itemstr[start:]
80 items =
set(map(parse_clang_tidy_item, sorted(items)))
86 p = argparse.ArgumentParser(description=__doc__)
87 p.add_argument(
"inputfile", help=
"The input file containing the warnings")
89 "output", default=
"codereport_clang_tidy.json", help=
"The resulting JSON file"
96 help=
"Exclude files that match any of these patterns",
102 help=
"Only include files that match any of these patterns",
108 help=
"Ignore items with codes matching any of these patterns",
110 p.add_argument(
"--cwd", type=Path)
111 p.add_argument(
"--strip-common", action=
"store_true")
113 args = p.parse_args()
115 with
open(args.inputfile,
"r", encoding="utf-8") as f:
121 if len(args.filter) > 0:
122 accept = accept
and all(fnmatch(item.path, e)
for e
in args.filter)
124 accept = accept
and not any(fnmatch(item.path, e)
for e
in args.exclude)
126 accept = accept
and not any(fnmatch(item.code, i)
for i
in args.ignore)
130 items = list(
filter(select, items))
134 item.path = (args.cwd / item.path).resolve()
136 if args.strip_common:
137 prefix = Path(os.path.commonprefix([i.path
for i
in items]))
140 path, line, col = m.groups()
141 path = Path(path).resolve().relative_to(prefix)
142 return f
"{path}:{line}:{col}:"
145 item.path = item.path.relative_to(prefix)
147 item.message = re.sub(
r"([\w/.\-+]+):(\d+):(\d+):", subpath, item.message)
149 print(
"Write to", args.output)
150 with
open(args.output,
"w+")
as jf:
154 if "__main__" == __name__: