cindex.py revision f498e00a30ca7fdaf4f49e778862f4cf84ffab2a
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('libclang.dylib')
75    elif name == 'Windows':
76        return cdll.LoadLibrary('libclang.dll')
77    else:
78        return cdll.LoadLibrary('libclang.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, ptr):
191        self.ptr = ptr
192
193    def __del__(self):
194        _clang_disposeDiagnostic(self)
195
196    @property
197    def severity(self):
198        return _clang_getDiagnosticSeverity(self)
199
200    @property
201    def location(self):
202        return _clang_getDiagnosticLocation(self)
203
204    @property
205    def spelling(self):
206        return _clang_getDiagnosticSpelling(self)
207
208    @property
209    def ranges(self):
210        class RangeIterator:
211            def __init__(self, diag):
212                self.diag = diag
213
214            def __len__(self):
215                return int(_clang_getDiagnosticNumRanges(self.diag))
216
217            def __getitem__(self, key):
218		if (key >= len(self)):
219			raise IndexError
220                return _clang_getDiagnosticRange(self.diag, key)
221
222        return RangeIterator(self)
223
224    @property
225    def fixits(self):
226        class FixItIterator:
227            def __init__(self, diag):
228                self.diag = diag
229
230            def __len__(self):
231                return int(_clang_getDiagnosticNumFixIts(self.diag))
232
233            def __getitem__(self, key):
234                range = SourceRange()
235                value = _clang_getDiagnosticFixIt(self.diag, key, byref(range))
236                if len(value) == 0:
237                    raise IndexError
238
239                return FixIt(range, value)
240
241        return FixItIterator(self)
242
243    def __repr__(self):
244        return "<Diagnostic severity %r, location %r, spelling %r>" % (
245            self.severity, self.location, self.spelling)
246
247    def from_param(self):
248      return self.ptr
249
250class FixIt(object):
251    """
252    A FixIt represents a transformation to be applied to the source to
253    "fix-it". The fix-it shouldbe applied by replacing the given source range
254    with the given value.
255    """
256
257    def __init__(self, range, value):
258        self.range = range
259        self.value = value
260
261    def __repr__(self):
262        return "<FixIt range %r, value %r>" % (self.range, self.value)
263
264### Cursor Kinds ###
265
266class CursorKind(object):
267    """
268    A CursorKind describes the kind of entity that a cursor points to.
269    """
270
271    # The unique kind objects, indexed by id.
272    _kinds = []
273    _name_map = None
274
275    def __init__(self, value):
276        if value >= len(CursorKind._kinds):
277            CursorKind._kinds += [None] * (value - len(CursorKind._kinds) + 1)
278        if CursorKind._kinds[value] is not None:
279            raise ValueError,'CursorKind already loaded'
280        self.value = value
281        CursorKind._kinds[value] = self
282        CursorKind._name_map = None
283
284    def from_param(self):
285        return self.value
286
287    @property
288    def name(self):
289        """Get the enumeration name of this cursor kind."""
290        if self._name_map is None:
291            self._name_map = {}
292            for key,value in CursorKind.__dict__.items():
293                if isinstance(value,CursorKind):
294                    self._name_map[value] = key
295        return self._name_map[self]
296
297    @staticmethod
298    def from_id(id):
299        if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
300            raise ValueError,'Unknown cursor kind'
301        return CursorKind._kinds[id]
302
303    @staticmethod
304    def get_all_kinds():
305        """Return all CursorKind enumeration instances."""
306        return filter(None, CursorKind._kinds)
307
308    def is_declaration(self):
309        """Test if this is a declaration kind."""
310        return CursorKind_is_decl(self)
311
312    def is_reference(self):
313        """Test if this is a reference kind."""
314        return CursorKind_is_ref(self)
315
316    def is_expression(self):
317        """Test if this is an expression kind."""
318        return CursorKind_is_expr(self)
319
320    def is_statement(self):
321        """Test if this is a statement kind."""
322        return CursorKind_is_stmt(self)
323
324    def is_invalid(self):
325        """Test if this is an invalid kind."""
326        return CursorKind_is_inv(self)
327
328    def __repr__(self):
329        return 'CursorKind.%s' % (self.name,)
330
331# FIXME: Is there a nicer way to expose this enumeration? We could potentially
332# represent the nested structure, or even build a class hierarchy. The main
333# things we want for sure are (a) simple external access to kinds, (b) a place
334# to hang a description and name, (c) easy to keep in sync with Index.h.
335
336###
337# Declaration Kinds
338
339# A declaration whose specific kind is not exposed via this interface.
340#
341# Unexposed declarations have the same operations as any other kind of
342# declaration; one can extract their location information, spelling, find their
343# definitions, etc. However, the specific kind of the declaration is not
344# reported.
345CursorKind.UNEXPOSED_DECL = CursorKind(1)
346
347# A C or C++ struct.
348CursorKind.STRUCT_DECL = CursorKind(2)
349
350# A C or C++ union.
351CursorKind.UNION_DECL = CursorKind(3)
352
353# A C++ class.
354CursorKind.CLASS_DECL = CursorKind(4)
355
356# An enumeration.
357CursorKind.ENUM_DECL = CursorKind(5)
358
359# A field (in C) or non-static data member (in C++) in a struct, union, or C++
360# class.
361CursorKind.FIELD_DECL = CursorKind(6)
362
363# An enumerator constant.
364CursorKind.ENUM_CONSTANT_DECL = CursorKind(7)
365
366# A function.
367CursorKind.FUNCTION_DECL = CursorKind(8)
368
369# A variable.
370CursorKind.VAR_DECL = CursorKind(9)
371
372# A function or method parameter.
373CursorKind.PARM_DECL = CursorKind(10)
374
375# An Objective-C @interface.
376CursorKind.OBJC_INTERFACE_DECL = CursorKind(11)
377
378# An Objective-C @interface for a category.
379CursorKind.OBJC_CATEGORY_DECL = CursorKind(12)
380
381# An Objective-C @protocol declaration.
382CursorKind.OBJC_PROTOCOL_DECL = CursorKind(13)
383
384# An Objective-C @property declaration.
385CursorKind.OBJC_PROPERTY_DECL = CursorKind(14)
386
387# An Objective-C instance variable.
388CursorKind.OBJC_IVAR_DECL = CursorKind(15)
389
390# An Objective-C instance method.
391CursorKind.OBJC_INSTANCE_METHOD_DECL = CursorKind(16)
392
393# An Objective-C class method.
394CursorKind.OBJC_CLASS_METHOD_DECL = CursorKind(17)
395
396# An Objective-C @implementation.
397CursorKind.OBJC_IMPLEMENTATION_DECL = CursorKind(18)
398
399# An Objective-C @implementation for a category.
400CursorKind.OBJC_CATEGORY_IMPL_DECL = CursorKind(19)
401
402# A typedef.
403CursorKind.TYPEDEF_DECL = CursorKind(20)
404
405# A C++ class method.
406CursorKind.CXX_METHOD = CursorKind(21)
407
408# A C++ namespace.
409CursorKind.NAMESPACE = CursorKind(22)
410
411# A linkage specification, e.g. 'extern "C"'.
412CursorKind.LINKAGE_SPEC = CursorKind(23)
413
414# A C++ constructor.
415CursorKind.CONSTRUCTOR = CursorKind(24)
416
417# A C++ destructor.
418CursorKind.DESTRUCTOR = CursorKind(25)
419
420# A C++ conversion function.
421CursorKind.CONVERSION_FUNCTION = CursorKind(26)
422
423# A C++ template type parameter
424CursorKind.TEMPLATE_TYPE_PARAMETER = CursorKind(27)
425
426# A C++ non-type template paramater.
427CursorKind.TEMPLATE_NON_TYPE_PARAMETER = CursorKind(28)
428
429# A C++ template template parameter.
430CursorKind.TEMPLATE_TEMPLATE_PARAMTER = CursorKind(29)
431
432# A C++ function template.
433CursorKind.FUNCTION_TEMPLATE = CursorKind(30)
434
435# A C++ class template.
436CursorKind.CLASS_TEMPLATE = CursorKind(31)
437
438# A C++ class template partial specialization.
439CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION = CursorKind(32)
440
441# A C++ namespace alias declaration.
442CursorKind.NAMESPACE_ALIAS = CursorKind(33)
443
444# A C++ using directive
445CursorKind.USING_DIRECTIVE = CursorKind(34)
446
447# A C++ using declaration
448CursorKind.USING_DECLARATION = CursorKind(35)
449
450###
451# Reference Kinds
452
453CursorKind.OBJC_SUPER_CLASS_REF = CursorKind(40)
454CursorKind.OBJC_PROTOCOL_REF = CursorKind(41)
455CursorKind.OBJC_CLASS_REF = CursorKind(42)
456
457# A reference to a type declaration.
458#
459# A type reference occurs anywhere where a type is named but not
460# declared. For example, given:
461#   typedef unsigned size_type;
462#   size_type size;
463#
464# The typedef is a declaration of size_type (CXCursor_TypedefDecl),
465# while the type of the variable "size" is referenced. The cursor
466# referenced by the type of size is the typedef for size_type.
467CursorKind.TYPE_REF = CursorKind(43)
468CursorKind.CXX_BASE_SPECIFIER = CursorKind(44)
469
470# A reference to a class template, function template, template
471# template parameter, or class template partial specialization.
472CursorKind.TEMPLATE_REF = CursorKind(45)
473
474# A reference to a namespace or namepsace alias.
475CursorKind.NAMESPACE_REF = CursorKind(46)
476
477# A reference to a member of a struct, union, or class that occurs in
478# some non-expression context, e.g., a designated initializer.
479CursorKind.MEMBER_REF = CursorKind(47)
480
481# A reference to a labeled statement.
482CursorKind.LABEL_REF = CursorKind(48)
483
484# A reference toa a set of overloaded functions or function templates
485# that has not yet been resolved to a specific function or function template.
486CursorKind.OVERLOADED_DECL_REF = CursorKind(49)
487
488###
489# Invalid/Error Kinds
490
491CursorKind.INVALID_FILE = CursorKind(70)
492CursorKind.NO_DECL_FOUND = CursorKind(71)
493CursorKind.NOT_IMPLEMENTED = CursorKind(72)
494CursorKind.INVALID_CODE = CursorKind(73)
495
496###
497# Expression Kinds
498
499# An expression whose specific kind is not exposed via this interface.
500#
501# Unexposed expressions have the same operations as any other kind of
502# expression; one can extract their location information, spelling, children,
503# etc. However, the specific kind of the expression is not reported.
504CursorKind.UNEXPOSED_EXPR = CursorKind(100)
505
506# An expression that refers to some value declaration, such as a function,
507# varible, or enumerator.
508CursorKind.DECL_REF_EXPR = CursorKind(101)
509
510# An expression that refers to a member of a struct, union, class, Objective-C
511# class, etc.
512CursorKind.MEMBER_REF_EXPR = CursorKind(102)
513
514# An expression that calls a function.
515CursorKind.CALL_EXPR = CursorKind(103)
516
517# An expression that sends a message to an Objective-C object or class.
518CursorKind.OBJC_MESSAGE_EXPR = CursorKind(104)
519
520# An expression that represents a block literal.
521CursorKind.BLOCK_EXPR = CursorKind(105)
522
523# A statement whose specific kind is not exposed via this interface.
524#
525# Unexposed statements have the same operations as any other kind of statement;
526# one can extract their location information, spelling, children, etc. However,
527# the specific kind of the statement is not reported.
528CursorKind.UNEXPOSED_STMT = CursorKind(200)
529
530# A labelled statement in a function.
531CursorKind.LABEL_STMT = CursorKind(201)
532
533
534###
535# Other Kinds
536
537# Cursor that represents the translation unit itself.
538#
539# The translation unit cursor exists primarily to act as the root cursor for
540# traversing the contents of a translation unit.
541CursorKind.TRANSLATION_UNIT = CursorKind(300)
542
543###
544# Attributes
545
546# An attribute whoe specific kind is note exposed via this interface
547CursorKind.UNEXPOSED_ATTR = CursorKind(400)
548
549CursorKind.IB_ACTION_ATTR = CursorKind(401)
550CursorKind.IB_OUTLET_ATTR = CursorKind(402)
551CursorKind.IB_OUTLET_COLLECTION_ATTR = CursorKind(403)
552
553###
554# Preprocessing
555CursorKind.PREPROCESSING_DIRECTIVE = CursorKind(500)
556CursorKind.MACRO_DEFINITION = CursorKind(501)
557CursorKind.MACRO_INSTANTIATION = CursorKind(502)
558CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
559
560### Cursors ###
561
562class Cursor(Structure):
563    """
564    The Cursor class represents a reference to an element within the AST. It
565    acts as a kind of iterator.
566    """
567    _fields_ = [("_kind_id", c_int), ("data", c_void_p * 3)]
568
569    def __eq__(self, other):
570        return Cursor_eq(self, other)
571
572    def __ne__(self, other):
573        return not Cursor_eq(self, other)
574
575    def is_definition(self):
576        """
577        Returns true if the declaration pointed at by the cursor is also a
578        definition of that entity.
579        """
580        return Cursor_is_def(self)
581
582    def get_definition(self):
583        """
584        If the cursor is a reference to a declaration or a declaration of
585        some entity, return a cursor that points to the definition of that
586        entity.
587        """
588        # TODO: Should probably check that this is either a reference or
589        # declaration prior to issuing the lookup.
590        return Cursor_def(self)
591
592    def get_usr(self):
593        """Return the Unified Symbol Resultion (USR) for the entity referenced
594        by the given cursor (or None).
595
596        A Unified Symbol Resolution (USR) is a string that identifies a
597        particular entity (function, class, variable, etc.) within a
598        program. USRs can be compared across translation units to determine,
599        e.g., when references in one translation refer to an entity defined in
600        another translation unit."""
601        return Cursor_usr(self)
602
603    @property
604    def kind(self):
605        """Return the kind of this cursor."""
606        return CursorKind.from_id(self._kind_id)
607
608    @property
609    def spelling(self):
610        """Return the spelling of the entity pointed at by the cursor."""
611        if not self.kind.is_declaration():
612            # FIXME: clang_getCursorSpelling should be fixed to not assert on
613            # this, for consistency with clang_getCursorUSR.
614            return None
615        return Cursor_spelling(self)
616
617    @property
618    def location(self):
619        """
620        Return the source location (the starting character) of the entity
621        pointed at by the cursor.
622        """
623        return Cursor_loc(self)
624
625    @property
626    def extent(self):
627        """
628        Return the source range (the range of text) occupied by the entity
629        pointed at by the cursor.
630        """
631        return Cursor_extent(self)
632
633    def get_children(self):
634        """Return an iterator for accessing the children of this cursor."""
635
636        # FIXME: Expose iteration from CIndex, PR6125.
637        def visitor(child, parent, children):
638            # FIXME: Document this assertion in API.
639            # FIXME: There should just be an isNull method.
640            assert child != Cursor_null()
641            children.append(child)
642            return 1 # continue
643        children = []
644        Cursor_visit(self, Cursor_visit_callback(visitor), children)
645        return iter(children)
646
647    @staticmethod
648    def from_result(res, fn, args):
649        assert isinstance(res, Cursor)
650        # FIXME: There should just be an isNull method.
651        if res == Cursor_null():
652            return None
653        return res
654
655## CIndex Objects ##
656
657# CIndex objects (derived from ClangObject) are essentially lightweight
658# wrappers attached to some underlying object, which is exposed via CIndex as
659# a void*.
660
661class ClangObject(object):
662    """
663    A helper for Clang objects. This class helps act as an intermediary for
664    the ctypes library and the Clang CIndex library.
665    """
666    def __init__(self, obj):
667        assert isinstance(obj, c_object_p) and obj
668        self.obj = self._as_parameter_ = obj
669
670    def from_param(self):
671        return self._as_parameter_
672
673
674class _CXUnsavedFile(Structure):
675    """Helper for passing unsaved file arguments."""
676    _fields_ = [("name", c_char_p), ("contents", c_char_p), ('length', c_ulong)]
677
678## Diagnostic Conversion ##
679
680_clang_getNumDiagnostics = lib.clang_getNumDiagnostics
681_clang_getNumDiagnostics.argtypes = [c_object_p]
682_clang_getNumDiagnostics.restype = c_uint
683
684_clang_getDiagnostic = lib.clang_getDiagnostic
685_clang_getDiagnostic.argtypes = [c_object_p, c_uint]
686_clang_getDiagnostic.restype = c_object_p
687
688_clang_disposeDiagnostic = lib.clang_disposeDiagnostic
689_clang_disposeDiagnostic.argtypes = [Diagnostic]
690
691_clang_getDiagnosticSeverity = lib.clang_getDiagnosticSeverity
692_clang_getDiagnosticSeverity.argtypes = [Diagnostic]
693_clang_getDiagnosticSeverity.restype = c_int
694
695_clang_getDiagnosticLocation = lib.clang_getDiagnosticLocation
696_clang_getDiagnosticLocation.argtypes = [Diagnostic]
697_clang_getDiagnosticLocation.restype = SourceLocation
698
699_clang_getDiagnosticSpelling = lib.clang_getDiagnosticSpelling
700_clang_getDiagnosticSpelling.argtypes = [Diagnostic]
701_clang_getDiagnosticSpelling.restype = _CXString
702_clang_getDiagnosticSpelling.errcheck = _CXString.from_result
703
704_clang_getDiagnosticNumRanges = lib.clang_getDiagnosticNumRanges
705_clang_getDiagnosticNumRanges.argtypes = [Diagnostic]
706_clang_getDiagnosticNumRanges.restype = c_uint
707
708_clang_getDiagnosticRange = lib.clang_getDiagnosticRange
709_clang_getDiagnosticRange.argtypes = [Diagnostic, c_uint]
710_clang_getDiagnosticRange.restype = SourceRange
711
712_clang_getDiagnosticNumFixIts = lib.clang_getDiagnosticNumFixIts
713_clang_getDiagnosticNumFixIts.argtypes = [Diagnostic]
714_clang_getDiagnosticNumFixIts.restype = c_uint
715
716_clang_getDiagnosticFixIt = lib.clang_getDiagnosticFixIt
717_clang_getDiagnosticFixIt.argtypes = [Diagnostic, c_uint, POINTER(SourceRange)]
718_clang_getDiagnosticFixIt.restype = _CXString
719_clang_getDiagnosticFixIt.errcheck = _CXString.from_result
720
721###
722
723class Index(ClangObject):
724    """
725    The Index type provides the primary interface to the Clang CIndex library,
726    primarily by providing an interface for reading and parsing translation
727    units.
728    """
729
730    @staticmethod
731    def create(excludeDecls=False):
732        """
733        Create a new Index.
734        Parameters:
735        excludeDecls -- Exclude local declarations from translation units.
736        """
737        return Index(Index_create(excludeDecls, 0))
738
739    def __del__(self):
740        Index_dispose(self)
741
742    def read(self, path):
743        """Load the translation unit from the given AST file."""
744        ptr = TranslationUnit_read(self, path)
745        return TranslationUnit(ptr) if ptr else None
746
747    def parse(self, path, args = [], unsaved_files = []):
748        """
749        Load the translation unit from the given source code file by running
750        clang and generating the AST before loading. Additional command line
751        parameters can be passed to clang via the args parameter.
752
753        In-memory contents for files can be provided by passing a list of pairs
754        to as unsaved_files, the first item should be the filenames to be mapped
755        and the second should be the contents to be substituted for the
756        file. The contents may be passed as strings or file objects.
757        """
758        arg_array = 0
759        if len(args):
760            arg_array = (c_char_p * len(args))(* args)
761        unsaved_files_array = 0
762        if len(unsaved_files):
763            unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))()
764            for i,(name,value) in enumerate(unsaved_files):
765                if not isinstance(value, str):
766                    # FIXME: It would be great to support an efficient version
767                    # of this, one day.
768                    value = value.read()
769                    print value
770                if not isinstance(value, str):
771                    raise TypeError,'Unexpected unsaved file contents.'
772                unsaved_files_array[i].name = name
773                unsaved_files_array[i].contents = value
774                unsaved_files_array[i].length = len(value)
775        ptr = TranslationUnit_parse(self, path, len(args), arg_array,
776                                    len(unsaved_files), unsaved_files_array)
777        return TranslationUnit(ptr) if ptr else None
778
779
780class TranslationUnit(ClangObject):
781    """
782    The TranslationUnit class represents a source code translation unit and
783    provides read-only access to its top-level declarations.
784    """
785
786    def __init__(self, ptr):
787        ClangObject.__init__(self, ptr)
788
789    def __del__(self):
790        TranslationUnit_dispose(self)
791
792    @property
793    def cursor(self):
794        """Retrieve the cursor that represents the given translation unit."""
795        return TranslationUnit_cursor(self)
796
797    @property
798    def spelling(self):
799        """Get the original translation unit source file name."""
800        return TranslationUnit_spelling(self)
801
802    def get_includes(self):
803        """
804        Return an iterable sequence of FileInclusion objects that describe the
805        sequence of inclusions in a translation unit. The first object in
806        this sequence is always the input file. Note that this method will not
807        recursively iterate over header files included through precompiled
808        headers.
809        """
810        def visitor(fobj, lptr, depth, includes):
811            loc = lptr.contents
812            includes.append(FileInclusion(loc.file, File(fobj), loc, depth))
813
814        # Automatically adapt CIndex/ctype pointers to python objects
815        includes = []
816        TranslationUnit_includes(self,
817                                 TranslationUnit_includes_callback(visitor),
818                                 includes)
819        return iter(includes)
820
821    @property
822    def diagnostics(self):
823        """
824        Return an iterable (and indexable) object containing the diagnostics.
825        """
826        class DiagIterator:
827            def __init__(self, tu):
828                self.tu = tu
829
830            def __len__(self):
831                return int(_clang_getNumDiagnostics(self.tu))
832
833            def __getitem__(self, key):
834                diag = _clang_getDiagnostic(self.tu, key)
835                if not diag:
836                    raise IndexError
837                return Diagnostic(diag)
838
839        return DiagIterator(self)
840
841class File(ClangObject):
842    """
843    The File class represents a particular source file that is part of a
844    translation unit.
845    """
846
847    @property
848    def name(self):
849        """Return the complete file and path name of the file."""
850        return File_name(self)
851
852    @property
853    def time(self):
854        """Return the last modification time of the file."""
855        return File_time(self)
856
857class FileInclusion(object):
858    """
859    The FileInclusion class represents the inclusion of one source file by
860    another via a '#include' directive or as the input file for the translation
861    unit. This class provides information about the included file, the including
862    file, the location of the '#include' directive and the depth of the included
863    file in the stack. Note that the input file has depth 0.
864    """
865
866    def __init__(self, src, tgt, loc, depth):
867        self.source = src
868        self.include = tgt
869        self.location = loc
870        self.depth = depth
871
872    @property
873    def is_input_file(self):
874        """True if the included file is the input file."""
875        return self.depth == 0
876
877# Additional Functions and Types
878
879# String Functions
880_CXString_dispose = lib.clang_disposeString
881_CXString_dispose.argtypes = [_CXString]
882
883_CXString_getCString = lib.clang_getCString
884_CXString_getCString.argtypes = [_CXString]
885_CXString_getCString.restype = c_char_p
886
887# Source Location Functions
888SourceLocation_loc = lib.clang_getInstantiationLocation
889SourceLocation_loc.argtypes = [SourceLocation, POINTER(c_object_p),
890                               POINTER(c_uint), POINTER(c_uint),
891                               POINTER(c_uint)]
892
893# Source Range Functions
894SourceRange_getRange = lib.clang_getRange
895SourceRange_getRange.argtypes = [SourceLocation, SourceLocation]
896SourceRange_getRange.restype = SourceRange
897
898SourceRange_start = lib.clang_getRangeStart
899SourceRange_start.argtypes = [SourceRange]
900SourceRange_start.restype = SourceLocation
901
902SourceRange_end = lib.clang_getRangeEnd
903SourceRange_end.argtypes = [SourceRange]
904SourceRange_end.restype = SourceLocation
905
906# CursorKind Functions
907CursorKind_is_decl = lib.clang_isDeclaration
908CursorKind_is_decl.argtypes = [CursorKind]
909CursorKind_is_decl.restype = bool
910
911CursorKind_is_ref = lib.clang_isReference
912CursorKind_is_ref.argtypes = [CursorKind]
913CursorKind_is_ref.restype = bool
914
915CursorKind_is_expr = lib.clang_isExpression
916CursorKind_is_expr.argtypes = [CursorKind]
917CursorKind_is_expr.restype = bool
918
919CursorKind_is_stmt = lib.clang_isStatement
920CursorKind_is_stmt.argtypes = [CursorKind]
921CursorKind_is_stmt.restype = bool
922
923CursorKind_is_inv = lib.clang_isInvalid
924CursorKind_is_inv.argtypes = [CursorKind]
925CursorKind_is_inv.restype = bool
926
927# Cursor Functions
928# TODO: Implement this function
929Cursor_get = lib.clang_getCursor
930Cursor_get.argtypes = [TranslationUnit, SourceLocation]
931Cursor_get.restype = Cursor
932
933Cursor_null = lib.clang_getNullCursor
934Cursor_null.restype = Cursor
935
936Cursor_usr = lib.clang_getCursorUSR
937Cursor_usr.argtypes = [Cursor]
938Cursor_usr.restype = _CXString
939Cursor_usr.errcheck = _CXString.from_result
940
941Cursor_is_def = lib.clang_isCursorDefinition
942Cursor_is_def.argtypes = [Cursor]
943Cursor_is_def.restype = bool
944
945Cursor_def = lib.clang_getCursorDefinition
946Cursor_def.argtypes = [Cursor]
947Cursor_def.restype = Cursor
948Cursor_def.errcheck = Cursor.from_result
949
950Cursor_eq = lib.clang_equalCursors
951Cursor_eq.argtypes = [Cursor, Cursor]
952Cursor_eq.restype = c_uint
953
954Cursor_spelling = lib.clang_getCursorSpelling
955Cursor_spelling.argtypes = [Cursor]
956Cursor_spelling.restype = _CXString
957Cursor_spelling.errcheck = _CXString.from_result
958
959Cursor_loc = lib.clang_getCursorLocation
960Cursor_loc.argtypes = [Cursor]
961Cursor_loc.restype = SourceLocation
962
963Cursor_extent = lib.clang_getCursorExtent
964Cursor_extent.argtypes = [Cursor]
965Cursor_extent.restype = SourceRange
966
967Cursor_ref = lib.clang_getCursorReferenced
968Cursor_ref.argtypes = [Cursor]
969Cursor_ref.restype = Cursor
970Cursor_ref.errcheck = Cursor.from_result
971
972Cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
973Cursor_visit = lib.clang_visitChildren
974Cursor_visit.argtypes = [Cursor, Cursor_visit_callback, py_object]
975Cursor_visit.restype = c_uint
976
977# Index Functions
978Index_create = lib.clang_createIndex
979Index_create.argtypes = [c_int, c_int]
980Index_create.restype = c_object_p
981
982Index_dispose = lib.clang_disposeIndex
983Index_dispose.argtypes = [Index]
984
985# Translation Unit Functions
986TranslationUnit_read = lib.clang_createTranslationUnit
987TranslationUnit_read.argtypes = [Index, c_char_p]
988TranslationUnit_read.restype = c_object_p
989
990TranslationUnit_parse = lib.clang_createTranslationUnitFromSourceFile
991TranslationUnit_parse.argtypes = [Index, c_char_p, c_int, c_void_p,
992                                  c_int, c_void_p]
993TranslationUnit_parse.restype = c_object_p
994
995TranslationUnit_cursor = lib.clang_getTranslationUnitCursor
996TranslationUnit_cursor.argtypes = [TranslationUnit]
997TranslationUnit_cursor.restype = Cursor
998TranslationUnit_cursor.errcheck = Cursor.from_result
999
1000TranslationUnit_spelling = lib.clang_getTranslationUnitSpelling
1001TranslationUnit_spelling.argtypes = [TranslationUnit]
1002TranslationUnit_spelling.restype = _CXString
1003TranslationUnit_spelling.errcheck = _CXString.from_result
1004
1005TranslationUnit_dispose = lib.clang_disposeTranslationUnit
1006TranslationUnit_dispose.argtypes = [TranslationUnit]
1007
1008TranslationUnit_includes_callback = CFUNCTYPE(None,
1009                                              c_object_p,
1010                                              POINTER(SourceLocation),
1011                                              c_uint, py_object)
1012TranslationUnit_includes = lib.clang_getInclusions
1013TranslationUnit_includes.argtypes = [TranslationUnit,
1014                                     TranslationUnit_includes_callback,
1015                                     py_object]
1016
1017# File Functions
1018File_name = lib.clang_getFileName
1019File_name.argtypes = [File]
1020File_name.restype = c_char_p
1021
1022File_time = lib.clang_getFileTime
1023File_time.argtypes = [File]
1024File_time.restype = c_uint
1025
1026###
1027
1028__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind',
1029           'Diagnostic', 'FixIt', 'SourceRange', 'SourceLocation', 'File']
1030