solargraph 0.52.0 → 0.53.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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +40 -0
  3. data/.github/workflows/rspec.yml +1 -3
  4. data/.github/workflows/typecheck.yml +34 -0
  5. data/CHANGELOG.md +30 -0
  6. data/README.md +13 -16
  7. data/SPONSORS.md +1 -7
  8. data/lib/solargraph/api_map/cache.rb +59 -21
  9. data/lib/solargraph/api_map/store.rb +45 -9
  10. data/lib/solargraph/api_map.rb +152 -93
  11. data/lib/solargraph/bench.rb +2 -2
  12. data/lib/solargraph/cache.rb +29 -5
  13. data/lib/solargraph/complex_type/type_methods.rb +53 -8
  14. data/lib/solargraph/complex_type/unique_type.rb +149 -59
  15. data/lib/solargraph/complex_type.rb +62 -9
  16. data/lib/solargraph/convention.rb +0 -1
  17. data/lib/solargraph/converters/dd.rb +5 -0
  18. data/lib/solargraph/converters/dl.rb +3 -0
  19. data/lib/solargraph/converters/dt.rb +3 -0
  20. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  21. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  22. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  23. data/lib/solargraph/diagnostics.rb +2 -2
  24. data/lib/solargraph/doc_map.rb +146 -0
  25. data/lib/solargraph/gem_pins.rb +64 -0
  26. data/lib/solargraph/language_server/host/cataloger.rb +1 -0
  27. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  28. data/lib/solargraph/language_server/host/dispatch.rb +10 -4
  29. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  30. data/lib/solargraph/language_server/host/sources.rb +7 -4
  31. data/lib/solargraph/language_server/host.rb +15 -6
  32. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  33. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  34. data/lib/solargraph/language_server/message/initialize.rb +5 -2
  35. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  36. data/lib/solargraph/language_server/message/text_document.rb +0 -1
  37. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  38. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  39. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  40. data/lib/solargraph/library.rb +58 -11
  41. data/lib/solargraph/location.rb +1 -0
  42. data/lib/solargraph/parser/comment_ripper.rb +3 -0
  43. data/lib/solargraph/parser/node_methods.rb +47 -8
  44. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  45. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +29 -3
  46. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  47. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +42 -34
  48. data/lib/solargraph/parser/{legacy → parser_gem}/node_methods.rb +201 -29
  49. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  50. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/args_node.rb +4 -1
  51. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  52. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  53. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  54. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  55. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +1 -1
  56. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  57. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  58. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  60. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  62. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  63. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  65. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  66. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  67. data/lib/solargraph/parser/parser_gem.rb +12 -0
  68. data/lib/solargraph/parser/snippet.rb +2 -0
  69. data/lib/solargraph/parser.rb +8 -11
  70. data/lib/solargraph/pin/base.rb +63 -8
  71. data/lib/solargraph/pin/base_variable.rb +6 -2
  72. data/lib/solargraph/pin/block.rb +11 -6
  73. data/lib/solargraph/pin/closure.rb +17 -2
  74. data/lib/solargraph/pin/common.rb +7 -3
  75. data/lib/solargraph/pin/conversions.rb +33 -3
  76. data/lib/solargraph/pin/documenting.rb +25 -34
  77. data/lib/solargraph/pin/instance_variable.rb +4 -0
  78. data/lib/solargraph/pin/local_variable.rb +13 -1
  79. data/lib/solargraph/pin/method.rb +109 -15
  80. data/lib/solargraph/pin/namespace.rb +16 -10
  81. data/lib/solargraph/pin/parameter.rb +41 -10
  82. data/lib/solargraph/pin/reference/override.rb +2 -2
  83. data/lib/solargraph/pin/reference.rb +8 -0
  84. data/lib/solargraph/pin/search.rb +3 -3
  85. data/lib/solargraph/pin/signature.rb +114 -2
  86. data/lib/solargraph/pin.rb +0 -1
  87. data/lib/solargraph/range.rb +2 -2
  88. data/lib/solargraph/rbs_map/conversions.rb +212 -25
  89. data/lib/solargraph/rbs_map/core_fills.rb +4 -26
  90. data/lib/solargraph/rbs_map/core_map.rb +1 -0
  91. data/lib/solargraph/rbs_map/core_signs.rb +2 -0
  92. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
  93. data/lib/solargraph/rbs_map.rb +19 -9
  94. data/lib/solargraph/shell.rb +62 -59
  95. data/lib/solargraph/source/chain/array.rb +4 -1
  96. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  97. data/lib/solargraph/source/chain/call.rb +95 -26
  98. data/lib/solargraph/source/chain/constant.rb +15 -1
  99. data/lib/solargraph/source/chain/if.rb +23 -0
  100. data/lib/solargraph/source/chain/link.rb +7 -1
  101. data/lib/solargraph/source/chain/or.rb +1 -1
  102. data/lib/solargraph/source/chain/z_super.rb +2 -2
  103. data/lib/solargraph/source/chain.rb +20 -4
  104. data/lib/solargraph/source/change.rb +3 -0
  105. data/lib/solargraph/source/cursor.rb +2 -0
  106. data/lib/solargraph/source/source_chainer.rb +6 -5
  107. data/lib/solargraph/source.rb +15 -16
  108. data/lib/solargraph/source_map/clip.rb +11 -7
  109. data/lib/solargraph/source_map/mapper.rb +10 -0
  110. data/lib/solargraph/source_map.rb +13 -3
  111. data/lib/solargraph/type_checker/checks.rb +10 -2
  112. data/lib/solargraph/type_checker.rb +74 -19
  113. data/lib/solargraph/version.rb +1 -1
  114. data/lib/solargraph/workspace/config.rb +8 -6
  115. data/lib/solargraph/workspace.rb +1 -1
  116. data/lib/solargraph/yard_map/cache.rb +6 -0
  117. data/lib/solargraph/yard_map/helpers.rb +1 -1
  118. data/lib/solargraph/yard_map/mapper/to_method.rb +11 -1
  119. data/lib/solargraph/yard_map/to_method.rb +11 -4
  120. data/lib/solargraph/yard_map.rb +0 -292
  121. data/lib/solargraph/yardoc.rb +52 -0
  122. data/lib/solargraph.rb +4 -1
  123. data/solargraph.gemspec +2 -2
  124. metadata +35 -57
  125. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  126. data/lib/solargraph/documentor.rb +0 -76
  127. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  128. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  129. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  130. data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
  131. data/lib/solargraph/parser/legacy.rb +0 -12
  132. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -151
  133. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -163
  134. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
  135. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  136. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  137. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  138. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  139. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  140. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  141. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  142. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  143. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  144. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  145. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  146. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  147. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  148. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  149. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
  150. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  151. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  152. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  153. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
  154. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  155. data/lib/solargraph/parser/rubyvm.rb +0 -40
@@ -1,14 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'thor'
4
+ require 'yard'
4
5
 
5
6
  module Solargraph
6
7
  class Shell < Thor
7
8
  include Solargraph::ServerMethods
8
9
 
10
+ # Tell Thor to ensure the process exits with status 1 if any error happens.
11
+ def self.exit_on_failure?
12
+ true
13
+ end
14
+
9
15
  map %w[--version -v] => :version
10
16
 
11
17
  desc "--version, -v", "Print the version"
18
+ # @return [void]
12
19
  def version
13
20
  puts Solargraph::VERSION
14
21
  end
@@ -16,6 +23,7 @@ module Solargraph
16
23
  desc 'socket', 'Run a Solargraph socket server'
17
24
  option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
18
25
  option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
26
+ # @return [void]
19
27
  def socket
20
28
  require 'backport'
21
29
  port = options[:port]
@@ -33,6 +41,7 @@ module Solargraph
33
41
  end
34
42
 
35
43
  desc 'stdio', 'Run a Solargraph stdio server'
44
+ # @return [void]
36
45
  def stdio
37
46
  require 'backport'
38
47
  Backport.run do
@@ -49,6 +58,8 @@ module Solargraph
49
58
 
50
59
  desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
51
60
  option :extensions, type: :boolean, aliases: :e, desc: 'Add installed extensions', default: true
61
+ # @param directory [String]
62
+ # @return [void]
52
63
  def config(directory = '.')
53
64
  matches = []
54
65
  if options[:extensions]
@@ -71,43 +82,11 @@ module Solargraph
71
82
  STDOUT.puts "Configuration file initialized."
72
83
  end
73
84
 
74
- desc 'download-core [VERSION]', 'Download core documentation [deprecated]', hide: true
75
- long_desc %(
76
- The `download-core` command is deprecated. Current versions of Solargraph
77
- use RBS for core and stdlib documentation.
78
- )
79
- # @deprecated
80
- def download_core _version = nil
81
- puts 'The `download-core` command is deprecated.'
82
- puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
83
- end
84
-
85
- desc 'list-cores', 'List the local documentation versions [deprecated]', hide: true
86
- long_desc %(
87
- The `list-cores` command is deprecated. Current versions of Solargraph use
88
- RBS for core and stdlib documentation.
89
- )
90
- # @deprecated
91
- def list_cores
92
- puts 'The `list-cores` command is deprecated.'
93
- puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
94
- end
95
-
96
- desc 'available-cores', 'List available documentation versions [deprecated]', hide: true
97
- long_desc %(
98
- The `available-cores` command is deprecated. Current versions of Solargraph
99
- use RBS for core and stdlib documentation.
100
- )
101
- # @deprecated
102
- def available_cores
103
- puts 'The `available-cores` command is deprecated.'
104
- puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
105
- end
106
-
107
85
  desc 'clear', 'Delete all cached documentation'
108
86
  long_desc %(
109
87
  This command will delete all core and gem documentation from the cache.
110
88
  )
89
+ # @return [void]
111
90
  def clear
112
91
  puts "Deleting the cached documentation"
113
92
  Solargraph::Cache.clear
@@ -115,18 +94,45 @@ module Solargraph
115
94
  map 'clear-cache' => :clear
116
95
  map 'clear-cores' => :clear
117
96
 
97
+ desc 'cache', 'Cache a gem', hide: true
98
+ # @return [void]
99
+ # @param gem [String]
100
+ # @param version [String, nil]
101
+ def cache gem, version = nil
102
+ spec = Gem::Specification.find_by_name(gem, version)
103
+ pins = GemPins.build(spec)
104
+ Cache.save('gems', "#{spec.name}-#{spec.version}.ser", pins)
105
+ end
106
+
118
107
  desc 'uncache GEM [...GEM]', "Delete cached gem documentation"
108
+ # @return [void]
119
109
  def uncache *gems
120
110
  raise ArgumentError, 'No gems specified.' if gems.empty?
121
111
  gems.each do |gem|
122
- Dir[File.join(Solargraph::YardMap::CoreDocs.cache_dir, 'gems', "#{gem}-*")].each do |dir|
123
- puts "Deleting cache: #{dir}"
124
- FileUtils.remove_entry_secure dir
112
+ spec = Gem::Specification.find_by_name(gem)
113
+ Cache.uncache('gems', "#{spec.name}-#{spec.version}.ser")
114
+ Cache.uncache('gems', "#{spec.name}-#{spec.version}.yardoc")
115
+ end
116
+ end
117
+
118
+ desc 'gems [GEM[=VERSION]]', 'Cache documentation for installed gems'
119
+ option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
120
+ # @return [void]
121
+ def gems *names
122
+ if names.empty?
123
+ Gem::Specification.to_a.each { |spec| do_cache spec }
124
+ else
125
+ names.each do |name|
126
+ spec = Gem::Specification.find_by_name(*name.split('='))
127
+ do_cache spec
128
+ rescue Gem::MissingSpecError
129
+ warn "Gem '#{name}' not found"
125
130
  end
126
131
  end
127
132
  end
128
133
 
129
134
  desc 'reporters', 'Get a list of diagnostics reporters'
135
+ # @return [void]
130
136
  def reporters
131
137
  puts Solargraph::Diagnostics.reporters
132
138
  end
@@ -140,9 +146,10 @@ module Solargraph
140
146
  )
141
147
  option :level, type: :string, aliases: [:mode, :m, :l], desc: 'Type checking level', default: 'normal'
142
148
  option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
149
+ # @return [void]
143
150
  def typecheck *files
144
151
  directory = File.realpath(options[:directory])
145
- api_map = Solargraph::ApiMap.load(directory)
152
+ api_map = Solargraph::ApiMap.load_with_cache(directory)
146
153
  if files.empty?
147
154
  files = api_map.source_maps.map(&:filename)
148
155
  else
@@ -160,6 +167,7 @@ module Solargraph
160
167
  probcount += problems.length
161
168
  end
162
169
  puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
170
+ # "
163
171
  exit 1 if probcount > 0
164
172
  end
165
173
 
@@ -172,12 +180,13 @@ module Solargraph
172
180
  )
173
181
  option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
174
182
  option :verbose, type: :boolean, aliases: :v, desc: 'Verbose output', default: false
183
+ # @return [void]
175
184
  def scan
176
185
  require 'benchmark'
177
186
  directory = File.realpath(options[:directory])
178
187
  api_map = nil
179
188
  time = Benchmark.measure {
180
- api_map = Solargraph::ApiMap.load(directory)
189
+ api_map = Solargraph::ApiMap.load_with_cache(directory)
181
190
  api_map.pins.each do |pin|
182
191
  begin
183
192
  puts pin_description(pin) if options[:verbose]
@@ -197,32 +206,13 @@ module Solargraph
197
206
  desc 'list', 'List the files in the workspace and the total count'
198
207
  option :count, type: :boolean, aliases: :c, desc: 'Display the file count only', default: false
199
208
  option :directory, type: :string, aliases: :d, desc: 'The directory to read', default: '.'
209
+ # @return [void]
200
210
  def list
201
211
  workspace = Solargraph::Workspace.new(options[:directory])
202
- unless options[:count]
203
- workspace.filenames.each { |f| puts f }
204
- end
212
+ puts workspace.filenames unless options[:count]
205
213
  puts "#{workspace.filenames.length} files total."
206
214
  end
207
215
 
208
- desc 'bundle', 'Generate documentation for bundled gems [deprecated]', hide: true
209
- long_desc %(
210
- The `bundle` command is deprecated. Solargraph currently uses RBS instead.
211
- )
212
- option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
213
- option :rebuild, type: :boolean, aliases: :r, desc: 'Rebuild existing documentation', default: false
214
- def bundle
215
- puts 'The `bundle` command is deprecated. Solargraph currently uses RBS instead.'
216
- end
217
-
218
- desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation [deprecated]', hide: true
219
- long_desc %(
220
- The `rdoc` command is deprecated. Solargraph currently uses RBS instead.
221
- )
222
- def rdoc _gem, _version = '>= 0'
223
- puts 'The `rdoc` command is deprecated. Solargraph currently uses RBS instead.'
224
- end
225
-
226
216
  private
227
217
 
228
218
  # @param pin [Solargraph::Pin::Base]
@@ -240,5 +230,18 @@ module Solargraph
240
230
  desc += " (#{pin.location.filename} #{pin.location.range.start.line})" if pin.location
241
231
  desc
242
232
  end
233
+
234
+ # @param gemspec [Gem::Specification]
235
+ # @return [void]
236
+ def do_cache gemspec
237
+ cached = Yardoc.cached?(gemspec)
238
+ if cached && !options.rebuild
239
+ puts "Cache already exists for #{gemspec.name} #{gemspec.version}"
240
+ else
241
+ puts "#{cached ? 'Rebuilding' : 'Caching'} gem documentation for #{gemspec.name} #{gemspec.version}"
242
+ pins = GemPins.build(gemspec)
243
+ Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
244
+ end
245
+ end
243
246
  end
244
247
  end
@@ -2,7 +2,7 @@ module Solargraph
2
2
  class Source
3
3
  class Chain
4
4
  class Array < Literal
5
- # @param type [String]
5
+ # @param children [::Array<Chain>]
6
6
  def initialize children
7
7
  super('::Array')
8
8
  @children = children
@@ -12,6 +12,9 @@ module Solargraph
12
12
  @word ||= "<#{@type}>"
13
13
  end
14
14
 
15
+ # @param api_map [ApiMap]
16
+ # @param name_pin [Pin::Base]
17
+ # @param locals [Enumerable<Pin::LocalVariable>]
15
18
  def resolve api_map, name_pin, locals
16
19
  child_types = @children.map do |child|
17
20
  child.infer(api_map, name_pin, locals).tag
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ class Chain
6
+ class BlockSymbol < Link
7
+ def resolve api_map, name_pin, locals
8
+ [Pin::ProxyType.anonymous(ComplexType.try_parse('Proc'))]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -7,26 +7,29 @@ module Solargraph
7
7
  # @return [String]
8
8
  attr_reader :word
9
9
 
10
- # @return [Array<Chain>]
10
+ # @return [::Array<Chain>]
11
11
  attr_reader :arguments
12
12
 
13
+ # @return [Chain, nil]
14
+ attr_reader :block
15
+
13
16
  # @param word [String]
14
17
  # @param arguments [::Array<Chain>]
15
- # @param with_block [Boolean] True if the chain is inside a block
16
- # @param head [Boolean] True if the call is the start of its chain
17
- def initialize word, arguments = [], with_block = false
18
+ # @param block [Chain, nil]
19
+ def initialize word, arguments = [], block = nil
18
20
  @word = word
19
21
  @arguments = arguments
20
- @with_block = with_block
22
+ @block = block
23
+ fix_block_pass
21
24
  end
22
25
 
23
26
  def with_block?
24
- @with_block
27
+ !!@block
25
28
  end
26
29
 
27
30
  # @param api_map [ApiMap]
28
31
  # @param name_pin [Pin::Base]
29
- # @param locals [::Array<Pin::Base>]
32
+ # @param locals [::Array<Pin::LocalVariable>]
30
33
  def resolve api_map, name_pin, locals
31
34
  return super_pins(api_map, name_pin) if word == 'super'
32
35
  return yield_pins(api_map, name_pin) if word == 'yield'
@@ -38,7 +41,7 @@ module Solargraph
38
41
  return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
39
42
  # @param [ComplexType::UniqueType]
40
43
  pins = name_pin.binder.each_unique_type.flat_map do |context|
41
- api_map.get_method_stack(context.namespace, word, scope: context.scope)
44
+ api_map.get_method_stack(context.namespace == '' ? '' : context.tag, word, scope: context.scope)
42
45
  end
43
46
  return [] if pins.empty?
44
47
  inferred_pins(pins, api_map, name_pin.context, locals)
@@ -46,43 +49,58 @@ module Solargraph
46
49
 
47
50
  private
48
51
 
49
- # @param pins [Array<Pin::Base>]
52
+ # @param pins [::Enumerable<Pin::Method>]
50
53
  # @param api_map [ApiMap]
51
54
  # @param context [ComplexType]
52
- # @param locals [Pin::LocalVariable]
53
- # @return [Array<Pin::Base>]
55
+ # @param locals [::Array<Pin::LocalVariable>]
56
+ # @return [::Array<Pin::Base>]
54
57
  def inferred_pins pins, api_map, context, locals
55
58
  result = pins.map do |p|
56
59
  next p unless p.is_a?(Pin::Method)
57
60
  overloads = p.signatures
58
61
  # next p if overloads.empty?
59
62
  type = ComplexType::UNDEFINED
60
- overloads.each do |ol|
61
- next unless arguments_match(arguments, ol)
62
- # next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
63
+ # start with overloads that require blocks; if we are
64
+ # passing a block, we want to find a signature that will
65
+ # use it. If we didn't pass a block, the logic below will
66
+ # reject it regardless
67
+
68
+ sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
69
+ new_signature_pin = nil
70
+ sorted_overloads.each do |ol|
71
+ next unless arity_matches?(arguments, ol)
63
72
  match = true
73
+
74
+ atypes = []
64
75
  arguments.each_with_index do |arg, idx|
65
76
  param = ol.parameters[idx]
66
77
  if param.nil?
67
- match = false unless ol.parameters.any?(&:restarg?)
78
+ match = ol.parameters.any?(&:restarg?)
68
79
  break
69
80
  end
70
- atype = arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
81
+ atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
71
82
  # @todo Weak type comparison
72
83
  # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
73
- unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name)
84
+ unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name) || param.return_type.generic?
74
85
  match = false
75
86
  break
76
87
  end
77
88
  end
78
89
  if match
79
- type = with_params(ol.return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if ol.return_type.defined?
90
+ if ol.block && with_block?
91
+ block_atypes = ol.block.parameters.map(&:return_type)
92
+ blocktype = block_call_type(api_map, context, block_atypes, locals)
93
+ end
94
+ new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
95
+ new_return_type = new_signature_pin.return_type
96
+ type = with_params(new_return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if new_return_type.defined?
80
97
  type ||= ComplexType::UNDEFINED
81
98
  end
82
99
  break if type.defined?
83
100
  end
101
+ p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
84
102
  next p.proxy(type) if type.defined?
85
- if p.is_a?(Pin::Method) && !p.macros.empty?
103
+ if !p.macros.empty?
86
104
  result = process_macro(p, api_map, context, locals)
87
105
  next result unless result.return_type.undefined?
88
106
  elsif !p.directives.empty?
@@ -102,13 +120,19 @@ module Solargraph
102
120
  end
103
121
  end
104
122
 
105
- # @param pin [Pin::Method]
123
+ # @param pin [Pin::Base]
106
124
  # @param api_map [ApiMap]
107
125
  # @param context [ComplexType]
108
- # @param locals [Pin::Base]
126
+ # @param locals [Enumerable<Pin::Base>]
109
127
  # @return [Pin::Base]
110
128
  def process_macro pin, api_map, context, locals
111
129
  pin.macros.each do |macro|
130
+ # @todo 'Wrong argument type for
131
+ # Solargraph::Source::Chain::Call#inner_process_macro:
132
+ # macro expected YARD::Tags::MacroDirective, received
133
+ # generic<Elem>' is because we lose 'rooted' information
134
+ # in the 'Chain::Array' class internally, leaving
135
+ # ::Array#each shadowed when it shouldn't be.
112
136
  result = inner_process_macro(pin, macro, api_map, context, locals)
113
137
  return result unless result.return_type.undefined?
114
138
  end
@@ -118,7 +142,7 @@ module Solargraph
118
142
  # @param pin [Pin::Method]
119
143
  # @param api_map [ApiMap]
120
144
  # @param context [ComplexType]
121
- # @param locals [Pin::Base]
145
+ # @param locals [Enumerable<Pin::Base>]
122
146
  # @return [Pin::ProxyType]
123
147
  def process_directive pin, api_map, context, locals
124
148
  pin.directives.each do |dir|
@@ -130,11 +154,11 @@ module Solargraph
130
154
  Pin::ProxyType.anonymous ComplexType::UNDEFINED
131
155
  end
132
156
 
133
- # @param pin [Pin]
157
+ # @param pin [Pin::Base]
134
158
  # @param macro [YARD::Tags::MacroDirective]
135
159
  # @param api_map [ApiMap]
136
160
  # @param context [ComplexType]
137
- # @param locals [Array<Pin::Base>]
161
+ # @param locals [Enumerable<Pin::Base>]
138
162
  # @return [Pin::ProxyType]
139
163
  def inner_process_macro pin, macro, api_map, context, locals
140
164
  vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
@@ -156,10 +180,22 @@ module Solargraph
156
180
  Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
157
181
  end
158
182
 
159
- # @param arguments [Array<Chain>]
183
+ # @param docstring [YARD::Docstring]
184
+ # @param context [ComplexType]
185
+ # @return [ComplexType, nil]
186
+ def extra_return_type docstring, context
187
+ if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?
188
+ return context.subtypes.first || ComplexType::UNDEFINED
189
+ elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
190
+ return context.value_types.first
191
+ end
192
+ nil
193
+ end
194
+
195
+ # @param arguments [::Array<Chain>]
160
196
  # @param signature [Pin::Signature]
161
197
  # @return [Boolean]
162
- def arguments_match arguments, signature
198
+ def arity_matches? arguments, signature
163
199
  parameters = signature.parameters
164
200
  argcount = arguments.length
165
201
  parcount = parameters.length
@@ -189,10 +225,43 @@ module Solargraph
189
225
 
190
226
  # @param type [ComplexType]
191
227
  # @param context [ComplexType]
228
+ # @return [ComplexType]
192
229
  def with_params type, context
193
230
  return type unless type.to_s.include?('$')
194
231
  ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
195
232
  end
233
+
234
+ # @return [void]
235
+ def fix_block_pass
236
+ argument = @arguments.last&.links&.first
237
+ @block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
238
+ end
239
+
240
+ # @param api_map [ApiMap]
241
+ # @param context [ComplexType]
242
+ # @param block_parameter_types [::Array<ComplexType>]
243
+ # @param locals [::Array<Pin::LocalVariable>]
244
+ # @return [ComplexType, nil]
245
+ def block_call_type(api_map, context, block_parameter_types, locals)
246
+ return nil unless with_block?
247
+
248
+ # @todo Handle BlockVariable
249
+ if block.links.map(&:class) == [BlockSymbol]
250
+ # Ruby's shorthand for sending the passed in method name
251
+ # to the first yield parameter with no arguments
252
+ block_symbol_name = block.links.first.word
253
+ block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
254
+ callee = api_map.get_path_pins(block_symbol_call_path).first
255
+ return_type = callee&.return_type
256
+ # @todo: Figure out why we get unresolved generics at
257
+ # this point and need to assume method return types
258
+ # based on the generic type
259
+ return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
260
+ return_type || ComplexType::UNDEFINED
261
+ else
262
+ block.infer(api_map, Pin::ProxyType.anonymous(context), locals)
263
+ end
264
+ end
196
265
  end
197
266
  end
198
267
  end
@@ -19,8 +19,14 @@ module Solargraph
19
19
  end
20
20
  parts = base.split('::')
21
21
  gates.each do |gate|
22
+ # @todo 'Wrong argument type for
23
+ # Solargraph::Source::Chain::Constant#deep_constant_type:
24
+ # gate expected String, received generic<Elem>' is because
25
+ # we lose 'rooted' information in the 'Chain::Array' class
26
+ # internally, leaving ::Array#each shadowed when it
27
+ # shouldn't be.
22
28
  type = deep_constant_type(gate, api_map)
23
- # Use deep inference to resolve root
29
+ # Use deep inference to resolve root
24
30
  parts[0..-2].each do |sym|
25
31
  pins = api_map.get_constants('', type.namespace).select{ |pin| pin.name == sym }
26
32
  type = first_pin_type(pins, api_map)
@@ -35,6 +41,8 @@ module Solargraph
35
41
 
36
42
  private
37
43
 
44
+ # @param pin [Pin::Base]
45
+ # @return [::Array<String>]
38
46
  def crawl_gates pin
39
47
  clos = pin
40
48
  until clos.nil?
@@ -48,6 +56,9 @@ module Solargraph
48
56
  ['']
49
57
  end
50
58
 
59
+ # @param pins [::Array<Pin::Base>]
60
+ # @param api_map [ApiMap]
61
+ # @return [ComplexType]
51
62
  def first_pin_type(pins, api_map)
52
63
  type = ComplexType::UNDEFINED
53
64
  pins.each do |pin|
@@ -59,6 +70,9 @@ module Solargraph
59
70
  type
60
71
  end
61
72
 
73
+ # @param gate [String]
74
+ # @param api_map [ApiMap]
75
+ # @return [ComplexType]
62
76
  def deep_constant_type(gate, api_map)
63
77
  type = ComplexType::ROOT
64
78
  return type if gate == ''
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ class Chain
6
+ class If < Link
7
+ def word
8
+ '<if>'
9
+ end
10
+
11
+ # @param links [::Array<Link>]
12
+ def initialize links
13
+ @links = links
14
+ end
15
+
16
+ def resolve api_map, name_pin, locals
17
+ types = @links.map { |link| link.infer(api_map, name_pin, locals) }
18
+ [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -7,8 +7,10 @@ module Solargraph
7
7
  # @return [String]
8
8
  attr_reader :word
9
9
 
10
+ # @return [Pin::Base]
10
11
  attr_accessor :last_context
11
12
 
13
+ # @param word [String]
12
14
  def initialize word = '<undefined>'
13
15
  @word = word
14
16
  end
@@ -23,12 +25,16 @@ module Solargraph
23
25
 
24
26
  # @param api_map [ApiMap]
25
27
  # @param name_pin [Pin::Base]
26
- # @param locals [Array<Pin::Base>]
28
+ # @param locals [::Enumerable<Pin::Base>]
27
29
  # @return [::Array<Pin::Base>]
28
30
  def resolve api_map, name_pin, locals
29
31
  []
30
32
  end
31
33
 
34
+ def inspect
35
+ "#{self.class} #{word}"
36
+ end
37
+
32
38
  def head?
33
39
  @head ||= false
34
40
  end
@@ -8,7 +8,7 @@ module Solargraph
8
8
  '<or>'
9
9
  end
10
10
 
11
- # @param type [String]
11
+ # @param links [::Array<Link>]
12
12
  def initialize links
13
13
  @links = links
14
14
  end
@@ -7,11 +7,11 @@ module Solargraph
7
7
  # @return [String]
8
8
  attr_reader :word
9
9
 
10
- # @return [Array<Chain>]
10
+ # @return [::Array<Chain>]
11
11
  attr_reader :arguments
12
12
 
13
13
  # @param word [String]
14
- # @param arguments [Array<Chain>]
14
+ # @param arguments [::Array<Chain>]
15
15
  # @param with_block [Boolean] True if the chain is inside a block
16
16
  # @param head [Boolean] True if the call is the start of its chain
17
17
  def initialize word, with_block = false