1import os 2 3from clang.cindex import ( 4 Config, 5 Cursor, 6 File, 7 SourceLocation, 8 SourceRange, 9 TranslationUnit, 10) 11 12if "CLANG_LIBRARY_PATH" in os.environ: 13 Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"]) 14 15import unittest 16 17from .util import get_cursor, get_tu 18 19baseInput = "int one;\nint two;\n" 20 21 22class TestLocation(unittest.TestCase): 23 def assert_location(self, loc, line, column, offset): 24 self.assertEqual(loc.line, line) 25 self.assertEqual(loc.column, column) 26 self.assertEqual(loc.offset, offset) 27 28 def test_location(self): 29 tu = get_tu(baseInput) 30 one = get_cursor(tu, "one") 31 two = get_cursor(tu, "two") 32 33 self.assertIsNotNone(one) 34 self.assertIsNotNone(two) 35 36 self.assert_location(one.location, line=1, column=5, offset=4) 37 self.assert_location(two.location, line=2, column=5, offset=13) 38 39 # adding a linebreak at top should keep columns same 40 tu = get_tu("\n" + baseInput) 41 one = get_cursor(tu, "one") 42 two = get_cursor(tu, "two") 43 44 self.assertIsNotNone(one) 45 self.assertIsNotNone(two) 46 47 self.assert_location(one.location, line=2, column=5, offset=5) 48 self.assert_location(two.location, line=3, column=5, offset=14) 49 50 # adding a space should affect column on first line only 51 tu = get_tu(" " + baseInput) 52 one = get_cursor(tu, "one") 53 two = get_cursor(tu, "two") 54 55 self.assert_location(one.location, line=1, column=6, offset=5) 56 self.assert_location(two.location, line=2, column=5, offset=14) 57 58 # define the expected location ourselves and see if it matches 59 # the returned location 60 tu = get_tu(baseInput) 61 62 file = File.from_name(tu, "t.c") 63 location = SourceLocation.from_position(tu, file, 1, 5) 64 cursor = Cursor.from_location(tu, location) 65 66 one = get_cursor(tu, "one") 67 self.assertIsNotNone(one) 68 self.assertEqual(one, cursor) 69 70 # Ensure locations referring to the same entity are equivalent. 71 location2 = SourceLocation.from_position(tu, file, 1, 5) 72 self.assertEqual(location, location2) 73 location3 = SourceLocation.from_position(tu, file, 1, 4) 74 self.assertNotEqual(location2, location3) 75 76 offset_location = SourceLocation.from_offset(tu, file, 5) 77 cursor = Cursor.from_location(tu, offset_location) 78 verified = False 79 for n in [n for n in tu.cursor.get_children() if n.spelling == "one"]: 80 self.assertEqual(n, cursor) 81 verified = True 82 83 self.assertTrue(verified) 84 85 def test_extent(self): 86 tu = get_tu(baseInput) 87 one = get_cursor(tu, "one") 88 two = get_cursor(tu, "two") 89 90 self.assert_location(one.extent.start, line=1, column=1, offset=0) 91 self.assert_location(one.extent.end, line=1, column=8, offset=7) 92 self.assertEqual( 93 baseInput[one.extent.start.offset : one.extent.end.offset], "int one" 94 ) 95 96 self.assert_location(two.extent.start, line=2, column=1, offset=9) 97 self.assert_location(two.extent.end, line=2, column=8, offset=16) 98 self.assertEqual( 99 baseInput[two.extent.start.offset : two.extent.end.offset], "int two" 100 ) 101 102 file = File.from_name(tu, "t.c") 103 location1 = SourceLocation.from_position(tu, file, 1, 1) 104 location2 = SourceLocation.from_position(tu, file, 1, 8) 105 106 range1 = SourceRange.from_locations(location1, location2) 107 range2 = SourceRange.from_locations(location1, location2) 108 self.assertEqual(range1, range2) 109 110 location3 = SourceLocation.from_position(tu, file, 1, 6) 111 range3 = SourceRange.from_locations(location1, location3) 112 self.assertNotEqual(range1, range3) 113 114 def test_is_system_location(self): 115 header = os.path.normpath("./fake/fake.h") 116 tu = TranslationUnit.from_source( 117 "fake.c", 118 [f"-isystem{os.path.dirname(header)}"], 119 unsaved_files=[ 120 ( 121 "fake.c", 122 """ 123#include <fake.h> 124int one; 125""", 126 ), 127 (header, "int two();"), 128 ], 129 ) 130 one = get_cursor(tu, "one") 131 two = get_cursor(tu, "two") 132 self.assertFalse(one.location.is_in_system_header) 133 self.assertTrue(two.location.is_in_system_header) 134 135 def test_operator_lt(self): 136 tu = get_tu("aaaaa") 137 t1_f = tu.get_file(tu.spelling) 138 tu2 = get_tu("aaaaa") 139 140 l_t1_12 = SourceLocation.from_position(tu, t1_f, 1, 2) 141 l_t1_13 = SourceLocation.from_position(tu, t1_f, 1, 3) 142 l_t1_14 = SourceLocation.from_position(tu, t1_f, 1, 4) 143 144 l_t2_13 = SourceLocation.from_position(tu2, tu2.get_file(tu2.spelling), 1, 3) 145 146 # In same file 147 assert l_t1_12 < l_t1_13 < l_t1_14 148 assert not l_t1_13 < l_t1_12 149 150 # In same file, different TU 151 assert l_t1_12 < l_t2_13 < l_t1_14 152 assert not l_t2_13 < l_t1_12 153 assert not l_t1_14 < l_t2_13 154