175 lines · python
1import os2from pathlib import Path3 4from clang.cindex import (5 Config,6 Cursor,7 File,8 SourceLocation,9 SourceRange,10 TranslationUnit,11)12 13if "CLANG_LIBRARY_PATH" in os.environ:14 Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])15 16import unittest17 18from .util import get_cursor, get_tu19 20INPUTS_DIR = Path(__file__).parent / "INPUTS"21 22BASE_INPUT = "int one;\nint two;\n"23 24 25class TestLocation(unittest.TestCase):26 def assert_location(self, loc, line, column, offset):27 self.assertEqual(loc.line, line)28 self.assertEqual(loc.column, column)29 self.assertEqual(loc.offset, offset)30 31 def test_location(self):32 tu = get_tu(BASE_INPUT)33 one = get_cursor(tu, "one")34 two = get_cursor(tu, "two")35 36 self.assertIsNotNone(one)37 self.assertIsNotNone(two)38 39 self.assert_location(one.location, line=1, column=5, offset=4)40 self.assert_location(two.location, line=2, column=5, offset=13)41 42 # adding a linebreak at top should keep columns same43 tu = get_tu("\n" + BASE_INPUT)44 one = get_cursor(tu, "one")45 two = get_cursor(tu, "two")46 47 self.assertIsNotNone(one)48 self.assertIsNotNone(two)49 50 self.assert_location(one.location, line=2, column=5, offset=5)51 self.assert_location(two.location, line=3, column=5, offset=14)52 53 # adding a space should affect column on first line only54 tu = get_tu(" " + BASE_INPUT)55 one = get_cursor(tu, "one")56 two = get_cursor(tu, "two")57 58 self.assert_location(one.location, line=1, column=6, offset=5)59 self.assert_location(two.location, line=2, column=5, offset=14)60 61 # define the expected location ourselves and see if it matches62 # the returned location63 tu = get_tu(BASE_INPUT)64 65 file = File.from_name(tu, "t.c")66 location = SourceLocation.from_position(tu, file, 1, 5)67 cursor = Cursor.from_location(tu, location)68 69 one = get_cursor(tu, "one")70 self.assertIsNotNone(one)71 self.assertEqual(one, cursor)72 73 # Ensure locations referring to the same entity are equivalent.74 location2 = SourceLocation.from_position(tu, file, 1, 5)75 self.assertEqual(location, location2)76 location3 = SourceLocation.from_position(tu, file, 1, 4)77 self.assertNotEqual(location2, location3)78 79 offset_location = SourceLocation.from_offset(tu, file, 5)80 cursor = Cursor.from_location(tu, offset_location)81 verified = False82 for n in [n for n in tu.cursor.get_children() if n.spelling == "one"]:83 self.assertEqual(n, cursor)84 verified = True85 86 self.assertTrue(verified)87 88 def test_extent(self):89 tu = get_tu(BASE_INPUT)90 one = get_cursor(tu, "one")91 two = get_cursor(tu, "two")92 93 self.assert_location(one.extent.start, line=1, column=1, offset=0)94 self.assert_location(one.extent.end, line=1, column=8, offset=7)95 self.assertEqual(96 BASE_INPUT[one.extent.start.offset : one.extent.end.offset], "int one"97 )98 99 self.assert_location(two.extent.start, line=2, column=1, offset=9)100 self.assert_location(two.extent.end, line=2, column=8, offset=16)101 self.assertEqual(102 BASE_INPUT[two.extent.start.offset : two.extent.end.offset], "int two"103 )104 105 file = File.from_name(tu, "t.c")106 location1 = SourceLocation.from_position(tu, file, 1, 1)107 location2 = SourceLocation.from_position(tu, file, 1, 8)108 109 range1 = SourceRange.from_locations(location1, location2)110 range2 = SourceRange.from_locations(location1, location2)111 self.assertEqual(range1, range2)112 113 location3 = SourceLocation.from_position(tu, file, 1, 6)114 range3 = SourceRange.from_locations(location1, location3)115 self.assertNotEqual(range1, range3)116 117 def test_is_system_location(self):118 header = os.path.normpath("./fake/fake.h")119 tu = TranslationUnit.from_source(120 "fake.c",121 [f"-isystem{os.path.dirname(header)}"],122 unsaved_files=[123 (124 "fake.c",125 """126#include <fake.h>127int one;128""",129 ),130 (header, "int two();"),131 ],132 )133 one = get_cursor(tu, "one")134 two = get_cursor(tu, "two")135 self.assertFalse(one.location.is_in_system_header)136 self.assertTrue(two.location.is_in_system_header)137 138 def test_operator_lt(self):139 tu = get_tu("aaaaa")140 t1_f = tu.get_file(tu.spelling)141 tu2 = get_tu("aaaaa")142 143 l_t1_12 = SourceLocation.from_position(tu, t1_f, 1, 2)144 l_t1_13 = SourceLocation.from_position(tu, t1_f, 1, 3)145 l_t1_14 = SourceLocation.from_position(tu, t1_f, 1, 4)146 147 l_t2_13 = SourceLocation.from_position(tu2, tu2.get_file(tu2.spelling), 1, 3)148 149 # In same file150 assert l_t1_12 < l_t1_13 < l_t1_14151 assert not l_t1_13 < l_t1_12152 153 # In same file, different TU154 assert l_t1_12 < l_t2_13 < l_t1_14155 assert not l_t2_13 < l_t1_12156 assert not l_t1_14 < l_t2_13157 158 def test_equality(self):159 path = INPUTS_DIR / "testfile.c"160 path_a = INPUTS_DIR / "a.inc"161 tu = TranslationUnit.from_source(path)162 main_file = File.from_name(tu, path)163 a_file = File.from_name(tu, path_a)164 165 location1 = SourceLocation.from_position(tu, main_file, 1, 3)166 location2 = SourceLocation.from_position(tu, main_file, 2, 2)167 location1_2 = SourceLocation.from_position(tu, main_file, 1, 3)168 file2_location1 = SourceLocation.from_position(tu, a_file, 1, 3)169 170 self.assertEqual(location1, location1)171 self.assertEqual(location1, location1_2)172 self.assertNotEqual(location1, location2)173 self.assertNotEqual(location1, file2_location1)174 self.assertNotEqual(location1, "foo")175