Index: bindings/python/clang/cindex.py =================================================================== --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -217,19 +217,48 @@ A SourceLocation represents a particular location within a source file. """ _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)] - _data = None - - def _get_instantiation(self): - if self._data is None: - f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint() - conf.lib.clang_getInstantiationLocation(self, byref(f), byref(l), - byref(c), byref(o)) - if f: - f = File(f) - else: - f = None - self._data = (f, int(l.value), int(c.value), int(o.value)) - return self._data + _expansion_data = None + _spelling_data = None + + def _get_expansion(self): + if self._expansion_data is None: + expansion_file = c_object_p() + expansion_line = c_uint() + expansion_column = c_uint() + expansion_offset = c_uint() + conf.lib.clang_getExpansionLocation(self, + byref(expansion_file), + byref(expansion_line), + byref(expansion_column), + byref(expansion_offset)) + + self._expansion_data = { + 'file': File(expansion_file) if expansion_file else None, + 'line': int(expansion_line.value), + 'column': int(expansion_column.value), + 'offset': int(expansion_offset.value), + } + return self._expansion_data + + def _get_spelling(self): + if self._spelling_data is None: + spelling_file = c_object_p() + spelling_line = c_uint() + spelling_column = c_uint() + spelling_offset = c_uint() + conf.lib.clang_getSpellingLocation(self, + byref(spelling_file), + byref(spelling_line), + byref(spelling_column), + byref(spelling_offset)) + + self._spelling_data = { + 'file': File(spelling_file) if spelling_file else None, + 'line': int(spelling_line.value), + 'column': int(spelling_column.value), + 'offset': int(spelling_offset.value), + } + return self._spelling_data @staticmethod def from_position(tu, file, line, column): @@ -252,22 +281,42 @@ @property def file(self): """Get the file represented by this source location.""" - return self._get_instantiation()[0] + return self._get_expansion()['file'] @property def line(self): """Get the line represented by this source location.""" - return self._get_instantiation()[1] + return self._get_expansion()['line'] @property def column(self): """Get the column represented by this source location.""" - return self._get_instantiation()[2] + return self._get_expansion()['column'] @property def offset(self): """Get the file offset represented by this source location.""" - return self._get_instantiation()[3] + return self._get_expansion()['offset'] + + @property + def spelling_file(self): + """Get the file represented by the spelling of this source location.""" + return self._get_spelling()['file'] + + @property + def spelling_line(self): + """Get the line represented by the spelling of this source location.""" + return self._get_spelling()['line'] + + @property + def spelling_column(self): + """Get the column represented by the spelling of this source location.""" + return self._get_spelling()['column'] + + @property + def spelling_offset(self): + """Get the file offset represented by the spelling of this source location.""" + return self._get_spelling()['offset'] def __eq__(self, other): return conf.lib.clang_equalLocations(self, other) @@ -3629,7 +3678,11 @@ ("clang_getInclusions", [TranslationUnit, callbacks['translation_unit_includes'], py_object]), - ("clang_getInstantiationLocation", + ("clang_getExpansionLocation", + [SourceLocation, POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint), + POINTER(c_uint)]), + + ("clang_getSpellingLocation", [SourceLocation, POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint)]), Index: bindings/python/tests/cindex/test_location.py =================================================================== --- bindings/python/tests/cindex/test_location.py +++ bindings/python/tests/cindex/test_location.py @@ -93,3 +93,10 @@ location3 = SourceLocation.from_position(tu, file, 1, 6) range3 = SourceRange.from_locations(location1, location3) assert range1 != range3 + +def test_spelling_location(): + tu = get_tu('''#define ONE int one +ONE;''') + one = get_cursor(tu, 'one') + assert one.location.spelling_line == 1 + assert one.location.line == 2 Index: tools/libclang/CXSourceLocation.cpp =================================================================== --- tools/libclang/CXSourceLocation.cpp +++ tools/libclang/CXSourceLocation.cpp @@ -319,7 +319,7 @@ const SourceManager &SM = *static_cast(location.ptr_data[0]); // FIXME: This should call SourceManager::getSpellingLoc(). - SourceLocation SpellLoc = SM.getFileLoc(Loc); + SourceLocation SpellLoc = SM.getSpellingLoc(Loc); std::pair LocInfo = SM.getDecomposedLoc(SpellLoc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second;