Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:10:43

0001 #!/usr/bin/env python3
0002 
0003 """
0004 This produces a structured normalized report json file based on warnings generated by another tool.
0005 Currently implemented is clang-tidy warnings.
0006 """
0007 
0008 import argparse
0009 import re
0010 import os
0011 from fnmatch import fnmatch
0012 from pathlib import Path
0013 
0014 from item import Item, ItemCollection
0015 
0016 
0017 def parse_clang_tidy_item(itemstr):
0018     try:
0019         m = re.match(
0020             r"(?P<file>[/.\-+\w]+):(?P<line>\d+):(?P<col>\d+): (?P<sev>.*?):(?P<msg>[\s\S]*)\[(?P<code>.*)\]\n(?P<info>[\s\S]*)",
0021             itemstr,
0022         )
0023 
0024         lines = itemstr.split("\n")
0025 
0026         item = Item(
0027             path=Path(m.group("file")),
0028             line=int(m.group("line")),
0029             col=int(m.group("col")),
0030             #  message=m.group("msg").strip(),
0031             message=m.group("msg").strip() + "\n" + "\n".join(lines[1:]),
0032             code=m.group("code"),
0033             severity=m.group("sev"),
0034         )
0035 
0036         #  print(repr(item))
0037 
0038         return item
0039     except:
0040         print("Failed parsing clang-tidy item:")
0041         print("-" * 20)
0042         print(itemstr)
0043         print("-" * 20)
0044         raise
0045 
0046 
0047 def parse_clang_tidy_output(output):
0048     # cleanup
0049     itemstr = output
0050     itemstr = re.sub(r"Enabled checks:\n[\S\s]+?\n\n", "", itemstr)
0051     itemstr = re.sub(r"clang-tidy-\d\.\d.*\n?", "", itemstr)
0052     itemstr = re.sub(r"clang-apply-.*", "", itemstr)
0053     itemstr = re.sub(r".*-header-filter.*", "", itemstr)
0054 
0055     items = []
0056     prevstart = 0
0057 
0058     matches = list(
0059         re.finditer(r"([\w/.\-+]+):(\d+):(\d+): (?:(?:warning)|(?:error)):", itemstr)
0060     )
0061     for idx, m in enumerate(matches):
0062         # print(m)
0063         start, end = m.span()
0064         if idx > 0:
0065             item = itemstr[prevstart:start]
0066             items.append(item)
0067         if idx + 1 == len(matches):
0068             item = itemstr[start:]
0069             items.append(item)
0070         prevstart = start
0071 
0072     items = set(map(parse_clang_tidy_item, sorted(items)))
0073 
0074     return items
0075 
0076 
0077 def main():
0078     p = argparse.ArgumentParser(description=__doc__)
0079     p.add_argument("inputfile", help="The input file containing the warnings")
0080     p.add_argument(
0081         "output", default="codereport_clang_tidy.json", help="The resulting JSON file"
0082     )
0083     p.add_argument(
0084         "--exclude",
0085         "-e",
0086         action="append",
0087         default=[],
0088         help="Exclude files that match any of these patterns",
0089     )
0090     p.add_argument(
0091         "--filter",
0092         action="append",
0093         default=[],
0094         help="Only include files that match any of these patterns",
0095     )
0096     p.add_argument(
0097         "--ignore",
0098         action="append",
0099         default=[],
0100         help="Ignore items with codes matching any of these patterns",
0101     )
0102     p.add_argument("--cwd", type=Path)
0103     p.add_argument("--strip-common", action="store_true")
0104 
0105     args = p.parse_args()
0106 
0107     with open(args.inputfile, "r", encoding="utf-8") as f:
0108         inputstr = f.read()
0109     items = parse_clang_tidy_output(inputstr)
0110 
0111     def select(item):
0112         accept = True
0113         if len(args.filter) > 0:
0114             accept = accept and all(fnmatch(item.path, e) for e in args.filter)
0115 
0116         accept = accept and not any(fnmatch(item.path, e) for e in args.exclude)
0117 
0118         accept = accept and not any(fnmatch(item.code, i) for i in args.ignore)
0119 
0120         return accept
0121 
0122     items = list(filter(select, items))
0123 
0124     if args.cwd:
0125         for item in items:
0126             item.path = (args.cwd / item.path).resolve()
0127 
0128     if args.strip_common:
0129         prefix = Path(os.path.commonprefix([i.path for i in items]))
0130 
0131         def subpath(m):
0132             path, line, col = m.groups()
0133             path = Path(path).resolve().relative_to(prefix)
0134             return f"{path}:{line}:{col}:"
0135 
0136         for item in items:
0137             item.path = item.path.relative_to(prefix)
0138 
0139             item.message = re.sub(r"([\w/.\-+]+):(\d+):(\d+):", subpath, item.message)
0140 
0141     print("Write to", args.output)
0142     with open(args.output, "w+") as jf:
0143         jf.write(ItemCollection(root=items).model_dump_json(indent=2))
0144 
0145 
0146 if "__main__" == __name__:
0147     main()