solargraph 0.38.6 → 0.39.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/SPONSORS.md +9 -0
  3. data/lib/solargraph.rb +1 -0
  4. data/lib/solargraph/api_map.rb +24 -13
  5. data/lib/solargraph/api_map/bundler_methods.rb +3 -0
  6. data/lib/solargraph/api_map/source_to_yard.rb +1 -6
  7. data/lib/solargraph/api_map/store.rb +19 -3
  8. data/lib/solargraph/complex_type/type_methods.rb +4 -4
  9. data/lib/solargraph/convention/base.rb +0 -5
  10. data/lib/solargraph/core_fills.rb +28 -2
  11. data/lib/solargraph/diagnostics/base.rb +1 -0
  12. data/lib/solargraph/diagnostics/type_check.rb +13 -13
  13. data/lib/solargraph/language_server/host.rb +11 -2
  14. data/lib/solargraph/language_server/host/sources.rb +20 -11
  15. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -11
  16. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  17. data/lib/solargraph/library.rb +3 -3
  18. data/lib/solargraph/parser.rb +26 -0
  19. data/lib/solargraph/parser/comment_ripper.rb +52 -0
  20. data/lib/solargraph/parser/legacy.rb +12 -0
  21. data/lib/solargraph/parser/legacy/class_methods.rb +105 -0
  22. data/lib/solargraph/parser/legacy/flawed_builder.rb +16 -0
  23. data/lib/solargraph/parser/legacy/node_chainer.rb +115 -0
  24. data/lib/solargraph/parser/legacy/node_methods.rb +289 -0
  25. data/lib/solargraph/parser/legacy/node_processors.rb +54 -0
  26. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +23 -0
  27. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +35 -0
  28. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +15 -0
  29. data/lib/solargraph/parser/legacy/node_processors/block_node.rb +22 -0
  30. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +25 -0
  31. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +23 -0
  32. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +63 -0
  33. data/lib/solargraph/parser/legacy/node_processors/defs_node.rb +36 -0
  34. data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +23 -0
  35. data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +38 -0
  36. data/lib/solargraph/parser/legacy/node_processors/lvasgn_node.rb +28 -0
  37. data/lib/solargraph/parser/legacy/node_processors/namespace_node.rb +39 -0
  38. data/lib/solargraph/parser/legacy/node_processors/orasgn_node.rb +16 -0
  39. data/lib/solargraph/parser/legacy/node_processors/resbody_node.rb +36 -0
  40. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +21 -0
  41. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +232 -0
  42. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +18 -0
  43. data/lib/solargraph/parser/node_methods.rb +43 -0
  44. data/lib/solargraph/parser/node_processor.rb +43 -0
  45. data/lib/solargraph/parser/node_processor/base.rb +77 -0
  46. data/lib/solargraph/{source_map → parser}/region.rb +11 -6
  47. data/lib/solargraph/parser/rubyvm.rb +40 -0
  48. data/lib/solargraph/parser/rubyvm/class_methods.rb +146 -0
  49. data/lib/solargraph/parser/rubyvm/node_chainer.rb +133 -0
  50. data/lib/solargraph/parser/rubyvm/node_methods.rb +279 -0
  51. data/lib/solargraph/parser/rubyvm/node_processors.rb +60 -0
  52. data/lib/solargraph/parser/rubyvm/node_processors/alias_node.rb +23 -0
  53. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +62 -0
  54. data/lib/solargraph/parser/rubyvm/node_processors/begin_node.rb +15 -0
  55. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +22 -0
  56. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +22 -0
  57. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +23 -0
  58. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +64 -0
  59. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +57 -0
  60. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +23 -0
  61. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +38 -0
  62. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +34 -0
  63. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +20 -0
  64. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +27 -0
  65. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +39 -0
  66. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +26 -0
  67. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +15 -0
  68. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +45 -0
  69. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +21 -0
  70. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +15 -0
  71. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +292 -0
  72. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +18 -0
  73. data/lib/solargraph/parser/snippet.rb +13 -0
  74. data/lib/solargraph/pin/attribute.rb +8 -0
  75. data/lib/solargraph/pin/base.rb +1 -1
  76. data/lib/solargraph/pin/base_method.rb +26 -4
  77. data/lib/solargraph/pin/base_variable.rb +7 -8
  78. data/lib/solargraph/pin/block.rb +1 -1
  79. data/lib/solargraph/pin/constant.rb +16 -0
  80. data/lib/solargraph/pin/conversions.rb +2 -2
  81. data/lib/solargraph/pin/method.rb +26 -14
  82. data/lib/solargraph/pin/parameter.rb +56 -2
  83. data/lib/solargraph/pin/reference.rb +1 -0
  84. data/lib/solargraph/pin/reference/override.rb +2 -0
  85. data/lib/solargraph/pin/reference/prepend.rb +10 -0
  86. data/lib/solargraph/pin/yard_pin/constant.rb +2 -4
  87. data/lib/solargraph/pin/yard_pin/method.rb +34 -18
  88. data/lib/solargraph/pin/yard_pin/namespace.rb +3 -11
  89. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +3 -12
  90. data/lib/solargraph/range.rb +8 -2
  91. data/lib/solargraph/shell.rb +17 -11
  92. data/lib/solargraph/source.rb +114 -135
  93. data/lib/solargraph/source/chain.rb +11 -3
  94. data/lib/solargraph/source/chain/call.rb +1 -2
  95. data/lib/solargraph/source/chain/constant.rb +44 -8
  96. data/lib/solargraph/source/chain/link.rb +1 -0
  97. data/lib/solargraph/source/cursor.rb +2 -28
  98. data/lib/solargraph/source/source_chainer.rb +12 -6
  99. data/lib/solargraph/source/updater.rb +2 -0
  100. data/lib/solargraph/source_map.rb +0 -2
  101. data/lib/solargraph/source_map/clip.rb +24 -17
  102. data/lib/solargraph/source_map/mapper.rb +34 -29
  103. data/lib/solargraph/type_checker.rb +367 -275
  104. data/lib/solargraph/type_checker/checks.rb +95 -0
  105. data/lib/solargraph/type_checker/param_def.rb +2 -17
  106. data/lib/solargraph/type_checker/rules.rb +53 -0
  107. data/lib/solargraph/version.rb +1 -1
  108. data/lib/solargraph/views/environment.erb +5 -3
  109. data/lib/solargraph/workspace.rb +17 -2
  110. data/lib/solargraph/workspace/config.rb +15 -7
  111. data/lib/solargraph/yard_map.rb +89 -49
  112. data/lib/solargraph/yard_map/core_docs.rb +1 -1
  113. data/solargraph.gemspec +2 -1
  114. metadata +88 -32
  115. data/OVERVIEW.md +0 -37
  116. data/lib/solargraph/source/flawed_builder.rb +0 -15
  117. data/lib/solargraph/source/node_chainer.rb +0 -111
  118. data/lib/solargraph/source/node_methods.rb +0 -240
  119. data/lib/solargraph/source_map/node_processor.rb +0 -85
  120. data/lib/solargraph/source_map/node_processor/alias_node.rb +0 -21
  121. data/lib/solargraph/source_map/node_processor/args_node.rb +0 -24
  122. data/lib/solargraph/source_map/node_processor/base.rb +0 -103
  123. data/lib/solargraph/source_map/node_processor/begin_node.rb +0 -13
  124. data/lib/solargraph/source_map/node_processor/block_node.rb +0 -21
  125. data/lib/solargraph/source_map/node_processor/casgn_node.rb +0 -21
  126. data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +0 -21
  127. data/lib/solargraph/source_map/node_processor/def_node.rb +0 -62
  128. data/lib/solargraph/source_map/node_processor/defs_node.rb +0 -33
  129. data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +0 -21
  130. data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +0 -34
  131. data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +0 -24
  132. data/lib/solargraph/source_map/node_processor/namespace_node.rb +0 -35
  133. data/lib/solargraph/source_map/node_processor/orasgn_node.rb +0 -14
  134. data/lib/solargraph/source_map/node_processor/resbody_node.rb +0 -32
  135. data/lib/solargraph/source_map/node_processor/sclass_node.rb +0 -19
  136. data/lib/solargraph/source_map/node_processor/send_node.rb +0 -217
  137. data/lib/solargraph/source_map/node_processor/sym_node.rb +0 -16
@@ -7,28 +7,20 @@ module Solargraph
7
7
  include YardMixin
8
8
 
9
9
  def initialize code_object, spec, closure = nil
10
- @code_object = code_object
11
- @spec = spec
12
10
  closure ||= Solargraph::Pin::Namespace.new(
13
11
  name: code_object.namespace.to_s,
14
12
  closure: Pin::ROOT_PIN,
15
13
  gates: [code_object.namespace.to_s]
16
14
  )
17
15
  super(
18
- location: location,
16
+ location: object_location(code_object, spec),
19
17
  name: code_object.name.to_s,
20
- comments: nil,
21
- type: namespace_type,
18
+ comments: code_object.docstring ? code_object.docstring.all.to_s : '',
19
+ type: code_object.is_a?(YARD::CodeObjects::ClassObject) ? :class : :module,
22
20
  visibility: code_object.visibility,
23
21
  closure: closure
24
22
  )
25
23
  end
26
-
27
- private
28
-
29
- def namespace_type
30
- code_object.is_a?(YARD::CodeObjects::ClassObject) ? :class : :module
31
- end
32
24
  end
33
25
  end
34
26
  end
@@ -8,23 +8,14 @@ module Solargraph
8
8
 
9
9
  attr_reader :spec
10
10
 
11
- @@gate_cache ||= {}
12
-
13
- def comments
14
- @comments ||= code_object.docstring ? code_object.docstring.all.to_s : ''
15
- end
11
+ attr_reader :location
16
12
 
17
- def location
18
- # Guarding with @located because nil locations are valid
19
- return @location if @located
20
- @located = true
21
- @location = object_location
22
- end
13
+ @@gate_cache ||= {}
23
14
 
24
15
  private
25
16
 
26
17
  # @return [Solargraph::Location, nil]
27
- def object_location
18
+ def object_location code_object, spec
28
19
  return nil if spec.nil? || code_object.nil? || code_object.file.nil? || code_object.line.nil?
29
20
  file = File.join(spec.full_gem_path, code_object.file)
30
21
  Solargraph::Location.new(file, Solargraph::Range.from_to(code_object.line - 1, 0, code_object.line - 1, 0))
@@ -62,10 +62,16 @@ module Solargraph
62
62
 
63
63
  # Get a range from a node.
64
64
  #
65
- # @param node [Parser::AST::Node]
65
+ # @param node [RubyVM::AbstractSyntaxTree::Node, Parser::AST::Node]
66
66
  # @return [Range]
67
67
  def self.from_node node
68
- from_expr(node.loc.expression)
68
+ if defined?(RubyVM::AbstractSyntaxTree::Node)
69
+ if node.is_a?(RubyVM::AbstractSyntaxTree::Node)
70
+ Solargraph::Range.from_to(node.first_lineno - 1, node.first_column, node.last_lineno - 1, node.last_column)
71
+ end
72
+ elsif node.loc && node.loc.expression
73
+ from_expr(node.loc.expression)
74
+ end
69
75
  end
70
76
 
71
77
  # Get a range from a Parser range, usually found in
@@ -14,7 +14,6 @@ module Solargraph
14
14
  end
15
15
 
16
16
  desc 'socket', 'Run a Solargraph socket server'
17
-
18
17
  option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
19
18
  option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
20
19
  def socket
@@ -77,6 +76,8 @@ module Solargraph
77
76
  ver = version || Solargraph::YardMap::CoreDocs.best_download
78
77
  puts "Downloading docs for #{ver}..."
79
78
  Solargraph::YardMap::CoreDocs.download ver
79
+ # Clear cached documentation if it exists
80
+ FileUtils.rm_rf Dir.glob(File.join(Solargraph::YardMap::CoreDocs.cache_dir, ver, '*.ser'))
80
81
  rescue ArgumentError => e
81
82
  STDERR.puts "ERROR: #{e.message}"
82
83
  STDERR.puts "Run `solargraph available-cores` for a list."
@@ -93,7 +94,13 @@ module Solargraph
93
94
  puts Solargraph::YardMap::CoreDocs.available.join("\n")
94
95
  end
95
96
 
96
- desc 'clear', 'Delete the cached documentation'
97
+ desc 'clear', 'Delete all cached documentation'
98
+ long_desc %(
99
+ This command will delete all core and gem documentation from the cache.
100
+ You can also delete specific gem caches with the `uncache` command or
101
+ update documentation for specific Ruby versions with the `download-core`
102
+ command.
103
+ )
97
104
  def clear
98
105
  puts "Deleting the cached documentation"
99
106
  Solargraph::YardMap::CoreDocs.clear
@@ -117,14 +124,14 @@ module Solargraph
117
124
  puts Solargraph::Diagnostics.reporters
118
125
  end
119
126
 
120
- desc 'typecheck [FILE]', 'Run the type checker'
127
+ desc 'typecheck [FILE(s)]', 'Run the type checker'
121
128
  long_desc %(
122
- Perform type checking on one or more files is a workspace.
123
- A normal check reports problems with type definitions in method
124
- parameters and return values. A strict check performs static analysis of
125
- code to validate return types and arguments in method calls.
129
+ Perform type checking on one or more files in a workspace. Check the
130
+ entire workspace if no files are specified.
131
+
132
+ Type checking levels are normal, typed, strict, and strong.
126
133
  )
127
- option :strict, type: :boolean, aliases: :s, desc: 'Use strict typing', default: false
134
+ option :level, type: :string, aliases: [:mode, :m, :l], desc: 'Type checking level', default: 'normal'
128
135
  option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
129
136
  def typecheck *files
130
137
  directory = File.realpath(options[:directory])
@@ -137,9 +144,8 @@ module Solargraph
137
144
  probcount = 0
138
145
  filecount = 0
139
146
  files.each do |file|
140
- checker = TypeChecker.new(file, api_map: api_map)
141
- problems = checker.param_type_problems + checker.return_type_problems
142
- problems.concat checker.strict_type_problems if options[:strict]
147
+ checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym)
148
+ problems = checker.problems
143
149
  next if problems.empty?
144
150
  problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
145
151
  puts problems.map { |prob| "#{prob.location.filename}:#{prob.location.range.start.line + 1} - #{prob.message}" }.join("\n")
@@ -1,25 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parser/current'
4
3
  require 'yard'
5
4
 
6
5
  module Solargraph
7
6
  # A Ruby file that has been parsed into an AST.
8
7
  #
9
8
  class Source
10
- autoload :FlawedBuilder, 'solargraph/source/flawed_builder'
9
+ # autoload :FlawedBuilder, 'solargraph/source/flawed_builder'
11
10
  autoload :Updater, 'solargraph/source/updater'
12
11
  autoload :Change, 'solargraph/source/change'
13
12
  autoload :Mapper, 'solargraph/source/mapper'
14
- autoload :NodeMethods, 'solargraph/source/node_methods'
13
+ # autoload :NodeMethods, 'solargraph/source/node_methods'
15
14
  autoload :EncodingFixes, 'solargraph/source/encoding_fixes'
16
15
  autoload :Cursor, 'solargraph/source/cursor'
17
16
  autoload :Chain, 'solargraph/source/chain'
18
17
  autoload :SourceChainer, 'solargraph/source/source_chainer'
19
- autoload :NodeChainer, 'solargraph/source/node_chainer'
18
+ # autoload :NodeChainer, 'solargraph/source/node_chainer'
20
19
 
21
20
  include EncodingFixes
22
- include NodeMethods
21
+ # include NodeMethods
23
22
 
24
23
  # @return [String]
25
24
  attr_reader :filename
@@ -30,7 +29,7 @@ module Solargraph
30
29
  # @return [Parser::AST::Node]
31
30
  attr_reader :node
32
31
 
33
- # @return [Array<Parser::Source::Comment>]
32
+ # @return [Hash{Integer => Array<String>}]
34
33
  attr_reader :comments
35
34
 
36
35
  # @todo Deprecate?
@@ -47,7 +46,8 @@ module Solargraph
47
46
  @version = version
48
47
  @domains = []
49
48
  begin
50
- @node, @comments = Source.parse_with_comments(@code, filename)
49
+ # @node, @comments = Source.parse_with_comments(@code, filename)
50
+ @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename)
51
51
  @parsed = true
52
52
  rescue Parser::SyntaxError, EncodingError => e
53
53
  # @todo 100% whitespace results in a nil node, so there's no reason to parse it.
@@ -55,12 +55,12 @@ module Solargraph
55
55
  # node with a location that encompasses the range.
56
56
  # @node, @comments = Source.parse_with_comments(@code.gsub(/[^\s]/, ' '), filename)
57
57
  @node = nil
58
- @comments = []
58
+ @comments = {}
59
59
  @parsed = false
60
- rescue Exception => e
61
- Solargraph.logger.warn "[#{e.class}] #{e.message}"
62
- Solargraph.logger.warn e.backtrace.join("\n")
63
- raise "Error parsing #{filename || '(source)'}: [#{e.class}] #{e.message}"
60
+ # rescue Exception => e
61
+ # Solargraph.logger.warn "[#{e.class}] #{e.message}"
62
+ # Solargraph.logger.warn e.backtrace.join("\n")
63
+ # raise "Error parsing #{filename || '(source)'}: [#{e.class}] #{e.message}"
64
64
  ensure
65
65
  @code.freeze
66
66
  end
@@ -193,25 +193,41 @@ module Solargraph
193
193
  # @param position [Position]
194
194
  # @return [Boolean]
195
195
  def string_at? position
196
- return false if Position.to_offset(code, position) >= code.length
197
- string_nodes.each do |node|
198
- range = Range.from_node(node)
199
- next if range.ending.line < position.line
200
- break if range.ending.line > position.line
201
- return true if node.type == :str && range.include?(position) && range.start != position
202
- if node.type == :dstr
203
- inner = node_at(position.line, position.column)
204
- next if inner.nil?
205
- inner_range = Range.from_node(inner)
206
- next unless range.include?(inner_range.ending)
207
- return true if inner.type == :str
208
- inner_code = at(Solargraph::Range.new(inner_range.start, position))
209
- return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
210
- (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
196
+ if Parser.rubyvm?
197
+ string_ranges.each do |range|
198
+ if synchronized?
199
+ return true if range.include?(position) || range.ending == position
200
+ else
201
+ return true if last_updater && last_updater.changes.one? && range.contain?(last_updater.changes.first.range.start)
202
+ end
211
203
  end
212
- break if range.ending.line > position.line
204
+ false
205
+ else
206
+ return false if Position.to_offset(code, position) >= code.length
207
+ string_nodes.each do |node|
208
+ range = Range.from_node(node)
209
+ next if range.ending.line < position.line
210
+ break if range.ending.line > position.line
211
+ return true if node.type == :str && range.include?(position) && range.start != position
212
+ return true if [:STR, :str].include?(node.type) && range.include?(position) && range.start != position
213
+ if node.type == :dstr
214
+ inner = node_at(position.line, position.column)
215
+ next if inner.nil?
216
+ inner_range = Range.from_node(inner)
217
+ next unless range.include?(inner_range.ending)
218
+ return true if inner.type == :str
219
+ inner_code = at(Solargraph::Range.new(inner_range.start, position))
220
+ return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
221
+ (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
222
+ end
223
+ break if range.ending.line > position.line
224
+ end
225
+ false
213
226
  end
214
- false
227
+ end
228
+
229
+ def string_ranges
230
+ @string_ranges ||= Parser.string_ranges(node)
215
231
  end
216
232
 
217
233
  # @param position [Position]
@@ -228,18 +244,7 @@ module Solargraph
228
244
  # @param name [String]
229
245
  # @return [Array<Location>]
230
246
  def references name
231
- inner_node_references(name, node).map do |n|
232
- offset = Position.to_offset(code, get_node_start_position(n))
233
- soff = code.index(name, offset)
234
- eoff = soff + name.length
235
- Location.new(
236
- filename,
237
- Range.new(
238
- Position.from_offset(code, soff),
239
- Position.from_offset(code, eoff)
240
- )
241
- )
242
- end
247
+ Parser.references self, name
243
248
  end
244
249
 
245
250
  # @return [Array<Range>]
@@ -250,8 +255,9 @@ module Solargraph
250
255
  # @param node [Parser::AST::Node]
251
256
  # @return [String]
252
257
  def code_for(node)
253
- b = Position.line_char_to_offset(@code, node.location.line, node.location.column)
254
- e = Position.line_char_to_offset(@code, node.location.last_line, node.location.last_column)
258
+ rng = Range.from_node(node)
259
+ b = Position.line_char_to_offset(@code, rng.start.line, rng.start.column)
260
+ e = Position.line_char_to_offset(@code, rng.ending.line, rng.ending.column)
255
261
  frag = code[b..e-1].to_s
256
262
  frag.strip.gsub(/,$/, '')
257
263
  end
@@ -259,9 +265,10 @@ module Solargraph
259
265
  # @param node [Parser::AST::Node]
260
266
  # @return [String]
261
267
  def comments_for node
262
- stringified_comments[node.loc.line] ||= begin
263
- arr = associated_comments[node.loc.line]
264
- arr ? stringify_comment_array(arr) : nil
268
+ rng = Range.from_node(node)
269
+ stringified_comments[rng.start.line] ||= begin
270
+ buff = associated_comments[rng.start.line]
271
+ buff ? stringify_comment_array(buff) : nil
265
272
  end
266
273
  end
267
274
 
@@ -275,9 +282,15 @@ module Solargraph
275
282
  Location.new(filename, range)
276
283
  end
277
284
 
278
- FOLDING_NODE_TYPES = %i[
279
- class sclass module def defs if str dstr array while unless kwbegin hash block
280
- ].freeze
285
+ FOLDING_NODE_TYPES = if Parser.rubyvm?
286
+ %i[
287
+ CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR
288
+ ].freeze
289
+ else
290
+ %i[
291
+ class sclass module def defs if str dstr array while unless kwbegin hash block
292
+ ].freeze
293
+ end
281
294
 
282
295
  # Get an array of ranges that can be folded, e.g., the range of a class
283
296
  # definition or an if condition.
@@ -305,23 +318,37 @@ module Solargraph
305
318
  def associated_comments
306
319
  @associated_comments ||= begin
307
320
  result = {}
308
- Parser::Source::Comment.associate_locations(node, comments).each_pair do |loc, all|
309
- block = all.select { |l| l.loc.line < loc.line }
310
- next if block.empty?
311
- result[loc.line] ||= []
312
- result[loc.line].concat block
321
+ buffer = String.new('')
322
+ last = nil
323
+ @comments.each_pair do |num, snip|
324
+ if !last || num == last + 1
325
+ buffer.concat "#{snip.text}\n"
326
+ else
327
+ result[first_not_empty_from(last + 1)] = buffer.clone
328
+ buffer.replace "#{snip.text}\n"
329
+ end
330
+ last = num
313
331
  end
332
+ result[first_not_empty_from(last + 1)] = buffer unless buffer.empty? || last.nil?
314
333
  result
315
334
  end
316
335
  end
317
336
 
318
337
  private
319
338
 
339
+ def first_not_empty_from line
340
+ cursor = line
341
+ cursor += 1 while cursor < code.lines.length && code.lines[cursor].strip.empty?
342
+ cursor = line if cursor > code.lines.length
343
+ cursor
344
+ end
345
+
320
346
  # @param top [Parser::AST::Node]
321
347
  # @param result [Array<Range>]
322
348
  # @return [void]
323
349
  def inner_folding_ranges top, result = []
324
- return unless top.is_a?(Parser::AST::Node)
350
+ # return unless top.is_a?(::Parser::AST::Node)
351
+ return unless Parser.is_ast_node?(top)
325
352
  if FOLDING_NODE_TYPES.include?(top.type)
326
353
  range = Range.from_node(top)
327
354
  if result.empty? || range.start.line > result.last.start.line
@@ -335,27 +362,24 @@ module Solargraph
335
362
 
336
363
  # Get a string representation of an array of comments.
337
364
  #
338
- # @param comments [Array<Parser::Source::Comment>]
365
+ # @param comments [String]
339
366
  # @return [String]
340
367
  def stringify_comment_array comments
341
- ctxt = ''
342
- num = nil
368
+ ctxt = String.new('')
343
369
  started = false
344
- last_line = nil
345
- comments.each { |l|
370
+ skip = nil
371
+ comments.lines.each { |l|
346
372
  # Trim the comment and minimum leading whitespace
347
- p = l.text.gsub(/^#+/, '')
348
- if num.nil? and !p.strip.empty?
349
- num = p.index(/[^ ]/)
350
- started = true
351
- elsif started and !p.strip.empty?
352
- cur = p.index(/[^ ]/)
353
- num = cur if cur < num
373
+ p = l.gsub(/^#+/, '')
374
+ if p.strip.empty?
375
+ next unless started
376
+ ctxt.concat p
377
+ else
378
+ here = p.index(/[^ \t]/)
379
+ skip = here if skip.nil? || here < skip
380
+ ctxt.concat p[skip..-1]
354
381
  end
355
- # Include blank lines between comments
356
- ctxt += ("\n" * (l.loc.first_line - last_line - 1)) unless last_line.nil? || l.loc.first_line - last_line <= 0
357
- ctxt += "#{p[num..-1]}\n" if started
358
- last_line = l.loc.last_line if last_line.nil? || l.loc.last_line > last_line
382
+ started = true
359
383
  }
360
384
  ctxt
361
385
  end
@@ -374,9 +398,7 @@ module Solargraph
374
398
 
375
399
  # @return [Array<Range>]
376
400
  def comment_ranges
377
- @comment_ranges ||= @comments.map do |cmnt|
378
- Range.from_expr(cmnt.loc.expression)
379
- end
401
+ @comment_ranges ||= @comments.values.map(&:range)
380
402
  end
381
403
 
382
404
  # Get an array of foldable comment block ranges. Blocks are excluded if
@@ -387,25 +409,15 @@ module Solargraph
387
409
  return [] unless synchronized?
388
410
  result = []
389
411
  grouped = []
390
- # @param cmnt [Parser::Source::Comment]
391
- @comments.each do |cmnt|
392
- if cmnt.document?
393
- result.push Range.from_expr(cmnt.loc.expression)
394
- elsif code.lines[cmnt.loc.expression.line].strip.start_with?('#')
395
- if grouped.empty? || cmnt.loc.expression.line == grouped.last.loc.expression.line + 1
396
- grouped.push cmnt
397
- else
398
- result.push Range.from_to(grouped.first.loc.expression.line, 0, grouped.last.loc.expression.line, 0) unless grouped.length < 3
399
- grouped = [cmnt]
400
- end
412
+ comments.keys.each do |l|
413
+ if grouped.empty? || l == grouped.last + 1
414
+ grouped.push l
401
415
  else
402
- unless grouped.length < 3
403
- result.push Range.from_to(grouped.first.loc.expression.line, 0, grouped.last.loc.expression.line, 0)
404
- end
405
- grouped.clear
416
+ result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3
417
+ grouped = [l]
406
418
  end
407
419
  end
408
- result.push Range.from_to(grouped.first.loc.expression.line, 0, grouped.last.loc.expression.line, 0) unless grouped.length < 3
420
+ result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3
409
421
  result
410
422
  end
411
423
 
@@ -413,8 +425,8 @@ module Solargraph
413
425
  # @return [Array<Parser::AST::Node>]
414
426
  def string_nodes_in n
415
427
  result = []
416
- if n.is_a?(Parser::AST::Node)
417
- if n.type == :str || n.type == :dstr
428
+ if Parser.is_ast_node?(n)
429
+ if n.type == :str || n.type == :dstr || n.type == :STR || n.type == :DSTR
418
430
  result.push n
419
431
  else
420
432
  n.children.each{ |c| result.concat string_nodes_in(c) }
@@ -429,27 +441,23 @@ module Solargraph
429
441
  # @return [void]
430
442
  def inner_tree_at node, position, stack
431
443
  return if node.nil?
432
- here = Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
433
- if here.contain?(position)
444
+ # here = Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
445
+ here = Range.from_node(node)
446
+ if here.contain?(position) || colonized(here, position, node)
434
447
  stack.unshift node
435
448
  node.children.each do |c|
436
- next unless c.is_a?(AST::Node)
437
- next if c.loc.expression.nil?
449
+ next unless Parser.is_ast_node?(c)
450
+ next if !Parser.rubyvm? && c.loc.expression.nil?
438
451
  inner_tree_at(c, position, stack)
439
452
  end
440
453
  end
441
454
  end
442
455
 
443
- # @param name [String]
444
- # @param top [AST::Node]
445
- # @return [Array<AST::Node>]
446
- def inner_node_references name, top
447
- result = []
448
- if top.is_a?(AST::Node) && top.to_s.include?(":#{name}")
449
- result.push top if top.children.any? { |c| c.to_s == name }
450
- top.children.each { |c| result.concat inner_node_references(name, c) }
451
- end
452
- result
456
+ def colonized range, position, node
457
+ node.type == :COLON2 &&
458
+ range.ending.line == position.line &&
459
+ range.ending.character == position.character - 2 &&
460
+ code[Position.to_offset(code, Position.new(position.line, position.character - 2)), 2] == '::'
453
461
  end
454
462
 
455
463
  protected
@@ -502,35 +510,6 @@ module Solargraph
502
510
  Source.new code, filename, version
503
511
  end
504
512
 
505
- # @param code [String]
506
- # @param filename [String]
507
- # @return [Array(Parser::AST::Node, Array<Parser::Source::Comment>)]
508
- def parse_with_comments code, filename = nil
509
- buffer = Parser::Source::Buffer.new(filename, 0)
510
- buffer.source = code
511
- parser.parse_with_comments(buffer)
512
- end
513
-
514
- # @param code [String]
515
- # @param filename [String, nil]
516
- # @param line [Integer]
517
- # @return [Parser::AST::Node]
518
- def parse code, filename = nil, line = 0
519
- buffer = Parser::Source::Buffer.new(filename, line)
520
- buffer.source = code
521
- parser.parse(buffer)
522
- end
523
-
524
- # @return [Parser::Base]
525
- def parser
526
- # @todo Consider setting an instance variable. We might not need to
527
- # recreate the parser every time we use it.
528
- parser = Parser::CurrentRuby.new(FlawedBuilder.new)
529
- parser.diagnostics.all_errors_are_fatal = true
530
- parser.diagnostics.ignore_warnings = true
531
- parser
532
- end
533
-
534
513
  # @param comments [String]
535
514
  # @return [YARD::DocstringParser]
536
515
  def parse_docstring comments