This patch adds a harness for invoking splint: http://splint.org/ returning the results in JSON format.
It runs "splint -csv TEMPFILE +csvoverwrite -strict", then uses firehose.parsers.splint.parse_splint_csv and firehose.parsers.splint.parse_splint_stderr to parse the csv and the stderr, turning them into firehose JSON (stderr is used to get at version information). checkers/ChangeLog: * splint.py: New file. --- checkers/splint.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100755 checkers/splint.py diff --git a/checkers/splint.py b/checkers/splint.py new file mode 100755 index 0000000..e8f79f2 --- /dev/null +++ b/checkers/splint.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# Copyright 2017 David Malcolm <dmalc...@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 sys +import tempfile + +from firehose.model import File, Issue +from firehose.parsers.splint import parse_splint_csv, parse_splint_stderr + +from checker import Checker, CheckerTests, tool_main + +class InvokeSplint(Checker): + """ + Checker subclass that invokes "splint -strict" + """ + name = 'splint' + + def __init__(self, ctxt): + Checker.__init__(self, ctxt) + self.tempfile = None + + def __del__(self): + del self.tempfile + + def raw_invoke(self, gccinv, sourcefile): + self.tempfile = tempfile.NamedTemporaryFile() + args = ['splint', '-csv', self.tempfile.name, '+csvoverwrite', '-strict', sourcefile] + # FIXME: why is overwrite needed? + return self._run_subprocess(sourcefile, args) + + def handle_output(self, result): + analysis = parse_splint_csv(self.tempfile.name) + analysis.metadata.file_ = File(result.sourcefile, None) + analysis.metadata.version = parse_splint_stderr(result.err) + self.set_custom_fields(result, analysis) + return analysis + + def set_custom_fields(self, result, analysis): + analysis.set_custom_field('splint-invocation', + ' '.join(result.argv)) + result.set_custom_fields(analysis) + +class SplintTests(CheckerTests): + def make_tool(self): + return self.make_tool_from_class(InvokeSplint) + + def verify_basic_metadata(self, analysis, sourcefile): + # Verify basic metadata: + self.assert_metadata(analysis, 'splint', sourcefile) + self.assert_has_custom_field(analysis, 'splint-invocation') + self.assert_has_custom_field(analysis, 'stdout') + self.assert_has_custom_field(analysis, 'stderr') + + def test_unconditional_leak(self): + analysis = self.invoke('test-sources/unconditional-file-leak.c') + self.assertEqual(len(analysis.results), 8) + r0 = analysis.results[0] + self.assertIsInstance(r0, Issue) + self.assertEqual(r0.testid, 'internalglobs') + +if __name__ == '__main__': + sys.exit(tool_main(sys.argv, InvokeSplint)) -- 1.8.5.3