solargraph 0.49.0 → 0.51.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +4 -6
  3. data/CHANGELOG.md +38 -0
  4. data/README.md +2 -4
  5. data/SPONSORS.md +2 -1
  6. data/lib/solargraph/cache.rb +3 -1
  7. data/lib/solargraph/complex_type.rb +9 -2
  8. data/lib/solargraph/convention.rb +0 -2
  9. data/lib/solargraph/language_server/host/cataloger.rb +1 -1
  10. data/lib/solargraph/language_server/host.rb +11 -1
  11. data/lib/solargraph/language_server/message/initialize.rb +8 -0
  12. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  13. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  14. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
  15. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  16. data/lib/solargraph/language_server/message/text_document.rb +1 -0
  17. data/lib/solargraph/language_server/message.rb +1 -0
  18. data/lib/solargraph/library.rb +22 -2
  19. data/lib/solargraph/parser/rubyvm/class_methods.rb +4 -0
  20. data/lib/solargraph/parser/rubyvm/node_chainer.rb +1 -1
  21. data/lib/solargraph/parser/rubyvm/node_methods.rb +3 -1
  22. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +10 -4
  23. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +2 -2
  24. data/lib/solargraph/parser/rubyvm/node_processors.rb +1 -0
  25. data/lib/solargraph/parser.rb +2 -2
  26. data/lib/solargraph/pin/base_variable.rb +1 -1
  27. data/lib/solargraph/pin/block.rb +1 -1
  28. data/lib/solargraph/pin/delegated_method.rb +97 -0
  29. data/lib/solargraph/pin/method.rb +5 -0
  30. data/lib/solargraph/pin/search.rb +1 -1
  31. data/lib/solargraph/pin.rb +1 -0
  32. data/lib/solargraph/range.rb +2 -4
  33. data/lib/solargraph/rbs_map/conversions.rb +8 -6
  34. data/lib/solargraph/rbs_map/core_fills.rb +7 -1
  35. data/lib/solargraph/rbs_map/core_map.rb +1 -1
  36. data/lib/solargraph/rbs_map/stdlib_map.rb +3 -0
  37. data/lib/solargraph/shell.rb +16 -6
  38. data/lib/solargraph/source/chain/call.rb +1 -1
  39. data/lib/solargraph/source/chain.rb +1 -1
  40. data/lib/solargraph/source_map/clip.rb +14 -0
  41. data/lib/solargraph/source_map/mapper.rb +6 -4
  42. data/lib/solargraph/source_map.rb +15 -2
  43. data/lib/solargraph/type_checker.rb +33 -21
  44. data/lib/solargraph/version.rb +1 -1
  45. data/lib/solargraph/workspace/config.rb +6 -5
  46. data/lib/solargraph/yard_map.rb +15 -7
  47. data/solargraph.gemspec +11 -5
  48. metadata +73 -22
  49. data/.travis.yml +0 -19
  50. data/lib/solargraph/convention/rspec.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0b66abd5cf5a0376d5521532dda16db328592eb38bac6acd84f997b19cb328c
4
- data.tar.gz: 51e038df27bae1457393c7ff023c9951b0f8919267678e29aab2e21efeb2b1a8
3
+ metadata.gz: 925e6692e134d83820ade3224a10e1e25ba8b7f65c5a8399b185574f225ad8e7
4
+ data.tar.gz: 319f943451956ac714e110f48db851391cfb5c4b2ceb1e3e8d2eb2d22dc56c05
5
5
  SHA512:
6
- metadata.gz: 9b8310748d4754c27fd62763ce1bd8759fc43fc825b1b40353d4537130f2b6143cdb59101da679a8b4a7fb0778430eeac2eccbb845f7a9a5ac11f402b3a71461
7
- data.tar.gz: 1b2f79f5396a3c056d0b2acbcb49d6c1385b02a49b33edbe1a3e452a7b451b9b87547b8b8d5974a17e25ea2f5c21db8dd315d2b3d856fb3c7ce2d300a4595c70
6
+ metadata.gz: df03f1f0ed8e51f8c286395c4b87b1c254c78a897761ec71a9af896ef86c01e6d4285530ddf2e40c72f17afb6b5d87be11e219cc46859d7d7b7c2e05e24687bf
7
+ data.tar.gz: dd6b4f96bc8e6361bcfd313129a4ba9d680c8db45484deea040ec5fa6ba5a8873dcefa2980af4824d26f2ecc16d68bd5b5554e4978ae71853e22df49ed427894
@@ -22,19 +22,17 @@ jobs:
22
22
  runs-on: ubuntu-latest
23
23
  strategy:
24
24
  matrix:
25
- ruby-version: ['2.6', '2.7', '3.0', '3.1']
25
+ ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', 'head']
26
26
 
27
27
  steps:
28
28
  - uses: actions/checkout@v3
29
29
  - name: Set up Ruby
30
- # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
31
- # change this to (see https://github.com/ruby/setup-ruby#versioning):
32
- # uses: ruby/setup-ruby@v1
33
- uses: ruby/setup-ruby@2b019609e2b0f1ea1a2bc8ca11cb82ab46ada124
30
+ uses: ruby/setup-ruby@v1
34
31
  with:
35
32
  ruby-version: ${{ matrix.ruby-version }}
36
33
  bundler-cache: false
37
- - run: bundle install
34
+ - name: Install gems
35
+ run: bundle install
38
36
  - name: Set up yardocs
39
37
  run: bundle exec yard gems
40
38
  - name: Run tests
data/CHANGELOG.md CHANGED
@@ -1,3 +1,41 @@
1
+ ## 0.51.0 - January 19, 2025
2
+ - Resolve self in yieldself tags
3
+ - Include absolute paths in config (#674)
4
+ - Enable diagnostics by default
5
+ - Fix cache resolution (#704)
6
+ - Modify rubocop option for rubocop < 1.30 (#665)
7
+ - Include absolute paths in config (#674)
8
+ - Enable diagnostics by default
9
+ - Remove RSpec convention (#716)
10
+ - Include convention pins in document_symbols (#724)
11
+ - Remove e2mmap dependency (#699)
12
+ - Update rbs to 3.0
13
+ - Relax reverse_markdown dependency (#729)
14
+ - Fix Ruby 3.4 and move all parsing to whitequark (#739)
15
+ - Add Pin::DelegatedMethod (#602)
16
+ - Complete global methods from a file inside namespaces (#714)
17
+ - gemspec dashes and required path slashes (#697)
18
+
19
+ ## 0.50.0 - December 5, 2023
20
+ - Remove .travis.yml as its not longer used (#627)
21
+ - Fix empty string case when processing requires (#644)
22
+ - Fix scope() method call on wrong object (#670)
23
+ - Parse comments that start with multiple hashes (#667)
24
+ - Use XDG_CACHE_HOME if it exists (#664)
25
+ - Add rbs mention to readme (#693)
26
+ - Remove Atom from the readme (#692)
27
+ - Add more metadata to the gemspec (#691)
28
+ - Do not deprecate clear command
29
+ - Library#locate_ref returns nil for unresolved requires (#675)
30
+ - Hide deprecated commands
31
+ - List command
32
+ - Fixes (or ignores) ffi crash (#676)
33
+ - increase sleep time on cataloger (#677)
34
+ - YardMap ignores absolute paths (#678)
35
+ - Clarify macros vs. directives
36
+ - Infer complex types from method calls
37
+ - Default cache uses XDG_CACHE_HOME default (#664)
38
+
1
39
  ## 0.49.0 - April 9, 2023
2
40
  - Better union type handling
3
41
  - First version of RBS support
data/README.md CHANGED
@@ -28,10 +28,6 @@ Plug-ins and extensions are available for the following editors:
28
28
  * Extension: https://marketplace.visualstudio.com/items?itemName=castwide.solargraph
29
29
  * GitHub: https://github.com/castwide/vscode-solargraph
30
30
 
31
- * **Atom**
32
- * Package: https://atom.io/packages/ruby-solargraph
33
- * GitHub: https://github.com/castwide/atom-solargraph
34
-
35
31
  * **Sublime Text**
36
32
  * Extension: https://packagecontrol.io/packages/LSP
37
33
  * GitHub: https://github.com/sublimelsp/LSP
@@ -71,6 +67,8 @@ As of version 0.33.0, Solargraph includes a [type checker](https://github.com/ca
71
67
 
72
68
  ### Updating Core Documentation
73
69
 
70
+ As of version 0.49.0, Solargraph uses [rbs](https://github.com/ruby/rbs) for core and stdlib documentation. The following only applies to prior versions.
71
+
74
72
  The Solargraph gem ships with documentation for Ruby 2.2.2. You can download documentation for other Ruby versions from the command line.
75
73
 
76
74
  $ solargraph list-cores # List the installed documentation versions
data/SPONSORS.md CHANGED
@@ -12,4 +12,5 @@ The following people and organizations provide funding or other resources. [Beco
12
12
 
13
13
  - Akira Yamada
14
14
  - Joel Drapper
15
- - Yutaka Tachibana
15
+ - Spencer
16
+ - Vince Broz
@@ -9,7 +9,9 @@ module Solargraph
9
9
  def base_dir
10
10
  # The directory is not stored in a variable so it can be overridden
11
11
  # in specs.
12
- ENV['SOLARGRAPH_CACHE'] || File.join(Dir.home, '.solargraph', 'cache')
12
+ ENV['SOLARGRAPH_CACHE'] ||
13
+ (ENV['XDG_CACHE_HOME'] ? File.join(ENV['XDG_CACHE_HOME'], 'solargraph') : nil) ||
14
+ File.join(Dir.home, '.cache', 'solargraph')
13
15
  end
14
16
 
15
17
  # The working directory for the current Ruby and Solargraph versions.
@@ -67,11 +67,18 @@ module Solargraph
67
67
  def select &block
68
68
  @items.select &block
69
69
  end
70
+
71
+ # @return [String]
70
72
  def namespace
71
73
  # cache this attr for high frequency call
72
74
  @namespace ||= method_missing(:namespace).to_s
73
75
  end
74
76
 
77
+ # @return [Array<String>]
78
+ def namespaces
79
+ @items.map(&:namespace)
80
+ end
81
+
75
82
  def method_missing name, *args, &block
76
83
  return if @items.first.nil?
77
84
  return @items.first.send(name, *args, &block) if respond_to_missing?(name)
@@ -113,7 +120,7 @@ module Solargraph
113
120
  return self unless selfy?
114
121
  red = reduce_class(dst)
115
122
  result = @items.map { |i| i.self_to red }
116
- ComplexType.parse(*result.map(&:tag))
123
+ ComplexType.parse(*result.map(&:to_s))
117
124
  end
118
125
 
119
126
  def nullable?
@@ -169,7 +176,7 @@ module Solargraph
169
176
  paren_stack = 0
170
177
  base = String.new
171
178
  subtype_string = String.new
172
- type_string.each_char do |char|
179
+ type_string&.each_char do |char|
173
180
  if char == '='
174
181
  #raise ComplexTypeError, "Invalid = in type #{type_string}" unless curly_stack > 0
175
182
  elsif char == '<'
@@ -9,7 +9,6 @@ module Solargraph
9
9
  module Convention
10
10
  autoload :Base, 'solargraph/convention/base'
11
11
  autoload :Gemfile, 'solargraph/convention/gemfile'
12
- autoload :Rspec, 'solargraph/convention/rspec'
13
12
  autoload :Gemspec, 'solargraph/convention/gemspec'
14
13
  autoload :Rakefile, 'solargraph/convention/rakefile'
15
14
 
@@ -43,7 +42,6 @@ module Solargraph
43
42
 
44
43
  register Gemfile
45
44
  register Gemspec
46
- register Rspec
47
45
  register Rakefile
48
46
  end
49
47
  end
@@ -34,7 +34,7 @@ module Solargraph
34
34
  Thread.new do
35
35
  until stopped?
36
36
  tick
37
- sleep 0.01
37
+ sleep 0.1
38
38
  end
39
39
  end
40
40
  end
@@ -533,6 +533,15 @@ module Solargraph
533
533
  library.definitions_at(uri_to_file(uri), line, column)
534
534
  end
535
535
 
536
+ # @param uri [String]
537
+ # @param line [Integer]
538
+ # @param column [Integer]
539
+ # @return [Array<Solargraph::Pin::Base>]
540
+ def type_definitions_at uri, line, column
541
+ library = library_for(uri)
542
+ library.type_definitions_at(uri_to_file(uri), line, column)
543
+ end
544
+
536
545
  # @param uri [String]
537
546
  # @param line [Integer]
538
547
  # @param column [Integer]
@@ -630,10 +639,11 @@ module Solargraph
630
639
  'hover' => true,
631
640
  'symbols' => true,
632
641
  'definitions' => true,
642
+ 'typeDefinitions' => true,
633
643
  'rename' => true,
634
644
  'references' => true,
635
645
  'autoformat' => false,
636
- 'diagnostics' => false,
646
+ 'diagnostics' => true,
637
647
  'formatting' => false,
638
648
  'folding' => true,
639
649
  'highlights' => true,
@@ -34,6 +34,7 @@ module Solargraph
34
34
  result[:capabilities].merge! static_document_formatting unless dynamic_registration_for?('textDocument', 'formatting')
35
35
  result[:capabilities].merge! static_document_symbols unless dynamic_registration_for?('textDocument', 'documentSymbol')
36
36
  result[:capabilities].merge! static_definitions unless dynamic_registration_for?('textDocument', 'definition')
37
+ result[:capabilities].merge! static_type_definitions unless dynamic_registration_for?('textDocument', 'typeDefinition')
37
38
  result[:capabilities].merge! static_rename unless dynamic_registration_for?('textDocument', 'rename')
38
39
  result[:capabilities].merge! static_references unless dynamic_registration_for?('textDocument', 'references')
39
40
  result[:capabilities].merge! static_workspace_symbols unless dynamic_registration_for?('workspace', 'symbol')
@@ -121,6 +122,13 @@ module Solargraph
121
122
  }
122
123
  end
123
124
 
125
+ def static_type_definitions
126
+ return {} unless host.options['type_definitions']
127
+ {
128
+ definitionProvider: true
129
+ }
130
+ end
131
+
124
132
  def static_rename
125
133
  {
126
134
  renameProvider: {prepareProvider: true}
@@ -13,6 +13,7 @@ module Solargraph
13
13
  textDocument/formatting
14
14
  textDocument/documentSymbol
15
15
  textDocument/definition
16
+ textDocument/typeDefinition
16
17
  textDocument/references
17
18
  textDocument/rename
18
19
  textDocument/prepareRename
@@ -6,6 +6,8 @@ class Solargraph::LanguageServer::Message::TextDocument::DocumentSymbol < Solarg
6
6
  def process
7
7
  pins = host.document_symbols params['textDocument']['uri']
8
8
  info = pins.map do |pin|
9
+ next nil unless pin.location&.filename
10
+
9
11
  result = {
10
12
  name: pin.name,
11
13
  containerName: pin.namespace,
@@ -17,7 +19,8 @@ class Solargraph::LanguageServer::Message::TextDocument::DocumentSymbol < Solarg
17
19
  deprecated: pin.deprecated?
18
20
  }
19
21
  result
20
- end
22
+ end.compact
23
+
21
24
  set_result info
22
25
  end
23
26
  end
@@ -17,17 +17,17 @@ module Solargraph
17
17
  args = cli_args(file_uri, config)
18
18
 
19
19
  require_rubocop(config['version'])
20
- options, paths = RuboCop::Options.new.parse(args)
20
+ options, paths = ::RuboCop::Options.new.parse(args)
21
21
  options[:stdin] = original
22
22
  corrections = redirect_stdout do
23
- RuboCop::Runner.new(options, RuboCop::ConfigStore.new).run(paths)
23
+ ::RuboCop::Runner.new(options, ::RuboCop::ConfigStore.new).run(paths)
24
24
  end
25
25
  result = options[:stdin]
26
26
 
27
27
  log_corrections(corrections)
28
28
 
29
29
  format original, result
30
- rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
30
+ rescue ::RuboCop::ValidationError, ::RuboCop::ConfigNotFoundError => e
31
31
  set_error(Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, "[#{e.class}] #{e.message}")
32
32
  end
33
33
 
@@ -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' ? '--autocorrect-all' : '--autocorrect',
57
+ config['cops'] == 'all' ? '-A' : '-a',
58
58
  '--cache', 'false',
59
59
  '--format', formatter_class(config).name,
60
60
  ]
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph::LanguageServer::Message::TextDocument
4
+ class TypeDefinition < Base
5
+ def process
6
+ @line = params['position']['line']
7
+ @column = params['position']['character']
8
+ set_result(code_location || [])
9
+ end
10
+
11
+ private
12
+
13
+ def code_location
14
+ suggestions = host.type_definitions_at(params['textDocument']['uri'], @line, @column)
15
+ return nil if suggestions.empty?
16
+ suggestions.reject { |pin| pin.location.nil? || pin.location.filename.nil? }.map do |pin|
17
+ {
18
+ uri: file_to_uri(pin.location.filename),
19
+ range: pin.location.range.to_hash
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -15,6 +15,7 @@ module Solargraph
15
15
  autoload :DiagnosticsQueue, 'solargraph/language_server/message/text_document/diagnostics_queue'
16
16
  autoload :OnTypeFormatting, 'solargraph/language_server/message/text_document/on_type_formatting'
17
17
  autoload :Definition, 'solargraph/language_server/message/text_document/definition'
18
+ autoload :TypeDefinition, 'solargraph/language_server/message/text_document/type_definition'
18
19
  autoload :DocumentSymbol, 'solargraph/language_server/message/text_document/document_symbol'
19
20
  autoload :Formatting, 'solargraph/language_server/message/text_document/formatting'
20
21
  autoload :References, 'solargraph/language_server/message/text_document/references'
@@ -66,6 +66,7 @@ module Solargraph
66
66
  register 'textDocument/didClose', TextDocument::DidClose
67
67
  register 'textDocument/hover', TextDocument::Hover
68
68
  register 'textDocument/definition', TextDocument::Definition
69
+ register 'textDocument/typeDefinition', TextDocument::TypeDefinition
69
70
  register 'textDocument/formatting', TextDocument::Formatting
70
71
  register 'textDocument/onTypeFormatting', TextDocument::OnTypeFormatting
71
72
  register 'textDocument/documentSymbol', TextDocument::DocumentSymbol
@@ -97,7 +97,7 @@ module Solargraph
97
97
  def create filename, text
98
98
  result = false
99
99
  mutex.synchronize do
100
- next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
100
+ next unless contain?(filename) || open?(filename)
101
101
  @synchronized = false
102
102
  source = Solargraph::Source.load_string(text, filename)
103
103
  workspace.merge(source)
@@ -199,6 +199,22 @@ module Solargraph
199
199
  handle_file_not_found(filename, e)
200
200
  end
201
201
 
202
+ # Get type definition suggestions for the expression at the specified file and
203
+ # location.
204
+ #
205
+ # @param filename [String] The file to analyze
206
+ # @param line [Integer] The zero-based line number
207
+ # @param column [Integer] The zero-based column number
208
+ # @return [Array<Solargraph::Pin::Base>]
209
+ # @todo Take filename/position instead of filename/line/column
210
+ def type_definitions_at filename, line, column
211
+ position = Position.new(line, column)
212
+ cursor = Source::Cursor.new(read(filename), position)
213
+ api_map.clip(cursor).types
214
+ rescue FileNotFoundError => e
215
+ handle_file_not_found filename, e
216
+ end
217
+
202
218
  # Get signature suggestions for the method at the specified file and
203
219
  # location.
204
220
  #
@@ -258,6 +274,10 @@ module Solargraph
258
274
  api_map.locate_pins(location).map { |pin| pin.realize(api_map) }
259
275
  end
260
276
 
277
+ # Match a require reference to a file.
278
+ #
279
+ # @param location [Location]
280
+ # @return [Location, nil]
261
281
  def locate_ref location
262
282
  map = source_map_hash[location.filename]
263
283
  return if map.nil?
@@ -268,7 +288,7 @@ module Solargraph
268
288
  next unless source_map_hash.key?(full)
269
289
  return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0))
270
290
  end
271
- # api_map.yard_map.require_reference(pin.name)
291
+ nil
272
292
  rescue FileNotFoundError
273
293
  nil
274
294
  end
@@ -108,9 +108,13 @@ module Solargraph
108
108
  end
109
109
 
110
110
  def node_range node
111
+ if node.nil?
112
+ nil
113
+ else
111
114
  st = Position.new(node.first_lineno - 1, node.first_column)
112
115
  en = Position.new(node.last_lineno - 1, node.last_column)
113
116
  Range.new(st, en)
117
+ end
114
118
  end
115
119
 
116
120
  def recipient_node tree
@@ -98,7 +98,7 @@ module Solargraph
98
98
  result.concat generate_links(n.children.last)
99
99
  elsif n.type == :OR
100
100
  result.push Chain::Or.new([NodeChainer.chain(n.children[0], @filename), NodeChainer.chain(n.children[1], @filename)])
101
- elsif n.type == :begin
101
+ elsif n.type == :BEGIN
102
102
  result.concat generate_links(n.children[0])
103
103
  elsif n.type == :BLOCK_PASS
104
104
  result.push Chain::BlockVariable.new("&#{n.children[1].children[0].to_s}")
@@ -32,10 +32,12 @@ module Solargraph
32
32
  def infer_literal_node_type node
33
33
  return nil unless Parser.is_ast_node?(node)
34
34
  case node.type
35
- when :LIT, :STR
35
+ when :LIT, :STR, :SYM
36
36
  "::#{node.children.first.class.to_s}"
37
37
  when :DSTR
38
38
  "::String"
39
+ when :INTEGER
40
+ '::Integer'
39
41
  when :ARRAY, :ZARRAY, :LIST, :ZLIST
40
42
  '::Array'
41
43
  when :HASH
@@ -22,7 +22,7 @@ module Solargraph
22
22
  locals.push Solargraph::Pin::LocalVariable.new(
23
23
  location: loc,
24
24
  closure: region.closure,
25
- name: node.children[1].children.first.children.first.to_s,
25
+ name: node.children[1].children.first.to_s,
26
26
  comments: "@type [#{types.join(',')}]",
27
27
  presence: presence
28
28
  )
@@ -34,9 +34,15 @@ module Solargraph
34
34
  private
35
35
 
36
36
  def exception_variable?
37
- Parser.is_ast_node?(node.children[1]) &&
38
- Parser.is_ast_node?(node.children[1].children.first) &&
39
- node.children[1].children.first.type == :LASGN
37
+ if RUBY_VERSION =~ /^3\.4\./
38
+ Parser.is_ast_node?(node.children[1]) &&
39
+ # Parser.is_ast_node?(node.children[1].children.first) &&
40
+ node.children[1].type == :LASGN
41
+ else
42
+ Parser.is_ast_node?(node.children[1]) &&
43
+ Parser.is_ast_node?(node.children[1].children.first) &&
44
+ node.children[1].children.first.type == :LASGN
45
+ end
40
46
  end
41
47
  end
42
48
  end
@@ -43,7 +43,7 @@ module Solargraph
43
43
  if node.type == :FCALL && Parser.is_ast_node?(node.children.last)
44
44
  node.children.last.children[0..-2].each do |child|
45
45
  # next unless child.is_a?(AST::Node) && (child.type == :sym || child.type == :str)
46
- if child.type == :LIT || child.type == :STR
46
+ if child.type == :LIT || child.type == :STR || child.type == :SYM
47
47
  name = child.children[0].to_s
48
48
  matches = pins.select{ |pin| pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == region.closure.full_context.namespace && pin.context.scope == (region.scope || :instance)}
49
49
  matches.each do |pin|
@@ -175,7 +175,7 @@ module Solargraph
175
175
  NodeProcessor.process node.children.last.children[0], region.update(visibility: :module_function), pins, locals
176
176
  else
177
177
  node.children.last.children[0..-2].each do |x|
178
- next unless [:LIT, :STR].include?(x.type)
178
+ next unless [:LIT, :STR, :SYM].include?(x.type)
179
179
  cn = x.children[0].to_s
180
180
  ref = pins.select { |p| p.is_a?(Pin::Method) && p.namespace == region.closure.full_context.namespace && p.name == cn }.first
181
181
  unless ref.nil?
@@ -58,6 +58,7 @@ module Solargraph
58
58
  register :FOR, Rubyvm::NodeProcessors::BlockNode
59
59
  register :OP_ASGN_OR, Rubyvm::NodeProcessors::OrasgnNode
60
60
  register :LIT, Rubyvm::NodeProcessors::LitNode
61
+ register :SYM, Rubyvm::NodeProcessors::LitNode
61
62
  end
62
63
  end
63
64
  end
@@ -13,8 +13,8 @@ module Solargraph
13
13
  # True if the parser can use RubyVM.
14
14
  #
15
15
  def self.rubyvm?
16
- !!defined?(RubyVM::AbstractSyntaxTree)
17
- # false
16
+ # !!defined?(RubyVM::AbstractSyntaxTree)
17
+ false
18
18
  end
19
19
 
20
20
  selected = rubyvm? ? Rubyvm : Legacy
@@ -56,7 +56,7 @@ module Solargraph
56
56
  end
57
57
  end
58
58
  return ComplexType::UNDEFINED if types.empty?
59
- ComplexType.try_parse(*types.map(&:tag))
59
+ ComplexType.try_parse(*types.map(&:to_s))
60
60
  end
61
61
 
62
62
  def == other
@@ -63,7 +63,7 @@ module Solargraph
63
63
  if receiver_pin && receiver_pin.docstring
64
64
  ys = receiver_pin.docstring.tag(:yieldself)
65
65
  if ys && ys.types && !ys.types.empty?
66
- return ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
66
+ return ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace).self_to(receiver_pin.full_context.namespace)
67
67
  end
68
68
  end
69
69
  nil
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ # A DelegatedMethod is a more complicated version of a MethodAlias that
6
+ # allows aliasing a method from a different closure (class/module etc).
7
+ class DelegatedMethod < Pin::Method
8
+ # A DelegatedMethod can be constructed with either a :resolved_method
9
+ # pin, or a :receiver_chain. When a :receiver_chain is supplied, it
10
+ # will be used to *dynamically* resolve a receiver type within the
11
+ # given closure/scope, and the delegated method will then be resolved
12
+ # to a method pin on that type.
13
+ #
14
+ # @param resolved_method [Method] an already resolved method pin.
15
+ # @param receiver [Source::Chain] the source code used to resolve the receiver for this delegated method.
16
+ # @param receiver_method_name [String] the method name that will be called on the receiver (defaults to :name).
17
+ def initialize(method: nil, receiver: nil, name: method&.name, receiver_method_name: name, **splat)
18
+ raise ArgumentError, 'either :method or :receiver is required' if (method && receiver) || (!method && !receiver)
19
+ super(name: name, **splat)
20
+
21
+ @receiver_chain = receiver
22
+ @resolved_method = method
23
+ @receiver_method_name = receiver_method_name
24
+ end
25
+
26
+ %i[comments parameters return_type location].each do |method|
27
+ define_method(method) do
28
+ @resolved_method ? @resolved_method.send(method) : super()
29
+ end
30
+ end
31
+
32
+ %i[typify realize infer probe].each do |method|
33
+ # @param api_map [ApiMap]
34
+ define_method(method) do |api_map|
35
+ resolve_method(api_map)
36
+ @resolved_method ? @resolved_method.send(method, api_map) : super(api_map)
37
+ end
38
+ end
39
+
40
+ def resolvable?(api_map)
41
+ resolve_method(api_map)
42
+ !!@resolved_method
43
+ end
44
+
45
+ private
46
+
47
+ # Resolves the receiver chain and method name to a method pin, resetting any previously resolution.
48
+ #
49
+ # @param api_map [ApiMap]
50
+ # @return [Pin::Method, nil]
51
+ def resolve_method api_map
52
+ return if @resolved_method
53
+
54
+ resolver = @receiver_chain.define(api_map, self, []).first
55
+
56
+ unless resolver
57
+ Solargraph.logger.warn \
58
+ "Delegated receiver for #{path} was resolved to nil from `#{print_chain(@receiver_chain)}'"
59
+ return
60
+ end
61
+
62
+ receiver_type = resolver.return_type
63
+
64
+ return if receiver_type.undefined?
65
+
66
+ receiver_path, method_scope =
67
+ if @receiver_chain.constant?
68
+ # HACK: the `return_type` of a constant is Class<Whatever>, but looking up a method expects
69
+ # the arguments `"Whatever"` and `scope: :class`.
70
+ [receiver_type.to_s.sub(/^Class<(.+)>$/, '\1'), :class]
71
+ else
72
+ [receiver_type.to_s, :instance]
73
+ end
74
+
75
+ method_stack = api_map.get_method_stack(receiver_path, @receiver_method_name, scope: method_scope)
76
+ @resolved_method = method_stack.first
77
+ end
78
+
79
+ # helper to print a source chain as code, probably not 100% correct.
80
+ #
81
+ # @param chain [Source::Chain]
82
+ def print_chain(chain)
83
+ out = +''
84
+ chain.links.each_with_index do |link, index|
85
+ if index > 0
86
+ if Source::Chain::Constant
87
+ out << '::' unless link.word.start_with?('::')
88
+ else
89
+ out << '.'
90
+ end
91
+ end
92
+ out << link.word
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -130,6 +130,11 @@ module Solargraph
130
130
  end
131
131
  @documentation += "\n\n" unless @documentation.empty?
132
132
  @documentation += "Visibility: #{visibility}"
133
+ example_tags = docstring.tags(:example)
134
+ unless example_tags.empty?
135
+ @documentation += "\n\nExamples:\n\n"
136
+ @documentation += example_tags.map(&:text).join("\n")
137
+ end
133
138
  end
134
139
  @documentation.to_s
135
140
  end
@@ -49,7 +49,7 @@ module Solargraph
49
49
  # @return [Float]
50
50
  def fuzzy_string_match str1, str2
51
51
  return (1.0 + (str2.length.to_f / str1.length.to_f)) if str1.downcase.include?(str2.downcase)
52
- JaroWinkler.distance(str1, str2, ignore_case: true)
52
+ JaroWinkler.similarity(str1, str2, ignore_case: true)
53
53
  end
54
54
  end
55
55
  end
@@ -12,6 +12,7 @@ module Solargraph
12
12
  autoload :Method, 'solargraph/pin/method'
13
13
  autoload :Signature, 'solargraph/pin/signature'
14
14
  autoload :MethodAlias, 'solargraph/pin/method_alias'
15
+ autoload :DelegatedMethod, 'solargraph/pin/delegated_method'
15
16
  autoload :BaseVariable, 'solargraph/pin/base_variable'
16
17
  autoload :InstanceVariable, 'solargraph/pin/instance_variable'
17
18
  autoload :ClassVariable, 'solargraph/pin/class_variable'