ffi-clang 0.2.0 → 0.2.1

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +12 -8
  3. data/README.md +3 -1
  4. data/ffi-clang.gemspec +1 -1
  5. data/lib/ffi/clang.rb +3 -1
  6. data/lib/ffi/clang/code_completion.rb +193 -0
  7. data/lib/ffi/clang/comment.rb +154 -11
  8. data/lib/ffi/clang/compilation_database.rb +125 -0
  9. data/lib/ffi/clang/cursor.rb +145 -9
  10. data/lib/ffi/clang/diagnostic.rb +36 -10
  11. data/lib/ffi/clang/file.rb +69 -0
  12. data/lib/ffi/clang/index.rb +9 -17
  13. data/lib/ffi/clang/lib.rb +25 -2
  14. data/lib/ffi/clang/lib/code_completion.rb +130 -0
  15. data/lib/ffi/clang/lib/comment.rb +73 -12
  16. data/lib/ffi/clang/lib/compilation_database.rb +58 -0
  17. data/lib/ffi/clang/lib/cursor.rb +78 -14
  18. data/lib/ffi/clang/lib/diagnostic.rb +32 -12
  19. data/lib/ffi/clang/lib/file.rb +15 -3
  20. data/lib/ffi/clang/lib/inclusions.rb +32 -0
  21. data/lib/ffi/clang/lib/source_location.rb +18 -0
  22. data/lib/ffi/clang/lib/source_range.rb +5 -0
  23. data/lib/ffi/clang/lib/token.rb +58 -0
  24. data/lib/ffi/clang/lib/translation_unit.rb +71 -1
  25. data/lib/ffi/clang/lib/type.rb +61 -3
  26. data/lib/ffi/clang/source_location.rb +102 -0
  27. data/lib/ffi/clang/source_range.rb +25 -4
  28. data/lib/ffi/clang/token.rb +95 -0
  29. data/lib/ffi/clang/translation_unit.rb +118 -2
  30. data/lib/ffi/clang/type.rb +61 -0
  31. data/lib/ffi/clang/unsaved_file.rb +16 -0
  32. data/lib/ffi/clang/utils.rb +38 -12
  33. data/lib/ffi/clang/version.rb +1 -1
  34. data/spec/clang/code_completion_spec.rb +181 -0
  35. data/spec/clang/comment_spec.rb +385 -12
  36. data/spec/clang/compilation_database_spec.rb +178 -0
  37. data/spec/clang/cursor_spec.rb +335 -12
  38. data/spec/clang/diagnostic_spec.rb +63 -4
  39. data/spec/clang/file_spec.rb +84 -0
  40. data/spec/clang/index_spec.rb +62 -5
  41. data/spec/clang/source_location_spec.rb +104 -4
  42. data/spec/clang/source_range_spec.rb +76 -0
  43. data/spec/clang/token_spec.rb +84 -0
  44. data/spec/clang/translation_unit_spec.rb +202 -5
  45. data/spec/clang/type_spec.rb +191 -0
  46. data/spec/clang/utils_spec.rb +2 -3
  47. data/spec/fixtures/a.c +3 -0
  48. data/spec/fixtures/compile_commands.json +17 -0
  49. data/spec/fixtures/completion.cxx +8 -0
  50. data/spec/fixtures/docs.c +1 -0
  51. data/spec/fixtures/docs.cc +1 -0
  52. data/spec/fixtures/docs.h +46 -3
  53. data/spec/fixtures/list.c +1 -0
  54. data/spec/fixtures/location1.c +7 -0
  55. data/spec/fixtures/simple.c +3 -0
  56. data/spec/fixtures/test.cxx +36 -0
  57. data/spec/spec_helper.rb +11 -0
  58. metadata +50 -21
@@ -0,0 +1,125 @@
1
+ # Copyright, 2014, by Masahiro Sano.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'ffi/clang/lib/compilation_database'
22
+
23
+ module FFI
24
+ module Clang
25
+ class CompilationDatabase < AutoPointer
26
+ class DatabaseLoadError < FFI::Clang::Error; end
27
+
28
+ def initialize(dirpath)
29
+ uint_ptr = MemoryPointer.new :uint
30
+ cdb_ptr = Lib.compilation_database_from_directory(dirpath, uint_ptr)
31
+ error_code = Lib::CompilationDatabaseError[uint_ptr.read_uint]
32
+ if error_code != :no_error
33
+ raise DatabaseLoadError, "Cannot load database: #{error_code}"
34
+ end
35
+ super cdb_ptr
36
+ end
37
+
38
+ def self.release(pointer)
39
+ Lib.compilation_database_dispose(pointer)
40
+ end
41
+
42
+ def compile_commands(filename)
43
+ CompileCommands.new Lib.compilation_database_get_compile_commands(self, filename), self
44
+ end
45
+
46
+ def all_compile_commands
47
+ CompileCommands.new Lib.compilation_database_get_all_compile_commands(self), self
48
+ end
49
+
50
+ class CompileCommands < AutoPointer
51
+ include Enumerable
52
+
53
+ def initialize(pointer, database)
54
+ super pointer
55
+ @database = database
56
+ end
57
+
58
+ def self.release(pointer)
59
+ Lib.compile_commands_dispose(pointer)
60
+ end
61
+
62
+ def size
63
+ Lib.compile_commands_get_size(self)
64
+ end
65
+
66
+ def command(i)
67
+ CompileCommand.new Lib.compile_commands_get_command(self, i)
68
+ end
69
+
70
+ def commands
71
+ size.times.map { |i| command(i) }
72
+ end
73
+
74
+ def each(&block)
75
+ size.times.map do |i|
76
+ block.call(command(i))
77
+ end
78
+ end
79
+ end
80
+
81
+ class CompileCommand
82
+ def initialize(pointer)
83
+ @pointer = pointer
84
+ end
85
+
86
+ def directory
87
+ Lib.extract_string Lib.compile_command_get_directory(@pointer)
88
+ end
89
+
90
+ def num_args
91
+ Lib.compile_command_get_num_args(@pointer)
92
+ end
93
+
94
+ def arg(i)
95
+ Lib.extract_string Lib.compile_command_get_arg(@pointer, i)
96
+ end
97
+
98
+ def args
99
+ num_args.times.map { |i| arg(i) }
100
+ end
101
+
102
+ def num_mapped_sources
103
+ raise NotImplementedError
104
+ # Lib.compile_command_get_num_mapped_sources(@pointer)
105
+ end
106
+
107
+ def mapped_source_path(i)
108
+ raise NotImplementedError
109
+ # Lib.extract_string Lib.compile_command_get_mapped_source_path(@pointer, i)
110
+ end
111
+
112
+ def mapped_source_content(i)
113
+ raise NotImplementedError
114
+ # Lib.extract_string Lib.compile_command_get_mapped_source_content(@pointer, i)
115
+ end
116
+
117
+ def mapped_sources
118
+ num_mapped_sources.times.map { |i|
119
+ {path: mapped_source_path(i), content: mapped_source_content(i)}
120
+ }
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -1,5 +1,6 @@
1
1
  # Copyright, 2010-2012 by Jari Bakken.
2
2
  # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
3
+ # Copyright, 2014, by Masahiro Sano.
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
6
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +24,7 @@ require 'ffi/clang/lib/cursor'
23
24
  require 'ffi/clang/source_location'
24
25
  require 'ffi/clang/comment'
25
26
  require 'ffi/clang/type'
27
+ require 'ffi/clang/lib/code_completion'
26
28
 
27
29
  module FFI
28
30
  module Clang
@@ -34,6 +36,11 @@ module FFI
34
36
  Cursor.new Lib.get_null_cursor, nil
35
37
  end
36
38
 
39
+ # this function is categorized as "Debugging facilities"
40
+ def self.kind_spelling(kind)
41
+ Lib.extract_string Lib.get_cursor_kind_spelling(kind)
42
+ end
43
+
37
44
  def initialize(cxcursor, translation_unit)
38
45
  @cursor = cxcursor
39
46
  @translation_unit = translation_unit
@@ -51,6 +58,14 @@ module FFI
51
58
  Comment.build_from Lib.cursor_get_parsed_comment(@cursor)
52
59
  end
53
60
 
61
+ def comment_range
62
+ SourceRange.new(Lib.cursor_get_comment_range(@cursor))
63
+ end
64
+
65
+ def completion
66
+ CodeCompletion::String.new Lib.get_cursor_completion_string(@cursor)
67
+ end
68
+
54
69
  def declaration?
55
70
  Lib.is_declaration(kind) != 0
56
71
  end
@@ -100,7 +115,7 @@ module FFI
100
115
  end
101
116
 
102
117
  def location
103
- SourceLocation.new(Lib.get_cursor_location(@cursor))
118
+ ExpansionLocation.new(Lib.get_cursor_location(@cursor))
104
119
  end
105
120
 
106
121
  def extent
@@ -123,6 +138,10 @@ module FFI
123
138
  @cursor[:kind]
124
139
  end
125
140
 
141
+ def kind_spelling
142
+ Cursor.kind_spelling @cursor[:kind]
143
+ end
144
+
126
145
  def type
127
146
  Type.new Lib.get_cursor_type(@cursor), @translation_unit
128
147
  end
@@ -136,7 +155,7 @@ module FFI
136
155
  end
137
156
 
138
157
  def enum_decl_integer_type
139
- Type.new Lib.get_decl_integer_type(@cursor), @translation_unit
158
+ Type.new Lib.get_enum_decl_integer_type(@cursor), @translation_unit
140
159
  end
141
160
 
142
161
  def virtual_base?
@@ -171,6 +190,10 @@ module FFI
171
190
  Lib.get_enum_value @cursor
172
191
  end
173
192
 
193
+ def enum_unsigned_value
194
+ Lib.get_enum_unsigned_value @cursor
195
+ end
196
+
174
197
  def specialized_template
175
198
  Cursor.new Lib.get_specialized_cursor_template(@cursor), @translation_unit
176
199
  end
@@ -207,6 +230,10 @@ module FFI
207
230
  Lib.get_language @cursor
208
231
  end
209
232
 
233
+ def translation_unit
234
+ @translation_unit
235
+ end
236
+
210
237
  def visit_children(&block)
211
238
  adapter = Proc.new do |cxcursor, parent_cursor, unused|
212
239
  block.call Cursor.new(cxcursor, @translation_unit), Cursor.new(parent_cursor, @translation_unit)
@@ -224,24 +251,133 @@ module FFI
224
251
  end
225
252
 
226
253
  def included_file
227
- raise NotImplementedError
254
+ File.new Lib.get_included_file(@cursor), @translation_unit
255
+ end
256
+
257
+ def platform_availability(max_availability_size = 4)
258
+ availability_ptr = FFI::MemoryPointer.new(Lib::CXPlatformAvailability, max_availability_size)
259
+ always_deprecated_ptr = FFI::MemoryPointer.new :int
260
+ always_unavailable_ptr = FFI::MemoryPointer.new :int
261
+ deprecated_message_ptr = FFI::MemoryPointer.new Lib::CXString
262
+ unavailable_message_ptr = FFI::MemoryPointer.new Lib::CXString
263
+
264
+ actual_availability_size = Lib.get_cursor_platform_availability(
265
+ @cursor,
266
+ always_deprecated_ptr, deprecated_message_ptr,
267
+ always_unavailable_ptr, unavailable_message_ptr,
268
+ availability_ptr, max_availability_size)
269
+
270
+ availability = []
271
+ cur_ptr = availability_ptr
272
+ [actual_availability_size, max_availability_size].min.times {
273
+ availability << PlatformAvailability.new(cur_ptr)
274
+ cur_ptr += Lib::CXPlatformAvailability.size
275
+ }
276
+
277
+ # return as Hash
278
+ {
279
+ always_deprecated: always_deprecated_ptr.get_int(0),
280
+ always_unavailable: always_unavailable_ptr.get_int(0),
281
+ deprecated_message: Lib.extract_string(Lib::CXString.new(deprecated_message_ptr)),
282
+ unavailable_message: Lib.extract_string(Lib::CXString.new(unavailable_message_ptr)),
283
+ availability: availability
284
+ }
285
+ end
286
+
287
+ def overriddens
288
+ cursor_ptr = FFI::MemoryPointer.new :pointer
289
+ num_ptr = FFI::MemoryPointer.new :uint
290
+ Lib.get_overridden_cursors(@cursor, cursor_ptr, num_ptr)
291
+ num = num_ptr.get_uint(0)
292
+ cur_ptr = cursor_ptr.get_pointer(0)
293
+
294
+ overriddens = []
295
+ num.times {
296
+ overriddens << Cursor.new(cur_ptr, @translation_unit)
297
+ cur_ptr += Lib::CXCursor.size
298
+ }
299
+ Lib.dispose_overridden_cursors(cursor_ptr.get_pointer(0)) if num != 0
300
+ overriddens
228
301
  end
229
302
 
230
- def platform_availability
231
- raise NotImplementedError
303
+ def hash
304
+ Lib.get_cursor_hash(@cursor)
232
305
  end
233
306
 
234
- def get_overridden_cursors
235
- raise NotImplementedError
307
+ def bitfield?
308
+ Lib.is_bit_field(@cursor) != 0
236
309
  end
237
310
 
238
- def hash
239
- Lib.get_cursor_hash(@cursor)
311
+ def bitwidth
312
+ Lib.get_field_decl_bit_width(@cursor)
313
+ end
314
+
315
+ def overloaded_decl(i)
316
+ Cursor.new Lib.get_overloaded_decl(@cursor, i), @translation_unit
317
+ end
318
+
319
+ def num_overloaded_decls
320
+ Lib.get_num_overloaded_decls(@cursor)
321
+ end
322
+
323
+ def objc_type_encoding
324
+ Lib.extract_string Lib.get_decl_objc_type_encoding(@cursor)
325
+ end
326
+
327
+ def argument(i)
328
+ Cursor.new Lib.cursor_get_argument(@cursor, i), @translation_unit
329
+ end
330
+
331
+ def num_arguments
332
+ Lib.cursor_get_num_arguments(@cursor)
240
333
  end
241
334
 
335
+ attr_reader :cursor
336
+
242
337
  def ==(other)
243
338
  Lib.are_equal(@cursor, other.cursor) != 0
244
339
  end
340
+
341
+ class PlatformAvailability < AutoPointer
342
+ def initialize(memory_pointer)
343
+ pointer = FFI::Pointer.new(memory_pointer)
344
+ super(pointer)
345
+
346
+ # I'm not sure this is safe.
347
+ # Keep a reference to CXPlatformAvailability itself allocated by MemoryPointer.
348
+ @memory_pointer = memory_pointer
349
+ @platform_availability = Lib::CXPlatformAvailability.new(memory_pointer)
350
+ end
351
+
352
+ def self.release(pointer)
353
+ # Memory allocated by get_cursor_platform_availability is managed by AutoPointer.
354
+ Lib.dispose_platform_availability(Lib::CXPlatformAvailability.new(pointer))
355
+ end
356
+
357
+ def platform
358
+ Lib.get_string @platform_availability[:platform]
359
+ end
360
+
361
+ def introduced
362
+ @platform_availability[:introduced]
363
+ end
364
+
365
+ def deprecated
366
+ @platform_availability[:deprecated]
367
+ end
368
+
369
+ def obsoleted
370
+ @platform_availability[:obsoleted]
371
+ end
372
+
373
+ def unavailable
374
+ @platform_availability[:unavailable] != 0
375
+ end
376
+
377
+ def message
378
+ Lib.get_string @platform_availability[:message]
379
+ end
380
+ end
245
381
  end
246
382
  end
247
383
  end
@@ -26,6 +26,10 @@ require 'ffi/clang/source_range'
26
26
  module FFI
27
27
  module Clang
28
28
  class Diagnostic < AutoPointer
29
+ def self.default_display_opts
30
+ Lib.opts_from Lib::DiagnosticDisplayOptions, Lib.default_diagnostic_display_options
31
+ end
32
+
29
33
  def initialize(translation_unit, pointer)
30
34
  super pointer
31
35
 
@@ -51,15 +55,16 @@ module FFI
51
55
 
52
56
  def location
53
57
  sl = Lib.get_diagnostic_location(self)
54
- SourceLocation.new sl
58
+ ExpansionLocation.new sl
55
59
  end
56
60
 
57
61
  def fixits
58
- raise NotImplementedError
59
- # unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag);
60
- # CXString clang_getDiagnosticFixIt(CXDiagnostic Diag,
61
- # unsigned FixIt,
62
- # CXSourceRange *ReplacementRange);
62
+ n = Lib.get_diagnostic_num_fix_its(self)
63
+ n.times.map { |i|
64
+ ptr = MemoryPointer.new Lib::CXSourceRange
65
+ replace_text = Lib.extract_string(Lib.get_diagnostic_fix_it(self, i, ptr))
66
+ {text: replace_text, range: SourceRange.new(ptr)}
67
+ }
63
68
  end
64
69
 
65
70
  def ranges
@@ -68,12 +73,34 @@ module FFI
68
73
  n.times.map {|i| SourceRange.new Lib.get_diagnostic_range(self, i)}
69
74
  end
70
75
 
71
- private
76
+ def children
77
+ diagnostic_set = Lib.get_child_diagnostics(self)
78
+ num_diagnostics = Lib.get_num_diagnostics_in_set(diagnostic_set)
79
+ num_diagnostics.times.map { |i|
80
+ Diagnostic.new(@translation_unit, Lib.get_diagnostic_in_set(diagnostic_set, i))
81
+ }
82
+ end
72
83
 
73
- def range_count
74
-
84
+ def enable_option
85
+ Lib.extract_string Lib.get_diagnostic_option(self, nil)
86
+ end
87
+
88
+ def disable_option
89
+ ptr = MemoryPointer.new Lib::CXString
90
+ Lib.get_diagnostic_option(self, ptr)
91
+ Lib.extract_string ptr
75
92
  end
76
93
 
94
+ def category
95
+ Lib.extract_string Lib.get_diagnostic_category_text(self)
96
+ end
97
+
98
+ def category_id
99
+ Lib.get_diagnostic_category(self)
100
+ end
101
+
102
+ private
103
+
77
104
  def display_opts(opts)
78
105
  if opts.empty?
79
106
  Lib.default_diagnostic_display_options
@@ -81,7 +108,6 @@ module FFI
81
108
  Lib.bitmask_from Lib::DiagnosticDisplayOptions, opts
82
109
  end
83
110
  end
84
-
85
111
  end
86
112
  end
87
113
  end
@@ -0,0 +1,69 @@
1
+ # Copyright, 2014, by Masahiro Sano.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'ffi/clang/lib/file'
22
+ require 'ffi/clang/utils'
23
+
24
+ module FFI
25
+ module Clang
26
+ class File < Pointer
27
+ attr_reader :translation_unit
28
+
29
+ def initialize(pointer, tu)
30
+ super pointer
31
+ @translation_unit = tu
32
+
33
+ if FFI::Clang::Utils.satisfy_version?('3.3')
34
+ pointer = MemoryPointer.new(Lib::CXFileUniqueID)
35
+ Lib.get_file_unique_id(self, pointer)
36
+ @unique_id = Lib::CXFileUniqueID.new(pointer)
37
+ end
38
+ end
39
+
40
+ def to_s
41
+ name
42
+ end
43
+
44
+ def name
45
+ Lib.extract_string Lib.get_file_name(self)
46
+ end
47
+
48
+ def time
49
+ Time.at(Lib.get_file_time(self))
50
+ end
51
+
52
+ def include_guarded?
53
+ Lib.is_file_multiple_include_guarded(@translation_unit, self) != 0
54
+ end
55
+
56
+ def device
57
+ @unique_id[:device]
58
+ end
59
+
60
+ def inode
61
+ @unique_id[:inode]
62
+ end
63
+
64
+ def modification
65
+ Time.at(@unique_id[:modification])
66
+ end
67
+ end
68
+ end
69
+ end