cindex.py revision 532fc63b51cd0eb795df36d3fe306645b8b980e4
1#===- cindex.py - Python Indexing Library Bindings -----------*- python -*--===# 2# 3# The LLVM Compiler Infrastructure 4# 5# This file is distributed under the University of Illinois Open Source 6# License. See LICENSE.TXT for details. 7# 8#===------------------------------------------------------------------------===# 9 10r""" 11Clang Indexing Library Bindings 12=============================== 13 14This module provides an interface to the Clang indexing library. It is a 15low-level interface to the indexing library which attempts to match the Clang 16API directly while also being "pythonic". Notable differences from the C API 17are: 18 19 * string results are returned as Python strings, not CXString objects. 20 21 * null cursors are translated to None. 22 23 * access to child cursors is done via iteration, not visitation. 24 25The major indexing objects are: 26 27 Index 28 29 The top-level object which manages some global library state. 30 31 TranslationUnit 32 33 High-level object encapsulating the AST for a single translation unit. These 34 can be loaded from .ast files or parsed on the fly. 35 36 Cursor 37 38 Generic object for representing a node in the AST. 39 40 SourceRange, SourceLocation, and File 41 42 Objects representing information about the input source. 43 44Most object information is exposed using properties, when the underlying API 45call is efficient. 46""" 47 48# TODO 49# ==== 50# 51# o API support for invalid translation units. Currently we can't even get the 52# diagnostics on failure because they refer to locations in an object that 53# will have been invalidated. 54# 55# o fix memory management issues (currently client must hold on to index and 56# translation unit, or risk crashes). 57# 58# o expose code completion APIs. 59# 60# o cleanup ctypes wrapping, would be nice to separate the ctypes details more 61# clearly, and hide from the external interface (i.e., help(cindex)). 62# 63# o implement additional SourceLocation, SourceRange, and File methods. 64 65from ctypes import * 66 67def get_cindex_library(): 68 # FIXME: It's probably not the case that the library is actually found in 69 # this location. We need a better system of identifying and loading the 70 # CIndex library. It could be on path or elsewhere, or versioned, etc. 71 import platform 72 name = platform.system() 73 if name == 'Darwin': 74 return cdll.LoadLibrary('libCIndex.dylib') 75 elif name == 'Windows': 76 return cdll.LoadLibrary('libCIndex.dll') 77 else: 78 return cdll.LoadLibrary('libCIndex.so') 79 80# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper 81# object. This is a problem, because it means that from_parameter will see an 82# integer and pass the wrong value on platforms where int != void*. Work around 83# this by marshalling object arguments as void**. 84c_object_p = POINTER(c_void_p) 85 86lib = get_cindex_library() 87 88### Structures and Utility Classes ### 89 90class _CXString(Structure): 91 """Helper for transforming CXString results.""" 92 93 _fields_ = [("spelling", c_char_p), ("free", c_int)] 94 95 def __del__(self): 96 _CXString_dispose(self) 97 98 @staticmethod 99 def from_result(res, fn, args): 100 assert isinstance(res, _CXString) 101 return _CXString_getCString(res) 102 103class SourceLocation(Structure): 104 """ 105 A SourceLocation represents a particular location within a source file. 106 """ 107 _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)] 108 _data = None 109 110 def _get_instantiation(self): 111 if self._data is None: 112 f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint() 113 SourceLocation_loc(self, byref(f), byref(l), byref(c), byref(o)) 114 f = File(f) if f else None 115 self._data = (f, int(l.value), int(c.value), int(c.value)) 116 return self._data 117 118 @property 119 def file(self): 120 """Get the file represented by this source location.""" 121 return self._get_instantiation()[0] 122 123 @property 124 def line(self): 125 """Get the line represented by this source location.""" 126 return self._get_instantiation()[1] 127 128 @property 129 def column(self): 130 """Get the column represented by this source location.""" 131 return self._get_instantiation()[2] 132 133 @property 134 def offset(self): 135 """Get the file offset represented by this source location.""" 136 return self._get_instantiation()[3] 137 138 def __repr__(self): 139 return "<SourceLocation file %r, line %r, column %r>" % ( 140 self.file.name if self.file else None, self.line, self.column) 141 142class SourceRange(Structure): 143 """ 144 A SourceRange describes a range of source locations within the source 145 code. 146 """ 147 _fields_ = [ 148 ("ptr_data", c_void_p * 2), 149 ("begin_int_data", c_uint), 150 ("end_int_data", c_uint)] 151 152 # FIXME: Eliminate this and make normal constructor? Requires hiding ctypes 153 # object. 154 @staticmethod 155 def from_locations(start, end): 156 return SourceRange_getRange(start, end) 157 158 @property 159 def start(self): 160 """ 161 Return a SourceLocation representing the first character within a 162 source range. 163 """ 164 return SourceRange_start(self) 165 166 @property 167 def end(self): 168 """ 169 Return a SourceLocation representing the last character within a 170 source range. 171 """ 172 return SourceRange_end(self) 173 174 def __repr__(self): 175 return "<SourceRange start %r, end %r>" % (self.start, self.end) 176 177class Diagnostic(object): 178 """ 179 A Diagnostic is a single instance of a Clang diagnostic. It includes the 180 diagnostic severity, the message, the location the diagnostic occurred, as 181 well as additional source ranges and associated fix-it hints. 182 """ 183 184 Ignored = 0 185 Note = 1 186 Warning = 2 187 Error = 3 188 Fatal = 4 189 190 def __init__(self, severity, location, spelling, ranges, fixits): 191 self.severity = severity 192 self.location = location 193 self.spelling = spelling 194 self.ranges = ranges 195 self.fixits = fixits 196 197 def __repr__(self): 198 return "<Diagnostic severity %r, location %r, spelling %r>" % ( 199 self.severity, self.location, self.spelling) 200 201class FixIt(object): 202 """ 203 A FixIt represents a transformation to be applied to the source to 204 "fix-it". The fix-it shouldbe applied by replacing the given source range 205 with the given value. 206 """ 207 208 def __init__(self, range, value): 209 self.range = range 210 self.value = value 211 212 def __repr__(self): 213 return "<FixIt range %r, value %r>" % (self.range, self.value) 214 215### Cursor Kinds ### 216 217class CursorKind(object): 218 """ 219 A CursorKind describes the kind of entity that a cursor points to. 220 """ 221 222 # The unique kind objects, indexed by id. 223 _kinds = [] 224 _name_map = None 225 226 def __init__(self, value): 227 if value >= len(CursorKind._kinds): 228 CursorKind._kinds += [None] * (value - len(CursorKind._kinds) + 1) 229 if CursorKind._kinds[value] is not None: 230 raise ValueError,'CursorKind already loaded' 231 self.value = value 232 CursorKind._kinds[value] = self 233 CursorKind._name_map = None 234 235 def from_param(self): 236 return self.value 237 238 @property 239 def name(self): 240 """Get the enumeration name of this cursor kind.""" 241 if self._name_map is None: 242 self._name_map = {} 243 for key,value in CursorKind.__dict__.items(): 244 if isinstance(value,CursorKind): 245 self._name_map[value] = key 246 return self._name_map[self] 247 248 @staticmethod 249 def from_id(id): 250 if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None: 251 raise ValueError,'Unknown cursor kind' 252 return CursorKind._kinds[id] 253 254 @staticmethod 255 def get_all_kinds(): 256 """Return all CursorKind enumeration instances.""" 257 return filter(None, CursorKind._kinds) 258 259 def is_declaration(self): 260 """Test if this is a declaration kind.""" 261 return CursorKind_is_decl(self) 262 263 def is_reference(self): 264 """Test if this is a reference kind.""" 265 return CursorKind_is_ref(self) 266 267 def is_expression(self): 268 """Test if this is an expression kind.""" 269 return CursorKind_is_expr(self) 270 271 def is_statement(self): 272 """Test if this is a statement kind.""" 273 return CursorKind_is_stmt(self) 274 275 def is_invalid(self): 276 """Test if this is an invalid kind.""" 277 return CursorKind_is_inv(self) 278 279 def __repr__(self): 280 return 'CursorKind.%s' % (self.name,) 281 282# FIXME: Is there a nicer way to expose this enumeration? We could potentially 283# represent the nested structure, or even build a class hierarchy. The main 284# things we want for sure are (a) simple external access to kinds, (b) a place 285# to hang a description and name, (c) easy to keep in sync with Index.h. 286 287### 288# Declaration Kinds 289 290# A declaration whose specific kind is not exposed via this interface. 291# 292# Unexposed declarations have the same operations as any other kind of 293# declaration; one can extract their location information, spelling, find their 294# definitions, etc. However, the specific kind of the declaration is not 295# reported. 296CursorKind.UNEXPOSED_DECL = CursorKind(1) 297 298# A C or C++ struct. 299CursorKind.STRUCT_DECL = CursorKind(2) 300 301# A C or C++ union. 302CursorKind.UNION_DECL = CursorKind(3) 303 304# A C++ class. 305CursorKind.CLASS_DECL = CursorKind(4) 306 307# An enumeration. 308CursorKind.ENUM_DECL = CursorKind(5) 309 310# A field (in C) or non-static data member (in C++) in a struct, union, or C++ 311# class. 312CursorKind.FIELD_DECL = CursorKind(6) 313 314# An enumerator constant. 315CursorKind.ENUM_CONSTANT_DECL = CursorKind(7) 316 317# A function. 318CursorKind.FUNCTION_DECL = CursorKind(8) 319 320# A variable. 321CursorKind.VAR_DECL = CursorKind(9) 322 323# A function or method parameter. 324CursorKind.PARM_DECL = CursorKind(10) 325 326# An Objective-C @interface. 327CursorKind.OBJC_INTERFACE_DECL = CursorKind(11) 328 329# An Objective-C @interface for a category. 330CursorKind.OBJC_CATEGORY_DECL = CursorKind(12) 331 332# An Objective-C @protocol declaration. 333CursorKind.OBJC_PROTOCOL_DECL = CursorKind(13) 334 335# An Objective-C @property declaration. 336CursorKind.OBJC_PROPERTY_DECL = CursorKind(14) 337 338# An Objective-C instance variable. 339CursorKind.OBJC_IVAR_DECL = CursorKind(15) 340 341# An Objective-C instance method. 342CursorKind.OBJC_INSTANCE_METHOD_DECL = CursorKind(16) 343 344# An Objective-C class method. 345CursorKind.OBJC_CLASS_METHOD_DECL = CursorKind(17) 346 347# An Objective-C @implementation. 348CursorKind.OBJC_IMPLEMENTATION_DECL = CursorKind(18) 349 350# An Objective-C @implementation for a category. 351CursorKind.OBJC_CATEGORY_IMPL_DECL = CursorKind(19) 352 353# A typedef. 354CursorKind.TYPEDEF_DECL = CursorKind(20) 355 356### 357# Reference Kinds 358 359CursorKind.OBJC_SUPER_CLASS_REF = CursorKind(40) 360CursorKind.OBJC_PROTOCOL_REF = CursorKind(41) 361CursorKind.OBJC_CLASS_REF = CursorKind(42) 362 363# A reference to a type declaration. 364# 365# A type reference occurs anywhere where a type is named but not 366# declared. For example, given: 367# typedef unsigned size_type; 368# size_type size; 369# 370# The typedef is a declaration of size_type (CXCursor_TypedefDecl), 371# while the type of the variable "size" is referenced. The cursor 372# referenced by the type of size is the typedef for size_type. 373CursorKind.TYPE_REF = CursorKind(43) 374 375### 376# Invalid/Error Kinds 377 378CursorKind.INVALID_FILE = CursorKind(70) 379CursorKind.NO_DECL_FOUND = CursorKind(71) 380CursorKind.NOT_IMPLEMENTED = CursorKind(72) 381 382### 383# Expression Kinds 384 385# An expression whose specific kind is not exposed via this interface. 386# 387# Unexposed expressions have the same operations as any other kind of 388# expression; one can extract their location information, spelling, children, 389# etc. However, the specific kind of the expression is not reported. 390CursorKind.UNEXPOSED_EXPR = CursorKind(100) 391 392# An expression that refers to some value declaration, such as a function, 393# varible, or enumerator. 394CursorKind.DECL_REF_EXPR = CursorKind(101) 395 396# An expression that refers to a member of a struct, union, class, Objective-C 397# class, etc. 398CursorKind.MEMBER_REF_EXPR = CursorKind(102) 399 400# An expression that calls a function. 401CursorKind.CALL_EXPR = CursorKind(103) 402 403# An expression that sends a message to an Objective-C object or class. 404CursorKind.OBJC_MESSAGE_EXPR = CursorKind(104) 405 406# A statement whose specific kind is not exposed via this interface. 407# 408# Unexposed statements have the same operations as any other kind of statement; 409# one can extract their location information, spelling, children, etc. However, 410# the specific kind of the statement is not reported. 411CursorKind.UNEXPOSED_STMT = CursorKind(200) 412 413### 414# Other Kinds 415 416# Cursor that represents the translation unit itself. 417# 418# The translation unit cursor exists primarily to act as the root cursor for 419# traversing the contents of a translation unit. 420CursorKind.TRANSLATION_UNIT = CursorKind(300) 421 422### Cursors ### 423 424class Cursor(Structure): 425 """ 426 The Cursor class represents a reference to an element within the AST. It 427 acts as a kind of iterator. 428 """ 429 _fields_ = [("_kind_id", c_int), ("data", c_void_p * 3)] 430 431 def __eq__(self, other): 432 return Cursor_eq(self, other) 433 434 def __ne__(self, other): 435 return not Cursor_eq(self, other) 436 437 def is_definition(self): 438 """ 439 Returns true if the declaration pointed at by the cursor is also a 440 definition of that entity. 441 """ 442 return Cursor_is_def(self) 443 444 def get_definition(self): 445 """ 446 If the cursor is a reference to a declaration or a declaration of 447 some entity, return a cursor that points to the definition of that 448 entity. 449 """ 450 # TODO: Should probably check that this is either a reference or 451 # declaration prior to issuing the lookup. 452 return Cursor_def(self) 453 454 def get_usr(self): 455 """Return the Unified Symbol Resultion (USR) for the entity referenced 456 by the given cursor (or None). 457 458 A Unified Symbol Resolution (USR) is a string that identifies a 459 particular entity (function, class, variable, etc.) within a 460 program. USRs can be compared across translation units to determine, 461 e.g., when references in one translation refer to an entity defined in 462 another translation unit.""" 463 return Cursor_usr(self) 464 465 @property 466 def kind(self): 467 """Return the kind of this cursor.""" 468 return CursorKind.from_id(self._kind_id) 469 470 @property 471 def spelling(self): 472 """Return the spelling of the entity pointed at by the cursor.""" 473 if not self.kind.is_declaration(): 474 # FIXME: clang_getCursorSpelling should be fixed to not assert on 475 # this, for consistency with clang_getCursorUSR. 476 return None 477 return Cursor_spelling(self) 478 479 @property 480 def location(self): 481 """ 482 Return the source location (the starting character) of the entity 483 pointed at by the cursor. 484 """ 485 return Cursor_loc(self) 486 487 @property 488 def extent(self): 489 """ 490 Return the source range (the range of text) occupied by the entity 491 pointed at by the cursor. 492 """ 493 return Cursor_extent(self) 494 495 def get_children(self): 496 """Return an iterator for accessing the children of this cursor.""" 497 498 # FIXME: Expose iteration from CIndex, PR6125. 499 def visitor(child, parent, children): 500 # FIXME: Document this assertion in API. 501 # FIXME: There should just be an isNull method. 502 assert child != Cursor_null() 503 children.append(child) 504 return 1 # continue 505 children = [] 506 Cursor_visit(self, Cursor_visit_callback(visitor), children) 507 return iter(children) 508 509 @staticmethod 510 def from_result(res, fn, args): 511 assert isinstance(res, Cursor) 512 # FIXME: There should just be an isNull method. 513 if res == Cursor_null(): 514 return None 515 return res 516 517## CIndex Objects ## 518 519# CIndex objects (derived from ClangObject) are essentially lightweight 520# wrappers attached to some underlying object, which is exposed via CIndex as 521# a void*. 522 523class ClangObject(object): 524 """ 525 A helper for Clang objects. This class helps act as an intermediary for 526 the ctypes library and the Clang CIndex library. 527 """ 528 def __init__(self, obj): 529 assert isinstance(obj, c_object_p) and obj 530 self.obj = self._as_parameter_ = obj 531 532 def from_param(self): 533 return self._as_parameter_ 534 535 536class _CXUnsavedFile(Structure): 537 """Helper for passing unsaved file arguments.""" 538 _fields_ = [("name", c_char_p), ("contents", c_char_p), ('length', c_ulong)] 539 540## Diagnostic Conversion ## 541 542# Diagnostic objects are temporary, we must extract all the information from the 543# diagnostic object when it is passed to the callback. 544 545_clang_getDiagnosticSeverity = lib.clang_getDiagnosticSeverity 546_clang_getDiagnosticSeverity.argtypes = [c_object_p] 547_clang_getDiagnosticSeverity.restype = c_int 548 549_clang_getDiagnosticLocation = lib.clang_getDiagnosticLocation 550_clang_getDiagnosticLocation.argtypes = [c_object_p] 551_clang_getDiagnosticLocation.restype = SourceLocation 552 553_clang_getDiagnosticSpelling = lib.clang_getDiagnosticSpelling 554_clang_getDiagnosticSpelling.argtypes = [c_object_p] 555_clang_getDiagnosticSpelling.restype = _CXString 556_clang_getDiagnosticSpelling.errcheck = _CXString.from_result 557 558_clang_getDiagnosticRanges = lib.clang_getDiagnosticRanges 559_clang_getDiagnosticRanges.argtypes = [c_object_p, 560 POINTER(POINTER(SourceRange)), 561 POINTER(c_uint)] 562_clang_getDiagnosticRanges.restype = None 563 564_clang_disposeDiagnosticRanges = lib.clang_disposeDiagnosticRanges 565_clang_disposeDiagnosticRanges.argtypes = [POINTER(SourceRange), c_uint] 566_clang_disposeDiagnosticRanges.restype = None 567 568_clang_getDiagnosticNumFixIts = lib.clang_getDiagnosticNumFixIts 569_clang_getDiagnosticNumFixIts.argtypes = [c_object_p] 570_clang_getDiagnosticNumFixIts.restype = c_uint 571 572_clang_getDiagnosticFixItKind = lib.clang_getDiagnosticFixItKind 573_clang_getDiagnosticFixItKind.argtypes = [c_object_p, c_uint] 574_clang_getDiagnosticFixItKind.restype = c_int 575 576_clang_getDiagnosticFixItInsertion = lib.clang_getDiagnosticFixItInsertion 577_clang_getDiagnosticFixItInsertion.argtypes = [c_object_p, c_uint, 578 POINTER(SourceLocation)] 579_clang_getDiagnosticFixItInsertion.restype = _CXString 580_clang_getDiagnosticFixItInsertion.errcheck = _CXString.from_result 581 582_clang_getDiagnosticFixItRemoval = lib.clang_getDiagnosticFixItRemoval 583_clang_getDiagnosticFixItRemoval.argtypes = [c_object_p, c_uint, 584 POINTER(SourceLocation)] 585_clang_getDiagnosticFixItRemoval.restype = _CXString 586_clang_getDiagnosticFixItRemoval.errcheck = _CXString.from_result 587 588_clang_getDiagnosticFixItReplacement = lib.clang_getDiagnosticFixItReplacement 589_clang_getDiagnosticFixItReplacement.argtypes = [c_object_p, c_uint, 590 POINTER(SourceRange)] 591_clang_getDiagnosticFixItReplacement.restype = _CXString 592_clang_getDiagnosticFixItReplacement.errcheck = _CXString.from_result 593 594def _convert_fixit(diag_ptr, index): 595 # We normalize all the fix-its to a single representation, this is more 596 # convenient. 597 # 598 # FIXME: Push this back into API? It isn't exactly clear what the 599 # SourceRange semantics are, we should make sure we can represent an empty 600 # range. 601 kind = _clang_getDiagnosticFixItKind(diag_ptr, index) 602 range = None 603 value = None 604 if kind == 0: # insertion 605 location = SourceLocation() 606 value = _clang_getDiagnosticFixItInsertion(diag_ptr, index, 607 byref(location)) 608 range = SourceRange.from_locations(location, location) 609 elif kind == 1: # removal 610 range = _clang_getDiagnosticFixItRemoval(diag_ptr, index) 611 value = '' 612 else: # replacement 613 assert kind == 2 614 range = SourceRange() 615 value = _clang_getDiagnosticFixItReplacement(diag_ptr, index, 616 byref(range)) 617 return FixIt(range, value) 618 619def _convert_diag(diag_ptr, diag_list): 620 severity = _clang_getDiagnosticSeverity(diag_ptr) 621 loc = _clang_getDiagnosticLocation(diag_ptr) 622 spelling = _clang_getDiagnosticSpelling(diag_ptr) 623 624 # Diagnostic ranges. 625 # 626 # FIXME: Use getNum... based API? 627 num_ranges = c_uint() 628 ranges_array = POINTER(SourceRange)() 629 _clang_getDiagnosticRanges(diag_ptr, byref(ranges_array), byref(num_ranges)) 630 631 # Copy the ranges array so we can dispose the original. 632 ranges = [SourceRange.from_buffer_copy(ranges_array[i]) 633 for i in range(num_ranges.value)] 634 _clang_disposeDiagnosticRanges(ranges_array, num_ranges) 635 636 fixits = [_convert_fixit(diag_ptr, i) 637 for i in range(_clang_getDiagnosticNumFixIts(diag_ptr))] 638 639 diag_list.append(Diagnostic(severity, loc, spelling, ranges, fixits)) 640 641### 642 643class Index(ClangObject): 644 """ 645 The Index type provides the primary interface to the Clang CIndex library, 646 primarily by providing an interface for reading and parsing translation 647 units. 648 """ 649 650 @staticmethod 651 def create(excludeDecls=False): 652 """ 653 Create a new Index. 654 Parameters: 655 excludeDecls -- Exclude local declarations from translation units. 656 """ 657 return Index(Index_create(excludeDecls)) 658 659 def __del__(self): 660 Index_dispose(self) 661 662 def read(self, path): 663 """Load the translation unit from the given AST file.""" 664 # FIXME: In theory, we could support streaming diagnostics. It's hard to 665 # integrate this into the API cleanly, however. Resolve. 666 diags = [] 667 ptr = TranslationUnit_read(self, path, 668 Diagnostic_callback(_convert_diag), diags) 669 return TranslationUnit(ptr) if ptr else None 670 671 def parse(self, path, args = [], unsaved_files = []): 672 """ 673 Load the translation unit from the given source code file by running 674 clang and generating the AST before loading. Additional command line 675 parameters can be passed to clang via the args parameter. 676 677 In-memory contents for files can be provided by passing a list of pairs 678 to as unsaved_files, the first item should be the filenames to be mapped 679 and the second should be the contents to be substituted for the 680 file. The contents may be passed as strings or file objects. 681 """ 682 arg_array = 0 683 if len(args): 684 arg_array = (c_char_p * len(args))(* args) 685 unsaved_files_array = 0 686 if len(unsaved_files): 687 unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))() 688 for i,(name,value) in enumerate(unsaved_files): 689 if not isinstance(value, str): 690 # FIXME: It would be great to support an efficient version 691 # of this, one day. 692 value = value.read() 693 print value 694 if not isinstance(value, str): 695 raise TypeError,'Unexpected unsaved file contents.' 696 unsaved_files_array[i].name = name 697 unsaved_files_array[i].contents = value 698 unsaved_files_array[i].length = len(value) 699 # FIXME: In theory, we could support streaming diagnostics. It's hard to 700 # integrate this into the API cleanly, however. Resolve. 701 diags = [] 702 ptr = TranslationUnit_parse(self, path, len(args), arg_array, 703 len(unsaved_files), unsaved_files_array, 704 Diagnostic_callback(_convert_diag), diags) 705 return TranslationUnit(ptr, diags) if ptr else None 706 707 708class TranslationUnit(ClangObject): 709 """ 710 The TranslationUnit class represents a source code translation unit and 711 provides read-only access to its top-level declarations. 712 """ 713 714 def __init__(self, ptr, diagnostics): 715 ClangObject.__init__(self, ptr) 716 self.diagnostics = diagnostics 717 718 def __del__(self): 719 TranslationUnit_dispose(self) 720 721 @property 722 def cursor(self): 723 """Retrieve the cursor that represents the given translation unit.""" 724 return TranslationUnit_cursor(self) 725 726 @property 727 def spelling(self): 728 """Get the original translation unit source file name.""" 729 return TranslationUnit_spelling(self) 730 731class File(ClangObject): 732 """ 733 The File class represents a particular source file that is part of a 734 translation unit. 735 """ 736 737 @property 738 def name(self): 739 """Return the complete file and path name of the file.""" 740 return File_name(self) 741 742 @property 743 def time(self): 744 """Return the last modification time of the file.""" 745 return File_time(self) 746 747# Additional Functions and Types 748 749# String Functions 750_CXString_dispose = lib.clang_disposeString 751_CXString_dispose.argtypes = [_CXString] 752 753_CXString_getCString = lib.clang_getCString 754_CXString_getCString.argtypes = [_CXString] 755_CXString_getCString.restype = c_char_p 756 757# Source Location Functions 758SourceLocation_loc = lib.clang_getInstantiationLocation 759SourceLocation_loc.argtypes = [SourceLocation, POINTER(c_object_p), 760 POINTER(c_uint), POINTER(c_uint), 761 POINTER(c_uint)] 762 763# Source Range Functions 764SourceRange_getRange = lib.clang_getRange 765SourceRange_getRange.argtypes = [SourceLocation, SourceLocation] 766SourceRange_getRange.restype = SourceRange 767 768SourceRange_start = lib.clang_getRangeStart 769SourceRange_start.argtypes = [SourceRange] 770SourceRange_start.restype = SourceLocation 771 772SourceRange_end = lib.clang_getRangeEnd 773SourceRange_end.argtypes = [SourceRange] 774SourceRange_end.restype = SourceLocation 775 776# CursorKind Functions 777CursorKind_is_decl = lib.clang_isDeclaration 778CursorKind_is_decl.argtypes = [CursorKind] 779CursorKind_is_decl.restype = bool 780 781CursorKind_is_ref = lib.clang_isReference 782CursorKind_is_ref.argtypes = [CursorKind] 783CursorKind_is_ref.restype = bool 784 785CursorKind_is_expr = lib.clang_isExpression 786CursorKind_is_expr.argtypes = [CursorKind] 787CursorKind_is_expr.restype = bool 788 789CursorKind_is_stmt = lib.clang_isStatement 790CursorKind_is_stmt.argtypes = [CursorKind] 791CursorKind_is_stmt.restype = bool 792 793CursorKind_is_inv = lib.clang_isInvalid 794CursorKind_is_inv.argtypes = [CursorKind] 795CursorKind_is_inv.restype = bool 796 797# Cursor Functions 798# TODO: Implement this function 799Cursor_get = lib.clang_getCursor 800Cursor_get.argtypes = [TranslationUnit, SourceLocation] 801Cursor_get.restype = Cursor 802 803Cursor_null = lib.clang_getNullCursor 804Cursor_null.restype = Cursor 805 806Cursor_usr = lib.clang_getCursorUSR 807Cursor_usr.argtypes = [Cursor] 808Cursor_usr.restype = _CXString 809Cursor_usr.errcheck = _CXString.from_result 810 811Cursor_is_def = lib.clang_isCursorDefinition 812Cursor_is_def.argtypes = [Cursor] 813Cursor_is_def.restype = bool 814 815Cursor_def = lib.clang_getCursorDefinition 816Cursor_def.argtypes = [Cursor] 817Cursor_def.restype = Cursor 818Cursor_def.errcheck = Cursor.from_result 819 820Cursor_eq = lib.clang_equalCursors 821Cursor_eq.argtypes = [Cursor, Cursor] 822Cursor_eq.restype = c_uint 823 824Cursor_spelling = lib.clang_getCursorSpelling 825Cursor_spelling.argtypes = [Cursor] 826Cursor_spelling.restype = _CXString 827Cursor_spelling.errcheck = _CXString.from_result 828 829Cursor_loc = lib.clang_getCursorLocation 830Cursor_loc.argtypes = [Cursor] 831Cursor_loc.restype = SourceLocation 832 833Cursor_extent = lib.clang_getCursorExtent 834Cursor_extent.argtypes = [Cursor] 835Cursor_extent.restype = SourceRange 836 837Cursor_ref = lib.clang_getCursorReferenced 838Cursor_ref.argtypes = [Cursor] 839Cursor_ref.restype = Cursor 840Cursor_ref.errcheck = Cursor.from_result 841 842Cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object) 843Cursor_visit = lib.clang_visitChildren 844Cursor_visit.argtypes = [Cursor, Cursor_visit_callback, py_object] 845Cursor_visit.restype = c_uint 846 847# Index Functions 848Index_create = lib.clang_createIndex 849Index_create.argtypes = [c_int] 850Index_create.restype = c_object_p 851 852Index_dispose = lib.clang_disposeIndex 853Index_dispose.argtypes = [Index] 854 855# Translation Unit Functions 856Diagnostic_callback = CFUNCTYPE(None, c_object_p, py_object) 857 858TranslationUnit_read = lib.clang_createTranslationUnit 859TranslationUnit_read.argtypes = [Index, c_char_p, 860 Diagnostic_callback, py_object] 861TranslationUnit_read.restype = c_object_p 862 863TranslationUnit_parse = lib.clang_createTranslationUnitFromSourceFile 864TranslationUnit_parse.argtypes = [Index, c_char_p, c_int, c_void_p, 865 c_int, c_void_p, 866 Diagnostic_callback, py_object] 867TranslationUnit_parse.restype = c_object_p 868 869TranslationUnit_cursor = lib.clang_getTranslationUnitCursor 870TranslationUnit_cursor.argtypes = [TranslationUnit] 871TranslationUnit_cursor.restype = Cursor 872TranslationUnit_cursor.errcheck = Cursor.from_result 873 874TranslationUnit_spelling = lib.clang_getTranslationUnitSpelling 875TranslationUnit_spelling.argtypes = [TranslationUnit] 876TranslationUnit_spelling.restype = _CXString 877TranslationUnit_spelling.errcheck = _CXString.from_result 878 879TranslationUnit_dispose = lib.clang_disposeTranslationUnit 880TranslationUnit_dispose.argtypes = [TranslationUnit] 881 882# File Functions 883File_name = lib.clang_getFileName 884File_name.argtypes = [File] 885File_name.restype = c_char_p 886 887File_time = lib.clang_getFileTime 888File_time.argtypes = [File] 889File_time.restype = c_uint 890 891### 892 893__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind', 894 'Diagnostic', 'FixIt', 'SourceRange', 'SourceLocation', 'File'] 895