Uphold AvailTC Invariant for associated data fams
[ghc.git] / .arc-linters / check-cpp.py
1 #!/usr/bin/env python3
2
3 # A linter to warn for ASSERT macros which are separated from their argument
4 # list by a space, which Clang's CPP barfs on
5
6 import sys
7 import logging
8 import os
9 import re
10 import json
11
12 def setup_logging(logger):
13 """
14 ``arc lint`` makes it quite tricky to catch debug output from linters.
15 Log to a file to work around this.
16 """
17 hdlr = logging.FileHandler('linter.log', 'w')
18 logger.addHandler(hdlr)
19 logger.setLevel(logging.DEBUG)
20 return logger
21
22 logger = logging.getLogger()
23 #setup_logging(logger)
24 logger.debug(sys.argv)
25
26 def add_warning(severity, message, line):
27 entry = {
28 'severity': severity,
29 'message': message,
30 'line': line
31 }
32 warnings.append(entry)
33
34 class Linter(object):
35 def __init__(self):
36 self.warnings = []
37
38 def add_warning(self, **entry):
39 self.warnings.append(entry)
40
41 def lint(self, path):
42 pass
43
44 class LineLinter(Linter):
45 def lint(self, path):
46 if os.path.isfile(path):
47 with open(path, 'rb') as f:
48 for lineno, line in enumerate(f):
49 self.lint_line(lineno+1, line)
50
51 def lint_line(self, lineno, line):
52 pass
53
54 class RegexpLinter(LineLinter):
55 def __init__(self, regex, **warning):
56 LineLinter.__init__(self)
57 self.re = re.compile(regex)
58 self.warning = warning
59
60 def lint_line(self, lineno, line):
61 if self.re.search(line):
62 warning = {
63 'line': lineno,
64 }
65 warning.update(self.warning)
66 self.add_warning(**warning)
67
68 linters = [
69 RegexpLinter(br'ASSERT\s+\(',
70 message='CPP macros should not have a space between the macro name and their argument list'),
71 RegexpLinter(br'#ifdef\s+',
72 message='`#if defined(x)` is preferred to `#ifdef x`',
73 severity='warning'),
74 RegexpLinter(br'#if\s+defined\s+',
75 message='`#if defined(x)` is preferred to `#if defined x`',
76 severity='warning'),
77 RegexpLinter(br'#ifndef\s+',
78 message='`#if !defined(x)` is preferred to `#ifndef x`',
79 severity='warning'),
80 ]
81
82 if __name__ == '__main__':
83 path = sys.argv[1]
84 for linter in linters:
85 linter.lint(path)
86
87 warnings = [warning
88 for linter in linters
89 for warning in linter.warnings]
90 logger.debug(warnings)
91 print(json.dumps(warnings))