From dd32ad81e1b3ffb44c42eeaa445703ad70630d35 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 2 Aug 2017 15:03:22 -0400
Subject: [PATCH 19/22] Add checkers/ianal.py

This patch is a demo of handling code metrics and metadata ("info" results
in Firehose terminology).

It adds a standalone tool harness which scans the main input file
looking for "Copyright" lines, returning information on them as
firehose JSON.

When sent through GCC's diagnostic subsystem by checker.cc, these
"info" results are emitted as notes, e.g.:

../../src/checkers/test-sources/cpychecker-demo.c:2:4: note: I am not a lawyer [not-a-lawyer:copyright-line]
    Copyright 2011 David Malcolm <dmalcolm@redhat.com>
    ^~~~~~~~~
../../src/checkers/test-sources/cpychecker-demo.c:3:4: note: I am not a lawyer [not-a-lawyer:copyright-line]
    Copyright 2011 Red Hat, Inc.
    ^~~~~~~~~

and they're captured in the generated binary by the watermarking code.

checkers/ChangeLog:
	* ianal.py: New file.
---
 checkers/ianal.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100755 checkers/ianal.py

diff --git a/checkers/ianal.py b/checkers/ianal.py
new file mode 100755
index 0000000..a918f41
--- /dev/null
+++ b/checkers/ianal.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+#   Copyright 2017 David Malcolm <dmalcolm@redhat.com>
+#   Copyright 2017 Red Hat, Inc.
+#
+#   This is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see
+#   <http://www.gnu.org/licenses/>.
+
+import re
+import sys
+
+from firehose.model import Analysis, Generator, Metadata, Info, \
+    Location, Message, Range, Point
+
+from checker import Checker, CheckerTests, make_file, tool_main
+
+class NotALawyer(Checker):
+    """
+    Checker subclass that looks for "Copyright" lines, as a demo
+    of handling "info" results.
+    """
+    name = 'not-a-lawyer'
+
+    def raw_invoke(self, gccinv, sourcefile):
+        results = []
+        file_ = make_file(sourcefile)
+        with open(sourcefile) as f:
+            for lineidx, line in enumerate(f):
+                m = re.match('.*(Copyright).*', line)
+                if m:
+                    start, end = m.span(1)
+                    linenum = lineidx + 1
+                    range_ = Range(start=Point(linenum, start + 1),
+                                   end=Point(linenum, end))
+                    location = Location(file_, None, range_=range_)
+                    info = Info(infoid='copyright-line',
+                                location=location,
+                                message=Message('I am not a lawyer'),
+                                customfields=None)
+                    results.append(info)
+        metadata = Metadata(generator=Generator(self.name), sut=None,
+                            file_=file_, stats=None)
+        analysis = Analysis(metadata, results)
+        return analysis
+
+class NotALawyerTests(CheckerTests):
+    def make_tool(self):
+        return self.make_tool_from_class(NotALawyer)
+
+    def verify_basic_metadata(self, analysis, sourcefile):
+        # Verify basic metadata:
+        self.assert_metadata(analysis, 'not-a-lawyer', sourcefile)
+
+    def test_basic(self):
+        analysis = self.invoke('test-sources/cpychecker-demo.c')
+        self.assertEqual(len(analysis.results), 2)
+        r0 = analysis.results[0]
+        self.assertIsInstance(r0, Info)
+        self.assertEqual(r0.infoid, 'copyright-line')
+        self.assertEqual(r0.location.file.givenpath,
+                         'test-sources/cpychecker-demo.c')
+        self.assertEqual(r0.message.text, 'I am not a lawyer')
+        self.assertEqual(r0.location.range_.start.line, 2)
+        self.assertEqual(r0.location.range_.start.column, 4)
+        self.assertEqual(r0.location.range_.end.line, 2)
+        self.assertEqual(r0.location.range_.end.column, 12)
+
+if __name__ == '__main__':
+    sys.exit(tool_main(sys.argv, NotALawyer))
-- 
1.8.5.3

