solargraph 0.45.0 → 0.49.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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/rspec.yml +1 -1
  4. data/CHANGELOG.md +41 -0
  5. data/LICENSE +1 -1
  6. data/README.md +8 -0
  7. data/SPONSORS.md +2 -4
  8. data/lib/solargraph/api_map/store.rb +13 -1
  9. data/lib/solargraph/api_map.rb +55 -32
  10. data/lib/solargraph/cache.rb +51 -0
  11. data/lib/solargraph/complex_type/type_methods.rb +10 -6
  12. data/lib/solargraph/complex_type/unique_type.rb +57 -0
  13. data/lib/solargraph/complex_type.rb +35 -2
  14. data/lib/solargraph/convention/rakefile.rb +17 -0
  15. data/lib/solargraph/convention.rb +2 -0
  16. data/lib/solargraph/diagnostics/require_not_found.rb +16 -0
  17. data/lib/solargraph/diagnostics/rubocop.rb +17 -3
  18. data/lib/solargraph/diagnostics/rubocop_helpers.rb +3 -1
  19. data/lib/solargraph/language_server/host.rb +22 -18
  20. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  21. data/lib/solargraph/language_server/message/initialize.rb +2 -0
  22. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -1
  23. data/lib/solargraph/language_server/message/text_document/hover.rb +16 -4
  24. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  25. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  26. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +1 -1
  27. data/lib/solargraph/library.rb +21 -20
  28. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +12 -2
  29. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +24 -3
  30. data/lib/solargraph/parser/rubyvm/class_methods.rb +7 -2
  31. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +13 -2
  32. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +20 -9
  33. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +14 -3
  34. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +2 -2
  35. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +14 -3
  36. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +4 -2
  37. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +47 -0
  38. data/lib/solargraph/pin/base.rb +5 -2
  39. data/lib/solargraph/pin/block.rb +2 -1
  40. data/lib/solargraph/pin/conversions.rb +2 -6
  41. data/lib/solargraph/pin/method.rb +100 -10
  42. data/lib/solargraph/pin/namespace.rb +4 -1
  43. data/lib/solargraph/pin/parameter.rb +10 -7
  44. data/lib/solargraph/pin/search.rb +56 -0
  45. data/lib/solargraph/pin/signature.rb +23 -0
  46. data/lib/solargraph/pin.rb +2 -0
  47. data/lib/solargraph/rbs_map/conversions.rb +394 -0
  48. data/lib/solargraph/rbs_map/core_fills.rb +61 -0
  49. data/lib/solargraph/rbs_map/core_map.rb +38 -0
  50. data/lib/solargraph/rbs_map/core_signs.rb +33 -0
  51. data/lib/solargraph/rbs_map/stdlib_map.rb +36 -0
  52. data/lib/solargraph/rbs_map.rb +73 -0
  53. data/lib/solargraph/shell.rb +38 -30
  54. data/lib/solargraph/source/chain/call.rb +34 -23
  55. data/lib/solargraph/source/chain.rb +21 -6
  56. data/lib/solargraph/source.rb +1 -1
  57. data/lib/solargraph/source_map/clip.rb +5 -0
  58. data/lib/solargraph/source_map/mapper.rb +31 -2
  59. data/lib/solargraph/source_map.rb +1 -10
  60. data/lib/solargraph/type_checker/checks.rb +13 -0
  61. data/lib/solargraph/type_checker.rb +88 -68
  62. data/lib/solargraph/version.rb +1 -1
  63. data/lib/solargraph/views/environment.erb +2 -2
  64. data/lib/solargraph/workspace.rb +12 -14
  65. data/lib/solargraph/yard_map/mapper/to_method.rb +7 -4
  66. data/lib/solargraph/yard_map.rb +51 -195
  67. data/lib/solargraph.rb +2 -2
  68. data/solargraph.gemspec +8 -6
  69. metadata +44 -36
  70. data/lib/solargraph/compat.rb +0 -37
  71. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  72. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  73. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  74. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  75. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  76. data/yardoc/2.2.2.tar.gz +0 -0
@@ -10,13 +10,15 @@ module Solargraph
10
10
  # Requires a specific version of rubocop, or the latest installed version
11
11
  # if _version_ is `nil`.
12
12
  #
13
- # @param version [String]
13
+ # @param version [String, nil]
14
14
  # @raise [InvalidRubocopVersionError] if _version_ is not installed
15
15
  def require_rubocop(version = nil)
16
16
  begin
17
17
  gem_path = Gem::Specification.find_by_name('rubocop', version).full_gem_path
18
18
  gem_lib_path = File.join(gem_path, 'lib')
19
19
  $LOAD_PATH.unshift(gem_lib_path) unless $LOAD_PATH.include?(gem_lib_path)
20
+ # @todo Gem::MissingSpecVersionError is undocumented for some reason
21
+ # @sg-ignore
20
22
  rescue Gem::MissingSpecVersionError => e
21
23
  raise InvalidRubocopVersionError,
22
24
  "could not find '#{e.name}' (#{e.requirement}) - "\
@@ -130,35 +130,39 @@ module Solargraph
130
130
  end
131
131
  end
132
132
 
133
- # Respond to a notification that a file was created in the workspace.
134
- # The libraries will determine whether the file should be merged; see
133
+ # Respond to a notification that files were created in the workspace.
134
+ # The libraries will determine whether the files should be merged; see
135
135
  # Solargraph::Library#create_from_disk.
136
136
  #
137
- # @param uri [String] The file uri.
138
- # @return [Boolean] True if a library accepted the file.
139
- def create uri
140
- filename = uri_to_file(uri)
137
+ # @param uris [Array<String>] The URIs of the files.
138
+ # @return [Boolean] True if at least one library accepted at least one file.
139
+ def create *uris
140
+ filenames = uris.map { |uri| uri_to_file(uri) }
141
141
  result = false
142
142
  libraries.each do |lib|
143
- result = true if lib.create_from_disk(filename)
143
+ result = true if lib.create_from_disk(*filenames)
144
+ end
145
+ uris.each do |uri|
146
+ diagnoser.schedule uri if open?(uri)
144
147
  end
145
- diagnoser.schedule uri if open?(uri)
146
148
  result
147
149
  end
148
150
 
149
- # Delete the specified file from the library.
151
+ # Delete the specified files from the library.
150
152
  #
151
- # @param uri [String] The file uri.
153
+ # @param uris [Array<String>] The file uris.
152
154
  # @return [void]
153
- def delete uri
154
- filename = uri_to_file(uri)
155
+ def delete *uris
156
+ filenames = uris.map { |uri| uri_to_file(uri) }
155
157
  libraries.each do |lib|
156
- lib.delete(filename)
158
+ lib.delete(*filenames)
159
+ end
160
+ uris.each do |uri|
161
+ send_notification "textDocument/publishDiagnostics", {
162
+ uri: uri,
163
+ diagnostics: []
164
+ }
157
165
  end
158
- send_notification "textDocument/publishDiagnostics", {
159
- uri: uri,
160
- diagnostics: []
161
- }
162
166
  end
163
167
 
164
168
  # Open the specified file in the library.
@@ -692,7 +696,7 @@ module Solargraph
692
696
  params['contentChanges'].each do |recvd|
693
697
  chng = check_diff(params['textDocument']['uri'], recvd)
694
698
  changes.push Solargraph::Source::Change.new(
695
- (chng['range'].nil? ?
699
+ (chng['range'].nil? ?
696
700
  nil :
697
701
  Solargraph::Range.from_to(chng['range']['start']['line'], chng['range']['start']['character'], chng['range']['end']['line'], chng['range']['end']['character'])
698
702
  ),
@@ -10,11 +10,7 @@ module Solargraph
10
10
  #
11
11
  class DownloadCore < Base
12
12
  def process
13
- ver = Solargraph::YardMap::CoreDocs.best_download
14
- Solargraph::YardMap::CoreDocs.download ver
15
- host.show_message "Downloaded documentation for Ruby #{ver}.", LanguageServer::MessageTypes::INFO
16
- rescue StandardError => e
17
- host.show_message "An error occurred while downloading documentation: [#{e.class}] #{e.message}", LanguageServer::MessageTypes::ERROR
13
+ host.show_message "Downloading cores is deprecated. Solargraph currently uses RBS for core and stdlib documentation", LanguageServer::MessageTypes::INFO
18
14
  end
19
15
  end
20
16
  end
@@ -25,6 +25,8 @@ module Solargraph
25
25
  }
26
26
  }
27
27
  }
28
+ # FIXME: lsp default is utf-16, may have different position
29
+ result[:capabilities][:positionEncoding] = "utf-32" if params.dig("capabilities", "general", "positionEncodings")&.include?("utf-32")
28
30
  result[:capabilities].merge! static_completion unless dynamic_registration_for?('textDocument', 'completion')
29
31
  result[:capabilities].merge! static_signature_help unless dynamic_registration_for?('textDocument', 'signatureHelp')
30
32
  # result[:capabilities].merge! static_on_type_formatting unless dynamic_registration_for?('textDocument', 'onTypeFormatting')
@@ -54,7 +54,7 @@ module Solargraph
54
54
  def cli_args file_uri, config
55
55
  file = UriHelpers.uri_to_file(file_uri)
56
56
  args = [
57
- config['cops'] == 'all' ? '--auto-correct-all' : '--auto-correct',
57
+ config['cops'] == 'all' ? '--autocorrect-all' : '--autocorrect',
58
58
  '--cache', 'false',
59
59
  '--format', formatter_class(config).name,
60
60
  ]
@@ -27,16 +27,28 @@ module Solargraph
27
27
  last_link = this_link unless this_link.nil?
28
28
  end
29
29
  set_result(
30
- contents: {
31
- kind: 'markdown',
32
- value: contents.join("\n\n")
33
- }
30
+ contents_or_nil(contents)
34
31
  )
35
32
  rescue FileNotFoundError => e
36
33
  Logging.logger.warn "[#{e.class}] #{e.message}"
37
34
  Logging.logger.warn e.backtrace.join("\n")
38
35
  set_result nil
39
36
  end
37
+
38
+ private
39
+
40
+ def contents_or_nil contents
41
+ stripped = contents
42
+ .map(&:strip)
43
+ .reject { |c| c.empty? }
44
+ return nil if stripped.empty?
45
+ {
46
+ contents: {
47
+ kind: 'markdown',
48
+ value: stripped.join("\n\n")
49
+ }
50
+ }
51
+ end
40
52
  end
41
53
  end
42
54
  end
@@ -9,13 +9,8 @@ module Solargraph
9
9
  line = params['position']['line']
10
10
  col = params['position']['character']
11
11
  suggestions = host.signatures_at(params['textDocument']['uri'], line, col)
12
- info = []
13
- suggestions.each do |pin|
14
- info.concat pin.overloads.map(&:signature_help)
15
- info.push pin.signature_help
16
- end
17
12
  set_result({
18
- signatures: info
13
+ signatures: suggestions.flat_map { |pin| pin.signature_help }
19
14
  })
20
15
  rescue FileNotFoundError => e
21
16
  Logging.logger.warn "[#{e.class}] #{e.message}"
@@ -10,22 +10,29 @@ module Solargraph::LanguageServer::Message::Workspace
10
10
 
11
11
  def process
12
12
  need_catalog = false
13
+ to_create = []
14
+ to_delete = []
15
+
13
16
  # @param change [Hash]
14
17
  params['changes'].each do |change|
15
18
  if change['type'] == CREATED
16
- host.create change['uri']
19
+ to_create << change['uri']
17
20
  need_catalog = true
18
21
  elsif change['type'] == CHANGED
19
22
  next if host.open?(change['uri'])
20
- host.create change['uri']
23
+ to_create << change['uri']
21
24
  need_catalog = true
22
25
  elsif change['type'] == DELETED
23
- host.delete change['uri']
26
+ to_delete << change['uri']
24
27
  need_catalog = true
25
28
  else
26
29
  set_error Solargraph::LanguageServer::ErrorCodes::INVALID_PARAMS, "Unknown change type ##{change['type']} for #{uri_to_file(change['uri'])}"
27
30
  end
28
31
  end
32
+
33
+ host.create *to_create
34
+ host.delete *to_delete
35
+
29
36
  # Force host to catalog libraries after file changes (see castwide/solargraph#139)
30
37
  host.catalog if need_catalog
31
38
  end
@@ -8,7 +8,7 @@ class Solargraph::LanguageServer::Message::Workspace::WorkspaceSymbol < Solargra
8
8
  info = pins.map do |pin|
9
9
  uri = file_to_uri(pin.location.filename)
10
10
  {
11
- name: pin.name,
11
+ name: pin.path,
12
12
  containerName: pin.namespace,
13
13
  kind: pin.symbol_kind,
14
14
  location: {
@@ -106,36 +106,37 @@ module Solargraph
106
106
  result
107
107
  end
108
108
 
109
- # Create a file source from a file on disk. The file is ignored if it is
109
+ # Create file sources from files on disk. A file is ignored if it is
110
110
  # neither open in the library nor included in the workspace.
111
111
  #
112
- # @param filename [String]
113
- # @return [Boolean] True if the file was added to the workspace.
114
- def create_from_disk filename
112
+ # @param filenames [Array<String>]
113
+ # @return [Boolean] True if at least one file was added to the workspace.
114
+ def create_from_disk *filenames
115
115
  result = false
116
116
  mutex.synchronize do
117
- next if File.directory?(filename) || !File.exist?(filename)
118
- next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
119
- source = Solargraph::Source.load_string(File.read(filename), filename)
120
- workspace.merge(source)
121
- maybe_map source
122
- result = true
117
+ sources = filenames
118
+ .reject { |filename| File.directory?(filename) || !File.exist?(filename) }
119
+ .map { |filename| Solargraph::Source.load_string(File.read(filename), filename) }
120
+ result = workspace.merge(*sources)
121
+ sources.each { |source| maybe_map source }
123
122
  end
124
123
  result
125
124
  end
126
125
 
127
- # Delete a file from the library. Deleting a file will make it unavailable
126
+ # Delete files from the library. Deleting a file will make it unavailable
128
127
  # for checkout and optionally remove it from the workspace unless the
129
128
  # workspace configuration determines that it should still exist.
130
129
  #
131
- # @param filename [String]
132
- # @return [Boolean] True if the file was deleted
133
- def delete filename
134
- detach filename
130
+ # @param filenames [Array<String>]
131
+ # @return [Boolean] True if any file was deleted
132
+ def delete *filenames
135
133
  result = false
136
- mutex.synchronize do
137
- result = workspace.remove(filename)
138
- @synchronized = !result if synchronized?
134
+ filenames.each do |filename|
135
+ detach filename
136
+ mutex.synchronize do
137
+ result ||= workspace.remove(filename)
138
+ @synchronized = !result if synchronized?
139
+ end
139
140
  end
140
141
  result
141
142
  end
@@ -267,7 +268,7 @@ module Solargraph
267
268
  next unless source_map_hash.key?(full)
268
269
  return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0))
269
270
  end
270
- api_map.yard_map.require_reference(pin.name)
271
+ # api_map.yard_map.require_reference(pin.name)
271
272
  rescue FileNotFoundError
272
273
  nil
273
274
  end
@@ -522,7 +523,7 @@ module Solargraph
522
523
  return unless source
523
524
  return unless @current == source || workspace.has_file?(source.filename)
524
525
  if source_map_hash.key?(source.filename)
525
- return if source_map_hash[source.filename].code == source.code &&
526
+ return if source_map_hash[source.filename].code == source.code &&
526
527
  source_map_hash[source.filename].source.synchronized? &&
527
528
  source.synchronized?
528
529
  if source.synchronized?
@@ -8,16 +8,26 @@ module Solargraph
8
8
  include Legacy::NodeMethods
9
9
 
10
10
  def process
11
- here = get_node_start_position(node)
12
11
  pins.push Solargraph::Pin::Constant.new(
13
12
  location: get_node_location(node),
14
13
  closure: region.closure,
15
- name: node.children[1].to_s,
14
+ name: const_name,
16
15
  comments: comments_for(node),
17
16
  assignment: node.children[2]
18
17
  )
19
18
  process_children
20
19
  end
20
+
21
+ private
22
+
23
+ # @return [String]
24
+ def const_name
25
+ if node.children[0]
26
+ Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
27
+ else
28
+ node.children[1].to_s
29
+ end
30
+ end
21
31
  end
22
32
  end
23
33
  end
@@ -6,11 +6,32 @@ module Solargraph
6
6
  module NodeProcessors
7
7
  class SclassNode < Parser::NodeProcessor::Base
8
8
  def process
9
- # @todo Temporarily skipping remote metaclasses
10
- return unless node.children[0].is_a?(AST::Node) && node.children[0].type == :self
9
+ sclass = node.children[0]
10
+ if sclass.is_a?(AST::Node) && sclass.type == :self
11
+ closure = region.closure
12
+ elsif sclass.is_a?(AST::Node) && sclass.type == :casgn
13
+ names = [region.closure.namespace, region.closure.name]
14
+ if sclass.children[0].nil? && names.last != sclass.children[1].to_s
15
+ names << sclass.children[1].to_s
16
+ else
17
+ names.concat [NodeMethods.unpack_name(sclass.children[0]), sclass.children[1].to_s]
18
+ end
19
+ name = names.reject(&:empty?).join('::')
20
+ closure = Solargraph::Pin::Namespace.new(name: name, location: region.closure.location)
21
+ elsif sclass.is_a?(AST::Node) && sclass.type == :const
22
+ names = [region.closure.namespace, region.closure.name]
23
+ also = NodeMethods.unpack_name(sclass)
24
+ if also != region.closure.name
25
+ names << also
26
+ end
27
+ name = names.reject(&:empty?).join('::')
28
+ closure = Solargraph::Pin::Namespace.new(name: name, location: region.closure.location)
29
+ else
30
+ return
31
+ end
11
32
  pins.push Solargraph::Pin::Singleton.new(
12
33
  location: get_node_location(node),
13
- closure: region.closure
34
+ closure: closure
14
35
  )
15
36
  process_children region.update(visibility: :public, scope: :class, closure: pins.last)
16
37
  end
@@ -1,4 +1,5 @@
1
1
  require 'solargraph/parser/rubyvm/node_processors'
2
+ require 'solargraph/parser/rubyvm/node_wrapper'
2
3
 
3
4
  module Solargraph
4
5
  module Parser
@@ -7,8 +8,10 @@ module Solargraph
7
8
  # @param code [String]
8
9
  # @param filename [String]
9
10
  # @return [Array(Parser::AST::Node, Array<Parser::Source::Comment>)]
11
+ # @sg-ignore
10
12
  def parse_with_comments code, filename = nil
11
13
  node = RubyVM::AbstractSyntaxTree.parse(code).children[2]
14
+ node &&= RubyVM::AbstractSyntaxTree::NodeWrapper.from(node, code.lines)
12
15
  comments = CommentRipper.new(code).parse
13
16
  [node, comments]
14
17
  rescue ::SyntaxError => e
@@ -19,8 +22,10 @@ module Solargraph
19
22
  # @param filename [String, nil]
20
23
  # @param line [Integer]
21
24
  # @return [Parser::AST::Node]
25
+ # @sg-ignore
22
26
  def parse code, filename = nil, line = 0
23
- RubyVM::AbstractSyntaxTree.parse(code).children[2]
27
+ node = RubyVM::AbstractSyntaxTree.parse(code).children[2]
28
+ node and RubyVM::AbstractSyntaxTree::NodeWrapper.from(node, code.lines)
24
29
  rescue ::SyntaxError => e
25
30
  raise Parser::SyntaxError, e.message
26
31
  end
@@ -87,7 +92,7 @@ module Solargraph
87
92
  end
88
93
 
89
94
  def infer_literal_node_type node
90
- # NodeMethods.infer_literal_node_type node
95
+ NodeMethods.infer_literal_node_type node
91
96
  end
92
97
 
93
98
  def version
@@ -9,12 +9,23 @@ module Solargraph
9
9
  pins.push Solargraph::Pin::Constant.new(
10
10
  location: get_node_location(node),
11
11
  closure: region.closure,
12
- name: node.children[0].to_s,
12
+ name: const_name,
13
13
  comments: comments_for(node),
14
- assignment: node.children[1]
14
+ assignment: node.children[2] || node.children[1]
15
15
  )
16
16
  process_children
17
17
  end
18
+
19
+ private
20
+
21
+ # @return [String]
22
+ def const_name
23
+ if Parser.is_ast_node?(node.children[0])
24
+ Parser::NodeMethods.unpack_name(node.children[0])
25
+ else
26
+ node.children[0].to_s
27
+ end
28
+ end
18
29
  end
19
30
  end
20
31
  end
@@ -6,7 +6,8 @@ module Solargraph
6
6
  module NodeProcessors
7
7
  class DefNode < Parser::NodeProcessor::Base
8
8
  def process
9
- loc = get_node_location(node)
9
+ anon_splat = node_has_anon_splat?
10
+
10
11
  methpin = Solargraph::Pin::Method.new(
11
12
  location: get_node_location(node),
12
13
  closure: region.closure,
@@ -14,17 +15,19 @@ module Solargraph
14
15
  comments: comments_for(node),
15
16
  scope: region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance),
16
17
  visibility: region.visibility,
17
- node: node
18
+ node: node,
19
+ anon_splat: anon_splat
18
20
  )
19
- if methpin.name == 'initialize' and methpin.scope == :instance
21
+ if methpin.name == 'initialize' && methpin.scope == :instance
20
22
  pins.push Solargraph::Pin::Method.new(
21
23
  location: methpin.location,
22
24
  closure: methpin.closure,
23
25
  name: 'new',
24
26
  comments: methpin.comments,
25
27
  scope: :class,
26
- parameters: methpin.parameters
27
- )
28
+ parameters: methpin.parameters,
29
+ anon_splat: anon_splat
30
+ )
28
31
  # @todo Smelly instance variable access.
29
32
  pins.last.instance_variable_set(:@return_type, ComplexType::SELF)
30
33
  pins.push methpin
@@ -40,8 +43,9 @@ module Solargraph
40
43
  scope: :class,
41
44
  visibility: :public,
42
45
  parameters: methpin.parameters,
43
- node: methpin.node
44
- )
46
+ node: methpin.node,
47
+ anon_splat: anon_splat
48
+ )
45
49
  pins.push Solargraph::Pin::Method.new(
46
50
  location: methpin.location,
47
51
  closure: methpin.closure,
@@ -50,13 +54,20 @@ module Solargraph
50
54
  scope: :instance,
51
55
  visibility: :private,
52
56
  parameters: methpin.parameters,
53
- node: methpin.node
54
- )
57
+ node: methpin.node,
58
+ anon_splat: anon_splat
59
+ )
55
60
  else
56
61
  pins.push methpin
57
62
  end
58
63
  process_children region.update(closure: methpin, scope: methpin.scope)
59
64
  end
65
+
66
+ private
67
+
68
+ def node_has_anon_splat?
69
+ node.children[1]&.children&.first == [nil]
70
+ end
60
71
  end
61
72
  end
62
73
  end
@@ -11,6 +11,8 @@ module Solargraph
11
11
  s_visi = region.visibility
12
12
  s_visi = :public if region.scope != :class
13
13
  loc = get_node_location(node)
14
+ anon_splat = node_has_anon_splat?
15
+
14
16
  if node.children[0].is_a?(RubyVM::AbstractSyntaxTree::Node) && node.children[0].type == :SELF
15
17
  closure = region.closure
16
18
  else
@@ -26,7 +28,8 @@ module Solargraph
26
28
  comments: comments_for(node),
27
29
  scope: :class,
28
30
  visibility: :public,
29
- node: node
31
+ node: node,
32
+ anon_splat: anon_splat
30
33
  )
31
34
  pins.push Solargraph::Pin::Method.new(
32
35
  location: loc,
@@ -35,7 +38,8 @@ module Solargraph
35
38
  comments: comments_for(node),
36
39
  scope: :instance,
37
40
  visibility: :private,
38
- node: node
41
+ node: node,
42
+ anon_splat: anon_splat
39
43
  )
40
44
  else
41
45
  pins.push Solargraph::Pin::Method.new(
@@ -45,11 +49,18 @@ module Solargraph
45
49
  comments: comments_for(node),
46
50
  scope: :class,
47
51
  visibility: s_visi,
48
- node: node
52
+ node: node,
53
+ anon_splat: anon_splat
49
54
  )
50
55
  end
51
56
  process_children region.update(closure: pins.last, scope: :class)
52
57
  end
58
+
59
+ private
60
+
61
+ def node_has_anon_splat?
62
+ node.children[2]&.children&.first == [nil]
63
+ end
53
64
  end
54
65
  end
55
66
  end
@@ -11,8 +11,8 @@ module Solargraph
11
11
  closure: region.closure,
12
12
  comments: comments_for(node),
13
13
  name: node.children[0].children[0].to_s,
14
- # assignment: require_keyword?(node) ? nil : node.children[0].children[1],
15
- asgn_code: require_keyword?(node) ? nil: region.code_for(node.children[0].children[1]),
14
+ assignment: require_keyword?(node) ? nil : node.children[0].children[1],
15
+ asgn_code: require_keyword?(node) ? nil : region.code_for(node.children[0].children[1]),
16
16
  presence: region.closure.location.range,
17
17
  decl: require_keyword?(node) ? :kwarg : :kwoptarg
18
18
  )
@@ -6,11 +6,22 @@ module Solargraph
6
6
  module NodeProcessors
7
7
  class SclassNode < Parser::NodeProcessor::Base
8
8
  def process
9
- # @todo Temporarily skipping remote metaclasses
10
- return unless node.children[0].is_a?(RubyVM::AbstractSyntaxTree::Node) && node.children[0].type == :SELF
9
+ sclass = node.children[0]
10
+ if sclass.is_a?(RubyVM::AbstractSyntaxTree::Node) && sclass.type == :SELF
11
+ closure = region.closure
12
+ elsif sclass.is_a?(RubyVM::AbstractSyntaxTree::Node) && %i[CDECL CONST].include?(sclass.type)
13
+ names = [region.closure.namespace, region.closure.name]
14
+ if names.last != sclass.children[0].to_s
15
+ names << sclass.children[0].to_s
16
+ end
17
+ name = names.reject(&:empty?).join('::')
18
+ closure = Solargraph::Pin::Namespace.new(name: name, location: region.closure.location)
19
+ else
20
+ return
21
+ end
11
22
  pins.push Solargraph::Pin::Singleton.new(
12
23
  location: get_node_location(node),
13
- closure: region.closure
24
+ closure: closure
14
25
  )
15
26
  process_children region.update(visibility: :public, scope: :class, closure: pins.last)
16
27
  end
@@ -226,8 +226,10 @@ module Solargraph
226
226
 
227
227
  # @return [void]
228
228
  def process_private_constant
229
- return unless Parser.is_ast_node?(node.children.last)
230
- node.children.last.children[0..-2].each do |child|
229
+ arr = node.children[1]
230
+ return unless Parser.is_ast_node?(arr) && [:ARRAY, :LIST].include?(arr.type)
231
+
232
+ arr.children.compact.each do |child|
231
233
  if [:LIT, :STR].include?(child.type)
232
234
  cn = child.children[0].to_s
233
235
  ref = pins.select{|p| [Solargraph::Pin::Namespace, Solargraph::Pin::Constant].include?(p.class) && p.namespace == region.closure.full_context.namespace && p.name == cn}.first
@@ -0,0 +1,47 @@
1
+ require 'delegate'
2
+
3
+ module RubyVM::AbstractSyntaxTree
4
+ # Wrapper for RubyVM::AbstractSyntaxTree::Node. for return character based column
5
+ class NodeWrapper < SimpleDelegator
6
+ attr_reader :code
7
+ # @param node [RubyVM::AbstractSyntaxTree::Node] wrapped node to return character based column
8
+ # @param code [Array<String>] source code lines for generated this node
9
+ def initialize(node, code)
10
+ @code = code
11
+ super(node)
12
+ end
13
+
14
+ def self.from(node, code)
15
+ return node unless node.is_a?(RubyVM::AbstractSyntaxTree::Node) and !node.kind_of?(SimpleDelegator)
16
+
17
+ new(node, code)
18
+ end
19
+
20
+ def is_a?(type)
21
+ __getobj__.is_a?(type) || super.is_a?(type)
22
+ end
23
+
24
+ def class
25
+ __getobj__.class
26
+ end
27
+
28
+
29
+ def first_column
30
+ @first_column ||= begin
31
+ line = @code[__getobj__.first_lineno - 1] || ""
32
+ line.byteslice(0, __getobj__.first_column).length
33
+ end
34
+ end
35
+
36
+ def last_column
37
+ @last_column ||= begin
38
+ line = @code[__getobj__.last_lineno - 1] || ""
39
+ line.byteslice(0, __getobj__.last_column).length
40
+ end
41
+ end
42
+
43
+ def children
44
+ @children ||= __getobj__.children.map do |node| NodeWrapper.from(node, @code) end
45
+ end
46
+ end
47
+ end
@@ -21,9 +21,12 @@ module Solargraph
21
21
  # @return [String]
22
22
  attr_reader :path
23
23
 
24
- # @param location [Solargraph::Location]
24
+ # @return [::Symbol]
25
+ attr_accessor :source
26
+
27
+ # @param location [Solargraph::Location, nil]
25
28
  # @param kind [Integer]
26
- # @param closure [Solargraph::Pin::Closure]
29
+ # @param closure [Solargraph::Pin::Closure, nil]
27
30
  # @param name [String]
28
31
  # @param comments [String]
29
32
  def initialize location: nil, closure: nil, name: '', comments: ''