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
@@ -9,23 +9,82 @@ describe Diagnostic do
9
9
  str.should be_kind_of(String)
10
10
  str.should =~ /does not match previous/
11
11
  end
12
-
12
+
13
13
  it "returns a string representation according to the given opts" do
14
14
  diagnostic.format(:source_location => true).should include("list.c:5")
15
15
  end
16
-
16
+
17
17
  it "returns the text of the diagnostic" do
18
18
  diagnostic.spelling.should be_kind_of(String)
19
19
  end
20
-
20
+
21
21
  it "returns the severity of the diagnostic" do
22
22
  diagnostic.severity.should == :error
23
23
  end
24
-
24
+
25
25
  it "returns the ranges of the diagnostic" do
26
26
  rs = diagnostics[1].ranges
27
27
  rs.should be_kind_of(Array)
28
28
  rs.should_not be_empty
29
29
  rs.first.should be_kind_of(SourceRange)
30
30
  end
31
+
32
+ it "calls dispose_diagnostic on GC" do
33
+ diagnostic.autorelease = false
34
+ expect(Lib).to receive(:dispose_diagnostic).with(diagnostic).once
35
+ expect{diagnostic.free}.not_to raise_error
36
+ end
37
+
38
+ context "#self.default_display_opts" do
39
+ it "returns the set of display options" do
40
+ expect(FFI::Clang::Diagnostic.default_display_opts).to be_kind_of(Hash)
41
+ expect(FFI::Clang::Diagnostic.default_display_opts.keys.map(&:class).uniq).to eq([Symbol])
42
+ expect(FFI::Clang::Diagnostic.default_display_opts.values.uniq).to eq([true])
43
+ end
44
+ end
45
+
46
+ context "#fixits" do
47
+ it "returns the replacement information by Array of Hash" do
48
+ expect(diagnostic.fixits).to be_kind_of(Array)
49
+ expect(diagnostic.fixits.first).to be_kind_of(Hash)
50
+ expect(diagnostic.fixits.first[:text]).to eq('struct')
51
+ expect(diagnostic.fixits.first[:range]).to be_kind_of(SourceRange)
52
+ end
53
+ end
54
+
55
+ context "#children" do
56
+ it "returns child diagnostics by Array" do
57
+ expect(diagnostic.children).to be_kind_of(Array)
58
+ expect(diagnostic.children.first).to be_kind_of(Diagnostic)
59
+ expect(diagnostic.children.first.severity).to eq(:note)
60
+ end
61
+ end
62
+
63
+ context "#enable_option" do
64
+ it "returns the name of the command-line option that enabled this diagnostic" do
65
+ expect(diagnostics[3].enable_option).to be_kind_of(String)
66
+ expect(diagnostics[3].enable_option).to eq('-Wempty-body')
67
+ end
68
+ end
69
+
70
+ context "#disable_option" do
71
+ it "returns the name of the command-line option that disables this diagnostic" do
72
+ expect(diagnostics[3].disable_option).to be_kind_of(String)
73
+ expect(diagnostics[3].disable_option).to eq('-Wno-empty-body')
74
+ end
75
+ end
76
+
77
+ context "#category" do
78
+ it "returns the diagnostic category text" do
79
+ expect(diagnostic.category).to be_kind_of(String)
80
+ expect(diagnostic.category).to eq('Semantic Issue')
81
+ end
82
+ end
83
+
84
+ context "#category_id" do
85
+ it "returns the category number" do
86
+ expect(diagnostic.category_id).to be_kind_of(Integer)
87
+ expect(diagnostic.category_id).to eq(2)
88
+ end
89
+ end
31
90
  end
@@ -0,0 +1,84 @@
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 'spec_helper'
22
+
23
+ describe File do
24
+ let(:file_list) { Index.new.parse_translation_unit(fixture_path("list.c")).file(fixture_path("list.c")) }
25
+ let(:file_docs) { Index.new.parse_translation_unit(fixture_path("docs.c")).file(fixture_path("docs.h")) }
26
+
27
+ it "can be obtained from a translation unit" do
28
+ expect(file_list).to be_kind_of(FFI::Clang::File)
29
+ end
30
+
31
+ describe "#name" do
32
+ let(:name) { file_list.name }
33
+
34
+ it 'returns its file name' do
35
+ expect(name).to be_kind_of(String)
36
+ expect(name).to eq(fixture_path("list.c"))
37
+ end
38
+ end
39
+
40
+ describe "#to_s" do
41
+ let(:name) { file_list.to_s }
42
+
43
+ it 'returns its file name' do
44
+ expect(name).to be_kind_of(String)
45
+ expect(name).to eq(fixture_path("list.c"))
46
+ end
47
+ end
48
+
49
+ describe "#time" do
50
+ let(:time) { file_list.time }
51
+
52
+ it 'returns file time' do
53
+ expect(time).to be_kind_of(Time)
54
+ end
55
+ end
56
+
57
+ describe "#include_guarded?" do
58
+ it 'returns false if included file is notguarded' do
59
+ expect(file_list.include_guarded?).to be false
60
+ end
61
+
62
+ it 'returns true if included file is guarded' do
63
+ expect(file_docs.include_guarded?).to be true
64
+ end
65
+ end
66
+
67
+ describe "#device", from_3_3: true do
68
+ it 'returns device from CXFileUniqueID' do
69
+ expect(file_list.device).to be_kind_of(Integer)
70
+ end
71
+ end
72
+
73
+ describe "#inode", from_3_3: true do
74
+ it 'returns inode from CXFileUniqueID' do
75
+ expect(file_list.inode).to be_kind_of(Integer)
76
+ end
77
+ end
78
+
79
+ describe "#modification", from_3_3: true do
80
+ it 'returns modification time as Time from CXFileUniqueID' do
81
+ expect(file_list.modification).to be_kind_of(Time)
82
+ end
83
+ end
84
+ end
@@ -1,14 +1,71 @@
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
+
1
21
  require 'spec_helper'
2
22
 
3
23
  describe Index do
24
+ before :all do
25
+ FileUtils.mkdir_p TMP_DIR
26
+ end
27
+
28
+ after :all do
29
+ FileUtils.rm_rf TMP_DIR
30
+ end
31
+
4
32
  let(:index) { Index.new }
5
33
 
6
- it "can parse a source file" do
7
- tu = index.parse_translation_unit fixture_path("a.c")
8
- tu.should be_kind_of(TranslationUnit)
34
+ it "calls dispose_index_debug_unit on GC" do
35
+ index.autorelease = false
36
+ expect(Lib).to receive(:dispose_index).with(index).once
37
+ expect{index.free}.not_to raise_error
9
38
  end
10
39
 
11
- it "raises error when file is not found" do
12
- expect { index.parse_translation_unit fixture_path("xxxxxxxxx.c") }.to raise_error
40
+ describe '#parse_translation_unit' do
41
+ it "can parse a source file" do
42
+ tu = index.parse_translation_unit fixture_path("a.c")
43
+ expect(tu).to be_kind_of(TranslationUnit)
44
+ end
45
+
46
+ it "raises error when file is not found" do
47
+ expect { index.parse_translation_unit fixture_path("xxxxxxxxx.c") }.to raise_error
48
+ end
49
+
50
+ it "can handle command line options" do
51
+ expect{index.parse_translation_unit(fixture_path("a.c"), ["-std=c++11"])}.not_to raise_error
52
+ end
53
+ end
54
+
55
+ describe '#create_translation_unit' do
56
+ before :all do
57
+ system("#{CLANG_COMPILER} -c #{fixture_path('simple.c')} -emit-ast -o #{TMP_DIR}/simple.ast")
58
+ end
59
+
60
+ it "can create translation unit from a ast file" do
61
+ expect(FileTest.exist?("#{TMP_DIR}/simple.ast")).to be true
62
+ tu = index.create_translation_unit "#{TMP_DIR}/simple.ast"
63
+ expect(tu).to be_kind_of(TranslationUnit)
64
+ end
65
+
66
+ it "raises error when file is not found" do
67
+ expect(FileTest.exist?('not_found.ast')).to be false
68
+ expect { index.create_translation_unit 'not_found.ast' }.to raise_error
69
+ end
13
70
  end
14
71
  end
@@ -1,6 +1,7 @@
1
1
  # Copyright, 2010-2012 by Jari Bakken.
2
2
  # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
3
3
  # Copyright, 2013, by Garry C. Marshall. <http://www.meaningfulname.net>
4
+ # Copyright, 2014, by Masahiro Sano.
4
5
  #
5
6
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
7
  # of this software and associated documentation files (the "Software"), to deal
@@ -26,15 +27,114 @@ describe SourceLocation do
26
27
  let(:tu) { Index.new.parse_translation_unit(fixture_path("list.c")) }
27
28
  let(:tu_location) { tu.cursor.location }
28
29
  let(:diagnostic_location) { tu.diagnostics.first.location }
30
+ let(:loc1_tu) { Index.new.parse_translation_unit(fixture_path("location1.c")) }
31
+ let(:loc1_cursor) { find_first(loc1_tu.cursor, :cursor_function) }
32
+ let(:docs_cursor) { Index.new.parse_translation_unit(fixture_path("docs.c")).cursor }
29
33
 
30
34
  it "should have a nil File if the SourceLocation is for a Translation Unit" do
31
- tu_location.file.should == nil
35
+ expect(tu_location.file).to be_nil
32
36
  end
33
37
 
34
38
  it "should provide a File, line and column for a Diagnostic" do
35
- diagnostic_location.file.should eq(fixture_path("list.c"))
36
- diagnostic_location.line.should equal(5)
37
- diagnostic_location.column.should equal(9)
39
+ expect(diagnostic_location.file).to eq(fixture_path("list.c"))
40
+ expect(diagnostic_location.line).to equal(5)
41
+ expect(diagnostic_location.column).to equal(9)
42
+ end
43
+
44
+ it "should be ExpansionLocation" do
45
+ expect(tu_location).to be_kind_of(SourceLocation)
46
+ expect(tu_location).to be_kind_of(ExpansionLocation)
47
+ end
48
+
49
+ describe "Null Location" do
50
+ let(:null_location) { SourceLocation.null_location }
51
+ it "can be a null location" do
52
+ expect(null_location).to be_kind_of(SourceLocation)
53
+ expect(null_location.file).to be_nil
54
+ expect(null_location.line).to eq(0)
55
+ expect(null_location.column).to eq(0)
56
+ expect(null_location.offset).to eq(0)
57
+ end
58
+
59
+ it "is null?" do
60
+ expect(null_location.null?).to equal(true)
61
+ end
62
+
63
+ it "compares as equal to another null location instance" do
64
+ expect(null_location).to eq(SourceLocation.null_location)
65
+ end
66
+ end
67
+
68
+ describe "#from_main_file?", from_3_4: true do
69
+ it "returns true if the cursor location is in main file" do
70
+ expect(loc1_cursor.location.from_main_file?).to be true
71
+ end
72
+
73
+ it "returns false if the cursor location is not in main file" do
74
+ expect(docs_cursor.location.from_main_file?).to be false
75
+ end
76
+ end
77
+
78
+ describe "#in_system_header?", from_3_4: true do
79
+ it "returns false if the cursor location is not in system header" do
80
+ expect(loc1_cursor.location.in_system_header?).to be false
81
+ end
82
+ end
83
+
84
+ describe "#expansion_location" do
85
+ let (:expansion_location) { loc1_cursor.location.expansion_location }
86
+
87
+ it "should be ExpansionLocaion" do
88
+ expect(expansion_location).to be_kind_of(SourceLocation)
89
+ expect(expansion_location).to be_kind_of(ExpansionLocation)
90
+ end
91
+
92
+ it "returns source location that does not care a # line directive" do
93
+ expect(expansion_location.line).to eq(3)
94
+ end
95
+ end
96
+
97
+ describe "#presumed_location" do
98
+ let (:presumed_location) { loc1_cursor.location.presumed_location }
99
+
100
+ it "should be FileLocaion" do
101
+ expect(presumed_location).to be_kind_of(SourceLocation)
102
+ expect(presumed_location).to be_kind_of(PresumedLocation)
103
+ end
104
+
105
+ it "returns preprocessed filename" do
106
+ expect(presumed_location.filename).to eq("dummy.c")
107
+ end
108
+
109
+ it "returns source location specified by a # line directive" do
110
+ expect(presumed_location.line).to eq(124)
111
+ end
112
+ end
113
+
114
+ describe "#file_location", from_3_3: true do
115
+ let (:file_location) { loc1_cursor.location.file_location }
116
+
117
+ it "should be FileLocaion" do
118
+ expect(file_location).to be_kind_of(SourceLocation)
119
+ expect(file_location).to be_kind_of(FileLocation)
120
+ end
121
+
122
+ it "returns source location that does not care a # line directive" do
123
+ expect(file_location.line).to eq(3)
124
+ end
125
+ end
126
+
127
+ describe "#spelling_location" do
128
+ let (:spelling_location) { loc1_cursor.location.spelling_location }
129
+
130
+ it "should be SpellingLocaion" do
131
+ expect(spelling_location).to be_kind_of(SourceLocation)
132
+ expect(spelling_location).to be_kind_of(SpellingLocation)
133
+ end
134
+
135
+ it "returns source location that does not care a # line directive" do
136
+ expect(spelling_location.line).to eq(3)
137
+ end
38
138
  end
39
139
 
40
140
  end
@@ -0,0 +1,76 @@
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 'spec_helper'
22
+
23
+ describe SourceRange do
24
+ let(:tu) { Index.new.parse_translation_unit(fixture_path("list.c")) }
25
+ let(:tu_range) { tu.cursor.extent }
26
+
27
+ it "can be obtained from a cursor" do
28
+ expect(tu_range).to be_kind_of(SourceRange)
29
+ expect(tu_range.null?).to be false
30
+ end
31
+
32
+ it "has start and end source location" do
33
+ expect(tu_range.start).to be_kind_of(SourceLocation)
34
+ expect(tu_range.start.null?).to be false
35
+ expect(tu_range.end).to be_kind_of(SourceLocation)
36
+ expect(tu_range.end.null?).to be false
37
+ end
38
+
39
+ describe "Null Range" do
40
+ let(:null_range) { SourceRange.null_range }
41
+ it "can be a null range" do
42
+ expect(null_range).to be_kind_of(SourceRange)
43
+ end
44
+
45
+ it "is null?" do
46
+ expect(null_range.null?).to equal(true)
47
+ end
48
+
49
+ it "has null locations" do
50
+ expect(null_range.start.null?).to be true
51
+ expect(null_range.end.null?).to be true
52
+ end
53
+
54
+ it "compares as equal to another null range instance" do
55
+ expect(null_range).to eq(SourceRange.null_range)
56
+ end
57
+ end
58
+
59
+ describe "Get Range" do
60
+ let(:range) { SourceRange.new(tu_range.start, tu_range.end) }
61
+
62
+ it "can be obtained from two source locations" do
63
+ expect(range).to be_kind_of(SourceRange)
64
+ expect(range.null?).to be false
65
+ end
66
+
67
+ it "is same to original source range" do
68
+ expect(range).to eq(tu_range)
69
+ end
70
+
71
+ it "is same to original source range's locations" do
72
+ expect(range.start).to eq(tu_range.start)
73
+ expect(range.end).to eq(tu_range.end)
74
+ end
75
+ end
76
+ end