solargraph 0.51.2 → 0.54.2

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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +40 -0
  3. data/.github/workflows/rspec.yml +1 -3
  4. data/.github/workflows/typecheck.yml +34 -0
  5. data/.yardopts +2 -2
  6. data/CHANGELOG.md +127 -5
  7. data/README.md +13 -16
  8. data/SPONSORS.md +1 -7
  9. data/lib/solargraph/api_map/cache.rb +50 -20
  10. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  11. data/lib/solargraph/api_map/store.rb +60 -15
  12. data/lib/solargraph/api_map.rb +282 -123
  13. data/lib/solargraph/bench.rb +3 -2
  14. data/lib/solargraph/cache.rb +29 -5
  15. data/lib/solargraph/complex_type/type_methods.rb +122 -39
  16. data/lib/solargraph/complex_type/unique_type.rb +310 -76
  17. data/lib/solargraph/complex_type.rb +166 -44
  18. data/lib/solargraph/convention.rb +0 -1
  19. data/lib/solargraph/converters/dd.rb +5 -0
  20. data/lib/solargraph/converters/dl.rb +3 -0
  21. data/lib/solargraph/converters/dt.rb +3 -0
  22. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  23. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  24. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  25. data/lib/solargraph/diagnostics.rb +2 -2
  26. data/lib/solargraph/doc_map.rb +187 -0
  27. data/lib/solargraph/gem_pins.rb +72 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +22 -5
  30. data/lib/solargraph/language_server/host/message_worker.rb +49 -5
  31. data/lib/solargraph/language_server/host/sources.rb +8 -65
  32. data/lib/solargraph/language_server/host.rb +65 -84
  33. data/lib/solargraph/language_server/message/base.rb +19 -12
  34. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  35. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  36. data/lib/solargraph/language_server/message/initialize.rb +19 -2
  37. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  38. data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
  39. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  40. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  41. data/lib/solargraph/language_server/message/text_document/hover.rb +3 -1
  42. data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
  43. data/lib/solargraph/language_server/message/text_document.rb +0 -1
  44. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  45. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  46. data/lib/solargraph/language_server/progress.rb +135 -0
  47. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  48. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  49. data/lib/solargraph/language_server.rb +1 -0
  50. data/lib/solargraph/library.rb +207 -111
  51. data/lib/solargraph/location.rb +15 -1
  52. data/lib/solargraph/page.rb +6 -0
  53. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  54. data/lib/solargraph/parser/node_methods.rb +47 -7
  55. data/lib/solargraph/parser/node_processor/base.rb +11 -1
  56. data/lib/solargraph/parser/node_processor.rb +1 -0
  57. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
  58. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +62 -43
  60. data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
  61. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  62. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +57 -0
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +7 -20
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  71. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +4 -4
  72. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  77. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +8 -6
  78. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  79. data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
  80. data/lib/solargraph/parser/parser_gem.rb +12 -0
  81. data/lib/solargraph/parser/region.rb +1 -1
  82. data/lib/solargraph/parser/snippet.rb +2 -0
  83. data/lib/solargraph/parser.rb +8 -12
  84. data/lib/solargraph/pin/base.rb +78 -10
  85. data/lib/solargraph/pin/base_variable.rb +40 -7
  86. data/lib/solargraph/pin/block.rb +69 -46
  87. data/lib/solargraph/pin/callable.rb +147 -0
  88. data/lib/solargraph/pin/closure.rb +23 -3
  89. data/lib/solargraph/pin/common.rb +6 -6
  90. data/lib/solargraph/pin/conversions.rb +36 -5
  91. data/lib/solargraph/pin/delegated_method.rb +6 -2
  92. data/lib/solargraph/pin/documenting.rb +25 -32
  93. data/lib/solargraph/pin/instance_variable.rb +6 -2
  94. data/lib/solargraph/pin/local_variable.rb +13 -1
  95. data/lib/solargraph/pin/method.rb +205 -32
  96. data/lib/solargraph/pin/namespace.rb +20 -7
  97. data/lib/solargraph/pin/parameter.rb +41 -36
  98. data/lib/solargraph/pin/proxy_type.rb +1 -1
  99. data/lib/solargraph/pin/reference/override.rb +2 -2
  100. data/lib/solargraph/pin/reference.rb +8 -0
  101. data/lib/solargraph/pin/search.rb +3 -3
  102. data/lib/solargraph/pin/signature.rb +8 -14
  103. data/lib/solargraph/pin.rb +4 -2
  104. data/lib/solargraph/range.rb +4 -6
  105. data/lib/solargraph/rbs_map/conversions.rb +326 -76
  106. data/lib/solargraph/rbs_map/core_fills.rb +16 -33
  107. data/lib/solargraph/rbs_map/core_map.rb +3 -13
  108. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
  109. data/lib/solargraph/rbs_map.rb +32 -13
  110. data/lib/solargraph/shell.rb +95 -72
  111. data/lib/solargraph/source/chain/array.rb +33 -0
  112. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  113. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  114. data/lib/solargraph/source/chain/call.rb +152 -69
  115. data/lib/solargraph/source/chain/constant.rb +15 -1
  116. data/lib/solargraph/source/chain/if.rb +23 -0
  117. data/lib/solargraph/source/chain/link.rb +17 -2
  118. data/lib/solargraph/source/chain/or.rb +2 -2
  119. data/lib/solargraph/source/chain/z_super.rb +3 -3
  120. data/lib/solargraph/source/chain.rb +85 -26
  121. data/lib/solargraph/source/change.rb +3 -0
  122. data/lib/solargraph/source/cursor.rb +16 -2
  123. data/lib/solargraph/source/source_chainer.rb +8 -5
  124. data/lib/solargraph/source/updater.rb +1 -0
  125. data/lib/solargraph/source.rb +120 -148
  126. data/lib/solargraph/source_map/clip.rb +16 -27
  127. data/lib/solargraph/source_map/data.rb +30 -0
  128. data/lib/solargraph/source_map/mapper.rb +15 -3
  129. data/lib/solargraph/source_map.rb +48 -24
  130. data/lib/solargraph/type_checker/checks.rb +10 -2
  131. data/lib/solargraph/type_checker/rules.rb +6 -1
  132. data/lib/solargraph/type_checker.rb +150 -39
  133. data/lib/solargraph/version.rb +1 -1
  134. data/lib/solargraph/views/environment.erb +3 -5
  135. data/lib/solargraph/workspace/config.rb +9 -6
  136. data/lib/solargraph/workspace.rb +30 -3
  137. data/lib/solargraph/yard_map/cache.rb +6 -0
  138. data/lib/solargraph/yard_map/helpers.rb +1 -1
  139. data/lib/solargraph/yard_map/mapper/to_method.rb +16 -3
  140. data/lib/solargraph/yard_map/mapper.rb +1 -1
  141. data/lib/solargraph/yard_map/to_method.rb +11 -4
  142. data/lib/solargraph/yard_map.rb +1 -292
  143. data/lib/solargraph/yard_tags.rb +20 -0
  144. data/lib/solargraph/yardoc.rb +52 -0
  145. data/lib/solargraph.rb +6 -4
  146. data/solargraph.gemspec +7 -6
  147. metadata +71 -82
  148. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  149. data/lib/solargraph/documentor.rb +0 -76
  150. data/lib/solargraph/language_server/host/cataloger.rb +0 -56
  151. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  152. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  153. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -50
  154. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  155. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  156. data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
  157. data/lib/solargraph/parser/legacy.rb +0 -12
  158. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -153
  159. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  160. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
  161. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  162. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  163. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  164. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  165. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  166. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  167. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  168. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  169. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  170. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  171. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  172. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  173. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  174. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  175. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
  176. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  177. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  178. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  179. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
  180. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  181. data/lib/solargraph/parser/rubyvm.rb +0 -40
  182. data/lib/solargraph/rbs_map/core_signs.rb +0 -33
  183. data/lib/yard-solargraph.rb +0 -33
@@ -8,7 +8,6 @@ module Solargraph
8
8
  class Source
9
9
  autoload :Updater, 'solargraph/source/updater'
10
10
  autoload :Change, 'solargraph/source/change'
11
- autoload :Mapper, 'solargraph/source/mapper'
12
11
  autoload :EncodingFixes, 'solargraph/source/encoding_fixes'
13
12
  autoload :Cursor, 'solargraph/source/cursor'
14
13
  autoload :Chain, 'solargraph/source/chain'
@@ -20,37 +19,35 @@ module Solargraph
20
19
  attr_reader :filename
21
20
 
22
21
  # @return [String]
23
- attr_reader :code
22
+ def code
23
+ finalize
24
+ @code
25
+ end
24
26
 
25
- # @return [Parser::AST::Node]
26
- attr_reader :node
27
+ # @return [Parser::AST::Node, nil]
28
+ def node
29
+ finalize
30
+ @node
31
+ end
27
32
 
28
33
  # @return [Hash{Integer => Array<String>}]
29
- attr_reader :comments
34
+ def comments
35
+ finalize
36
+ @comments
37
+ end
30
38
 
31
39
  # @todo Deprecate?
32
40
  # @return [Integer]
33
41
  attr_reader :version
34
42
 
35
43
  # @param code [String]
36
- # @param filename [String]
44
+ # @param filename [String, nil]
37
45
  # @param version [Integer]
38
46
  def initialize code, filename = nil, version = 0
39
47
  @code = normalize(code)
40
48
  @repaired = code
41
49
  @filename = filename
42
50
  @version = version
43
- @domains = []
44
- begin
45
- @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename)
46
- @parsed = true
47
- rescue Parser::SyntaxError, EncodingError => e
48
- @node = nil
49
- @comments = {}
50
- @parsed = false
51
- ensure
52
- @code.freeze
53
- end
54
51
  end
55
52
 
56
53
  # @param range [Solargraph::Range]
@@ -65,9 +62,9 @@ module Solargraph
65
62
  # @param c2 [Integer]
66
63
  # @return [String]
67
64
  def from_to l1, c1, l2, c2
68
- b = Solargraph::Position.line_char_to_offset(@code, l1, c1)
69
- e = Solargraph::Position.line_char_to_offset(@code, l2, c2)
70
- @code[b..e-1]
65
+ b = Solargraph::Position.line_char_to_offset(code, l1, c1)
66
+ e = Solargraph::Position.line_char_to_offset(code, l2, c2)
67
+ code[b..e-1]
71
68
  end
72
69
 
73
70
  # Get the nearest node that contains the specified index.
@@ -86,57 +83,12 @@ module Solargraph
86
83
  # @param column [Integer]
87
84
  # @return [Array<AST::Node>]
88
85
  def tree_at(line, column)
89
- # offset = Position.line_char_to_offset(@code, line, column)
90
86
  position = Position.new(line, column)
91
87
  stack = []
92
- inner_tree_at @node, position, stack
88
+ inner_tree_at node, position, stack
93
89
  stack
94
90
  end
95
91
 
96
- # Start synchronizing the source. This method updates the code without
97
- # parsing a new AST. The resulting Source object will be marked not
98
- # synchronized (#synchronized? == false).
99
- #
100
- # @param updater [Source::Updater]
101
- # @return [Source]
102
- def start_synchronize updater
103
- raise 'Invalid synchronization' unless updater.filename == filename
104
- real_code = updater.write(@code)
105
- src = Source.allocate
106
- src.filename = filename
107
- src.code = real_code
108
- src.version = updater.version
109
- src.parsed = parsed?
110
- src.repaired = updater.repair(@repaired)
111
- src.synchronized = false
112
- src.node = @node
113
- src.comments = @comments
114
- src.error_ranges = error_ranges
115
- src.last_updater = updater
116
- return src.finish_synchronize unless real_code.lines.length == @code.lines.length
117
- src
118
- end
119
-
120
- # Finish synchronizing a source that was updated via #start_synchronize.
121
- # This method returns self if the source is already synchronized. Otherwise
122
- # it parses the AST and returns a new synchronized Source.
123
- #
124
- # @return [Source]
125
- def finish_synchronize
126
- return self if synchronized?
127
- synced = Source.new(@code, filename)
128
- if synced.parsed?
129
- synced.version = version
130
- return synced
131
- end
132
- synced = Source.new(@repaired, filename)
133
- synced.error_ranges.concat (error_ranges + last_updater.changes.map(&:range))
134
- synced.code = @code
135
- synced.synchronized = true
136
- synced.version = version
137
- synced
138
- end
139
-
140
92
  # Synchronize the Source with an update. This method applies changes to the
141
93
  # code, parses the new code's AST, and returns the resulting Source object.
142
94
  #
@@ -149,70 +101,56 @@ module Solargraph
149
101
  @version = updater.version
150
102
  return self
151
103
  end
152
- synced = Source.new(real_code, filename)
153
- if synced.parsed?
154
- synced.version = updater.version
155
- return synced
104
+ Source.new(@code, filename, updater.version).tap do |src|
105
+ src.repaired = @repaired
106
+ src.error_ranges.concat error_ranges
107
+ src.changes.concat(changes + updater.changes)
156
108
  end
157
- incr_code = updater.repair(@repaired)
158
- synced = Source.new(incr_code, filename)
159
- synced.error_ranges.concat (error_ranges + updater.changes.map(&:range))
160
- synced.code = real_code
161
- synced.version = updater.version
162
- synced
163
109
  end
164
110
 
165
111
  # @param position [Position, Array(Integer, Integer)]
166
112
  # @return [Source::Cursor]
167
113
  def cursor_at position
114
+ finalize
168
115
  Cursor.new(self, position)
169
116
  end
170
117
 
171
118
  # @return [Boolean]
172
119
  def parsed?
120
+ finalize
173
121
  @parsed
174
122
  end
175
123
 
176
124
  def repaired?
177
- @is_repaired ||= (@code != @repaired)
125
+ code != @repaired
178
126
  end
179
127
 
180
128
  # @param position [Position]
181
129
  # @return [Boolean]
182
130
  def string_at? position
183
- if Parser.rubyvm?
184
- string_ranges.each do |range|
185
- if synchronized?
186
- return true if range.include?(position) || range.ending == position
187
- else
188
- return true if last_updater && last_updater.changes.one? && range.contain?(last_updater.changes.first.range.start)
189
- end
190
- end
191
- false
192
- else
193
- return false if Position.to_offset(code, position) >= code.length
194
- string_nodes.each do |node|
195
- range = Range.from_node(node)
196
- next if range.ending.line < position.line
197
- break if range.ending.line > position.line
198
- return true if node.type == :str && range.include?(position) && range.start != position
199
- return true if [:STR, :str].include?(node.type) && range.include?(position) && range.start != position
200
- if node.type == :dstr
201
- inner = node_at(position.line, position.column)
202
- next if inner.nil?
203
- inner_range = Range.from_node(inner)
204
- next unless range.include?(inner_range.ending)
205
- return true if inner.type == :str
206
- inner_code = at(Solargraph::Range.new(inner_range.start, position))
207
- return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
208
- (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
209
- end
210
- break if range.ending.line > position.line
131
+ return false if Position.to_offset(code, position) >= code.length
132
+ string_nodes.each do |node|
133
+ range = Range.from_node(node)
134
+ next if range.ending.line < position.line
135
+ break if range.ending.line > position.line
136
+ return true if node.type == :str && range.include?(position) && range.start != position
137
+ return true if [:STR, :str].include?(node.type) && range.include?(position) && range.start != position
138
+ if node.type == :dstr
139
+ inner = node_at(position.line, position.column)
140
+ next if inner.nil?
141
+ inner_range = Range.from_node(inner)
142
+ next unless range.include?(inner_range.ending)
143
+ return true if inner.type == :str
144
+ inner_code = at(Solargraph::Range.new(inner_range.start, position))
145
+ return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
146
+ (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
211
147
  end
212
- false
148
+ break if range.ending.line > position.line
213
149
  end
150
+ false
214
151
  end
215
152
 
153
+ # @return [::Array<Range>]
216
154
  def string_ranges
217
155
  @string_ranges ||= Parser.string_ranges(node)
218
156
  end
@@ -243,14 +181,14 @@ module Solargraph
243
181
  # @return [String]
244
182
  def code_for(node)
245
183
  rng = Range.from_node(node)
246
- b = Position.line_char_to_offset(@code, rng.start.line, rng.start.column)
247
- e = Position.line_char_to_offset(@code, rng.ending.line, rng.ending.column)
184
+ b = Position.line_char_to_offset(code, rng.start.line, rng.start.column)
185
+ e = Position.line_char_to_offset(code, rng.ending.line, rng.ending.column)
248
186
  frag = code[b..e-1].to_s
249
187
  frag.strip.gsub(/,$/, '')
250
188
  end
251
189
 
252
190
  # @param node [Parser::AST::Node]
253
- # @return [String]
191
+ # @return [String, nil]
254
192
  def comments_for node
255
193
  rng = Range.from_node(node)
256
194
  stringified_comments[rng.start.line] ||= begin
@@ -269,15 +207,9 @@ module Solargraph
269
207
  Location.new(filename, range)
270
208
  end
271
209
 
272
- FOLDING_NODE_TYPES = if Parser.rubyvm?
273
- %i[
274
- CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR HASH ARRAY LIST
275
- ].freeze
276
- else
277
- %i[
210
+ FOLDING_NODE_TYPES = %i[
278
211
  class sclass module def defs if str dstr array while unless kwbegin hash block
279
212
  ].freeze
280
- end
281
213
 
282
214
  # Get an array of ranges that can be folded, e.g., the range of a class
283
215
  # definition or an if condition.
@@ -295,19 +227,19 @@ module Solargraph
295
227
  end
296
228
 
297
229
  def synchronized?
298
- @synchronized = true if @synchronized.nil?
299
- @synchronized
230
+ true
300
231
  end
301
232
 
302
233
  # Get a hash of comments grouped by the line numbers of the associated code.
303
234
  #
304
- # @return [Hash{Integer => Array<Parser::Source::Comment>}]
235
+ # @return [Hash{Integer => String}]
305
236
  def associated_comments
306
237
  @associated_comments ||= begin
307
238
  result = {}
308
239
  buffer = String.new('')
240
+ # @type [Integer, nil]
309
241
  last = nil
310
- @comments.each_pair do |num, snip|
242
+ comments.each_pair do |num, snip|
311
243
  if !last || num == last + 1
312
244
  buffer.concat "#{snip.text}\n"
313
245
  else
@@ -323,6 +255,8 @@ module Solargraph
323
255
 
324
256
  private
325
257
 
258
+ # @param line [Integer]
259
+ # @return [Integer]
326
260
  def first_not_empty_from line
327
261
  cursor = line
328
262
  cursor += 1 while cursor < code_lines.length && code_lines[cursor].strip.empty?
@@ -332,17 +266,14 @@ module Solargraph
332
266
 
333
267
  # @param top [Parser::AST::Node]
334
268
  # @param result [Array<Range>]
335
- # @param parent [Symbol]
269
+ # @param parent [Symbol, nil]
336
270
  # @return [void]
337
271
  def inner_folding_ranges top, result = [], parent = nil
338
272
  return unless Parser.is_ast_node?(top)
339
273
  if FOLDING_NODE_TYPES.include?(top.type)
340
- # @todo Smelly exception for hash's first-level array in RubyVM
341
- unless [:ARRAY, :LIST].include?(top.type) && parent == :HASH
342
- range = Range.from_node(top)
343
- if result.empty? || range.start.line > result.last.start.line
344
- result.push range unless range.ending.line - range.start.line < 2
345
- end
274
+ range = Range.from_node(top)
275
+ if result.empty? || range.start.line > result.last.start.line
276
+ result.push range unless range.ending.line - range.start.line < 2
346
277
  end
347
278
  end
348
279
  top.children.each do |child|
@@ -383,12 +314,12 @@ module Solargraph
383
314
 
384
315
  # @return [Array<Parser::AST::Node>]
385
316
  def string_nodes
386
- @string_nodes ||= string_nodes_in(@node)
317
+ @string_nodes ||= string_nodes_in(node)
387
318
  end
388
319
 
389
320
  # @return [Array<Range>]
390
321
  def comment_ranges
391
- @comment_ranges ||= @comments.values.map(&:range)
322
+ @comment_ranges ||= comments.values.map(&:range)
392
323
  end
393
324
 
394
325
  # Get an array of foldable comment block ranges. Blocks are excluded if
@@ -411,7 +342,7 @@ module Solargraph
411
342
  result
412
343
  end
413
344
 
414
- # @param n [Parser::AST::Node]
345
+ # @param n [Parser::AST::Node, nil]
415
346
  # @return [Array<Parser::AST::Node>]
416
347
  def string_nodes_in n
417
348
  result = []
@@ -425,66 +356,103 @@ module Solargraph
425
356
  result
426
357
  end
427
358
 
428
- # @param node [Parser::AST::Node]
359
+ # @param node [Parser::AST::Node, nil]
429
360
  # @param position [Position]
430
361
  # @param stack [Array<Parser::AST::Node>]
431
362
  # @return [void]
432
363
  def inner_tree_at node, position, stack
433
364
  return if node.nil?
434
365
  here = Range.from_node(node)
435
- if here.contain?(position) || colonized(here, position, node)
366
+ if here.contain?(position)
436
367
  stack.unshift node
437
368
  node.children.each do |c|
438
369
  next unless Parser.is_ast_node?(c)
439
- next if !Parser.rubyvm? && c.loc.expression.nil?
370
+ next if c.loc.expression.nil?
440
371
  inner_tree_at(c, position, stack)
441
372
  end
442
373
  end
443
374
  end
444
375
 
445
- def colonized range, position, node
446
- node.type == :COLON2 &&
447
- range.ending.line == position.line &&
448
- range.ending.character == position.character - 2 &&
449
- code[Position.to_offset(code, Position.new(position.line, position.character - 2)), 2] == '::'
450
- end
451
-
452
376
  protected
453
377
 
378
+ def changes
379
+ @changes ||= []
380
+ end
381
+
454
382
  # @return [String]
455
383
  attr_writer :filename
456
384
 
457
385
  # @return [Integer]
458
386
  attr_writer :version
459
387
 
388
+ def finalize
389
+ return if @finalized && changes.empty?
390
+
391
+ changes.each do |change|
392
+ @code = change.write(@code)
393
+ end
394
+ @finalized = true
395
+ begin
396
+ @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename)
397
+ @parsed = true
398
+ @repaired = @code
399
+ rescue Parser::SyntaxError, EncodingError => e
400
+ @node = nil
401
+ @comments = {}
402
+ @parsed = false
403
+ ensure
404
+ @code.freeze
405
+ end
406
+ if !@parsed && !changes.empty?
407
+ changes.each do |change|
408
+ @repaired = change.repair(@repaired)
409
+ end
410
+ error_ranges.concat(changes.map(&:range))
411
+ begin
412
+ @node, @comments = Solargraph::Parser.parse_with_comments(@repaired, filename)
413
+ @parsed = true
414
+ rescue Parser::SyntaxError, EncodingError => e
415
+ @node = nil
416
+ @comments = {}
417
+ @parsed = false
418
+ end
419
+ elsif @parsed
420
+ error_ranges.clear
421
+ end
422
+ changes.clear
423
+ end
424
+
460
425
  # @param val [String]
461
426
  # @return [String]
462
427
  def code=(val)
463
- @code_lines= nil
428
+ @code_lines = nil
429
+ @finalized = false
464
430
  @code = val
465
431
  end
466
432
 
467
- # @return [Parser::AST::Node]
433
+ # @return [Parser::AST::Node, nil]
468
434
  attr_writer :node
469
435
 
470
436
  # @return [Array<Range>]
471
437
  attr_writer :error_ranges
472
438
 
473
439
  # @return [String]
474
- attr_accessor :repaired
440
+ attr_writer :repaired
441
+
442
+ def repaired
443
+ finalize
444
+ @repaired
445
+ end
475
446
 
476
447
  # @return [Boolean]
477
448
  attr_writer :parsed
478
449
 
479
- # @return [Array<Parser::Source::Comment>]
450
+ # @return [Hash{Integer => String}
480
451
  attr_writer :comments
481
452
 
482
453
  # @return [Boolean]
483
454
  attr_writer :synchronized
484
455
 
485
- # @return [Source::Updater]
486
- attr_accessor :last_updater
487
-
488
456
  private
489
457
 
490
458
  # @return [Array<String>]
@@ -503,7 +471,7 @@ module Solargraph
503
471
  end
504
472
 
505
473
  # @param code [String]
506
- # @param filename [String]
474
+ # @param filename [String, nil]
507
475
  # @param version [Integer]
508
476
  # @return [Solargraph::Source]
509
477
  def load_string code, filename = nil, version = 0
@@ -516,6 +484,10 @@ module Solargraph
516
484
  # HACK: Pass a dummy code object to the parser for plugins that
517
485
  # expect it not to be nil
518
486
  YARD::Docstring.parser.parse(comments, YARD::CodeObjects::Base.new(:root, 'stub'))
487
+ rescue StandardError => e
488
+ Solargraph.logger.info "YARD failed to parse docstring: [#{e.class}] #{e.message}"
489
+ Solargraph.logger.debug "Unparsed comment: #{comments}"
490
+ YARD::Docstring.parser
519
491
  end
520
492
  end
521
493
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Solargraph
4
4
  class SourceMap
5
- # A static analysis tool for obtaining definitions, completions,
6
- # signatures, and type inferences from a cursor.
5
+ # A static analysis tool for obtaining definitions, Completions,
6
+ # signatures, and type inferences from a Cursor.
7
7
  #
8
8
  class Clip
9
9
  # @param api_map [ApiMap]
@@ -11,9 +11,10 @@ module Solargraph
11
11
  def initialize api_map, cursor
12
12
  @api_map = api_map
13
13
  @cursor = cursor
14
+ block.rebind(api_map) if block.is_a?(Pin::Block)
14
15
  end
15
16
 
16
- # @return [Array<Pin::Base>]
17
+ # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
17
18
  def define
18
19
  return [] if cursor.comment? || cursor.chain.literal?
19
20
  result = cursor.chain.define(api_map, block, locals)
@@ -50,23 +51,24 @@ module Solargraph
50
51
  def infer
51
52
  result = cursor.chain.infer(api_map, block, locals)
52
53
  if result.tag == 'Class'
53
- # HACK: Exception to return Object from Class#new
54
+ # HACK: Exception to return BasicObject from Class#new
54
55
  dfn = cursor.chain.define(api_map, block, locals).first
55
- return ComplexType.try_parse('Object') if dfn && dfn.path == 'Class#new'
56
+ return ComplexType.try_parse('::BasicObject') if dfn && dfn.path == 'Class#new'
56
57
  end
57
58
  return result unless result.tag == 'self'
58
- ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).namespace)
59
+ cursor.chain.base.infer(api_map, block, locals)
59
60
  end
60
61
 
61
62
  # Get an array of all the locals that are visible from the cursors's
62
63
  # position. Locals can be local variables, method parameters, or block
63
64
  # parameters. The array starts with the nearest local pin.
64
65
  #
65
- # @return [Array<Solargraph::Pin::Base>]
66
+ # @return [::Array<Solargraph::Pin::Base>]
66
67
  def locals
67
68
  @locals ||= source_map.locals_at(location)
68
69
  end
69
70
 
71
+ # @return [::Array<String>]
70
72
  def gates
71
73
  block.gates
72
74
  end
@@ -99,11 +101,12 @@ module Solargraph
99
101
  @source_map ||= api_map.source_map(cursor.filename)
100
102
  end
101
103
 
104
+ # @return [Location]
102
105
  def location
103
106
  Location.new(source_map.filename, Solargraph::Range.new(cursor.position, cursor.position))
104
107
  end
105
108
 
106
- # @return [Solargraph::Pin::Base]
109
+ # @return [Solargraph::Pin::Closure]
107
110
  def block
108
111
  @block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
109
112
  end
@@ -115,22 +118,7 @@ module Solargraph
115
118
  @context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
116
119
  end
117
120
 
118
- # @return [Array<Pin::Base>]
119
- def yielded_self_pins
120
- return [] unless block.is_a?(Pin::Block) && block.receiver
121
- chain = Parser.chain(block.receiver, source_map.source.filename)
122
- receiver_pin = chain.define(api_map, context_pin, locals).first
123
- return [] if receiver_pin.nil?
124
- result = []
125
- ys = receiver_pin.docstring.tag(:yieldpublic)
126
- unless ys.nil? || ys.types.empty?
127
- ysct = ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
128
- result.concat api_map.get_complex_type_methods(ysct, '', false)
129
- end
130
- result
131
- end
132
-
133
- # @return [Array<Pin::KeywordParam]
121
+ # @return [Array<Pin::KeywordParam>]
134
122
  def complete_keyword_parameters
135
123
  return [] unless cursor.argument? && cursor.chain.links.one? && cursor.word =~ /^[a-z0-9_]*:?$/
136
124
  pins = signify
@@ -154,7 +142,7 @@ module Solargraph
154
142
  result
155
143
  end
156
144
 
157
- # @param result [Array<Pin::Base>]
145
+ # @param result [Enumerable<Pin::Base>]
158
146
  # @return [Completion]
159
147
  def package_completions result
160
148
  frag_start = cursor.start_of_word.to_s.downcase
@@ -165,6 +153,7 @@ module Solargraph
165
153
  Completion.new(filtered, cursor.range)
166
154
  end
167
155
 
156
+ # @return [Completion]
168
157
  def tag_complete
169
158
  result = []
170
159
  match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i)
@@ -183,6 +172,7 @@ module Solargraph
183
172
  package_completions(result)
184
173
  end
185
174
 
175
+ # @return [Completion]
186
176
  def code_complete
187
177
  result = []
188
178
  result.concat complete_keyword_parameters
@@ -224,14 +214,13 @@ module Solargraph
224
214
  result.concat api_map.get_constants(context_pin.context.namespace, *gates)
225
215
  result.concat api_map.get_methods(block.binder.namespace, scope: block.binder.scope, visibility: [:public, :private, :protected])
226
216
  result.concat api_map.get_methods('Kernel')
227
- # result.concat ApiMap.keywords
228
217
  result.concat api_map.keyword_pins.to_a
229
- result.concat yielded_self_pins
230
218
  end
231
219
  end
232
220
  package_completions(result)
233
221
  end
234
222
 
223
+ # @return [Array<Pin::Base>]
235
224
  def file_global_methods
236
225
  return [] if cursor.word.empty?
237
226
  source_map.pins.select do |pin|
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class SourceMap
5
+ class Data
6
+ def initialize source
7
+ @source = source
8
+ end
9
+
10
+ def pins
11
+ generate
12
+ @pins || []
13
+ end
14
+
15
+ def locals
16
+ generate
17
+ @locals || []
18
+ end
19
+
20
+ private
21
+
22
+ def generate
23
+ return if @generated
24
+
25
+ @generated = true
26
+ @pins, @locals = Mapper.map(@source)
27
+ end
28
+ end
29
+ end
30
+ end