ffi-clang 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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