arc-linters: Add linting of #ifdef x and #if defined x
authorBen Gamari <bgamari.foss@gmail.com>
Wed, 12 Apr 2017 18:10:01 +0000 (14:10 -0400)
committerBen Gamari <ben@smart-cactus.org>
Wed, 12 Apr 2017 18:53:06 +0000 (14:53 -0400)
Reviewers: austin, erikd

Reviewed By: erikd

Subscribers: rwbarton, thomie, erikd

Differential Revision: https://phabricator.haskell.org/D3423

.arc-linters/check-cpp.py

index d81e58b..7115488 100755 (executable)
@@ -23,19 +23,64 @@ logger = logging.getLogger()
 #setup_logging(logger)
 logger.debug(sys.argv)
 
-path = sys.argv[1]
-warnings = []
-r = re.compile(br'ASSERT\s+\(')
-if os.path.isfile(path):
-    with open(path, 'rb') as f:
-        for lineno, line in enumerate(f):
-            if r.search(line):
-                warning = {
-                    'severity': 'warning',
-                    'message': 'CPP macros should not have a space between the macro name and their argument list',
-                    'line': lineno+1,
-                }
-                warnings.append(warning)
-
-logger.debug(warnings)
-print(json.dumps(warnings))
+def add_warning(severity, message, line):
+    entry = {
+        'severity': severity,
+        'message': message,
+        'line': line
+    }
+    warnings.append(entry)
+
+class Linter(object):
+    def __init__(self):
+        self.warnings = []
+
+    def add_warning(self, **entry):
+        self.warnings.append(entry)
+
+    def lint(self, path):
+        pass
+
+class LineLinter(Linter):
+    def lint(self, path):
+        if os.path.isfile(path):
+            with open(path, 'rb') as f:
+                for lineno, line in enumerate(f):
+                    self.lint_line(lineno+1, line)
+
+    def lint_line(self, lineno, line):
+        pass
+
+class RegexpLinter(LineLinter):
+    def __init__(self, regex, **warning):
+        LineLinter.__init__(self)
+        self.re = re.compile(regex)
+        self.warning = warning
+
+    def lint_line(self, lineno, line):
+        if self.re.search(line):
+            warning = {
+                'line': lineno,
+            }
+            warning.update(self.warning)
+            self.add_warning(**warning)
+
+linters = [
+    RegexpLinter(br'ASSERT\s+\(',
+                 message='CPP macros should not have a space between the macro name and their argument list'),
+    RegexpLinter(br'#ifdef\s+',
+                 message='`#if defined(x)` is preferred to `#ifdef x`'),
+    RegexpLinter(br'#if\s+defined\s+',
+                 message='`#if defined(x)` is preferred to `#if defined x`'),
+]
+
+if __name__ == '__main__':
+    path = sys.argv[1]
+    for linter in linters:
+        linter.lint(path)
+
+    warnings = [warning
+                for linter in linters
+                for warning in linter.warnings]
+    logger.debug(warnings)
+    print(json.dumps(warnings))