solargraph 0.39.3 → 0.39.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/.rubocop.yml +21 -0
  3. data/lib/solargraph.rb +3 -0
  4. data/lib/solargraph/api_map.rb +27 -21
  5. data/lib/solargraph/api_map/cache.rb +4 -0
  6. data/lib/solargraph/api_map/store.rb +35 -47
  7. data/lib/solargraph/compat.rb +9 -0
  8. data/lib/solargraph/diagnostics/rubocop.rb +2 -1
  9. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  10. data/lib/solargraph/documentor.rb +2 -0
  11. data/lib/solargraph/language_server/host.rb +1 -1
  12. data/lib/solargraph/language_server/message/text_document/formatting.rb +6 -2
  13. data/lib/solargraph/language_server/uri_helpers.rb +23 -3
  14. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +10 -0
  15. data/lib/solargraph/parser/rubyvm/node_methods.rb +1 -0
  16. data/lib/solargraph/parser/rubyvm/node_processors.rb +1 -0
  17. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +6 -1
  18. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +6 -1
  19. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +13 -40
  20. data/lib/solargraph/pin/attribute.rb +1 -1
  21. data/lib/solargraph/pin/base.rb +2 -2
  22. data/lib/solargraph/pin/base_method.rb +1 -1
  23. data/lib/solargraph/pin/base_variable.rb +1 -1
  24. data/lib/solargraph/pin/block.rb +28 -14
  25. data/lib/solargraph/pin/closure.rb +1 -1
  26. data/lib/solargraph/pin/constant.rb +1 -1
  27. data/lib/solargraph/pin/local_variable.rb +1 -1
  28. data/lib/solargraph/pin/method.rb +1 -1
  29. data/lib/solargraph/pin/method_alias.rb +1 -1
  30. data/lib/solargraph/pin/namespace.rb +1 -1
  31. data/lib/solargraph/pin/parameter.rb +2 -2
  32. data/lib/solargraph/pin/proxy_type.rb +1 -1
  33. data/lib/solargraph/shell.rb +1 -1
  34. data/lib/solargraph/source.rb +14 -3
  35. data/lib/solargraph/source/chain.rb +0 -31
  36. data/lib/solargraph/source/source_chainer.rb +2 -1
  37. data/lib/solargraph/source_map.rb +15 -1
  38. data/lib/solargraph/source_map/mapper.rb +4 -2
  39. data/lib/solargraph/stdlib_fills.rb +8 -0
  40. data/lib/solargraph/type_checker.rb +2 -3
  41. data/lib/solargraph/version.rb +1 -1
  42. data/lib/solargraph/views/_name_type_tag.erb +1 -1
  43. data/lib/solargraph/workspace.rb +1 -1
  44. data/lib/solargraph/yard_map.rb +23 -1
  45. data/lib/solargraph/yard_map/mapper.rb +3 -0
  46. data/lib/solargraph/yard_map/rdoc_to_yard.rb +13 -6
  47. data/solargraph.gemspec +1 -1
  48. data/yardoc/2.2.2.tar.gz +0 -0
  49. metadata +10 -9
  50. data/.rubocop.yml +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7445b5b059ff10d5ff6b998209d3988a4d9f20b48b0b3e51b8e6b63000f18d1b
4
- data.tar.gz: d17e09c8fecf38bb4bff9ca4d6985c898a2256cc6c56e4c54599b4be907e27b9
3
+ metadata.gz: 17711680892b43f0ee8848707305dfdb801e7fc15f65e3426fab759dc0309c20
4
+ data.tar.gz: 6e8a9089d203ef9a405da33e449f3c4291d57d741e0bde5d615ecc629276a60a
5
5
  SHA512:
6
- metadata.gz: 61ed8f3f9f68ce49f2496e5fe07eeefbc1121350c15827bc0d600a2417e041d4f2b5d89c861c2f3b4873c20e02bd8fa708d2697b3e73d8e0ee0c858cb7c0f090
7
- data.tar.gz: 6c3646376224f2237e404e4c6fcea9eaf02eaa1cfedebf9a01b6f89896d6454c03b7cbbdc16255549b528243d4c7f73a491f7d94e2d5866c6d15bc18a6db0323
6
+ metadata.gz: 33685a93c52c6417d88f07a76dd4af8c77bf6446d551615e3a745462c622a7808b200638d0af8dbe269cd41c92cac6ba234bb86c29bf7f385ff9d39dd1155ff7
7
+ data.tar.gz: a53bfd06eb1d3e56564ca03b434ba48169e2f56e7712d7eda0f26f67a3830741a70729df280cc80414d69e6586034cbdb7eea11bf31ee87a83a1eabe3b04da05
@@ -0,0 +1,21 @@
1
+ Layout/EndOfLine:
2
+ EnforcedStyle: lf
3
+ Style/MethodDefParentheses:
4
+ Enabled: false
5
+ Layout/EmptyLineAfterGuardClause:
6
+ Enabled: false
7
+ Layout/SpaceAroundMethodCallOperator:
8
+ Enabled: true
9
+ Lint/RaiseException:
10
+ Enabled: true
11
+ Lint/StructNewOverride:
12
+ Enabled: true
13
+ Style/ExponentialNotation:
14
+ Enabled: true
15
+ Style/HashEachMethods:
16
+ Enabled: true
17
+ Style/HashTransformKeys:
18
+ Enabled: true
19
+ Style/HashTransformValues:
20
+ Enabled: true
21
+
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ Encoding.default_external = 'UTF-8'
4
+
5
+ require 'solargraph/compat'
3
6
  require 'solargraph/version'
4
7
 
5
8
  # The top-level namespace for the Solargraph code mapping, documentation,
@@ -26,7 +26,6 @@ module Solargraph
26
26
  def initialize pins: []
27
27
  @source_map_hash = {}
28
28
  @cache = Cache.new
29
- @mutex = Mutex.new
30
29
  @method_alias_stack = []
31
30
  index pins
32
31
  end
@@ -34,13 +33,11 @@ module Solargraph
34
33
  # @param pins [Array<Pin::Base>]
35
34
  # @return [self]
36
35
  def index pins
37
- @mutex.synchronize {
38
- @source_map_hash.clear
39
- @cache.clear
40
- @store = Store.new(pins + YardMap.new.pins)
41
- @unresolved_requires = []
42
- workspace_filenames.clear
43
- }
36
+ @source_map_hash.clear
37
+ @cache.clear
38
+ @store = Store.new(pins + YardMap.new.pins)
39
+ @unresolved_requires = []
40
+ workspace_filenames.clear
44
41
  self
45
42
  end
46
43
 
@@ -123,14 +120,14 @@ module Solargraph
123
120
  reqs.merge br.keys
124
121
  yard_map.change(reqs.to_a, br, bundle.workspace.gemnames)
125
122
  new_store = Store.new(pins + yard_map.pins)
126
- @mutex.synchronize {
127
- @cache.clear
128
- @source_map_hash = new_map_hash
129
- @store = new_store
130
- @unresolved_requires = yard_map.unresolved_requires
131
- workspace_filenames.clear
132
- workspace_filenames.concat bundle.workspace.filenames
133
- }
123
+ @cache.clear
124
+ @source_map_hash = new_map_hash
125
+ @store = new_store
126
+ @unresolved_requires = yard_map.unresolved_requires
127
+ workspace_filenames.clear
128
+ workspace_filenames.concat bundle.workspace.filenames
129
+ @rebindable_method_names = nil
130
+ store.block_pins.each { |blk| blk.rebind(self) }
134
131
  self
135
132
  end
136
133
 
@@ -179,6 +176,16 @@ module Solargraph
179
176
  store.pins
180
177
  end
181
178
 
179
+ def rebindable_method_names
180
+ @rebindable_method_names ||= begin
181
+ result = yard_map.rebindable_method_names
182
+ source_maps.each do |map|
183
+ result.merge map.rebindable_method_names
184
+ end
185
+ result
186
+ end
187
+ end
188
+
182
189
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
183
190
  #
184
191
  # @return [Array<Solargraph::Pin::Keyword>]
@@ -280,8 +287,7 @@ module Solargraph
280
287
 
281
288
  # @return [Array<Solargraph::Pin::GlobalVariable>]
282
289
  def get_global_variable_pins
283
- # @todo Slow version
284
- pins.select{ |p| p.is_a?(Pin::GlobalVariable) }
290
+ store.pins_by_class(Pin::GlobalVariable)
285
291
  end
286
292
 
287
293
  # Get an array of methods available in a particular context.
@@ -535,17 +541,17 @@ module Solargraph
535
541
  #
536
542
  # @return [Hash{String => SourceMap}]
537
543
  def source_map_hash
538
- @mutex.synchronize { @source_map_hash }
544
+ @source_map_hash
539
545
  end
540
546
 
541
547
  # @return [ApiMap::Store]
542
548
  def store
543
- @mutex.synchronize { @store }
549
+ @store
544
550
  end
545
551
 
546
552
  # @return [Solargraph::ApiMap::Cache]
547
553
  def cache
548
- @mutex.synchronize { @cache }
554
+ @cache
549
555
  end
550
556
 
551
557
  # @param fqns [String] A fully qualified namespace
@@ -10,6 +10,7 @@ module Solargraph
10
10
  @receiver_definitions = {}
11
11
  end
12
12
 
13
+ # @return [Array<Pin::BaseMethod>]
13
14
  def get_methods fqns, scope, visibility, deep
14
15
  @methods[[fqns, scope, visibility.sort, deep]]
15
16
  end
@@ -18,6 +19,7 @@ module Solargraph
18
19
  @methods[[fqns, scope, visibility.sort, deep]] = value
19
20
  end
20
21
 
22
+ # @return [Array<Pin::Base>]
21
23
  def get_constants namespace, context
22
24
  @constants[[namespace, context]]
23
25
  end
@@ -26,6 +28,7 @@ module Solargraph
26
28
  @constants[[namespace, context]] = value
27
29
  end
28
30
 
31
+ # @return [String]
29
32
  def get_qualified_namespace name, context
30
33
  @qualified_namespaces[[name, context]]
31
34
  end
@@ -38,6 +41,7 @@ module Solargraph
38
41
  @receiver_definitions.key? path
39
42
  end
40
43
 
44
+ # @return [Pin::BaseMethod]
41
45
  def get_receiver_definition path
42
46
  @receiver_definitions[path]
43
47
  end
@@ -99,12 +99,12 @@ module Solargraph
99
99
 
100
100
  # @return [Array<Solargraph::Pin::Base>]
101
101
  def namespace_pins
102
- @namespace_pins ||= []
102
+ pins_by_class(Solargraph::Pin::Namespace)
103
103
  end
104
104
 
105
- # @return [Array<Solargraph::Pin::Base>]
105
+ # @return [Array<Solargraph::Pin::BaseMethod>]
106
106
  def method_pins
107
- @method_pins ||= []
107
+ pins_by_class(Solargraph::Pin::BaseMethod)
108
108
  end
109
109
 
110
110
  # @param fqns [String]
@@ -133,7 +133,7 @@ module Solargraph
133
133
 
134
134
  # @return [Array<Pin::Block>]
135
135
  def block_pins
136
- @block_pins ||= []
136
+ pins_by_class(Pin::Block)
137
137
  end
138
138
 
139
139
  def inspect
@@ -141,6 +141,12 @@ module Solargraph
141
141
  to_s
142
142
  end
143
143
 
144
+ # @param klass [Class]
145
+ # @return [Array<Solargraph::Pin::Base>]
146
+ def pins_by_class klass
147
+ @pin_select_cache[klass] ||= @pin_class_hash.select { |key, _| key <= klass }.values.flatten
148
+ end
149
+
144
150
  private
145
151
 
146
152
  # @param fqns [String]
@@ -167,7 +173,7 @@ module Solargraph
167
173
 
168
174
  # @return [Array<Solargraph::Pin::Symbol>]
169
175
  def symbols
170
- @symbols ||= []
176
+ pins_by_class(Pin::Symbol)
171
177
  end
172
178
 
173
179
  def superclass_references
@@ -198,7 +204,7 @@ module Solargraph
198
204
  end
199
205
 
200
206
  def all_instance_variables
201
- @all_instance_variables ||= []
207
+ pins_by_class(Pin::InstanceVariable)
202
208
  end
203
209
 
204
210
  def path_pin_hash
@@ -207,48 +213,29 @@ module Solargraph
207
213
 
208
214
  # @return [void]
209
215
  def index
210
- namespace_map.clear
211
- namespaces.clear
212
- namespace_pins.clear
213
- method_pins.clear
214
- symbols.clear
215
- block_pins.clear
216
- all_instance_variables.clear
217
- path_pin_hash.clear
218
- namespace_map[''] = []
219
- override_pins = []
220
- pins.each do |pin|
221
- namespace_map[pin.namespace] ||= []
222
- namespace_map[pin.namespace].push pin
223
- namespaces.add pin.path if pin.is_a?(Pin::Namespace) && !pin.path.empty?
224
- namespace_pins.push pin if pin.is_a?(Pin::Namespace)
225
- method_pins.push pin if pin.is_a?(Pin::BaseMethod)
226
- symbols.push pin if pin.is_a?(Pin::Symbol)
227
- if pin.is_a?(Pin::Reference::Include)
228
- include_references[pin.namespace] ||= []
229
- include_references[pin.namespace].push pin.name
230
- elsif pin.is_a?(Pin::Reference::Prepend)
231
- prepend_references[pin.namespace] ||= []
232
- prepend_references[pin.namespace].push pin.name
233
- elsif pin.is_a?(Pin::Reference::Extend)
234
- extend_references[pin.namespace] ||= []
235
- extend_references[pin.namespace].push pin.name
236
- elsif pin.is_a?(Pin::Reference::Superclass)
237
- superclass_references[pin.namespace] ||= []
238
- superclass_references[pin.namespace].push pin.name
239
- elsif pin.is_a?(Pin::Block)
240
- block_pins.push pin
241
- elsif pin.is_a?(Pin::InstanceVariable)
242
- all_instance_variables.push pin
243
- elsif pin.is_a?(Pin::Reference::Override)
244
- override_pins.push pin
245
- end
246
- if pin.path
247
- path_pin_hash[pin.path] ||= []
248
- path_pin_hash[pin.path].push pin
249
- end
216
+ set = pins.to_set
217
+ @pin_class_hash = set.classify(&:class).transform_values(&:to_a)
218
+ @pin_select_cache = {}
219
+ @namespace_map = set.classify(&:namespace).transform_values(&:to_a)
220
+ @path_pin_hash = set.classify(&:path).transform_values(&:to_a)
221
+ @namespaces = @path_pin_hash.keys.compact
222
+ pins_by_class(Pin::Reference::Include).each do |pin|
223
+ include_references[pin.namespace] ||= []
224
+ include_references[pin.namespace].push pin.name
225
+ end
226
+ pins_by_class(Pin::Reference::Prepend).each do |pin|
227
+ prepend_references[pin.namespace] ||= []
228
+ prepend_references[pin.namespace].push pin.name
229
+ end
230
+ pins_by_class(Pin::Reference::Extend).each do |pin|
231
+ extend_references[pin.namespace] ||= []
232
+ extend_references[pin.namespace].push pin.name
233
+ end
234
+ pins_by_class(Pin::Reference::Superclass).each do |pin|
235
+ superclass_references[pin.namespace] ||= []
236
+ superclass_references[pin.namespace].push pin.name
250
237
  end
251
- override_pins.each do |ovr|
238
+ pins_by_class(Pin::Reference::Override).each do |ovr|
252
239
  pin = get_path_pins(ovr.name).first
253
240
  next if pin.nil?
254
241
  (ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
@@ -261,6 +248,7 @@ module Solargraph
261
248
  # @todo This is probably not the best place for these overrides
262
249
  superclass_references['Integer'] = ['Numeric']
263
250
  superclass_references['Float'] = ['Numeric']
251
+ superclass_references['File'] = ['IO']
264
252
  end
265
253
  end
266
254
  end
@@ -0,0 +1,9 @@
1
+ unless Hash.method_defined?(:transform_values)
2
+ class Hash
3
+ def transform_values &block
4
+ each_pair do |k, v|
5
+ self[k] = block.call(v)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -24,7 +24,8 @@ module Solargraph
24
24
  # @return [Array<Hash>]
25
25
  def diagnose source, _api_map
26
26
  options, paths = generate_options(source.filename, source.code)
27
- runner = RuboCop::Runner.new(options, RuboCop::ConfigStore.new)
27
+ store = RuboCop::ConfigStore.new
28
+ runner = RuboCop::Runner.new(options, store)
28
29
  result = redirect_stdout{ runner.run(paths) }
29
30
  make_array JSON.parse(result)
30
31
  rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
@@ -17,7 +17,8 @@ module Solargraph
17
17
  rubocop_file = find_rubocop_file(filename)
18
18
  args.push('-c', fix_drive_letter(rubocop_file)) unless rubocop_file.nil?
19
19
  args.push filename
20
- options, paths = RuboCop::Options.new.parse(args)
20
+ base_options = RuboCop::Options.new
21
+ options, paths = base_options.parse(args)
21
22
  options[:stdin] = code
22
23
  [options, paths]
23
24
  end
@@ -27,6 +28,8 @@ module Solargraph
27
28
  # @param filename [String]
28
29
  # @return [String, nil]
29
30
  def find_rubocop_file filename
31
+ return nil unless File.exist?(filename)
32
+ filename = File.realpath(filename)
30
33
  dir = File.dirname(filename)
31
34
  until File.dirname(dir) == dir
32
35
  here = File.join(dir, '.rubocop.yml')
@@ -5,6 +5,7 @@ require 'json'
5
5
  require 'open3'
6
6
  require 'shellwords'
7
7
  require 'yard'
8
+ require 'fileutils'
8
9
 
9
10
  module Solargraph
10
11
  class Documentor
@@ -25,6 +26,7 @@ module Solargraph
25
26
  Documentor.specs_from_bundle(@directory).each_pair do |name, version|
26
27
  yd = YARD::Registry.yardoc_file_for_gem(name, "= #{version}")
27
28
  if !yd || @rebuild
29
+ FileUtils.safe_unlink File.join(YardMap::CoreDocs.cache_dir, 'gems', "#{name}-#{version}.ser")
28
30
  @out.puts "Documenting #{name} #{version}"
29
31
  `yard gems #{name} #{version} #{@rebuild ? '--rebuild' : ''}`
30
32
  yd = YARD::Registry.yardoc_file_for_gem(name, "= #{version}")
@@ -99,7 +99,7 @@ module Solargraph
99
99
  message = Message.select(request['method']).new(self, request)
100
100
  begin
101
101
  message.process
102
- rescue Exception => e
102
+ rescue StandardError => e
103
103
  logger.warn "Error processing request: [#{e.class}] #{e.message}"
104
104
  logger.warn e.backtrace.join("\n")
105
105
  message.set_error Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, "[#{e.class}] #{e.message}"
@@ -16,11 +16,15 @@ module Solargraph
16
16
  # detects the correct configuration
17
17
  # the .rb extension is needed for ruby file without extension, else rubocop won't format
18
18
  tempfile = File.join(File.dirname(filename), "_tmp_#{SecureRandom.hex(8)}_#{File.basename(filename)}.rb")
19
+ rubocop_file = Diagnostics::RubocopHelpers.find_rubocop_file(filename)
19
20
  original = host.read_text(params['textDocument']['uri'])
20
21
  File.write tempfile, original
21
22
  begin
22
- options, paths = RuboCop::Options.new.parse(['-a', '-f', 'fi', tempfile])
23
- redirect_stdout { RuboCop::Runner.new(options, RuboCop::ConfigStore.new).run(paths) }
23
+ args = ['-a', '-f', 'fi', tempfile]
24
+ args.unshift('-c', fix_drive_letter(rubocop_file)) unless rubocop_file.nil?
25
+ options, paths = RuboCop::Options.new.parse(args)
26
+ store = RuboCop::ConfigStore.new
27
+ redirect_stdout { RuboCop::Runner.new(options, store).run(paths) }
24
28
  result = File.read(tempfile)
25
29
  File.unlink tempfile
26
30
  format original, result
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'uri'
3
+ require 'cgi'
4
4
 
5
5
  module Solargraph
6
6
  module LanguageServer
@@ -14,7 +14,7 @@ module Solargraph
14
14
  # @param uri [String]
15
15
  # @return [String]
16
16
  def uri_to_file uri
17
- URI.decode(uri).sub(/^file\:\/\//, '').sub(/^\/([a-z]\:)/i, '\1')
17
+ decode(uri).sub(/^file\:\/\//, '').sub(/^\/([a-z]\:)/i, '\1')
18
18
  end
19
19
 
20
20
  # Convert a file path to a URI.
@@ -22,7 +22,27 @@ module Solargraph
22
22
  # @param file [String]
23
23
  # @return [String]
24
24
  def file_to_uri file
25
- "file://#{URI.encode(file.gsub(/^([a-z]\:)/i, '/\1'))}"
25
+ "file://#{encode(file.gsub(/^([a-z]\:)/i, '/\1'))}"
26
+ end
27
+
28
+ # Encode text to be used as a URI path component in LSP.
29
+ #
30
+ # @param text [String]
31
+ # @return [String]
32
+ def encode text
33
+ CGI.escape(text)
34
+ .gsub('%3A', ':')
35
+ .gsub('%5C', '\\')
36
+ .gsub('%2F', '/')
37
+ .gsub('+', '%20')
38
+ end
39
+
40
+ # Decode text from a URI path component in LSP.
41
+ #
42
+ # @param text [String]
43
+ # @return [String]
44
+ def decode text
45
+ CGI.unescape(text)
26
46
  end
27
47
  end
28
48
  end
@@ -36,6 +36,8 @@ module Solargraph
36
36
  process_prepend
37
37
  elsif node.children[1] == :require
38
38
  process_require
39
+ elsif node.children[1] == :autoload
40
+ process_autoload
39
41
  elsif node.children[1] == :private_constant
40
42
  process_private_constant
41
43
  elsif node.children[1] == :alias_method && node.children[2] && node.children[2] && node.children[2].type == :sym && node.children[3] && node.children[3].type == :sym
@@ -138,6 +140,14 @@ module Solargraph
138
140
  end
139
141
  end
140
142
 
143
+ # @return [void]
144
+ def process_autoload
145
+ if node.children[3].is_a?(AST::Node) && node.children[3].type == :str
146
+ path = node.children[3].children[0].to_s
147
+ pins.push Pin::Reference::Require.new(get_node_location(node), path)
148
+ end
149
+ end
150
+
141
151
  # @return [void]
142
152
  def process_module_function
143
153
  if node.children[2].nil?