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
@@ -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