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
@@ -2,6 +2,7 @@
2
2
  # Copyright, 2010-2012 by Jari Bakken.
3
3
  # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
4
  # Copyright, 2013, by Garry C. Marshall. <http://www.meaningfulname.net>
5
+ # Copyright, 2014, by Masahiro Sano.
5
6
  #
6
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
7
8
  # of this software and associated documentation files (the "Software"), to deal
@@ -21,19 +22,39 @@
21
22
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
23
  # THE SOFTWARE.
23
24
 
25
+ require 'ffi/clang/lib/source_range'
26
+
24
27
  module FFI
25
28
  module Clang
26
29
  class SourceRange
27
- def initialize(range)
28
- @range = range
30
+ def self.null_range
31
+ SourceRange.new Lib.get_null_range
32
+ end
33
+
34
+ def initialize(range_or_begin_location, end_location = nil)
35
+ if end_location.nil?
36
+ @range = range_or_begin_location
37
+ else
38
+ @range = Lib.get_range(range_or_begin_location.location, end_location.location)
39
+ end
29
40
  end
30
41
 
31
42
  def start
32
- SourceLocation.new(Lib.get_range_start @range)
43
+ ExpansionLocation.new(Lib.get_range_start @range)
33
44
  end
34
45
 
35
46
  def end
36
- SourceLocation.new(Lib.get_range_end @range)
47
+ ExpansionLocation.new(Lib.get_range_end @range)
48
+ end
49
+
50
+ def null?
51
+ Lib.range_is_null(@range) != 0
52
+ end
53
+
54
+ attr_reader :range
55
+
56
+ def ==(other)
57
+ Lib.equal_range(@range, other.range) != 0
37
58
  end
38
59
  end
39
60
  end
@@ -0,0 +1,95 @@
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/token'
22
+ require 'ffi/clang/lib/cursor'
23
+ require 'ffi/clang/source_location'
24
+
25
+ module FFI
26
+ module Clang
27
+ class Tokens < AutoPointer
28
+ include Enumerable
29
+
30
+ attr_reader :size
31
+ attr_reader :tokens
32
+
33
+ def initialize(pointer, token_size, translation_unit)
34
+ ptr = Lib::TokensPointer.new(pointer,token_size, translation_unit)
35
+ super ptr
36
+
37
+ @translation_unit = translation_unit
38
+ @size = token_size
39
+
40
+ @tokens = []
41
+ cur_ptr = pointer
42
+ token_size.times {
43
+ @tokens << Token.new(cur_ptr, translation_unit)
44
+ cur_ptr += Lib::CXToken.size
45
+ }
46
+ end
47
+
48
+ def self.release(pointer)
49
+ Lib.dispose_tokens(pointer, pointer.token_size, pointer.translation_unit)
50
+ end
51
+
52
+ def each(&block)
53
+ @tokens.each do |token|
54
+ block.call(token)
55
+ end
56
+ end
57
+
58
+ def cursors
59
+ ptr = MemoryPointer.new(Lib::CXCursor, @size)
60
+ Lib.annotate_tokens(@translation_unit, self, @size, ptr)
61
+
62
+ cur_ptr = ptr
63
+ arr = []
64
+ @size.times {
65
+ arr << Cursor.new(cur_ptr, @translation_unit)
66
+ cur_ptr += Lib::CXCursor.size
67
+ }
68
+ arr
69
+ end
70
+ end
71
+
72
+ class Token
73
+ def initialize(token, translation_unit)
74
+ @token = token
75
+ @translation_unit = translation_unit
76
+ end
77
+
78
+ def kind
79
+ Lib.get_token_kind(@token)
80
+ end
81
+
82
+ def spelling
83
+ Lib.extract_string Lib.get_token_spelliing(@translation_unit, @token)
84
+ end
85
+
86
+ def location
87
+ ExpansionLocation.new Lib.get_token_location(@translation_unit, @token)
88
+ end
89
+
90
+ def extent
91
+ SourceRange.new Lib.get_token_extent(@translation_unit, @token)
92
+ end
93
+ end
94
+ end
95
+ 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
@@ -20,7 +21,10 @@
20
21
  # THE SOFTWARE.
21
22
 
22
23
  require 'ffi/clang/lib/translation_unit'
24
+ require 'ffi/clang/lib/inclusions'
23
25
  require 'ffi/clang/cursor'
26
+ require 'ffi/clang/file'
27
+ require 'ffi/clang/token'
24
28
 
25
29
  module FFI
26
30
  module Clang
@@ -34,6 +38,35 @@ module FFI
34
38
  Lib.dispose_translation_unit(pointer)
35
39
  end
36
40
 
41
+ def self.default_editing_translation_unit_options
42
+ bitmask = Lib.default_editing_translation_unit_options
43
+ Lib.opts_from Lib::TranslationUnitFlags, bitmask
44
+ end
45
+
46
+ def default_save_options
47
+ bitmask = Lib.default_save_options(self)
48
+ Lib.opts_from Lib::SaveTranslationUnitFlags, bitmask
49
+ end
50
+
51
+ def save(filename, opts = {})
52
+ ret = Lib.save_translation_unit(self, filename, 0)
53
+ sym = Lib::SaveError[ret]
54
+ raise Error, "unknown return values: #{ret} #{sym.inspect}" unless sym
55
+ raise Error, "save error: #{sym.inspect}, filename: #{filename}" if sym != :none
56
+ end
57
+
58
+ def default_reparse_options
59
+ bitmask = Lib.default_save_options(self)
60
+ Lib.opts_from Lib::ReparseFlags, bitmask
61
+ end
62
+
63
+ def reparse(unsaved = [], opts = {})
64
+ unsaved_files = UnsavedFile.unsaved_pointer_from(unsaved)
65
+ if Lib.reparse_translation_unit(self, unsaved.size, unsaved_files, 0) != 0
66
+ raise Error, "reparse error"
67
+ end
68
+ end
69
+
37
70
  def diagnostics
38
71
  n = Lib.get_num_diagnostics(self)
39
72
 
@@ -42,8 +75,91 @@ module FFI
42
75
  end
43
76
  end
44
77
 
45
- def cursor
46
- Cursor.new(Lib.get_translation_unit_cursor(self), self)
78
+ def cursor(location = nil)
79
+ if location.nil?
80
+ Cursor.new Lib.get_translation_unit_cursor(self), self
81
+ else
82
+ Cursor.new Lib.get_cursor(self, location.location), self
83
+ end
84
+ end
85
+
86
+ def location(file, line, column)
87
+ ExpansionLocation.new Lib.get_location(self, file, line, column)
88
+ end
89
+
90
+ def location_offset(file, offset)
91
+ ExpansionLocation.new Lib.get_location_offset(self, file, offset)
92
+ end
93
+
94
+ def file(file_name)
95
+ File.new(Lib.get_file(self, file_name), self)
96
+ end
97
+
98
+ def spelling
99
+ Lib.get_translation_unit_spelling(self)
100
+ end
101
+
102
+ def resource_usage
103
+ FFI::Clang::TranslationUnit::ResourceUsage.new Lib.resource_usage(self)
104
+ end
105
+
106
+ def tokenize(range)
107
+ token_ptr = MemoryPointer.new :pointer
108
+ uint_ptr = MemoryPointer.new :uint
109
+ Lib.tokenize(self, range.range, token_ptr, uint_ptr)
110
+ Tokens.new(token_ptr.get_pointer(0), uint_ptr.get_uint(0), self)
111
+ end
112
+
113
+ def code_complete(source_file, line, column, unsaved = [], opts = nil)
114
+ opts = CodeCompletion.default_code_completion_options if opts.nil?
115
+ unsaved_files = UnsavedFile.unsaved_pointer_from(unsaved)
116
+ option_bitmask = Lib.bitmask_from(Lib::CodeCompleteFlags, opts)
117
+ ptr = Lib.code_complete_at(self, source_file, line, column, unsaved_files, unsaved.length, option_bitmask)
118
+ CodeCompletion::Results.new ptr, self
119
+ end
120
+
121
+ def inclusions(&block)
122
+ adapter = Proc.new do |included_file, inclusion_stack, include_len, unused|
123
+ file = Lib.extract_string Lib.get_file_name(included_file)
124
+ cur_ptr = inclusion_stack
125
+ inclusions = []
126
+ include_len.times {
127
+ inclusions << SourceLocation.new(Lib::CXSourceLocation.new(cur_ptr))
128
+ cur_ptr += Lib::CXSourceLocation.size
129
+ }
130
+ block.call file, inclusions
131
+ end
132
+
133
+ Lib.get_inclusions(self, adapter, nil)
134
+ end
135
+
136
+ class ResourceUsage < AutoPointer
137
+ def initialize(resource_usage)
138
+ # CXResourceUsage is returned by value and should be freed explicitly.
139
+ # Get FFI::pointer of the data so that the data is handled by AutoPointer.
140
+ pointer = FFI::Pointer.new(resource_usage.to_ptr)
141
+ super(pointer)
142
+ @resource_usage = resource_usage
143
+ end
144
+
145
+ def self.release(pointer)
146
+ # clang_disposeCXTUResourceUsage requires value type, so create it by pointer
147
+ Lib.dispose_resource_usage(Lib::CXTUResourceUsage.new(pointer))
148
+ end
149
+
150
+ def self.name(kind)
151
+ Lib.resource_usage_name(kind)
152
+ end
153
+
154
+ def entries
155
+ ary = []
156
+ ptr = @resource_usage[:entries]
157
+ @resource_usage[:numEntries].times {
158
+ ary << Lib::CXTUResourceUsageEntry.new(ptr)
159
+ ptr += Lib::CXTUResourceUsageEntry.size
160
+ }
161
+ ary
162
+ end
47
163
  end
48
164
  end
49
165
  end
@@ -1,4 +1,5 @@
1
1
  # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ # Copyright, 2014, by Masahiro Sano.
2
3
  #
3
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -18,9 +19,13 @@
18
19
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
20
  # THE SOFTWARE.
20
21
 
22
+ require 'ffi/clang/cursor'
23
+
21
24
  module FFI
22
25
  module Clang
23
26
  class Type
27
+ attr_reader :type
28
+
24
29
  def initialize(type, translation_unit)
25
30
  @type = type
26
31
  @translation_unit = translation_unit
@@ -58,10 +63,22 @@ module FFI
58
63
  Type.new Lib.get_canonical_type(@type), @translation_unit
59
64
  end
60
65
 
66
+ def class_type
67
+ Type.new Lib.type_get_class_type(@type), @translation_unit
68
+ end
69
+
61
70
  def const_qualified?
62
71
  Lib.is_const_qualified_type(@type) != 0
63
72
  end
64
73
 
74
+ def volatile_qualified?
75
+ Lib.is_volatile_qualified_type(@type) != 0
76
+ end
77
+
78
+ def restrict_qualified?
79
+ Lib.is_restrict_qualified_type(@type) != 0
80
+ end
81
+
65
82
  def arg_type(i)
66
83
  Type.new Lib.get_arg_type(@type, i), @translation_unit
67
84
  end
@@ -69,6 +86,50 @@ module FFI
69
86
  def result_type
70
87
  Type.new Lib.get_result_type(@type), @translation_unit
71
88
  end
89
+
90
+ def element_type
91
+ Type.new Lib.get_element_type(@type), @translation_unit
92
+ end
93
+
94
+ def num_elements
95
+ Lib.get_num_elements(@type)
96
+ end
97
+
98
+ def array_element_type
99
+ Type.new Lib.get_array_element_type(@type), @translation_unit
100
+ end
101
+
102
+ def array_size
103
+ Lib.get_array_size(@type)
104
+ end
105
+
106
+ def alignof
107
+ Lib.type_get_align_of(@type)
108
+ end
109
+
110
+ def sizeof
111
+ Lib.type_get_size_of(@type)
112
+ end
113
+
114
+ def offsetof(field)
115
+ Lib.type_get_offset_of(@type, field)
116
+ end
117
+
118
+ def ref_qualifier
119
+ Lib.type_get_cxx_ref_qualifier(@type)
120
+ end
121
+
122
+ def calling_conv
123
+ Lib.get_fuction_type_calling_conv(@type)
124
+ end
125
+
126
+ def declaration
127
+ Cursor.new Lib.get_type_declaration(@type), @translation_unit
128
+ end
129
+
130
+ def ==(other)
131
+ Lib.equal_types(@type, other.type) != 0
132
+ end
72
133
  end
73
134
  end
74
135
  end
@@ -28,6 +28,22 @@ module FFI
28
28
  end
29
29
 
30
30
  attr_accessor :filename, :contents
31
+
32
+
33
+ def self.unsaved_pointer_from(unsaved)
34
+ return nil if unsaved.length == 0
35
+
36
+ vec = MemoryPointer.new(Lib::CXUnsavedFile, unsaved.length)
37
+
38
+ unsaved.each_with_index do |file, i|
39
+ uf = Lib::CXUnsavedFile.new(vec + i * Lib::CXUnsavedFile.size)
40
+ uf[:filename] = MemoryPointer.from_string(file.filename)
41
+ uf[:contents] = MemoryPointer.from_string(file.contents)
42
+ uf[:length] = file.contents.length
43
+ end
44
+
45
+ vec
46
+ end
31
47
  end
32
48
  end
33
49
  end
@@ -1,4 +1,5 @@
1
1
  # Copyright, 2014 by Masahiro Sano.
2
+ # Copyright, 2014 by Samuel Williams.
2
3
  #
3
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,35 +24,60 @@ require 'ffi/clang/lib/string'
23
24
 
24
25
  module FFI
25
26
  module Clang
26
- class Utils
27
+ module Utils
28
+ @@clang_version = nil
29
+
27
30
  def self.clang_version_string
28
31
  Lib.extract_string Lib.get_clang_version
29
32
  end
30
33
 
31
34
  def self.clang_version
32
- version = clang_version_string
33
- version.match(/clang version (\d+\.\d+)/).values_at(1).first
35
+ unless @@clang_version
36
+ # Version string vary wildy:
37
+ # Ubuntu: "Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on LLVM 3.0)"
38
+ # Mac OS X: "Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)"
39
+ # Linux: "clang version 3.3"
40
+
41
+ if parts = clang_version_string.match(/(?:clang version|based on LLVM) (\d+)\.(\d+)(svn)?/)
42
+ major = parts[1].to_i
43
+ minor = parts[2].to_i
44
+ rc = parts[3]
45
+
46
+ # Mac OS X currently reports support for 3.3svn, but this support is broken in some ways, so we revert it back to 3.2 which it supports completely.
47
+ if rc == 'svn'
48
+ minor -= 1
49
+ end
50
+
51
+ @@clang_version = [major, minor]
52
+
53
+ puts "Clang version detected: #{@@clang_version.inspect}"
54
+ else
55
+ abort "Invalid/unsupported clang version string."
56
+ end
57
+ end
58
+
59
+ return @@clang_version
34
60
  end
35
61
 
36
62
  def self.clang_version_symbol
37
- version = "clang_" + clang_version.tr('.', '_')
38
- version.intern
63
+ "clang_#{clang_version.join('_')}".to_sym
39
64
  end
40
65
 
41
66
  def self.clang_major_version
42
- version = clang_version_string
43
- version.match(/clang version (\d+)\./).values_at(1).first.to_i
67
+ clang_version[0]
44
68
  end
45
69
 
46
70
  def self.clang_minor_version
47
- version = clang_version_string
48
- version.match(/clang version \d+\.(\d+)/).values_at(1).first.to_i
71
+ clang_version[1]
49
72
  end
50
73
 
74
+ # Returns true if the current clang version is >= min version and optionally <= max_version
51
75
  def self.satisfy_version?(min_version, max_version = nil)
52
- Gem::Version.create(self.clang_version) >= Gem::Version.create(min_version) and
53
- (max_version.nil? or
54
- Gem::Version.create(self.clang_version) <= Gem::Version.create(max_version))
76
+ min_version = Gem::Version.create(min_version)
77
+ max_version = Gem::Version.create(max_version) if max_version
78
+ current_version = Gem::Version.create(self.clang_version.join('.'))
79
+
80
+ return (current_version >= min_version) && (!max_version || current_version <= max_version)
55
81
  end
56
82
  end
57
83
  end