| 1 | import os |
| 2 | from clang.cindex import Config |
| 3 | if 'CLANG_LIBRARY_PATH' in os.environ: |
| 4 | Config.set_library_path(os.environ['CLANG_LIBRARY_PATH']) |
| 5 | |
| 6 | from clang.cindex import * |
| 7 | from .util import get_tu |
| 8 | |
| 9 | import unittest |
| 10 | |
| 11 | |
| 12 | # FIXME: We need support for invalid translation units to test better. |
| 13 | |
| 14 | |
| 15 | class TestDiagnostics(unittest.TestCase): |
| 16 | def test_diagnostic_warning(self): |
| 17 | tu = get_tu('int f0() {}\n') |
| 18 | self.assertEqual(len(tu.diagnostics), 1) |
| 19 | self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning) |
| 20 | self.assertEqual(tu.diagnostics[0].location.line, 1) |
| 21 | self.assertEqual(tu.diagnostics[0].location.column, 11) |
| 22 | self.assertEqual(tu.diagnostics[0].spelling, |
| 23 | 'control reaches end of non-void function') |
| 24 | |
| 25 | def test_diagnostic_note(self): |
| 26 | # FIXME: We aren't getting notes here for some reason. |
| 27 | tu = get_tu('#define A x\nvoid *A = 1;\n') |
| 28 | self.assertEqual(len(tu.diagnostics), 1) |
| 29 | self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning) |
| 30 | self.assertEqual(tu.diagnostics[0].location.line, 2) |
| 31 | self.assertEqual(tu.diagnostics[0].location.column, 7) |
| 32 | self.assertIn('incompatible', tu.diagnostics[0].spelling) |
| 33 | # self.assertEqual(tu.diagnostics[1].severity, Diagnostic.Note) |
| 34 | # self.assertEqual(tu.diagnostics[1].location.line, 1) |
| 35 | # self.assertEqual(tu.diagnostics[1].location.column, 11) |
| 36 | # self.assertEqual(tu.diagnostics[1].spelling, 'instantiated from') |
| 37 | |
| 38 | def test_diagnostic_fixit(self): |
| 39 | tu = get_tu('struct { int f0; } x = { f0 : 1 };') |
| 40 | self.assertEqual(len(tu.diagnostics), 1) |
| 41 | self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning) |
| 42 | self.assertEqual(tu.diagnostics[0].location.line, 1) |
| 43 | self.assertEqual(tu.diagnostics[0].location.column, 26) |
| 44 | self.assertRegexpMatches(tu.diagnostics[0].spelling, |
| 45 | 'use of GNU old-style.*') |
| 46 | self.assertEqual(len(tu.diagnostics[0].fixits), 1) |
| 47 | self.assertEqual(tu.diagnostics[0].fixits[0].range.start.line, 1) |
| 48 | self.assertEqual(tu.diagnostics[0].fixits[0].range.start.column, 26) |
| 49 | self.assertEqual(tu.diagnostics[0].fixits[0].range.end.line, 1) |
| 50 | self.assertEqual(tu.diagnostics[0].fixits[0].range.end.column, 30) |
| 51 | self.assertEqual(tu.diagnostics[0].fixits[0].value, '.f0 = ') |
| 52 | |
| 53 | def test_diagnostic_range(self): |
| 54 | tu = get_tu('void f() { int i = "a"; }') |
| 55 | self.assertEqual(len(tu.diagnostics), 1) |
| 56 | self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning) |
| 57 | self.assertEqual(tu.diagnostics[0].location.line, 1) |
| 58 | self.assertEqual(tu.diagnostics[0].location.column, 16) |
| 59 | self.assertRegexpMatches(tu.diagnostics[0].spelling, |
| 60 | 'incompatible pointer to.*') |
| 61 | self.assertEqual(len(tu.diagnostics[0].fixits), 0) |
| 62 | self.assertEqual(len(tu.diagnostics[0].ranges), 1) |
| 63 | self.assertEqual(tu.diagnostics[0].ranges[0].start.line, 1) |
| 64 | self.assertEqual(tu.diagnostics[0].ranges[0].start.column, 20) |
| 65 | self.assertEqual(tu.diagnostics[0].ranges[0].end.line, 1) |
| 66 | self.assertEqual(tu.diagnostics[0].ranges[0].end.column, 23) |
| 67 | with self.assertRaises(IndexError): |
| 68 | tu.diagnostics[0].ranges[1].start.line |
| 69 | |
| 70 | def test_diagnostic_category(self): |
| 71 | """Ensure that category properties work.""" |
| 72 | tu = get_tu('int f(int i) { return 7; }', all_warnings=True) |
| 73 | self.assertEqual(len(tu.diagnostics), 1) |
| 74 | d = tu.diagnostics[0] |
| 75 | |
| 76 | self.assertEqual(d.severity, Diagnostic.Warning) |
| 77 | self.assertEqual(d.location.line, 1) |
| 78 | self.assertEqual(d.location.column, 11) |
| 79 | |
| 80 | self.assertEqual(d.category_number, 2) |
| 81 | self.assertEqual(d.category_name, 'Semantic Issue') |
| 82 | |
| 83 | def test_diagnostic_option(self): |
| 84 | """Ensure that category option properties work.""" |
| 85 | tu = get_tu('int f(int i) { return 7; }', all_warnings=True) |
| 86 | self.assertEqual(len(tu.diagnostics), 1) |
| 87 | d = tu.diagnostics[0] |
| 88 | |
| 89 | self.assertEqual(d.option, '-Wunused-parameter') |
| 90 | self.assertEqual(d.disable_option, '-Wno-unused-parameter') |
| 91 | |
| 92 | def test_diagnostic_children(self): |
| 93 | tu = get_tu('void f(int x) {} void g() { f(); }') |
| 94 | self.assertEqual(len(tu.diagnostics), 1) |
| 95 | d = tu.diagnostics[0] |
| 96 | |
| 97 | children = d.children |
| 98 | self.assertEqual(len(children), 1) |
| 99 | self.assertEqual(children[0].severity, Diagnostic.Note) |
| 100 | self.assertRegexpMatches(children[0].spelling, |
| 101 | '.*declared here') |
| 102 | self.assertEqual(children[0].location.line, 1) |
| 103 | self.assertEqual(children[0].location.column, 1) |
| 104 | |
| 105 | def test_diagnostic_string_repr(self): |
| 106 | tu = get_tu('struct MissingSemicolon{}') |
| 107 | self.assertEqual(len(tu.diagnostics), 1) |
| 108 | d = tu.diagnostics[0] |
| 109 | |
| 110 | self.assertEqual(repr(d), '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">') |
| 111 | |