solargraph 0.39.0 → 0.40.0

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -7
  3. data/CHANGELOG.md +984 -0
  4. data/Rakefile +12 -1
  5. data/SPONSORS.md +6 -0
  6. data/lib/.rubocop.yml +21 -0
  7. data/lib/solargraph/api_map/cache.rb +4 -0
  8. data/lib/solargraph/api_map/store.rb +35 -51
  9. data/lib/solargraph/api_map.rb +94 -87
  10. data/lib/solargraph/{bundle.rb → bench.rb} +6 -2
  11. data/lib/solargraph/compat.rb +23 -0
  12. data/lib/solargraph/complex_type.rb +2 -2
  13. data/lib/solargraph/convention/base.rb +16 -8
  14. data/lib/solargraph/convention/gemfile.rb +2 -5
  15. data/lib/solargraph/convention/gemspec.rb +3 -6
  16. data/lib/solargraph/convention/rspec.rb +3 -6
  17. data/lib/solargraph/convention.rb +14 -5
  18. data/lib/solargraph/diagnostics/rubocop.rb +2 -1
  19. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  20. data/lib/solargraph/documentor.rb +4 -0
  21. data/lib/solargraph/environ.rb +11 -6
  22. data/lib/solargraph/language_server/host.rb +1 -1
  23. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +6 -1
  24. data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
  25. data/lib/solargraph/language_server/message/text_document/formatting.rb +7 -3
  26. data/lib/solargraph/language_server/uri_helpers.rb +23 -3
  27. data/lib/solargraph/library.rb +22 -8
  28. data/lib/solargraph/parser/legacy/class_methods.rb +4 -0
  29. data/lib/solargraph/parser/legacy/node_chainer.rb +10 -7
  30. data/lib/solargraph/parser/legacy/node_methods.rb +16 -3
  31. data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +1 -1
  32. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +48 -23
  33. data/lib/solargraph/parser/node_processor/base.rb +3 -0
  34. data/lib/solargraph/parser/rubyvm/class_methods.rb +6 -2
  35. data/lib/solargraph/parser/rubyvm/node_chainer.rb +11 -9
  36. data/lib/solargraph/parser/rubyvm/node_methods.rb +6 -1
  37. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +35 -11
  38. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +1 -1
  39. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +6 -1
  40. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +6 -1
  41. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +52 -67
  42. data/lib/solargraph/parser/rubyvm/node_processors.rb +2 -0
  43. data/lib/solargraph/pin/base.rb +2 -2
  44. data/lib/solargraph/pin/base_variable.rb +1 -1
  45. data/lib/solargraph/pin/block.rb +28 -14
  46. data/lib/solargraph/pin/closure.rb +1 -1
  47. data/lib/solargraph/pin/common.rb +1 -1
  48. data/lib/solargraph/pin/constant.rb +1 -1
  49. data/lib/solargraph/pin/conversions.rb +3 -4
  50. data/lib/solargraph/pin/documenting.rb +6 -11
  51. data/lib/solargraph/pin/local_variable.rb +1 -1
  52. data/lib/solargraph/pin/method.rb +143 -9
  53. data/lib/solargraph/pin/method_alias.rb +2 -2
  54. data/lib/solargraph/pin/namespace.rb +1 -1
  55. data/lib/solargraph/pin/parameter.rb +2 -2
  56. data/lib/solargraph/pin/proxy_type.rb +1 -1
  57. data/lib/solargraph/pin.rb +0 -3
  58. data/lib/solargraph/position.rb +2 -14
  59. data/lib/solargraph/shell.rb +2 -1
  60. data/lib/solargraph/source/chain/call.rb +9 -0
  61. data/lib/solargraph/source/chain/head.rb +14 -8
  62. data/lib/solargraph/source/chain/z_super.rb +30 -0
  63. data/lib/solargraph/source/chain.rb +19 -36
  64. data/lib/solargraph/source/source_chainer.rb +2 -1
  65. data/lib/solargraph/source.rb +24 -9
  66. data/lib/solargraph/source_map/clip.rb +78 -44
  67. data/lib/solargraph/source_map/mapper.rb +41 -21
  68. data/lib/solargraph/source_map.rb +20 -2
  69. data/lib/solargraph/type_checker/param_def.rb +1 -1
  70. data/lib/solargraph/type_checker.rb +61 -42
  71. data/lib/solargraph/version.rb +1 -1
  72. data/lib/solargraph/views/_name_type_tag.erb +1 -1
  73. data/lib/solargraph/workspace.rb +1 -1
  74. data/lib/solargraph/yard_map/core_fills.rb +185 -0
  75. data/lib/solargraph/yard_map/helpers.rb +16 -0
  76. data/lib/solargraph/{pin/yard_pin/constant.rb → yard_map/mapper/to_constant.rb} +6 -6
  77. data/lib/solargraph/yard_map/mapper/to_method.rb +78 -0
  78. data/lib/solargraph/{pin/yard_pin/namespace.rb → yard_map/mapper/to_namespace.rb} +6 -6
  79. data/lib/solargraph/yard_map/mapper.rb +17 -8
  80. data/lib/solargraph/yard_map/rdoc_to_yard.rb +26 -15
  81. data/lib/solargraph/yard_map/stdlib_fills.rb +43 -0
  82. data/lib/solargraph/yard_map/to_method.rb +79 -0
  83. data/lib/solargraph/yard_map.rb +140 -92
  84. data/lib/solargraph.rb +5 -4
  85. data/solargraph.gemspec +5 -5
  86. data/yardoc/2.2.2.tar.gz +0 -0
  87. metadata +29 -41
  88. data/.rubocop.yml +0 -6
  89. data/lib/solargraph/core_fills.rb +0 -159
  90. data/lib/solargraph/pin/attribute.rb +0 -49
  91. data/lib/solargraph/pin/base_method.rb +0 -141
  92. data/lib/solargraph/pin/yard_pin/method.rb +0 -65
  93. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -26
  94. data/lib/solargraph/pin/yard_pin.rb +0 -12
  95. data/lib/solargraph/stdlib_fills.rb +0 -32
  96. data/travis-bundler.rb +0 -11
@@ -12,7 +12,7 @@ module Solargraph
12
12
 
13
13
  # @param types [Array<UniqueType>]
14
14
  def initialize types = [UniqueType::UNDEFINED]
15
- @items = types
15
+ @items = types.uniq(&:to_s)
16
16
  end
17
17
 
18
18
  # @param api_map [ApiMap]
@@ -113,7 +113,7 @@ module Solargraph
113
113
  #
114
114
  # @param *strings [Array<String>] The type definitions to parse
115
115
  # @param partial [Boolean] True if the string is part of a another type
116
- # @return [ComplexType]
116
+ # @return [ComplexType, Array, nil]
117
117
  def parse *strings, partial: false
118
118
  @cache ||= {}
119
119
  unless partial
@@ -2,22 +2,30 @@
2
2
 
3
3
  module Solargraph
4
4
  module Convention
5
+ # The base class for Conventions.
6
+ #
7
+ # A Convention provides Environs that customize ApiMaps with additional
8
+ # pins and other information. Subclasses should implement the `local` and
9
+ # `global` methods as necessary.
10
+ #
5
11
  class Base
6
12
  EMPTY_ENVIRON = Environ.new
7
13
 
8
- # True if the source qualifies for this convention.
9
- # Subclasses should override this method.
14
+ # The Environ for a source map.
15
+ # Subclasses can override this method.
10
16
  #
11
- # @param source [Source]
12
- def match? source
13
- false
17
+ # @param source_map [SourceMap]
18
+ # @return [Environ]
19
+ def local source_map
20
+ EMPTY_ENVIRON
14
21
  end
15
22
 
16
- # The Environ for this convention.
17
- # Subclasses should override this method.
23
+ # The Environ for a YARD map.
24
+ # Subclasses can override this method.
18
25
  #
26
+ # @param yard_map [YardMap]
19
27
  # @return [Environ]
20
- def environ
28
+ def global yard_map
21
29
  EMPTY_ENVIRON
22
30
  end
23
31
  end
@@ -3,11 +3,8 @@
3
3
  module Solargraph
4
4
  module Convention
5
5
  class Gemfile < Base
6
- def match? source
7
- File.basename(source.filename) == 'Gemfile'
8
- end
9
-
10
- def environ
6
+ def local source_map
7
+ return EMPTY_ENVIRON unless File.basename(source_map.filename) == 'Gemfile'
11
8
  @environ ||= Environ.new(
12
9
  requires: ['bundler'],
13
10
  domains: ['Bundler::Dsl']
@@ -3,14 +3,11 @@
3
3
  module Solargraph
4
4
  module Convention
5
5
  class Gemspec < Base
6
- def match? source
7
- File.basename(source.filename).end_with?('.gemspec')
8
- end
9
-
10
- def environ
6
+ def local source_map
7
+ return EMPTY_ENVIRON unless File.basename(source_map.filename).end_with?('.gemspec')
11
8
  @environ ||= Environ.new(
12
9
  requires: ['rubygems'],
13
- overrides: [
10
+ pins: [
14
11
  Solargraph::Pin::Reference::Override.from_comment(
15
12
  'Gem::Specification.new',
16
13
  %(
@@ -3,18 +3,15 @@
3
3
  module Solargraph
4
4
  module Convention
5
5
  class Rspec < Base
6
- def match? source
7
- File.basename(source.filename) =~ /_spec\.rb$/
8
- end
9
-
10
- def environ
6
+ def local source_map
7
+ return EMPTY_ENVIRON unless File.basename(source_map.filename) =~ /_spec\.rb$/
11
8
  @environ ||= Environ.new(
12
9
  requires: ['rspec'],
13
10
  domains: ['RSpec::Matchers', 'RSpec::ExpectationGroups'],
14
11
  # This override is necessary due to an erroneous @return tag in
15
12
  # rspec's YARD documentation.
16
13
  # @todo The return types have been fixed (https://github.com/rspec/rspec-expectations/pull/1121)
17
- overrides: [
14
+ pins: [
18
15
  Solargraph::Pin::Reference::Override.method_return('RSpec::Matchers#expect', 'RSpec::Expectations::ExpectationTarget')
19
16
  ]
20
17
  )
@@ -15,18 +15,27 @@ module Solargraph
15
15
  @@conventions = Set.new
16
16
 
17
17
  # @param convention [Class<Convention::Base>]
18
- # @return [Convention::Base]
18
+ # @return [void]
19
19
  def self.register convention
20
20
  @@conventions.add convention.new
21
21
  end
22
22
 
23
- # @param source [Source]
23
+ # @param source_map [SourceMap]
24
24
  # @return [Environ]
25
- def self.for(source)
25
+ def self.for_local(source_map)
26
26
  result = Environ.new
27
- return result if source.filename.nil? || source.filename.empty?
28
27
  @@conventions.each do |conv|
29
- result.merge conv.environ if conv.match?(source)
28
+ result.merge conv.local(source_map)
29
+ end
30
+ result
31
+ end
32
+
33
+ # @param yard_map [YardMap]
34
+ # @return [Environ]
35
+ def self.for_global(yard_map)
36
+ result = Environ.new
37
+ @@conventions.each do |conv|
38
+ result.merge conv.global(yard_map)
30
39
  end
31
40
  result
32
41
  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}")
@@ -53,6 +55,8 @@ module Solargraph
53
55
  false
54
56
  end
55
57
 
58
+ # @param directory [String]
59
+ # @return [Hash]
56
60
  def self.specs_from_bundle directory
57
61
  Solargraph.with_clean_env do
58
62
  Dir.chdir directory do
@@ -1,6 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
+ # A collection of additional data, such as map pins and required paths, that
5
+ # can be added to an ApiMap.
6
+ #
7
+ # Conventions are used to add Environs.
8
+ #
4
9
  class Environ
5
10
  # @return [Array<String>]
6
11
  attr_reader :requires
@@ -9,22 +14,22 @@ module Solargraph
9
14
  attr_reader :domains
10
15
 
11
16
  # @return [Array<Pin::Reference::Override>]
12
- attr_reader :overrides
17
+ attr_reader :pins
13
18
 
14
19
  # @param requires [Array<String>]
15
20
  # @param domains [Array<String>]
16
- # @param overrides [Array<Pin::Reference::Override>]
17
- def initialize requires: [], domains: [], overrides: []
21
+ # @param pins [Array<Pin::Base>]
22
+ def initialize requires: [], domains: [], pins: []
18
23
  @requires = requires
19
24
  @domains = domains
20
- @overrides = overrides
25
+ @pins = pins
21
26
  end
22
27
 
23
28
  # @return [self]
24
29
  def clear
25
30
  domains.clear
26
31
  requires.clear
27
- overrides.clear
32
+ pins.clear
28
33
  self
29
34
  end
30
35
 
@@ -33,7 +38,7 @@ module Solargraph
33
38
  def merge other
34
39
  domains.concat other.domains
35
40
  requires.concat other.requires
36
- overrides.concat other.overrides
41
+ pins.concat other.pins
37
42
  self
38
43
  end
39
44
  end
@@ -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}"
@@ -34,7 +34,12 @@ module Solargraph
34
34
  LanguageServer::MessageTypes::INFO,
35
35
  ['Update now'] do |result|
36
36
  next unless result == 'Update now'
37
- o, s = Open3.capture2("gem update solargraph")
37
+ cmd = if host.options['useBundler']
38
+ 'bundle update solargraph'
39
+ else
40
+ 'gem update solargraph'
41
+ end
42
+ o, s = Open3.capture2(cmd)
38
43
  if s == 0
39
44
  host.show_message 'Successfully updated the Solargraph gem.', LanguageServer::MessageTypes::INFO
40
45
  host.send_notification '$/solargraph/restart', {}
@@ -13,7 +13,7 @@ module Solargraph::LanguageServer::Message::TextDocument
13
13
  def code_location
14
14
  suggestions = host.definitions_at(params['textDocument']['uri'], @line, @column)
15
15
  return nil if suggestions.empty?
16
- suggestions.reject{|pin| pin.location.nil?}.map do |pin|
16
+ suggestions.reject { |pin| pin.location.nil? || pin.location.filename.nil? }.map do |pin|
17
17
  {
18
18
  uri: file_to_uri(pin.location.filename),
19
19
  range: pin.location.range.to_hash
@@ -16,16 +16,20 @@ 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
- File.unlink tempfile
26
29
  format original, result
27
30
  rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
28
31
  set_error(Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, "[#{e.class}] #{e.message}")
32
+ ensure
29
33
  File.unlink tempfile
30
34
  end
31
35
  end
@@ -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
@@ -20,7 +20,7 @@ module Solargraph
20
20
  def initialize workspace = Solargraph::Workspace.new, name = nil
21
21
  @workspace = workspace
22
22
  @name = name
23
- api_map.catalog bundle
23
+ api_map.catalog bench
24
24
  @synchronized = true
25
25
  @catalog_mutex = Mutex.new
26
26
  end
@@ -171,7 +171,21 @@ module Solargraph
171
171
  def definitions_at filename, line, column
172
172
  position = Position.new(line, column)
173
173
  cursor = Source::Cursor.new(read(filename), position)
174
- api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
174
+ if cursor.comment?
175
+ source = read(filename)
176
+ offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
177
+ lft = source.code[0..offset-1].match(/\[[a-z0-9_:<, ]*?([a-z0-9_:]*)\z/i)
178
+ rgt = source.code[offset..-1].match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
179
+ if lft && rgt
180
+ tag = (lft[1] + rgt[1]).sub(/:+$/, '')
181
+ clip = api_map.clip(cursor)
182
+ clip.translate tag
183
+ else
184
+ []
185
+ end
186
+ else
187
+ api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
188
+ end
175
189
  end
176
190
 
177
191
  # Get signature suggestions for the method at the specified file and
@@ -245,7 +259,7 @@ module Solargraph
245
259
  end
246
260
 
247
261
  # @param query [String]
248
- # @return [Array<YARD::CodeObject::Base>]
262
+ # @return [Array<YARD::CodeObjects::Base>]
249
263
  def document query
250
264
  catalog
251
265
  api_map.document query
@@ -337,9 +351,9 @@ module Solargraph
337
351
  @catalog_mutex.synchronize do
338
352
  break if synchronized?
339
353
  logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
340
- api_map.catalog bundle
354
+ api_map.catalog bench
341
355
  @synchronized = true
342
- logger.info "Catalog complete (#{api_map.pins.length} pins)"
356
+ logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)" if logger.info?
343
357
  end
344
358
  end
345
359
 
@@ -389,9 +403,9 @@ module Solargraph
389
403
  @api_map ||= Solargraph::ApiMap.new
390
404
  end
391
405
 
392
- # @return [Bundle]
393
- def bundle
394
- Bundle.new(
406
+ # @return [Bench]
407
+ def bench
408
+ Bench.new(
395
409
  workspace: workspace,
396
410
  opened: @current ? [@current] : []
397
411
  )
@@ -78,6 +78,10 @@ module Solargraph
78
78
  NodeChainer.chain *args
79
79
  end
80
80
 
81
+ def chain_string *args
82
+ NodeChainer.load_string *args
83
+ end
84
+
81
85
  def process_node *args
82
86
  Solargraph::Parser::NodeProcessor.process *args
83
87
  end
@@ -14,7 +14,7 @@ module Solargraph
14
14
  def initialize node, filename = nil, in_block = false
15
15
  @node = node
16
16
  @filename = filename
17
- @in_block = in_block
17
+ @in_block = in_block ? 1 : 0
18
18
  end
19
19
 
20
20
  # @return [Source::Chain]
@@ -51,9 +51,9 @@ module Solargraph
51
51
  return generate_links(n.children[0]) if n.type == :splat
52
52
  result = []
53
53
  if n.type == :block
54
- @in_block = true
54
+ @in_block += 1
55
55
  result.concat generate_links(n.children[0])
56
- @in_block = false
56
+ @in_block -= 1
57
57
  elsif n.type == :send
58
58
  if n.children[0].is_a?(::Parser::AST::Node)
59
59
  result.concat generate_links(n.children[0])
@@ -61,20 +61,23 @@ module Solargraph
61
61
  n.children[2..-1].each do |c|
62
62
  args.push NodeChainer.chain(c)
63
63
  end
64
- result.push Chain::Call.new(n.children[1].to_s, args, @in_block || block_passed?(n))
64
+ result.push Chain::Call.new(n.children[1].to_s, args, @in_block > 0 || block_passed?(n))
65
65
  elsif n.children[0].nil?
66
66
  args = []
67
67
  n.children[2..-1].each do |c|
68
68
  args.push NodeChainer.chain(c)
69
69
  end
70
- result.push Chain::Call.new(n.children[1].to_s, args, @in_block || block_passed?(n))
70
+ result.push Chain::Call.new(n.children[1].to_s, args, @in_block > 0 || block_passed?(n))
71
71
  else
72
72
  raise "No idea what to do with #{n}"
73
73
  end
74
74
  elsif n.type == :self
75
75
  result.push Chain::Head.new('self')
76
- elsif [:super, :zsuper].include?(n.type)
77
- result.push Chain::Head.new('super')
76
+ elsif n.type == :zsuper
77
+ result.push Chain::ZSuper.new('super', @in_block > 0 || block_passed?(n))
78
+ elsif n.type == :super
79
+ args = n.children.map { |c| NodeChainer.chain(c) }
80
+ result.push Chain::Call.new('super', args, @in_block > 0 || block_passed?(n))
78
81
  elsif n.type == :const
79
82
  const = unpack_name(n)
80
83
  result.push Chain::Constant.new(const)
@@ -124,11 +124,20 @@ module Solargraph
124
124
  result = []
125
125
  if node.type == :block
126
126
  result.push node
127
- node.children[0].children[2..-1].each { |child| result.concat call_nodes_from(child) }
127
+ if Parser.is_ast_node?(node.children[0]) && node.children[0].children.length > 2
128
+ node.children[0].children[2..-1].each { |child| result.concat call_nodes_from(child) }
129
+ end
128
130
  node.children[1..-1].each { |child| result.concat call_nodes_from(child) }
129
131
  elsif node.type == :send
130
132
  result.push node
131
133
  node.children[2..-1].each { |child| result.concat call_nodes_from(child) }
134
+ elsif [:super, :zsuper].include?(node.type)
135
+ result.push node
136
+ node.children.each { |child| result.concat call_nodes_from(child) }
137
+ elsif node.type == :masgn
138
+ # @todo We're treating a mass assignment as a call node, but the
139
+ # type checker still needs the logic to handle it.
140
+ result.push node
132
141
  else
133
142
  node.children.each { |child| result.concat call_nodes_from(child) }
134
143
  end
@@ -210,8 +219,12 @@ module Solargraph
210
219
  result.concat get_return_nodes_only(node.children[2])
211
220
  elsif node.type == :case
212
221
  node.children[1..-1].each do |cc|
213
- result.concat reduce_to_value_nodes(cc.children[1..-2])
214
- result.concat reduce_to_value_nodes([cc.children.last])
222
+ if cc.nil?
223
+ result.push NIL_NODE
224
+ else
225
+ result.concat reduce_to_value_nodes(cc.children[1..-2]) unless cc.children.length < 1
226
+ result.concat reduce_to_value_nodes([cc.children.last])
227
+ end
215
228
  end
216
229
  else
217
230
  result.push node
@@ -19,7 +19,7 @@ module Solargraph
19
19
  if region.visibility == :module_function
20
20
  here = get_node_start_position(node)
21
21
  named_path = named_path_pin(here)
22
- if named_path.is_a?(Pin::BaseMethod)
22
+ if named_path.is_a?(Pin::Method)
23
23
  pins.push Solargraph::Pin::InstanceVariable.new(
24
24
  location: loc,
25
25
  closure: Pin::Namespace.new(type: :module, closure: region.closure.closure, name: region.closure.name),