solargraph 0.51.2 → 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 (162) 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/.yardopts +2 -2
  6. data/CHANGELOG.md +55 -5
  7. data/README.md +13 -16
  8. data/SPONSORS.md +1 -7
  9. data/lib/solargraph/api_map/cache.rb +60 -20
  10. data/lib/solargraph/api_map/store.rb +47 -11
  11. data/lib/solargraph/api_map.rb +161 -95
  12. data/lib/solargraph/bench.rb +2 -2
  13. data/lib/solargraph/cache.rb +29 -5
  14. data/lib/solargraph/complex_type/type_methods.rb +54 -9
  15. data/lib/solargraph/complex_type/unique_type.rb +155 -58
  16. data/lib/solargraph/complex_type.rb +73 -16
  17. data/lib/solargraph/convention.rb +0 -1
  18. data/lib/solargraph/converters/dd.rb +5 -0
  19. data/lib/solargraph/converters/dl.rb +3 -0
  20. data/lib/solargraph/converters/dt.rb +3 -0
  21. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  22. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  23. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  24. data/lib/solargraph/diagnostics.rb +2 -2
  25. data/lib/solargraph/doc_map.rb +146 -0
  26. data/lib/solargraph/gem_pins.rb +64 -0
  27. data/lib/solargraph/language_server/host/cataloger.rb +1 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +10 -4
  30. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  31. data/lib/solargraph/language_server/host/sources.rb +7 -4
  32. data/lib/solargraph/language_server/host.rb +15 -6
  33. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  34. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  35. data/lib/solargraph/language_server/message/initialize.rb +5 -2
  36. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  37. data/lib/solargraph/language_server/message/text_document.rb +0 -1
  38. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  39. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  40. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  41. data/lib/solargraph/library.rb +70 -16
  42. data/lib/solargraph/location.rb +1 -0
  43. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  44. data/lib/solargraph/parser/node_methods.rb +47 -7
  45. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  46. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
  47. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  48. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +49 -36
  49. data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -0
  50. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  51. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/args_node.rb +4 -1
  52. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  53. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  54. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  55. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  56. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +1 -1
  57. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  58. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  60. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  62. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  63. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  66. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  68. data/lib/solargraph/parser/parser_gem.rb +12 -0
  69. data/lib/solargraph/parser/region.rb +1 -1
  70. data/lib/solargraph/parser/snippet.rb +2 -0
  71. data/lib/solargraph/parser.rb +8 -9
  72. data/lib/solargraph/pin/base.rb +64 -9
  73. data/lib/solargraph/pin/base_variable.rb +6 -2
  74. data/lib/solargraph/pin/block.rb +13 -8
  75. data/lib/solargraph/pin/closure.rb +17 -2
  76. data/lib/solargraph/pin/common.rb +7 -3
  77. data/lib/solargraph/pin/conversions.rb +33 -3
  78. data/lib/solargraph/pin/delegated_method.rb +1 -1
  79. data/lib/solargraph/pin/documenting.rb +25 -34
  80. data/lib/solargraph/pin/instance_variable.rb +4 -0
  81. data/lib/solargraph/pin/local_variable.rb +13 -1
  82. data/lib/solargraph/pin/method.rb +169 -18
  83. data/lib/solargraph/pin/namespace.rb +18 -5
  84. data/lib/solargraph/pin/parameter.rb +44 -14
  85. data/lib/solargraph/pin/reference/override.rb +2 -2
  86. data/lib/solargraph/pin/reference.rb +8 -0
  87. data/lib/solargraph/pin/search.rb +3 -3
  88. data/lib/solargraph/pin/signature.rb +123 -3
  89. data/lib/solargraph/pin.rb +0 -1
  90. data/lib/solargraph/range.rb +2 -2
  91. data/lib/solargraph/rbs_map/conversions.rb +287 -45
  92. data/lib/solargraph/rbs_map/core_fills.rb +6 -29
  93. data/lib/solargraph/rbs_map/core_map.rb +2 -1
  94. data/lib/solargraph/rbs_map/core_signs.rb +2 -0
  95. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
  96. data/lib/solargraph/rbs_map.rb +20 -11
  97. data/lib/solargraph/shell.rb +62 -59
  98. data/lib/solargraph/source/chain/array.rb +32 -0
  99. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  100. data/lib/solargraph/source/chain/call.rb +99 -46
  101. data/lib/solargraph/source/chain/constant.rb +15 -1
  102. data/lib/solargraph/source/chain/if.rb +23 -0
  103. data/lib/solargraph/source/chain/link.rb +8 -2
  104. data/lib/solargraph/source/chain/or.rb +1 -1
  105. data/lib/solargraph/source/chain/z_super.rb +3 -3
  106. data/lib/solargraph/source/chain.rb +29 -14
  107. data/lib/solargraph/source/change.rb +3 -0
  108. data/lib/solargraph/source/cursor.rb +2 -0
  109. data/lib/solargraph/source/source_chainer.rb +8 -5
  110. data/lib/solargraph/source.rb +18 -19
  111. data/lib/solargraph/source_map/clip.rb +11 -23
  112. data/lib/solargraph/source_map/mapper.rb +12 -1
  113. data/lib/solargraph/source_map.rb +15 -5
  114. data/lib/solargraph/type_checker/checks.rb +10 -2
  115. data/lib/solargraph/type_checker.rb +92 -26
  116. data/lib/solargraph/version.rb +1 -1
  117. data/lib/solargraph/workspace/config.rb +8 -6
  118. data/lib/solargraph/workspace.rb +3 -2
  119. data/lib/solargraph/yard_map/cache.rb +6 -0
  120. data/lib/solargraph/yard_map/helpers.rb +1 -1
  121. data/lib/solargraph/yard_map/mapper/to_method.rb +11 -1
  122. data/lib/solargraph/yard_map/mapper.rb +1 -1
  123. data/lib/solargraph/yard_map/to_method.rb +11 -4
  124. data/lib/solargraph/yard_map.rb +1 -292
  125. data/lib/solargraph/yard_tags.rb +20 -0
  126. data/lib/solargraph/yardoc.rb +52 -0
  127. data/lib/solargraph.rb +6 -4
  128. data/solargraph.gemspec +3 -2
  129. metadata +51 -58
  130. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  131. data/lib/solargraph/documentor.rb +0 -76
  132. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  133. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  134. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  135. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  136. data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
  137. data/lib/solargraph/parser/legacy.rb +0 -12
  138. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -153
  139. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  140. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
  141. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  142. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  143. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  144. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  145. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  146. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  147. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  148. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  149. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  150. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  151. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  152. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  153. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  154. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  155. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
  156. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  157. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  158. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  159. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
  160. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  161. data/lib/solargraph/parser/rubyvm.rb +0 -40
  162. data/lib/yard-solargraph.rb +0 -33
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rbs'
4
- require 'set'
5
4
 
6
5
  module Solargraph
7
6
  class RbsMap
@@ -19,19 +18,24 @@ module Solargraph
19
18
  attr_reader :library
20
19
 
21
20
  # @param library [String]
22
- def initialize library
21
+ def initialize library, version = nil
23
22
  @library = library
23
+ @version = version
24
+ @collection = nil
24
25
  loader = RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
25
- add_library loader, library
26
+ add_library loader, library, version
26
27
  return unless resolved?
27
- environment = RBS::Environment.from_loader(loader).resolve_type_names
28
- environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
28
+ load_environment_to_pins(loader)
29
29
  end
30
30
 
31
+ # @param path [String]
32
+ # @return [Pin::Base, nil]
31
33
  def path_pin path
32
34
  pins.find { |p| p.path == path }
33
35
  end
34
36
 
37
+ # @param path [String]
38
+ # @return [Array<Pin::Base>]
35
39
  def path_pins path
36
40
  pins.select { |p| p.path == path }
37
41
  end
@@ -40,14 +44,18 @@ module Solargraph
40
44
  @resolved
41
45
  end
42
46
 
47
+ def repository
48
+ @repository ||= RBS::Repository.new(no_stdlib: false)
49
+ end
50
+
43
51
  # @param library [String]
44
52
  # @return [RbsMap]
45
53
  def self.load library
46
54
  @@rbs_maps_hash[library] ||= RbsMap.new(library)
47
55
  end
48
56
 
49
- def repository
50
- @repository ||= RBS::Repository.new(no_stdlib: true)
57
+ def self.from_gemspec(gemspec)
58
+ RbsMap.new(gemspec.name, gemspec.version)
51
59
  end
52
60
 
53
61
  private
@@ -55,17 +63,18 @@ module Solargraph
55
63
  # @param loader [RBS::EnvironmentLoader]
56
64
  # @param library [String]
57
65
  # @return [Boolean] true if adding the library succeeded
58
- def add_library loader, library
59
- @resolved = if loader.has_library?(library: library, version: nil)
60
- loader.add library: library
66
+ def add_library loader, library, version
67
+ @resolved = if loader.has_library?(library: library, version: version)
68
+ loader.add library: library, version: version
61
69
  Solargraph.logger.info "#{short_name} successfully loaded library #{library}"
62
70
  true
63
71
  else
64
- Solargraph.logger.info "#{short_name} failed to load library #{library}"
72
+ Solargraph.logger.debug "#{short_name} failed to load library #{library}"
65
73
  false
66
74
  end
67
75
  end
68
76
 
77
+ # @return [String]
69
78
  def short_name
70
79
  self.class.name.split('::').last
71
80
  end
@@ -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
@@ -0,0 +1,32 @@
1
+ module Solargraph
2
+ class Source
3
+ class Chain
4
+ class Array < Literal
5
+ # @param children [::Array<Chain>]
6
+ def initialize children
7
+ super('::Array')
8
+ @children = children
9
+ end
10
+
11
+ def word
12
+ @word ||= "<#{@type}>"
13
+ end
14
+
15
+ # @param api_map [ApiMap]
16
+ # @param name_pin [Pin::Base]
17
+ # @param locals [Enumerable<Pin::LocalVariable>]
18
+ def resolve api_map, name_pin, locals
19
+ child_types = @children.map do |child|
20
+ child.infer(api_map, name_pin, locals).tag
21
+ end
22
+ type = if child_types.uniq.length == 1 && child_types.first != 'undefined'
23
+ "::Array<#{child_types.first}>"
24
+ else
25
+ '::Array'
26
+ end
27
+ [Pin::ProxyType.anonymous(ComplexType.try_parse(type))]
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -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,28 +7,32 @@ 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
- # @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
17
+ # @param arguments [::Array<Chain>]
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'
35
+ return yield_pins(api_map, name_pin) if word == 'yield'
32
36
  found = if head?
33
37
  locals.select { |p| p.name == word }
34
38
  else
@@ -37,7 +41,7 @@ module Solargraph
37
41
  return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
38
42
  # @param [ComplexType::UniqueType]
39
43
  pins = name_pin.binder.each_unique_type.flat_map do |context|
40
- 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)
41
45
  end
42
46
  return [] if pins.empty?
43
47
  inferred_pins(pins, api_map, name_pin.context, locals)
@@ -45,58 +49,58 @@ module Solargraph
45
49
 
46
50
  private
47
51
 
48
- # @param pins [Array<Pin::Base>]
52
+ # @param pins [::Enumerable<Pin::Method>]
49
53
  # @param api_map [ApiMap]
50
54
  # @param context [ComplexType]
51
- # @param locals [Pin::LocalVariable]
52
- # @return [Array<Pin::Base>]
55
+ # @param locals [::Array<Pin::LocalVariable>]
56
+ # @return [::Array<Pin::Base>]
53
57
  def inferred_pins pins, api_map, context, locals
54
58
  result = pins.map do |p|
55
59
  next p unless p.is_a?(Pin::Method)
56
60
  overloads = p.signatures
57
61
  # next p if overloads.empty?
58
62
  type = ComplexType::UNDEFINED
59
- overloads.each do |ol|
60
- next unless arguments_match(arguments, ol)
61
- # 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)
62
72
  match = true
73
+
74
+ atypes = []
63
75
  arguments.each_with_index do |arg, idx|
64
76
  param = ol.parameters[idx]
65
77
  if param.nil?
66
- match = false unless ol.parameters.any?(&:restarg?)
78
+ match = ol.parameters.any?(&:restarg?)
67
79
  break
68
80
  end
69
- atype = arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
81
+ atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
70
82
  # @todo Weak type comparison
71
83
  # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
72
- 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?
73
85
  match = false
74
86
  break
75
87
  end
76
88
  end
77
89
  if match
78
- type = extra_return_type(p.docstring, context)
79
- break if type
80
- 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?
81
97
  type ||= ComplexType::UNDEFINED
82
98
  end
83
99
  break if type.defined?
84
100
  end
101
+ p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
85
102
  next p.proxy(type) if type.defined?
86
- type = extra_return_type(p.docstring, context)
87
- if type
88
- next Solargraph::Pin::Method.new(
89
- location: p.location,
90
- closure: p.closure,
91
- name: p.name,
92
- comments: "@return [#{context.subtypes.first.to_s}]",
93
- scope: p.scope,
94
- visibility: p.visibility,
95
- parameters: p.parameters,
96
- node: p.node
97
- )
98
- end
99
- if p.is_a?(Pin::Method) && !p.macros.empty?
103
+ if !p.macros.empty?
100
104
  result = process_macro(p, api_map, context, locals)
101
105
  next result unless result.return_type.undefined?
102
106
  elsif !p.directives.empty?
@@ -116,13 +120,19 @@ module Solargraph
116
120
  end
117
121
  end
118
122
 
119
- # @param pin [Pin::Method]
123
+ # @param pin [Pin::Base]
120
124
  # @param api_map [ApiMap]
121
125
  # @param context [ComplexType]
122
- # @param locals [Pin::Base]
126
+ # @param locals [Enumerable<Pin::Base>]
123
127
  # @return [Pin::Base]
124
128
  def process_macro pin, api_map, context, locals
125
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.
126
136
  result = inner_process_macro(pin, macro, api_map, context, locals)
127
137
  return result unless result.return_type.undefined?
128
138
  end
@@ -132,7 +142,7 @@ module Solargraph
132
142
  # @param pin [Pin::Method]
133
143
  # @param api_map [ApiMap]
134
144
  # @param context [ComplexType]
135
- # @param locals [Pin::Base]
145
+ # @param locals [Enumerable<Pin::Base>]
136
146
  # @return [Pin::ProxyType]
137
147
  def process_directive pin, api_map, context, locals
138
148
  pin.directives.each do |dir|
@@ -144,11 +154,11 @@ module Solargraph
144
154
  Pin::ProxyType.anonymous ComplexType::UNDEFINED
145
155
  end
146
156
 
147
- # @param pin [Pin]
157
+ # @param pin [Pin::Base]
148
158
  # @param macro [YARD::Tags::MacroDirective]
149
159
  # @param api_map [ApiMap]
150
160
  # @param context [ComplexType]
151
- # @param locals [Array<Pin::Base>]
161
+ # @param locals [Enumerable<Pin::Base>]
152
162
  # @return [Pin::ProxyType]
153
163
  def inner_process_macro pin, macro, api_map, context, locals
154
164
  vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
@@ -172,20 +182,20 @@ module Solargraph
172
182
 
173
183
  # @param docstring [YARD::Docstring]
174
184
  # @param context [ComplexType]
175
- # @return [ComplexType]
185
+ # @return [ComplexType, nil]
176
186
  def extra_return_type docstring, context
177
- if docstring.has_tag?(:return_single_parameter) #&& context.subtypes.one?
187
+ if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?
178
188
  return context.subtypes.first || ComplexType::UNDEFINED
179
- elsif docstring.has_tag?(:return_value_parameter) && context.value_types.one?
189
+ elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
180
190
  return context.value_types.first
181
191
  end
182
192
  nil
183
193
  end
184
194
 
185
- # @param arguments [Array<Chain>]
195
+ # @param arguments [::Array<Chain>]
186
196
  # @param signature [Pin::Signature]
187
197
  # @return [Boolean]
188
- def arguments_match arguments, signature
198
+ def arity_matches? arguments, signature
189
199
  parameters = signature.parameters
190
200
  argcount = arguments.length
191
201
  parcount = parameters.length
@@ -197,18 +207,61 @@ module Solargraph
197
207
 
198
208
  # @param api_map [ApiMap]
199
209
  # @param name_pin [Pin::Base]
200
- # @return [Array<Pin::Base>]
210
+ # @return [::Array<Pin::Base>]
201
211
  def super_pins api_map, name_pin
202
212
  pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
203
213
  pins.reject{|p| p.path == name_pin.path}
204
214
  end
205
215
 
216
+ # @param api_map [ApiMap]
217
+ # @param name_pin [Pin::Base]
218
+ # @return [::Array<Pin::Base>]
219
+ def yield_pins api_map, name_pin
220
+ method_pin = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope).first
221
+ return [] if method_pin.nil?
222
+
223
+ method_pin.signatures.map(&:block).compact
224
+ end
225
+
206
226
  # @param type [ComplexType]
207
227
  # @param context [ComplexType]
228
+ # @return [ComplexType]
208
229
  def with_params type, context
209
230
  return type unless type.to_s.include?('$')
210
231
  ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
211
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
212
265
  end
213
266
  end
214
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 == ''