ffi-clang 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/ext/rakefile.rb +2 -2
  4. data/lib/ffi/clang/clang_version.rb +7 -3
  5. data/lib/ffi/clang/code_completion.rb +121 -44
  6. data/lib/ffi/clang/comment.rb +164 -57
  7. data/lib/ffi/clang/compilation_database.rb +79 -25
  8. data/lib/ffi/clang/cursor.rb +395 -149
  9. data/lib/ffi/clang/diagnostic.rb +57 -23
  10. data/lib/ffi/clang/error.rb +12 -0
  11. data/lib/ffi/clang/file.rb +30 -11
  12. data/lib/ffi/clang/index.rb +37 -13
  13. data/lib/ffi/clang/lib/clang_version.rb +2 -2
  14. data/lib/ffi/clang/lib/code_completion.rb +15 -11
  15. data/lib/ffi/clang/lib/comment.rb +16 -14
  16. data/lib/ffi/clang/lib/compilation_database.rb +5 -5
  17. data/lib/ffi/clang/lib/cursor.rb +74 -56
  18. data/lib/ffi/clang/lib/diagnostic.rb +14 -14
  19. data/lib/ffi/clang/lib/file.rb +10 -6
  20. data/lib/ffi/clang/lib/inclusions.rb +3 -3
  21. data/lib/ffi/clang/lib/index.rb +7 -5
  22. data/lib/ffi/clang/lib/printing_policy.rb +36 -36
  23. data/lib/ffi/clang/lib/source_location.rb +9 -7
  24. data/lib/ffi/clang/lib/source_range.rb +5 -3
  25. data/lib/ffi/clang/lib/string.rb +9 -4
  26. data/lib/ffi/clang/lib/token.rb +17 -4
  27. data/lib/ffi/clang/lib/translation_unit.rb +17 -13
  28. data/lib/ffi/clang/lib/type.rb +19 -17
  29. data/lib/ffi/clang/lib.rb +35 -19
  30. data/lib/ffi/clang/platform.rb +25 -0
  31. data/lib/ffi/clang/printing_policy.rb +31 -18
  32. data/lib/ffi/clang/source_location.rb +119 -36
  33. data/lib/ffi/clang/source_range.rb +30 -12
  34. data/lib/ffi/clang/token.rb +48 -23
  35. data/lib/ffi/clang/translation_unit.rb +97 -33
  36. data/lib/ffi/clang/types/array.rb +15 -1
  37. data/lib/ffi/clang/types/elaborated.rb +19 -4
  38. data/lib/ffi/clang/types/function.rb +35 -10
  39. data/lib/ffi/clang/types/pointer.rb +23 -7
  40. data/lib/ffi/clang/types/record.rb +23 -8
  41. data/lib/ffi/clang/types/type.rb +80 -36
  42. data/lib/ffi/clang/types/type_def.rb +14 -2
  43. data/lib/ffi/clang/types/vector.rb +13 -1
  44. data/lib/ffi/clang/unsaved_file.rb +18 -8
  45. data/lib/ffi/clang/version.rb +4 -2
  46. data/lib/ffi/clang.rb +23 -45
  47. data/license.md +3 -2
  48. data/readme.md +12 -13
  49. data/releases.md +5 -0
  50. data.tar.gz.sig +0 -0
  51. metadata +10 -5
  52. metadata.gz.sig +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2013, by Garry Marshall.
5
- # Copyright, 2013-2024, by Samuel Williams.
5
+ # Copyright, 2013-2025, by Samuel Williams.
6
6
  # Copyright, 2013, by Carlos Martín Nieto.
7
7
  # Copyright, 2013, by Dave Wilkinson.
8
8
  # Copyright, 2013, by Takeshi Watanabe.
@@ -11,139 +11,216 @@
11
11
  # Copyright, 2014, by Niklas Therning.
12
12
  # Copyright, 2019, by Michael Metivier.
13
13
  # Copyright, 2022, by Motonori Iwamuro.
14
- # Copyright, 2023-2024, by Charlie Savage.
14
+ # Copyright, 2023-2025, by Charlie Savage.
15
15
 
16
- require_relative 'lib/cursor'
17
- require_relative 'lib/code_completion'
16
+ require_relative "lib/cursor"
17
+ require_relative "lib/code_completion"
18
18
 
19
- require_relative 'printing_policy'
20
- require_relative 'source_location'
21
- require_relative 'source_range'
22
- require_relative 'comment'
19
+ require_relative "printing_policy"
20
+ require_relative "source_location"
21
+ require_relative "source_range"
22
+ require_relative "comment"
23
23
 
24
24
  module FFI
25
25
  module Clang
26
+ # Represents a cursor in the abstract syntax tree (AST).
26
27
  class Cursor
27
28
  include Enumerable
28
-
29
+
30
+ # @attribute [FFI::Lib::CXCursor] The underlying libclang cursor structure.
29
31
  attr_reader :cursor
32
+
33
+ # @attribute [TranslationUnit] The translation unit this cursor belongs to.
30
34
  attr_reader :translation_unit
31
-
35
+
36
+ # Get a null cursor.
37
+ # @returns [Cursor] A null cursor instance.
32
38
  def self.null_cursor
33
39
  Cursor.new Lib.get_null_cursor, nil
34
40
  end
35
-
36
- # this function is categorized as "Debugging facilities"
41
+
42
+ # Get the spelling of a cursor kind.
43
+ # @parameter kind [Symbol] The cursor kind.
44
+ # @returns [String] The string representation of the cursor kind.
37
45
  def self.kind_spelling(kind)
38
46
  Lib.extract_string Lib.get_cursor_kind_spelling(kind)
39
47
  end
40
-
48
+
49
+ # Initialize a cursor with a libclang cursor structure.
50
+ # @parameter cxcursor [Lib::CXCursor] The libclang cursor.
51
+ # @parameter translation_unit [TranslationUnit] The parent translation unit.
41
52
  def initialize(cxcursor, translation_unit)
42
53
  @cursor = cxcursor
43
54
  @translation_unit = translation_unit
44
55
  end
45
-
56
+
57
+ # Check if this cursor is null.
58
+ # @returns [Boolean] True if the cursor is null.
46
59
  def null?
47
60
  Lib.cursor_is_null(@cursor) != 0
48
61
  end
49
-
62
+
63
+ # Get the raw comment text associated with this cursor.
64
+ # @returns [String] The raw comment text.
50
65
  def raw_comment_text
51
66
  Lib.extract_string Lib.cursor_get_raw_comment_text(@cursor)
52
67
  end
53
-
68
+
69
+ # Get the parsed comment associated with this cursor.
70
+ # @returns [Comment] The parsed comment structure.
54
71
  def comment
55
72
  Comment.build_from Lib.cursor_get_parsed_comment(@cursor)
56
73
  end
57
-
74
+
75
+ # Get the source range of the comment.
76
+ # @returns [SourceRange] The comment source range.
58
77
  def comment_range
59
78
  SourceRange.new(Lib.cursor_get_comment_range(@cursor))
60
79
  end
61
-
80
+
81
+ # Get the code completion string for this cursor.
82
+ # @returns [CodeCompletion::String] The completion string.
62
83
  def completion
63
84
  CodeCompletion::String.new Lib.get_cursor_completion_string(@cursor)
64
85
  end
65
-
86
+
87
+ # Check if this cursor is anonymous.
88
+ # @returns [Boolean] True if the cursor is anonymous.
66
89
  def anonymous?
67
90
  Lib.cursor_is_anonymous(@cursor) != 0
68
91
  end
69
-
92
+
93
+ # Check if this cursor is an anonymous record declaration.
94
+ # @returns [Boolean] True if it's an anonymous record declaration.
70
95
  def anonymous_record_declaration?
71
96
  Lib.cursor_is_anonymous_record_decl(@cursor) != 0
72
97
  end
73
-
98
+
99
+ # Check if this cursor is a declaration.
100
+ # @returns [Boolean] True if it's a declaration.
74
101
  def declaration?
75
102
  Lib.is_declaration(kind) != 0
76
103
  end
77
-
104
+
105
+ # Check if this cursor is a reference.
106
+ # @returns [Boolean] True if it's a reference.
78
107
  def reference?
79
108
  Lib.is_reference(kind) != 0
80
109
  end
81
-
110
+
111
+ # Check if this cursor is an expression.
112
+ # @returns [Boolean] True if it's an expression.
82
113
  def expression?
83
114
  Lib.is_expression(kind) != 0
84
115
  end
85
-
116
+
117
+ # Check if this cursor is a statement.
118
+ # @returns [Boolean] True if it's a statement.
86
119
  def statement?
87
120
  Lib.is_statement(kind) != 0
88
121
  end
89
-
122
+
123
+ # Check if this cursor is an attribute.
124
+ # @returns [Boolean] True if it's an attribute.
90
125
  def attribute?
91
126
  Lib.is_attribute(kind) != 0
92
127
  end
93
-
128
+
129
+ # Check if this cursor has public access.
130
+ # @returns [Boolean] True if the cursor is public.
94
131
  def public?
95
132
  Lib.cxx_get_access_specifier(@cursor) == :public
96
133
  end
97
-
134
+
135
+ # Check if this cursor has private access.
136
+ # @returns [Boolean] True if the cursor is private.
98
137
  def private?
99
138
  Lib.cxx_get_access_specifier(@cursor) == :private
100
139
  end
101
-
140
+
141
+ # Check if this cursor has protected access.
142
+ # @returns [Boolean] True if the cursor is protected.
102
143
  def protected?
103
144
  Lib.cxx_get_access_specifier(@cursor) == :protected
104
145
  end
105
-
146
+
147
+ # Check if this cursor is invalid.
148
+ # @returns [Boolean] True if the cursor is invalid.
106
149
  def invalid?
107
150
  Lib.is_invalid(kind) != 0
108
151
  end
109
-
152
+
153
+ # Check if this cursor is a translation unit.
154
+ # @returns [Boolean] True if it's a translation unit.
110
155
  def translation_unit?
111
156
  Lib.is_translation_unit(kind) != 0
112
157
  end
113
-
158
+
159
+ # Check if this cursor is a preprocessing directive.
160
+ # @returns [Boolean] True if it's a preprocessing directive.
114
161
  def preprocessing?
115
162
  Lib.is_preprocessing(kind) != 0
116
163
  end
117
-
164
+
165
+ # Check if this cursor is unexposed.
166
+ # @returns [Boolean] True if the cursor is unexposed.
118
167
  def unexposed?
119
168
  Lib.is_unexposed(kind) != 0
120
169
  end
121
-
170
+
171
+ # Get the expansion location of this cursor.
172
+ # @returns [ExpansionLocation] The expansion location.
122
173
  def expansion_location
123
174
  ExpansionLocation.new(Lib.get_cursor_location(@cursor))
124
175
  end
125
176
  alias :location :expansion_location
126
-
177
+
178
+ # Get the presumed location of this cursor.
179
+ # @returns [PresumedLocation] The presumed location.
127
180
  def presumed_location
128
181
  PresumedLocation.new(Lib.get_cursor_location(@cursor))
129
182
  end
130
-
183
+
184
+ # Get the spelling location of this cursor.
185
+ # @returns [SpellingLocation] The spelling location.
131
186
  def spelling_location
132
187
  SpellingLocation.new(Lib.get_cursor_location(@cursor))
133
188
  end
134
-
189
+
190
+ # Get the file location of this cursor.
191
+ # @returns [FileLocation] The file location.
135
192
  def file_location
136
193
  FileLocation.new(Lib.get_cursor_location(@cursor))
137
194
  end
138
-
195
+
196
+ # Get the source extent of this cursor.
197
+ # @returns [SourceRange] The source extent.
139
198
  def extent
140
199
  SourceRange.new(Lib.get_cursor_extent(@cursor))
141
200
  end
142
-
201
+
202
+ # Get the display name of this cursor.
203
+ # @returns [String] The display name.
143
204
  def display_name
144
205
  Lib.extract_string Lib.get_cursor_display_name(@cursor)
145
206
  end
146
-
207
+
208
+ # Get the qualified display name including parent scope.
209
+ # @returns [String | Nil] The qualified display name, or `nil` for translation units.
210
+ # @raises [ArgumentError] If the semantic parent is invalid.
211
+ def qualified_display_name
212
+ if self.kind != :cursor_translation_unit
213
+ if self.semantic_parent.kind == :cursor_invalid_file
214
+ raise(ArgumentError, "Invalid semantic parent: #{self}")
215
+ end
216
+ result = self.semantic_parent.qualified_display_name
217
+ result ? "#{result}::#{self.display_name}" : self.display_name
218
+ end
219
+ end
220
+
221
+ # Get the fully qualified name of this cursor.
222
+ # @returns [String | Nil] The qualified name, or `nil` for translation units.
223
+ # @raises [ArgumentError] If the semantic parent is invalid.
147
224
  def qualified_name
148
225
  if self.kind != :cursor_translation_unit
149
226
  if self.semantic_parent.kind == :cursor_invalid_file
@@ -153,96 +230,142 @@ module FFI
153
230
  result ? "#{result}::#{self.spelling}" : self.spelling
154
231
  end
155
232
  end
156
-
233
+
234
+ # Get the spelling (name) of this cursor.
235
+ # @returns [String] The cursor spelling.
157
236
  def spelling
158
237
  Lib.extract_string Lib.get_cursor_spelling(@cursor)
159
238
  end
160
-
239
+
240
+ # Get the printing policy for this cursor.
241
+ # @returns [PrintingPolicy] The printing policy.
161
242
  def printing_policy
162
243
  PrintingPolicy.new(cursor)
163
244
  end
164
-
245
+
246
+ # Get the Unified Symbol Resolution (USR) for this cursor.
247
+ # @returns [String] The USR string.
165
248
  def usr
166
249
  Lib.extract_string Lib.get_cursor_usr(@cursor)
167
250
  end
168
-
251
+
252
+ # Get the kind of this cursor.
253
+ # @returns [Symbol | Nil] The cursor kind.
169
254
  def kind
170
255
  @cursor ? @cursor[:kind] : nil
171
256
  end
172
-
257
+
258
+ # Get the spelling of the cursor kind.
259
+ # @returns [String] The cursor kind spelling.
173
260
  def kind_spelling
174
261
  Cursor.kind_spelling @cursor[:kind]
175
262
  end
176
-
263
+
264
+ # Get the type of this cursor.
265
+ # @returns [Types::Type] The cursor type.
177
266
  def type
178
267
  Types::Type.create Lib.get_cursor_type(@cursor), @translation_unit
179
268
  end
180
-
269
+
270
+ # Get the result type for a function cursor.
271
+ # @returns [Types::Type] The result type.
181
272
  def result_type
182
273
  Types::Type.create Lib.get_cursor_result_type(@cursor), @translation_unit
183
274
  end
184
-
275
+
276
+ # Get the underlying type for a typedef cursor.
277
+ # @returns [Types::Type] The underlying type.
185
278
  def underlying_type
186
279
  Types::Type.create Lib.get_typedef_decl_underlying_type(@cursor), @translation_unit
187
280
  end
188
-
281
+
282
+ # Check if this cursor is a virtual base class.
283
+ # @returns [Boolean] True if it's a virtual base.
189
284
  def virtual_base?
190
285
  Lib.is_virtual_base(@cursor) != 0
191
286
  end
192
-
287
+
288
+ # Check if this cursor is a dynamic call.
289
+ # @returns [Boolean] True if it's a dynamic call.
193
290
  def dynamic_call?
194
291
  Lib.is_dynamic_call(@cursor) != 0
195
292
  end
196
-
293
+
294
+ # Check if this cursor is variadic.
295
+ # @returns [Boolean] True if the cursor is variadic.
197
296
  def variadic?
198
297
  Lib.is_variadic(@cursor) != 0
199
298
  end
200
-
299
+
300
+ # Check if this cursor is a definition.
301
+ # @returns [Boolean] True if the cursor is a definition.
201
302
  def definition?
202
303
  Lib.is_definition(@cursor) != 0
203
304
  end
204
-
305
+
306
+ # Check if this is a static method.
307
+ # @returns [Boolean] True if the method is static.
205
308
  def static?
206
309
  Lib.cxx_method_is_static(@cursor) != 0
207
310
  end
208
-
311
+
312
+ # Check if this is a virtual method.
313
+ # @returns [Boolean] True if the method is virtual.
209
314
  def virtual?
210
315
  Lib.cxx_method_is_virtual(@cursor) != 0
211
316
  end
212
-
317
+
318
+ # Check if this is a pure virtual method.
319
+ # @returns [Boolean] True if the method is pure virtual.
213
320
  def pure_virtual?
214
321
  Lib.cxx_method_is_pure_virtual(@cursor) != 0
215
322
  end
216
-
323
+
324
+ # Get the value of an enum constant.
325
+ # @returns [Integer] The enum value.
217
326
  def enum_value
218
327
  Lib.get_enum_value @cursor
219
328
  end
220
-
329
+
330
+ # Get the unsigned value of an enum constant.
331
+ # @returns [Integer] The unsigned enum value.
221
332
  def enum_unsigned_value
222
333
  Lib.get_enum_unsigned_value @cursor
223
334
  end
224
-
335
+
336
+ # Get the integer type of an enum declaration.
337
+ # @returns [Types::Type] The enum's underlying integer type.
225
338
  def enum_type
226
339
  Types::Type.create Lib.get_enum_decl_integer_type(@cursor), @translation_unit
227
340
  end
228
-
341
+
342
+ # Get the template that this cursor specializes.
343
+ # @returns [Cursor] The specialized template cursor.
229
344
  def specialized_template
230
345
  Cursor.new Lib.get_specialized_cursor_template(@cursor), @translation_unit
231
346
  end
232
-
347
+
348
+ # Get the canonical cursor for this cursor.
349
+ # @returns [Cursor] The canonical cursor.
233
350
  def canonical
234
351
  Cursor.new Lib.get_canonical_cursor(@cursor), @translation_unit
235
352
  end
236
-
353
+
354
+ # Get the definition cursor for this cursor.
355
+ # @returns [Cursor] The definition cursor.
237
356
  def definition
238
357
  Cursor.new Lib.get_cursor_definition(@cursor), @translation_unit
239
358
  end
240
-
359
+
360
+ # Check if this is an opaque declaration without a definition.
361
+ # @returns [Boolean] True if it's an opaque declaration.
241
362
  def opaque_declaration?
242
363
  # Is this a declaration that does not have a definition in the translation unit
243
364
  self.declaration? && !self.definition? && self.definition.invalid?
244
365
  end
245
-
366
+
367
+ # Check if this is a forward declaration.
368
+ # @returns [Boolean] True if it's a forward declaration.
246
369
  def forward_declaration?
247
370
  # Is this a forward declaration for a definition contained in the same translation_unit?
248
371
  # https://joshpeterson.github.io/identifying-a-forward-declaration-with-libclang
@@ -252,77 +375,109 @@ module FFI
252
375
  # !self.definition? && self.definition
253
376
  self.declaration? && !self.eql?(self.definition) && !self.definition.invalid?
254
377
  end
255
-
378
+
379
+ # Get the cursor referenced by this cursor.
380
+ # @returns [Cursor] The referenced cursor.
256
381
  def referenced
257
382
  Cursor.new Lib.get_cursor_referenced(@cursor), @translation_unit
258
383
  end
259
-
384
+
385
+ # Get the semantic parent of this cursor.
386
+ # @returns [Cursor] The semantic parent cursor.
260
387
  def semantic_parent
261
388
  Cursor.new Lib.get_cursor_semantic_parent(@cursor), @translation_unit
262
389
  end
263
-
390
+
391
+ # Get the lexical parent of this cursor.
392
+ # @returns [Cursor] The lexical parent cursor.
264
393
  def lexical_parent
265
394
  Cursor.new Lib.get_cursor_lexical_parent(@cursor), @translation_unit
266
395
  end
267
-
396
+
397
+ # Get the template cursor kind.
398
+ # @returns [Symbol] The template cursor kind.
268
399
  def template_kind
269
400
  Lib.get_template_cursor_kind @cursor
270
401
  end
271
-
402
+
403
+ # Get the C++ access specifier.
404
+ # @returns [Symbol] The access specifier (`:public`, `:private`, or `:protected`).
272
405
  def access_specifier
273
406
  Lib.get_cxx_access_specifier @cursor
274
407
  end
275
-
408
+
409
+ # Get the programming language of this cursor.
410
+ # @returns [Symbol] The language symbol.
276
411
  def language
277
412
  Lib.get_language @cursor
278
413
  end
279
-
414
+
415
+ # Get the number of arguments for this cursor.
416
+ # @returns [Integer] The number of arguments.
280
417
  def num_args
281
418
  Lib.get_num_args @cursor
282
419
  end
283
-
420
+
421
+ # Iterate over child cursors.
422
+ # @parameter recurse [Boolean] Whether to recurse into children by default.
423
+ # @yields {|cursor, parent| ...} Each child cursor with its parent.
424
+ # @parameter cursor [Cursor] The child cursor.
425
+ # @parameter parent [Cursor] The parent cursor.
426
+ # @returns [Enumerator] If no block is given.
284
427
  def each(recurse = true, &block)
285
428
  return to_enum(:each, recurse) unless block_given?
286
-
429
+
287
430
  adapter = Proc.new do |cxcursor, parent_cursor, unused|
288
431
  # Call the block and capture the result. This lets advanced users
289
432
  # modify the recursion on a case by case basis if needed
290
433
  result = block.call Cursor.new(cxcursor, @translation_unit), Cursor.new(parent_cursor, @translation_unit)
291
434
  case result
292
- when :continue
293
- :continue
294
- when :recurse
295
- :recurse
296
- else
297
- recurse ? :recurse : :continue
435
+ when :continue
436
+ :continue
437
+ when :recurse
438
+ :recurse
439
+ else
440
+ recurse ? :recurse : :continue
298
441
  end
299
442
  end
300
-
443
+
301
444
  Lib.visit_children(@cursor, adapter, nil)
302
445
  end
303
-
446
+
447
+ # Visit only direct children without recursing.
448
+ # @yields {|cursor, parent| ...} Each direct child cursor.
449
+ # @parameter cursor [Cursor] The child cursor.
450
+ # @parameter parent [Cursor] The parent cursor.
304
451
  def visit_children(&block)
305
452
  each(false, &block)
306
453
  end
307
-
308
- def ancestors_by_kind(*kinds)
309
- result = Array.new
310
-
311
- parent = self
312
- while parent != self.semantic_parent
313
- parent = self.semantic_parent
314
- if kinds.include?(parent.kind)
315
- result << parent
316
- end
317
- end
318
- result
319
- end
320
-
454
+
455
+ # Find ancestors of this cursor by kind.
456
+ # @parameter kinds [Array(Symbol)] The cursor kinds to search for.
457
+ # @returns [Array(Cursor)] Array of ancestor cursors matching the kinds.
458
+ def ancestors_by_kind(*kinds)
459
+ result = Array.new
460
+
461
+ parent = self
462
+ while parent != self.semantic_parent
463
+ parent = self.semantic_parent
464
+ if kinds.include?(parent.kind)
465
+ result << parent
466
+ end
467
+ end
468
+ result
469
+ end
470
+
471
+ # Find child cursors by kind.
472
+ # @parameter recurse [Boolean | Nil] Whether to recurse into children.
473
+ # @parameter kinds [Array(Symbol)] The cursor kinds to search for.
474
+ # @returns [Array(Cursor)] Array of matching cursors.
475
+ # @raises [RuntimeError] If recurse parameter is not nil or boolean.
321
476
  def find_by_kind(recurse, *kinds)
322
- unless (recurse == nil || recurse == true || recurse == false)
323
- raise("Recurse parameter must be nil or a boolean value. Value was: #{recurse}")
324
- end
325
-
477
+ unless (recurse == nil || recurse == true || recurse == false)
478
+ raise("Recurse parameter must be nil or a boolean value. Value was: #{recurse}")
479
+ end
480
+
326
481
  result = Array.new
327
482
  self.each(recurse) do |child, parent|
328
483
  if kinds.include?(child.kind)
@@ -331,55 +486,70 @@ module FFI
331
486
  end
332
487
  result
333
488
  end
334
-
489
+
490
+ # Find all references to this cursor in a file.
491
+ # @parameter file [String | Nil] The file path, or `nil` to use the translation unit file.
492
+ # @yields {|cursor, range| ...} Each reference with its cursor and source range.
493
+ # @parameter cursor [Cursor] The reference cursor.
494
+ # @parameter range [SourceRange] The source range of the reference.
335
495
  def find_references_in_file(file = nil, &block)
336
496
  file ||= Lib.extract_string Lib.get_translation_unit_spelling(@translation_unit)
337
-
497
+
338
498
  visit_adapter = Proc.new do |unused, cxcursor, cxsource_range|
339
499
  block.call Cursor.new(cxcursor, @translation_unit), SourceRange.new(cxsource_range)
340
500
  end
341
501
  visitor = FFI::Clang::Lib::CXCursorAndRangeVisitor.new
342
502
  visitor[:visit] = visit_adapter
343
-
503
+
344
504
  Lib.find_references_in_file(@cursor, Lib.get_file(@translation_unit, file), visitor)
345
505
  end
346
-
506
+
507
+ # Get the linkage of this cursor.
508
+ # @returns [Symbol] The linkage kind.
347
509
  def linkage
348
510
  Lib.get_cursor_linkage(@cursor)
349
511
  end
350
-
512
+
513
+ # Get the exception specification type for this cursor.
514
+ # @returns [Symbol] The exception specification type.
351
515
  def exception_specification
352
516
  Lib.get_cursor_exception_specification_type(@cursor)
353
517
  end
354
-
518
+
519
+ # Get the availability of this cursor.
520
+ # @returns [Symbol] The availability status.
355
521
  def availability
356
522
  Lib.get_cursor_availability(@cursor)
357
523
  end
358
-
524
+
525
+ # Get the file included by this cursor.
526
+ # @returns [File] The included file.
359
527
  def included_file
360
528
  File.new Lib.get_included_file(@cursor), @translation_unit
361
529
  end
362
-
530
+
531
+ # Get platform availability information for this cursor.
532
+ # @parameter max_availability_size [Integer] Maximum number of platforms to query.
533
+ # @returns [Hash] Platform availability information.
363
534
  def platform_availability(max_availability_size = 4)
364
535
  availability_ptr = FFI::MemoryPointer.new(Lib::CXPlatformAvailability, max_availability_size)
365
536
  always_deprecated_ptr = FFI::MemoryPointer.new :int
366
537
  always_unavailable_ptr = FFI::MemoryPointer.new :int
367
538
  deprecated_message_ptr = FFI::MemoryPointer.new Lib::CXString
368
539
  unavailable_message_ptr = FFI::MemoryPointer.new Lib::CXString
369
-
540
+
370
541
  actual_availability_size = Lib.get_cursor_platform_availability(
371
542
  @cursor,
372
543
  always_deprecated_ptr, deprecated_message_ptr,
373
544
  always_unavailable_ptr, unavailable_message_ptr,
374
545
  availability_ptr, max_availability_size)
375
-
546
+
376
547
  availability = []
377
548
  cur_ptr = availability_ptr
378
- [actual_availability_size, max_availability_size].min.times {
379
- availability << PlatformAvailability.new(cur_ptr)
380
- cur_ptr += Lib::CXPlatformAvailability.size
549
+ [actual_availability_size, max_availability_size].min.times {availability << PlatformAvailability.new(cur_ptr)
550
+ cur_ptr += Lib::CXPlatformAvailability.size
381
551
  }
382
-
552
+
383
553
  # return as Hash
384
554
  {
385
555
  always_deprecated: always_deprecated_ptr.get_int(0),
@@ -389,64 +559,91 @@ module FFI
389
559
  availability: availability
390
560
  }
391
561
  end
392
-
562
+
563
+ # Get all cursors that this cursor overrides.
564
+ # @returns [Array(Cursor)] Array of overridden cursors.
393
565
  def overriddens
394
566
  cursor_ptr = FFI::MemoryPointer.new :pointer
395
567
  num_ptr = FFI::MemoryPointer.new :uint
396
568
  Lib.get_overridden_cursors(@cursor, cursor_ptr, num_ptr)
397
569
  num = num_ptr.get_uint(0)
398
570
  cur_ptr = cursor_ptr.get_pointer(0)
399
-
571
+
400
572
  overriddens = []
401
- num.times {
402
- overriddens << Cursor.new(cur_ptr, @translation_unit)
403
- cur_ptr += Lib::CXCursor.size
573
+ num.times {overriddens << Cursor.new(cur_ptr, @translation_unit)
574
+ cur_ptr += Lib::CXCursor.size
404
575
  }
405
576
  Lib.dispose_overridden_cursors(cursor_ptr.get_pointer(0)) if num != 0
406
577
  overriddens
407
578
  end
408
-
579
+
580
+ # Check if this cursor represents a bitfield.
581
+ # @returns [Boolean] True if it's a bitfield.
409
582
  def bitfield?
410
583
  Lib.is_bit_field(@cursor) != 0
411
584
  end
412
-
585
+
586
+ # Get the bit width of a bitfield.
587
+ # @returns [Integer] The bitfield width.
413
588
  def bitwidth
414
589
  Lib.get_field_decl_bit_width(@cursor)
415
590
  end
416
-
591
+
592
+ # Get an overloaded declaration by index.
593
+ # @parameter i [Integer] The index of the overloaded declaration.
594
+ # @returns [Cursor] The overloaded declaration cursor.
417
595
  def overloaded_decl(i)
418
596
  Cursor.new Lib.get_overloaded_decl(@cursor, i), @translation_unit
419
597
  end
420
-
598
+
599
+ # Get the number of overloaded declarations.
600
+ # @returns [Integer] The number of overloaded declarations.
421
601
  def num_overloaded_decls
422
602
  Lib.get_num_overloaded_decls(@cursor)
423
603
  end
424
-
604
+
605
+ # Get the Objective-C type encoding.
606
+ # @returns [String] The Objective-C type encoding.
425
607
  def objc_type_encoding
426
608
  Lib.extract_string Lib.get_decl_objc_type_encoding(@cursor)
427
609
  end
428
-
610
+
611
+ # Get a function or method argument by index.
612
+ # @parameter i [Integer] The argument index.
613
+ # @returns [Cursor] The argument cursor.
429
614
  def argument(i)
430
615
  Cursor.new Lib.cursor_get_argument(@cursor, i), @translation_unit
431
616
  end
432
-
617
+
618
+ # Get the number of arguments.
619
+ # @returns [Integer] The number of arguments.
433
620
  def num_arguments
434
621
  Lib.cursor_get_num_arguments(@cursor)
435
622
  end
436
-
623
+
624
+ # Check if this cursor equals another cursor.
625
+ # @parameter other [Cursor] The cursor to compare with.
626
+ # @returns [Boolean] True if the cursors are equal.
437
627
  def eql?(other)
438
628
  Lib.are_equal(@cursor, other.cursor) != 0
439
629
  end
440
630
  alias == eql?
441
-
631
+
632
+ # Get the hash code for this cursor.
633
+ # @returns [Integer] The hash code.
442
634
  def hash
443
635
  Lib.get_cursor_hash(@cursor)
444
636
  end
445
-
637
+
638
+ # Get a string representation of this cursor.
639
+ # @returns [String] The cursor string representation.
446
640
  def to_s
447
641
  "Cursor <#{self.kind.to_s.gsub(/^cursor_/, '')}: #{self.spelling}>"
448
642
  end
449
-
643
+
644
+ # Find all references to this cursor.
645
+ # @parameter file [String | Nil] The file to search in, or `nil` for the translation unit file.
646
+ # @returns [Array(Cursor)] Array of reference cursors.
450
647
  def references(file = nil)
451
648
  refs = []
452
649
  self.find_references_in_file(file) do |cursor, unused|
@@ -455,95 +652,144 @@ module FFI
455
652
  end
456
653
  refs
457
654
  end
458
-
655
+
656
+ # Check if this is a converting constructor.
657
+ # @returns [Boolean] True if it's a converting constructor.
459
658
  def converting_constructor?
460
659
  Lib.is_converting_constructor(@cursor) != 0
461
660
  end
462
-
661
+
662
+ # Check if this is a copy constructor.
663
+ # @returns [Boolean] True if it's a copy constructor.
463
664
  def copy_constructor?
464
665
  Lib.is_copy_constructor(@cursor) != 0
465
666
  end
466
-
667
+
668
+ # Check if this is a default constructor.
669
+ # @returns [Boolean] True if it's a default constructor.
467
670
  def default_constructor?
468
671
  Lib.is_default_constructor(@cursor) != 0
469
672
  end
470
-
673
+
674
+ # Check if this is a move constructor.
675
+ # @returns [Boolean] True if it's a move constructor.
471
676
  def move_constructor?
472
677
  Lib.is_move_constructor(@cursor) != 0
473
678
  end
474
-
679
+
680
+ # Check if this cursor is mutable.
681
+ # @returns [Boolean] True if it's mutable.
475
682
  def mutable?
476
683
  Lib.is_mutable(@cursor) != 0
477
684
  end
478
-
685
+
686
+ # Check if this cursor is defaulted.
687
+ # @returns [Boolean] True if it's defaulted.
479
688
  def defaulted?
480
689
  Lib.is_defaulted(@cursor) != 0
481
690
  end
482
-
691
+
692
+ # Check if this cursor is deleted.
693
+ # @returns [Boolean] True if it's deleted.
483
694
  def deleted?
484
695
  Lib.is_deleted(@cursor) != 0
485
696
  end
486
-
697
+
698
+ # Check if this is a copy assignment operator.
699
+ # @returns [Boolean] True if it's a copy assignment operator.
487
700
  def copy_assignment_operator?
488
701
  Lib.is_copy_assignment_operator(@cursor) != 0
489
702
  end
490
-
703
+
704
+ # Check if this is a move assignment operator.
705
+ # @returns [Boolean] True if it's a move assignment operator.
491
706
  def move_assignment_operator?
492
707
  Lib.is_move_assignment_operator(@cursor) != 0
493
708
  end
494
-
709
+
710
+ # Check if this cursor is explicit.
711
+ # @returns [Boolean] True if it's explicit.
495
712
  def explicit?
496
713
  Lib.is_explicit(@cursor) != 0
497
714
  end
498
-
715
+
716
+ # Check if this cursor is abstract.
717
+ # @returns [Boolean] True if it's abstract.
499
718
  def abstract?
500
719
  Lib.is_abstract(@cursor) != 0
501
720
  end
502
-
721
+
722
+ # Check if this is a scoped enum.
723
+ # @returns [Boolean] True if it's a scoped enum.
503
724
  def enum_scoped?
504
725
  Lib.is_enum_scoped(@cursor) != 0
505
726
  end
506
-
727
+
728
+ # Check if this cursor is const-qualified.
729
+ # @returns [Boolean] True if it's const.
507
730
  def const?
508
731
  Lib.is_const(@cursor) != 0
509
732
  end
510
-
733
+
734
+ # Represents platform availability information for a cursor.
511
735
  class PlatformAvailability < AutoPointer
736
+ # Initialize platform availability from a memory pointer.
737
+ # @parameter memory_pointer [FFI::MemoryPointer] The memory pointer.
512
738
  def initialize(memory_pointer)
513
739
  pointer = FFI::Pointer.new(memory_pointer)
514
740
  super(pointer)
515
-
741
+
516
742
  # I'm not sure this is safe.
517
743
  # Keep a reference to CXPlatformAvailability itself allocated by MemoryPointer.
518
744
  @memory_pointer = memory_pointer
519
745
  @platform_availability = Lib::CXPlatformAvailability.new(memory_pointer)
520
746
  end
521
-
747
+
748
+ # Release the platform availability pointer.
749
+ # @parameter pointer [FFI::Pointer] The pointer to release.
522
750
  def self.release(pointer)
523
751
  # Memory allocated by get_cursor_platform_availability is managed by AutoPointer.
524
752
  Lib.dispose_platform_availability(Lib::CXPlatformAvailability.new(pointer))
525
753
  end
526
-
754
+
755
+ # Get the platform name.
756
+ # @returns [String] The platform name.
527
757
  def platform
528
758
  Lib.get_string @platform_availability[:platform]
529
759
  end
530
-
760
+
761
+ # Get the platform name.
762
+ # @returns [String] The platform name.
763
+ def platform
764
+ Lib.get_string @platform_availability[:platform]
765
+ end
766
+
767
+ # Get the version where the feature was introduced.
768
+ # @returns [Lib::CXVersion] The introduced version.
531
769
  def introduced
532
770
  @platform_availability[:introduced]
533
771
  end
534
-
772
+
773
+ # Get the version where the feature was deprecated.
774
+ # @returns [Lib::CXVersion] The deprecated version.
535
775
  def deprecated
536
776
  @platform_availability[:deprecated]
537
777
  end
538
-
778
+
779
+ # Get the version where the feature was obsoleted.
780
+ # @returns [Lib::CXVersion] The obsoleted version.
539
781
  def obsoleted
540
782
  @platform_availability[:obsoleted]
541
783
  end
542
-
784
+
785
+ # Check if the feature is unavailable.
786
+ # @returns [Boolean] True if unavailable.
543
787
  def unavailable
544
788
  @platform_availability[:unavailable] != 0
545
789
  end
546
-
790
+
791
+ # Get the availability message.
792
+ # @returns [String] The availability message.
547
793
  def message
548
794
  Lib.get_string @platform_availability[:message]
549
795
  end