blob: 394214c3a987a69b3cfb116fdbe8099fa2ed7ee7 [file] [log] [blame]
Daniel Dunbar30c0f262010-01-24 02:02:07 +00001# -*- coding: utf-8 -*-
2
3from ctypes import *
4
5def get_cindex_library():
6 # FIXME: It's probably not the case that the library is actually found in
7 # this location. We need a better system of identifying and loading the
8 # CIndex library. It could be on path or elsewhere, or versioned, etc.
9 import platform
10 name = platform.system()
11 if name == 'Darwin':
12 return cdll.LoadLibrary('libCIndex.dylib')
13 elif name == 'Windows':
14 return cdll.LoadLibrary('libCIndex.dll')
15 else:
16 return cdll.LoadLibrary('libCIndex.so')
17
18## Utility Types and Functions ##
19def alloc_string_vector(strs):
20 """
21 Allocate a string buffer large enough to accommodate the given list of
22 python strings.
23 """
24 n = 0
25 for i in strs: n += len(i) + 1
26 return create_string_buffer(n)
27
28def copy_string_vector(vec, strs):
29 """
30 Copy the contents of each string into the vector, preserving null
31 terminated elements.
32 """
33 n = 0
34 for i in strs:
35 # This is terribly inefficient, but I can't figure out how to copy a
36 # chunk of characters into the resultant vector. t should be: something
37 # like this: vec[n:n + len(i)] = i[:]; n += len(i) + 1
38 for j in i:
39 vec[n] = j
40 n += 1
41 n += 1
42
43def create_string_vector(strs):
44 """
45 Create a string vector (char *[]) from the given list of strings.
46 """
47 vec = alloc_string_vector(strs)
48 copy_string_vector(vec, strs)
49 return vec
50
51# Aliases for convenience
52c_int_p = POINTER(c_int)
53c_uint_p = POINTER(c_uint)
54c_bool = c_uint
55
56# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
57# object. This is a problem, because it means that from_parameter will see an
58# integer and pass the wrong value on platforms where int != void*. Work around
59# this by marshalling object arguments as void**.
60c_object_p = POINTER(c_void_p)
61
62lib = get_cindex_library()
63
64## Typedefs ##
65CursorKind = c_int
66
67### Structures and Utility Classes ###
68
69class String(Structure):
70 """
71 The String class is a simple wrapper around constant string data returned
72 from functions in the CIndex library.
73
74 String objects do not provide any of the operations that Python strings
75 support. However, these objects can be explicitly cast using the str()
76 function.
77 """
78 _fields_ = [("spelling", c_char_p), ("free", c_int)]
79
80 def __del__(self):
81 if self.free:
82 String_dispose(self)
83
84 def __str__(self):
85 return self.spelling
86
87class SourceLocation(Structure):
88 """
Daniel Dunbar149f38a2010-01-24 04:09:58 +000089 A SourceLocation represents a particular location within a source file.
Daniel Dunbar30c0f262010-01-24 02:02:07 +000090 """
91 _fields_ = [("ptr_data", c_void_p), ("int_data", c_uint)]
92
93 def init(self):
94 """
95 Initialize the source location, setting its file, line and column.
96 """
Daniel Dunbar7b48b352010-01-24 04:09:34 +000097 f, l, c = c_object_p(), c_uint(), c_uint()
Daniel Dunbar30c0f262010-01-24 02:02:07 +000098 SourceLocation_loc(self, byref(f), byref(l), byref(c))
Daniel Dunbar7b48b352010-01-24 04:09:34 +000099 f = File(f) if f else None
100 self.file, self.line, self.column = f, int(l.value), int(c.value)
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000101 return self
102
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000103 def __repr__(self):
104 return "<SourceLocation file %r, line %r, column %r>" % (
105 self.file.name if self.file else None, self.line, self.column)
106
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000107class SourceRange(Structure):
108 """
109 A SourceRange describes a range of source locations within the source
110 code.
111 """
112 _fields_ = [
113 ("ptr_data", c_void_p),
114 ("begin_int_data", c_uint),
115 ("end_int_data", c_uint)]
116
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000117 @property
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000118 def start(self):
119 """
120 Return a SourceLocation representing the first character within a
121 source range.
122 """
123 return SourceRange_start(self).init()
124
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000125 @property
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000126 def end(self):
127 """
128 Return a SourceLocation representing the last character within a
129 source range.
130 """
131 return SourceRange_end(self).init()
132
133class Cursor(Structure):
134 """
135 The Cursor class represents a reference to an element within the AST. It
136 acts as a kind of iterator.
137 """
138 _fields_ = [("kind", c_int), ("data", c_void_p * 3)]
139
140 def __eq__(self, other):
141 return Cursor_eq(self, other)
142
143 def __ne__(self, other):
144 return not Cursor_eq(self, other)
145
146 @staticmethod
147 def null():
148 """Return the null cursor object."""
149 return Cursor_null()
150
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000151 def is_declaration(self):
152 """Return True if the cursor points to a declaration."""
153 return Cursor_is_decl(self.kind)
154
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000155 def is_reference(self):
Daniel Dunbar149f38a2010-01-24 04:09:58 +0000156 """Return True if the cursor points to a reference."""
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000157 return Cursor_is_ref(self.kind)
158
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000159 def is_expression(self):
160 """Return True if the cursor points to an expression."""
161 return Cursor_is_expr(self.kind)
162
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000163 def is_statement(self):
164 """Return True if the cursor points to a statement."""
165 return Cursor_is_stmt(self.kind)
166
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000167 def is_translation_unit(self):
168 """Return True if the cursor points to a translation unit."""
169 return Cursor_is_tu(self.kind)
170
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000171 def is_invalid(self):
172 """Return True if the cursor points to an invalid entity."""
173 return Cursor_is_inv(self.kind)
174
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000175 def is_definition(self):
176 """
177 Returns true if the declaration pointed at by the cursor is also a
178 definition of that entity.
179 """
180 return Cursor_is_def(self)
181
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000182 def get_definition(self):
183 """
184 If the cursor is a reference to a declaration or a declaration of
185 some entity, return a cursor that points to the definition of that
186 entity.
187 """
188 # TODO: Should probably check that this is either a reference or
189 # declaration prior to issuing the lookup.
190 return Cursor_def(self)
191
192 @property
193 def spelling(self):
194 """Return the spelling of the entity pointed at by the cursor."""
Daniel Dunbaraa229842010-01-24 04:09:23 +0000195 if not self.is_declaration():
196 # FIXME: This should be documented in Index.h
197 raise ValueError("Cursor does not refer to a Declaration")
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000198 return Cursor_spelling(self)
199
200 @property
201 def location(self):
202 """
203 Return the source location (the starting character) of the entity
204 pointed at by the cursor.
205 """
206 return Cursor_loc(self).init()
207
208 @property
209 def extent(self):
210 """
211 Return the source range (the range of text) occupied by the entity
212 pointed at by the cursor.
213 """
214 return Cursor_extent(self)
215
216 @property
217 def file(self):
218 """
219 Return the file containing the pointed-at entity. This is an alias for
220 location.file.
221 """
222 return self.location.file
223
Daniel Dunbarde3b8e52010-01-24 04:10:22 +0000224 def get_children(self):
225 """Return an iterator for the accessing children of this cursor."""
226
227 # FIXME: Expose iteration from CIndex, PR6125.
228 def visitor(child, parent, children):
229 children.append(child)
230 return 1 # continue
231 children = []
232 Cursor_visit(self, Callback(visitor), children)
233 return iter(children)
234
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000235## CIndex Objects ##
236
237# CIndex objects (derived from ClangObject) are essentially lightweight
238# wrappers attached to some underlying object, which is exposed via CIndex as
239# a void*.
240
241class ClangObject(object):
242 """
243 A helper for Clang objects. This class helps act as an intermediary for
244 the ctypes library and the Clang CIndex library.
245 """
246 def __init__(self, obj):
247 assert isinstance(obj, c_object_p) and obj
248 self.obj = self._as_parameter_ = obj
249
250 def from_param(self):
251 return self._as_parameter_
252
253class Index(ClangObject):
254 """
255 The Index type provides the primary interface to the Clang CIndex library,
256 primarily by providing an interface for reading and parsing translation
257 units.
258 """
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000259
260 @staticmethod
261 def create(excludeDecls=False, displayDiags=False):
262 """
263 Create a new Index.
264 Parameters:
265 excludeDecls -- Exclude local declarations from translation units.
266 displayDiags -- Display diagnostics during translation unit creation.
267 """
268 return Index(Index_create(excludeDecls, displayDiags))
269
270 def __del__(self):
271 Index_dispose(self)
272
273 def read(self, path):
274 """Load the translation unit from the given AST file."""
275 return TranslationUnit.read(self, path)
276
277 def parse(self, path, args = []):
278 """
279 Load the translation unit from the given source code file by running
280 clang and generating the AST before loading. Additional command line
281 parameters can be passed to clang via the args parameter.
282 """
283 return TranslationUnit.parse(self, path, args)
284
285
286class TranslationUnit(ClangObject):
287 """
288 The TranslationUnit class represents a source code translation unit and
289 provides read-only access to its top-level declarations.
290 """
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000291
292 def __del__(self):
Daniel Dunbar99d593e2010-01-24 04:09:51 +0000293 TranslationUnit_dispose(self)
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000294
Daniel Dunbar1b945a72010-01-24 04:09:43 +0000295 @property
296 def cursor(self):
297 """Retrieve the cursor that represents the given translation unit."""
298 return TranslationUnit_cursor(self)
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000299
300 @property
301 def spelling(self):
Daniel Dunbar1b945a72010-01-24 04:09:43 +0000302 """Get the original translation unit source file name."""
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000303 return TranslationUnit_spelling(self)
304
305 @staticmethod
306 def read(ix, path):
307 """Create a translation unit from the given AST file."""
308 ptr = TranslationUnit_read(ix, path)
Daniel Dunbar99d593e2010-01-24 04:09:51 +0000309 return TranslationUnit(ptr) if ptr else None
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000310
311 @staticmethod
312 def parse(ix, path, args = []):
313 """
314 Construct a translation unit from the given source file, applying
315 the given command line argument.
316 """
317 # TODO: Support unsaved files.
318 argc, argv = len(args), create_string_vector(args)
319 ptr = TranslationUnit_parse(ix, path, argc, byref(argv), 0, 0)
Daniel Dunbar99d593e2010-01-24 04:09:51 +0000320 return TranslationUnit(ptr) if ptr else None
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000321
322class File(ClangObject):
323 """
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000324 The File class represents a particular source file that is part of a
325 translation unit.
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000326 """
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000327
328 @property
329 def name(self):
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000330 """Return the complete file and path name of the file, if valid."""
331 return File_name(self)
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000332
333 @property
334 def time(self):
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000335 """Return the last modification time of the file, if valid."""
336 return File_time(self)
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000337
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000338# Additional Functions and Types
339
Daniel Dunbarde3b8e52010-01-24 04:10:22 +0000340# Wrap calls to TranslationUnit._load and Decl._load.
341Callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000342
343# String Functions
344String_dispose = lib.clang_disposeString
345String_dispose.argtypes = [String]
346
347# Source Location Functions
348SourceLocation_loc = lib.clang_getInstantiationLocation
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000349SourceLocation_loc.argtypes = [SourceLocation, POINTER(c_object_p), c_uint_p,
350 c_uint_p]
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000351
352# Source Range Functions
353SourceRange_start = lib.clang_getRangeStart
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000354SourceRange_start.argtypes = [SourceRange]
355SourceRange_start.restype = SourceLocation
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000356
357SourceRange_end = lib.clang_getRangeEnd
Daniel Dunbar7b48b352010-01-24 04:09:34 +0000358SourceRange_end.argtypes = [SourceRange]
359SourceRange_end.restype = SourceLocation
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000360
361# Cursor Functions
362# TODO: Implement this function
363Cursor_get = lib.clang_getCursor
Daniel Dunbarde3b8e52010-01-24 04:10:22 +0000364Cursor_get.argtypes = [TranslationUnit, SourceLocation]
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000365Cursor.restype = Cursor
366
367Cursor_null = lib.clang_getNullCursor
368Cursor_null.restype = Cursor
369
370Cursor_kind = lib.clang_getCursorKind
371Cursor_kind.argtypes = [Cursor]
372Cursor_kind.res = c_int
373
374# FIXME: Not really sure what a USR is or what this function actually does...
375Cursor_usr = lib.clang_getCursorUSR
376
377Cursor_is_decl = lib.clang_isDeclaration
378Cursor_is_decl.argtypes = [CursorKind]
379Cursor_is_decl.restype = c_bool
380
381Cursor_is_ref = lib.clang_isReference
382Cursor_is_ref.argtypes = [CursorKind]
383Cursor_is_ref.restype = c_bool
384
385Cursor_is_expr = lib.clang_isExpression
386Cursor_is_expr.argtypes = [CursorKind]
387Cursor_is_expr.restype = c_bool
388
389Cursor_is_stmt = lib.clang_isStatement
390Cursor_is_stmt.argtypes = [CursorKind]
391Cursor_is_stmt.restype = c_bool
392
393Cursor_is_inv = lib.clang_isInvalid
394Cursor_is_inv.argtypes = [CursorKind]
395Cursor_is_inv.restype = c_bool
396
397Cursor_is_tu = lib.clang_isTranslationUnit
398Cursor_is_tu.argtypes = [CursorKind]
399Cursor_is_tu.restype = c_bool
400
401Cursor_is_def = lib.clang_isCursorDefinition
402Cursor_is_def.argtypes = [Cursor]
403Cursor_is_def.restype = c_bool
404
405Cursor_def = lib.clang_getCursorDefinition
406Cursor_def.argtypes = [Cursor]
407Cursor_def.restype = Cursor
408
409Cursor_eq = lib.clang_equalCursors
410Cursor_eq.argtypes = [Cursor, Cursor]
411Cursor_eq.restype = c_uint
412
413Cursor_spelling = lib.clang_getCursorSpelling
414Cursor_spelling.argtypes = [Cursor]
415Cursor_spelling.restype = String
416
417Cursor_loc = lib.clang_getCursorLocation
418Cursor_loc.argtypes = [Cursor]
419Cursor_loc.restype = SourceLocation
420
421Cursor_extent = lib.clang_getCursorExtent
422Cursor_extent.argtypes = [Cursor]
423Cursor_extent.restype = SourceRange
424
425Cursor_ref = lib.clang_getCursorReferenced
426Cursor_ref.argtypes = [Cursor]
427Cursor_ref.restype = Cursor
428
Daniel Dunbarde3b8e52010-01-24 04:10:22 +0000429Cursor_visit = lib.clang_visitChildren
430Cursor_visit.argtypes = [Cursor, Callback, py_object]
431Cursor_visit.restype = c_uint
432
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000433# Index Functions
434Index_create = lib.clang_createIndex
435Index_create.argtypes = [c_int, c_int]
436Index_create.restype = c_object_p
437
438Index_dispose = lib.clang_disposeIndex
439Index_dispose.argtypes = [Index]
440
441# Translation Unit Functions
442TranslationUnit_read = lib.clang_createTranslationUnit
443TranslationUnit_read.argtypes = [Index, c_char_p]
444TranslationUnit_read.restype = c_object_p
445
446TranslationUnit_parse = lib.clang_createTranslationUnitFromSourceFile
447TranslationUnit_parse.argtypes = [Index, c_char_p, c_int, c_void_p,
448 c_int, c_void_p]
449TranslationUnit_parse.restype = c_object_p
450
Daniel Dunbar1b945a72010-01-24 04:09:43 +0000451TranslationUnit_cursor = lib.clang_getTranslationUnitCursor
452TranslationUnit_cursor.argtypes = [TranslationUnit]
453TranslationUnit_cursor.restype = Cursor
454
Daniel Dunbar30c0f262010-01-24 02:02:07 +0000455TranslationUnit_spelling = lib.clang_getTranslationUnitSpelling
456TranslationUnit_spelling.argtypes = [TranslationUnit]
457TranslationUnit_spelling.restype = String
458
459TranslationUnit_dispose = lib.clang_disposeTranslationUnit
460TranslationUnit_dispose.argtypes = [TranslationUnit]
461
462# File Functions
463File_name = lib.clang_getFileName
464File_name.argtypes = [File]
465File_name.restype = c_char_p
466
467File_time = lib.clang_getFileTime
468File_time.argtypes = [File]
469File_time.restype = c_uint