solargraph 0.54.4 → 0.57.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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +125 -0
  3. data/.github/workflows/plugins.yml +149 -5
  4. data/.github/workflows/rspec.yml +39 -4
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +2627 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +104 -0
  13. data/README.md +20 -6
  14. data/Rakefile +125 -13
  15. data/lib/solargraph/api_map/cache.rb +3 -2
  16. data/lib/solargraph/api_map/constants.rb +218 -0
  17. data/lib/solargraph/api_map/index.rb +44 -42
  18. data/lib/solargraph/api_map/source_to_yard.rb +10 -4
  19. data/lib/solargraph/api_map/store.rb +165 -32
  20. data/lib/solargraph/api_map.rb +319 -243
  21. data/lib/solargraph/bench.rb +18 -1
  22. data/lib/solargraph/complex_type/type_methods.rb +7 -1
  23. data/lib/solargraph/complex_type/unique_type.rb +105 -16
  24. data/lib/solargraph/complex_type.rb +40 -7
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  26. data/lib/solargraph/convention/base.rb +20 -3
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  29. data/lib/solargraph/convention/data_definition.rb +105 -0
  30. data/lib/solargraph/convention/gemspec.rb +3 -2
  31. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  33. data/lib/solargraph/convention/struct_definition.rb +164 -0
  34. data/lib/solargraph/convention.rb +35 -4
  35. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  36. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
  37. data/lib/solargraph/doc_map.rb +313 -65
  38. data/lib/solargraph/environ.rb +9 -2
  39. data/lib/solargraph/gem_pins.rb +60 -38
  40. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  41. data/lib/solargraph/language_server/host/message_worker.rb +13 -7
  42. data/lib/solargraph/language_server/host.rb +14 -3
  43. data/lib/solargraph/language_server/message/base.rb +2 -1
  44. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  45. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  46. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  47. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
  49. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  50. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  51. data/lib/solargraph/language_server/progress.rb +8 -0
  52. data/lib/solargraph/language_server/request.rb +1 -0
  53. data/lib/solargraph/library.rb +53 -32
  54. data/lib/solargraph/location.rb +23 -0
  55. data/lib/solargraph/logging.rb +12 -2
  56. data/lib/solargraph/page.rb +4 -0
  57. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  58. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  59. data/lib/solargraph/parser/node_methods.rb +16 -2
  60. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  61. data/lib/solargraph/parser/node_processor.rb +26 -9
  62. data/lib/solargraph/parser/parser_gem/class_methods.rb +17 -15
  63. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  64. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +8 -4
  66. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  68. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  69. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  70. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  73. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  74. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  75. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  76. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  77. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
  79. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  80. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
  81. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  83. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  84. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +63 -30
  85. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  86. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  89. data/lib/solargraph/parser/region.rb +4 -1
  90. data/lib/solargraph/parser/snippet.rb +2 -0
  91. data/lib/solargraph/parser.rb +1 -0
  92. data/lib/solargraph/pin/base.rb +360 -30
  93. data/lib/solargraph/pin/base_variable.rb +16 -10
  94. data/lib/solargraph/pin/block.rb +2 -0
  95. data/lib/solargraph/pin/breakable.rb +9 -0
  96. data/lib/solargraph/pin/callable.rb +83 -3
  97. data/lib/solargraph/pin/closure.rb +20 -1
  98. data/lib/solargraph/pin/common.rb +10 -1
  99. data/lib/solargraph/pin/constant.rb +2 -0
  100. data/lib/solargraph/pin/delegated_method.rb +21 -1
  101. data/lib/solargraph/pin/documenting.rb +16 -0
  102. data/lib/solargraph/pin/keyword.rb +7 -2
  103. data/lib/solargraph/pin/local_variable.rb +18 -6
  104. data/lib/solargraph/pin/method.rb +175 -46
  105. data/lib/solargraph/pin/method_alias.rb +3 -0
  106. data/lib/solargraph/pin/namespace.rb +17 -9
  107. data/lib/solargraph/pin/parameter.rb +78 -19
  108. data/lib/solargraph/pin/proxy_type.rb +13 -6
  109. data/lib/solargraph/pin/reference/override.rb +24 -6
  110. data/lib/solargraph/pin/reference/require.rb +2 -2
  111. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  112. data/lib/solargraph/pin/reference.rb +26 -0
  113. data/lib/solargraph/pin/search.rb +3 -1
  114. data/lib/solargraph/pin/signature.rb +44 -0
  115. data/lib/solargraph/pin/singleton.rb +1 -1
  116. data/lib/solargraph/pin/symbol.rb +8 -2
  117. data/lib/solargraph/pin/until.rb +18 -0
  118. data/lib/solargraph/pin/while.rb +18 -0
  119. data/lib/solargraph/pin.rb +4 -1
  120. data/lib/solargraph/pin_cache.rb +245 -0
  121. data/lib/solargraph/position.rb +11 -0
  122. data/lib/solargraph/range.rb +10 -0
  123. data/lib/solargraph/rbs_map/conversions.rb +226 -70
  124. data/lib/solargraph/rbs_map/core_fills.rb +32 -16
  125. data/lib/solargraph/rbs_map/core_map.rb +37 -11
  126. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  127. data/lib/solargraph/rbs_map.rb +88 -18
  128. data/lib/solargraph/shell.rb +20 -18
  129. data/lib/solargraph/source/chain/array.rb +11 -7
  130. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  131. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  132. data/lib/solargraph/source/chain/call.rb +53 -23
  133. data/lib/solargraph/source/chain/constant.rb +1 -1
  134. data/lib/solargraph/source/chain/hash.rb +4 -3
  135. data/lib/solargraph/source/chain/head.rb +1 -1
  136. data/lib/solargraph/source/chain/if.rb +1 -1
  137. data/lib/solargraph/source/chain/link.rb +12 -1
  138. data/lib/solargraph/source/chain/literal.rb +22 -2
  139. data/lib/solargraph/source/chain/or.rb +1 -1
  140. data/lib/solargraph/source/chain/z_super.rb +1 -1
  141. data/lib/solargraph/source/chain.rb +84 -47
  142. data/lib/solargraph/source/change.rb +2 -2
  143. data/lib/solargraph/source/cursor.rb +2 -3
  144. data/lib/solargraph/source/source_chainer.rb +3 -3
  145. data/lib/solargraph/source.rb +5 -2
  146. data/lib/solargraph/source_map/clip.rb +4 -2
  147. data/lib/solargraph/source_map/data.rb +4 -0
  148. data/lib/solargraph/source_map/mapper.rb +13 -7
  149. data/lib/solargraph/source_map.rb +21 -31
  150. data/lib/solargraph/type_checker/checks.rb +4 -0
  151. data/lib/solargraph/type_checker/param_def.rb +2 -0
  152. data/lib/solargraph/type_checker/rules.rb +8 -0
  153. data/lib/solargraph/type_checker.rb +208 -128
  154. data/lib/solargraph/version.rb +1 -1
  155. data/lib/solargraph/views/_method.erb +10 -10
  156. data/lib/solargraph/views/_namespace.erb +3 -3
  157. data/lib/solargraph/views/document.erb +10 -10
  158. data/lib/solargraph/workspace/config.rb +1 -3
  159. data/lib/solargraph/workspace/require_paths.rb +98 -0
  160. data/lib/solargraph/workspace.rb +38 -52
  161. data/lib/solargraph/yard_map/helpers.rb +29 -1
  162. data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
  163. data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
  164. data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
  165. data/lib/solargraph/yard_map/mapper.rb +4 -3
  166. data/lib/solargraph/yard_map/to_method.rb +4 -2
  167. data/lib/solargraph/yardoc.rb +22 -10
  168. data/lib/solargraph.rb +34 -1
  169. data/rbs/fills/tuple.rbs +149 -0
  170. data/rbs_collection.yaml +19 -0
  171. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  172. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  173. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  174. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  175. data/solargraph.gemspec +15 -4
  176. metadata +157 -15
  177. data/lib/.rubocop.yml +0 -22
  178. data/lib/solargraph/cache.rb +0 -77
@@ -5,23 +5,49 @@ module Solargraph
5
5
  # Ruby core pins
6
6
  #
7
7
  class CoreMap
8
- include Conversions
9
8
 
10
- def initialize
11
- cache = Cache.load('core.ser')
9
+ def resolved?
10
+ true
11
+ end
12
+
13
+ FILLS_DIRECTORY = File.join(File.dirname(__FILE__), '..', '..', '..', 'rbs', 'fills')
14
+
15
+ def initialize; end
16
+
17
+ # @return [Enumerable<Pin::Base>]
18
+ def pins
19
+ return @pins if @pins
20
+
21
+ @pins = []
22
+ cache = PinCache.deserialize_core
12
23
  if cache
13
- pins.replace cache
24
+ @pins.replace cache
14
25
  else
15
- loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
16
- RBS::Environment.from_loader(loader).resolve_type_names
17
- load_environment_to_pins(loader)
18
- pins.concat RbsMap::CoreFills::ALL
26
+ loader.add(path: Pathname(FILLS_DIRECTORY))
27
+ @pins = conversions.pins
28
+ @pins.concat RbsMap::CoreFills::ALL
19
29
  processed = ApiMap::Store.new(pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
20
- processed.each { |pin| pin.source = :rbs }
21
- pins.replace processed
30
+ @pins.replace processed
22
31
 
23
- Cache.save('core.ser', pins)
32
+ PinCache.serialize_core @pins
24
33
  end
34
+ @pins
35
+ end
36
+
37
+ def loader
38
+ @loader ||= RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
39
+ end
40
+
41
+ private
42
+
43
+ # @return [RBS::EnvironmentLoader]
44
+ def loader
45
+ @loader ||= RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
46
+ end
47
+
48
+ # @return [Conversions]
49
+ def conversions
50
+ @conversions ||= Conversions.new(loader: loader)
25
51
  end
26
52
  end
27
53
  end
@@ -7,19 +7,29 @@ module Solargraph
7
7
  # Ruby stdlib pins
8
8
  #
9
9
  class StdlibMap < RbsMap
10
+ include Logging
11
+
10
12
  # @type [Hash{String => RbsMap}]
11
13
  @stdlib_maps_hash = {}
12
14
 
13
15
  # @param library [String]
14
16
  def initialize library
15
- cache = Cache.load('stdlib', "#{library}.ser")
16
- if cache
17
- pins.replace cache
17
+ cached_pins = PinCache.deserialize_stdlib_require library
18
+ if cached_pins
19
+ @pins = cached_pins
18
20
  @resolved = true
21
+ @loaded = true
22
+ logger.debug { "Deserialized #{cached_pins.length} cached pins for stdlib require #{library.inspect}" }
19
23
  else
20
24
  super
21
- return unless resolved?
22
- Cache.save('stdlib', "#{library}.ser", pins)
25
+ unless resolved?
26
+ @pins = []
27
+ logger.info { "Could not resolve #{library.inspect}" }
28
+ return
29
+ end
30
+ generated_pins = pins
31
+ logger.debug { "Found #{generated_pins.length} pins for stdlib library #{library}" }
32
+ PinCache.serialize_stdlib_require library, generated_pins
23
33
  end
24
34
  end
25
35
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'digest'
3
4
  require 'pathname'
4
5
  require 'rbs'
5
6
 
@@ -10,25 +11,86 @@ module Solargraph
10
11
  autoload :CoreFills, 'solargraph/rbs_map/core_fills'
11
12
  autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
12
13
 
13
- include Conversions
14
+ include Logging
14
15
 
15
16
  # @type [Hash{String => RbsMap}]
16
17
  @@rbs_maps_hash = {}
17
18
 
18
19
  attr_reader :library
19
20
 
21
+ attr_reader :rbs_collection_paths
22
+
23
+ attr_reader :rbs_collection_config_path
24
+
20
25
  # @param library [String]
21
- # @param version [String, nil]
22
- # @param directories [Array<Pathname, String>]
23
- def initialize library, version = nil, directories: []
26
+ # @param version [String, nil
27
+ # @param rbs_collection_config_path [String, Pathname, nil]
28
+ # @param rbs_collection_paths [Array<Pathname, String>]
29
+ def initialize library, version = nil, rbs_collection_config_path: nil, rbs_collection_paths: []
30
+ if rbs_collection_config_path.nil? && !rbs_collection_paths.empty?
31
+ raise 'Please provide rbs_collection_config_path if you provide rbs_collection_paths'
32
+ end
24
33
  @library = library
25
34
  @version = version
26
- @collection = nil
27
- @directories = directories
28
- loader = RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
35
+ @rbs_collection_config_path = rbs_collection_config_path
36
+ @rbs_collection_paths = rbs_collection_paths
29
37
  add_library loader, library, version
30
- return unless resolved?
31
- load_environment_to_pins(loader)
38
+ end
39
+
40
+ # @return [RBS::EnvironmentLoader]
41
+ def loader
42
+ @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
43
+ end
44
+
45
+ # @return [String] representing the version of the RBS info fetched
46
+ # for the given library. Must change when the RBS info is
47
+ # updated upstream for the same library and version. May change
48
+ # if the config for where information comes form changes.
49
+ def cache_key
50
+ @hextdigest ||= begin
51
+ # @type [String, nil]
52
+ data = nil
53
+ if rbs_collection_config_path
54
+ lockfile_path = RBS::Collection::Config.to_lockfile_path(Pathname.new(rbs_collection_config_path))
55
+ if lockfile_path.exist?
56
+ collection_config = RBS::Collection::Config.from_path lockfile_path
57
+ gem_config = collection_config.gem(library)
58
+ data = gem_config&.to_s
59
+ end
60
+ end
61
+ if data.nil? || data.empty?
62
+ if resolved?
63
+ # definitely came from the gem itself and not elsewhere -
64
+ # only one version per gem
65
+ 'gem-export'
66
+ else
67
+ 'unresolved'
68
+ end
69
+ else
70
+ Digest::SHA1.hexdigest(data)
71
+ end
72
+ end
73
+ end
74
+
75
+ # @param gemspec [Gem::Specification]
76
+ # @param rbs_collection_path [String, Pathname, nil]
77
+ # @param rbs_collection_config_path [String, Pathname, nil]
78
+ # @return [RbsMap]
79
+ def self.from_gemspec gemspec, rbs_collection_path, rbs_collection_config_path
80
+ rbs_map = RbsMap.new(gemspec.name, gemspec.version,
81
+ rbs_collection_paths: [rbs_collection_path].compact,
82
+ rbs_collection_config_path: rbs_collection_config_path)
83
+ return rbs_map if rbs_map.resolved?
84
+
85
+ # try any version of the gem in the collection
86
+ RbsMap.new(gemspec.name, nil,
87
+ rbs_collection_paths: [rbs_collection_path].compact,
88
+ rbs_collection_config_path: rbs_collection_config_path)
89
+ end
90
+
91
+ # @return [Array<Pin::Base>]
92
+ def pins
93
+ @pins ||= resolved? ? conversions.pins : []
32
94
  end
33
95
 
34
96
  # @generic T
@@ -50,11 +112,13 @@ module Solargraph
50
112
  @resolved
51
113
  end
52
114
 
115
+ # @return [RBS::Repository]
53
116
  def repository
54
117
  @repository ||= RBS::Repository.new(no_stdlib: false).tap do |repo|
55
- # @todo Temporarily ignoring external directories due to issues with
56
- # incomplete/broken gem_rbs_collection installations
57
- # @directories.each { |dir| repo.add(Pathname.new(dir)) }
118
+ @rbs_collection_paths.each do |dir|
119
+ dir_path = Pathname.new(dir)
120
+ repo.add(dir_path) if dir_path.exist? && dir_path.directory?
121
+ end
58
122
  end
59
123
  end
60
124
 
@@ -64,23 +128,29 @@ module Solargraph
64
128
  @@rbs_maps_hash[library] ||= RbsMap.new(library)
65
129
  end
66
130
 
67
- # @param gemspec [Gem::Specification]
68
- def self.from_gemspec(gemspec)
69
- RbsMap.new(gemspec.name, gemspec.version)
131
+ private
132
+
133
+ # @return [RBS::EnvironmentLoader]
134
+ def loader
135
+ @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
70
136
  end
71
137
 
72
- private
138
+ # @return [Conversions]
139
+ def conversions
140
+ @conversions ||= Conversions.new(loader: loader)
141
+ end
73
142
 
74
143
  # @param loader [RBS::EnvironmentLoader]
75
144
  # @param library [String]
145
+ # @param version [String, nil]
76
146
  # @return [Boolean] true if adding the library succeeded
77
147
  def add_library loader, library, version
78
148
  @resolved = if loader.has_library?(library: library, version: version)
79
149
  loader.add library: library, version: version
80
- Solargraph.logger.info "#{short_name} successfully loaded library #{library}"
150
+ logger.debug { "#{short_name} successfully loaded library #{library}:#{version}" }
81
151
  true
82
152
  else
83
- Solargraph.logger.info "#{short_name} failed to load library #{library}"
153
+ logger.info { "#{short_name} did not find data for library #{library}:#{version}" }
84
154
  false
85
155
  end
86
156
  end
@@ -36,6 +36,7 @@ module Solargraph
36
36
  Signal.trap("TERM") do
37
37
  Backport.stop
38
38
  end
39
+ # @sg-ignore Wrong argument type for Backport.prepare_tcp_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
39
40
  Backport.prepare_tcp_server host: options[:host], port: port, adapter: Solargraph::LanguageServer::Transport::Adapter
40
41
  STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
41
42
  end
@@ -52,6 +53,7 @@ module Solargraph
52
53
  Signal.trap("TERM") do
53
54
  Backport.stop
54
55
  end
56
+ # @sg-ignore Wrong argument type for Backport.prepare_stdio_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
55
57
  Backport.prepare_stdio_server adapter: Solargraph::LanguageServer::Transport::Adapter
56
58
  STDERR.puts "Solargraph is listening on stdio PID=#{Process.pid}"
57
59
  end
@@ -90,19 +92,20 @@ module Solargraph
90
92
  # @return [void]
91
93
  def clear
92
94
  puts "Deleting all cached documentation (gems, core and stdlib)"
93
- Solargraph::Cache.clear
95
+ Solargraph::PinCache.clear
94
96
  end
95
97
  map 'clear-cache' => :clear
96
98
  map 'clear-cores' => :clear
97
99
 
98
100
  desc 'cache', 'Cache a gem', hide: true
101
+ option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
99
102
  # @return [void]
100
103
  # @param gem [String]
101
104
  # @param version [String, nil]
102
105
  def cache gem, version = nil
106
+ api_map = Solargraph::ApiMap.load(Dir.pwd)
103
107
  spec = Gem::Specification.find_by_name(gem, version)
104
- pins = GemPins.build(spec)
105
- Cache.save('gems', "#{spec.name}-#{spec.version}.ser", pins)
108
+ api_map.cache_gem(spec, rebuild: options[:rebuild], out: $stdout)
106
109
  end
107
110
 
108
111
  desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
@@ -117,18 +120,17 @@ module Solargraph
117
120
  raise ArgumentError, 'No gems specified.' if gems.empty?
118
121
  gems.each do |gem|
119
122
  if gem == 'core'
120
- Cache.uncache("core.ser")
123
+ PinCache.uncache_core
121
124
  next
122
125
  end
123
126
 
124
127
  if gem == 'stdlib'
125
- Cache.uncache("stdlib")
128
+ PinCache.uncache_stdlib
126
129
  next
127
130
  end
128
131
 
129
132
  spec = Gem::Specification.find_by_name(gem)
130
- Cache.uncache('gems', "#{spec.name}-#{spec.version}.ser")
131
- Cache.uncache('gems', "#{spec.name}-#{spec.version}.yardoc")
133
+ PinCache.uncache_gem(spec, out: $stdout)
132
134
  end
133
135
  end
134
136
 
@@ -137,15 +139,18 @@ module Solargraph
137
139
  # @param names [Array<String>]
138
140
  # @return [void]
139
141
  def gems *names
142
+ api_map = ApiMap.load('.')
140
143
  if names.empty?
141
- Gem::Specification.to_a.each { |spec| do_cache spec }
144
+ Gem::Specification.to_a.each { |spec| do_cache spec, api_map }
145
+ STDERR.puts "Documentation cached for all #{Gem::Specification.count} gems."
142
146
  else
143
147
  names.each do |name|
144
148
  spec = Gem::Specification.find_by_name(*name.split('='))
145
- do_cache spec
149
+ do_cache spec, api_map
146
150
  rescue Gem::MissingSpecError
147
151
  warn "Gem '#{name}' not found"
148
152
  end
153
+ STDERR.puts "Documentation cached for #{names.count} gems."
149
154
  end
150
155
  end
151
156
 
@@ -206,6 +211,7 @@ module Solargraph
206
211
  # @return [void]
207
212
  def scan
208
213
  directory = File.realpath(options[:directory])
214
+ # @type [Solargraph::ApiMap, nil]
209
215
  api_map = nil
210
216
  time = Benchmark.measure {
211
217
  api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
@@ -254,16 +260,12 @@ module Solargraph
254
260
  end
255
261
 
256
262
  # @param gemspec [Gem::Specification]
263
+ # @param api_map [ApiMap]
257
264
  # @return [void]
258
- def do_cache gemspec
259
- cached = Yardoc.cached?(gemspec)
260
- if cached && !options.rebuild
261
- puts "Cache already exists for #{gemspec.name} #{gemspec.version}"
262
- else
263
- puts "#{cached ? 'Rebuilding' : 'Caching'} gem documentation for #{gemspec.name} #{gemspec.version}"
264
- pins = GemPins.build(gemspec)
265
- Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
266
- end
265
+ def do_cache gemspec, api_map
266
+ # @todo if the rebuild: option is passed as a positional arg,
267
+ # typecheck doesn't complain on the below line
268
+ api_map.cache_gem(gemspec, rebuild: options.rebuild, out: $stdout)
267
269
  end
268
270
  end
269
271
  end
@@ -3,8 +3,9 @@ module Solargraph
3
3
  class Chain
4
4
  class Array < Literal
5
5
  # @param children [::Array<Chain>]
6
- def initialize children
7
- super('::Array')
6
+ # @param node [Parser::AST::Node]
7
+ def initialize children, node
8
+ super('::Array', node)
8
9
  @children = children
9
10
  end
10
11
 
@@ -17,15 +18,18 @@ module Solargraph
17
18
  # @param locals [::Array<Pin::Parameter, Pin::LocalVariable>]
18
19
  def resolve api_map, name_pin, locals
19
20
  child_types = @children.map do |child|
20
- child.infer(api_map, name_pin, locals)
21
+ child.infer(api_map, name_pin, locals).simplify_literals
21
22
  end
22
-
23
- type = if child_types.uniq.length == 1 && child_types.first.defined?
23
+ type = if child_types.length == 0 || child_types.any?(&:undefined?)
24
+ ComplexType::UniqueType.new('Array', rooted: true)
25
+ elsif child_types.uniq.length == 1 && child_types.first.defined?
24
26
  ComplexType::UniqueType.new('Array', [], child_types.uniq, rooted: true, parameters_type: :list)
27
+ elsif child_types.length == 0
28
+ ComplexType::UniqueType.new('Array', rooted: true, parameters_type: :list)
25
29
  else
26
- ComplexType::UniqueType.new('Array', rooted: true)
30
+ ComplexType::UniqueType.new('Array', [], child_types, rooted: true, parameters_type: :fixed)
27
31
  end
28
- [Pin::ProxyType.anonymous(type)]
32
+ [Pin::ProxyType.anonymous(type, source: :chain)]
29
33
  end
30
34
  end
31
35
  end
@@ -5,7 +5,7 @@ module Solargraph
5
5
  class Chain
6
6
  class BlockSymbol < Link
7
7
  def resolve api_map, name_pin, locals
8
- [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'))]
8
+ [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'), source: :chain)]
9
9
  end
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ module Solargraph
5
5
  class Chain
6
6
  class BlockVariable < Link
7
7
  def resolve api_map, name_pin, locals
8
- [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'))]
8
+ [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'), source: :chain)]
9
9
  end
10
10
  end
11
11
  end
@@ -3,12 +3,20 @@
3
3
  module Solargraph
4
4
  class Source
5
5
  class Chain
6
+ #
7
+ # Handles both method calls and local variable references by
8
+ # first looking for a variable with the name 'word', then
9
+ # proceeding to method signature resolution if not found.
10
+ #
6
11
  class Call < Chain::Link
7
12
  include Solargraph::Parser::NodeMethods
8
13
 
9
14
  # @return [String]
10
15
  attr_reader :word
11
16
 
17
+ # @return [Location]
18
+ attr_reader :location
19
+
12
20
  # @return [::Array<Chain>]
13
21
  attr_reader :arguments
14
22
 
@@ -16,10 +24,12 @@ module Solargraph
16
24
  attr_reader :block
17
25
 
18
26
  # @param word [String]
27
+ # @param location [Location, nil]
19
28
  # @param arguments [::Array<Chain>]
20
29
  # @param block [Chain, nil]
21
- def initialize word, arguments = [], block = nil
30
+ def initialize word, location = nil, arguments = [], block = nil
22
31
  @word = word
32
+ @location = location
23
33
  @arguments = arguments
24
34
  @block = block
25
35
  fix_block_pass
@@ -35,20 +45,21 @@ module Solargraph
35
45
  end
36
46
 
37
47
  # @param api_map [ApiMap]
38
- # @param name_pin [Pin::Closure] name_pin.binder should give us the object on which 'word' will be invoked
48
+ # @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
39
49
  # @param locals [::Array<Pin::LocalVariable>]
40
50
  def resolve api_map, name_pin, locals
41
51
  return super_pins(api_map, name_pin) if word == 'super'
42
52
  return yield_pins(api_map, name_pin) if word == 'yield'
43
53
  found = if head?
44
- locals.select { |p| p.name == word }
54
+ api_map.visible_pins(locals, word, name_pin, location)
45
55
  else
46
56
  []
47
57
  end
48
58
  return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
49
59
  pins = name_pin.binder.each_unique_type.flat_map do |context|
50
- ns = context.namespace == '' ? '' : context.namespace_type.tag
51
- api_map.get_method_stack(ns, word, scope: context.scope)
60
+ ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
61
+ stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
62
+ [stack.first].compact
52
63
  end
53
64
  return [] if pins.empty?
54
65
  inferred_pins(pins, api_map, name_pin, locals)
@@ -72,7 +83,9 @@ module Solargraph
72
83
  # use it. If we didn't pass a block, the logic below will
73
84
  # reject it regardless
74
85
 
75
- sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
86
+ with_block, without_block = overloads.partition(&:block?)
87
+ sorted_overloads = with_block + without_block
88
+ # @type [Pin::Signature, nil]
76
89
  new_signature_pin = nil
77
90
  sorted_overloads.each do |ol|
78
91
  next unless ol.arity_matches?(arguments, with_block?)
@@ -85,13 +98,8 @@ module Solargraph
85
98
  match = ol.parameters.any?(&:restarg?)
86
99
  break
87
100
  end
88
- atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context), locals)
89
- # make sure we get types from up the method
90
- # inheritance chain if we don't have them on this pin
91
- ptype = param.typify api_map
92
- # @todo Weak type comparison
93
- # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
94
- unless ptype.undefined? || atype.name == ptype.name || ptype.any? { |current_ptype| api_map.super_and_sub?(current_ptype.name, atype.name) } || ptype.generic? || param.restarg?
101
+ atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context, source: :chain), locals)
102
+ unless param.compatible_arg?(atype, api_map) || param.restarg?
95
103
  match = false
96
104
  break
97
105
  end
@@ -106,9 +114,30 @@ module Solargraph
106
114
  blocktype = block_call_type(api_map, name_pin, locals)
107
115
  end
108
116
  end
117
+ # @type new_signature_pin [Pin::Signature]
109
118
  new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
110
119
  new_return_type = new_signature_pin.return_type
111
- type = with_params(new_return_type.self_to_type(name_pin.context), name_pin.context).qualify(api_map, name_pin.context.namespace) if new_return_type.defined?
120
+ if head?
121
+ # If we're at the head of the chain, we called a
122
+ # method somewhere that marked itself as returning
123
+ # self. Given we didn't invoke this on an object,
124
+ # this must be a method in this same class - so we
125
+ # use our own self type
126
+ self_type = name_pin.context
127
+ else
128
+ # if we're past the head in the chain, whatever the
129
+ # type of the lhs side is what 'self' will be in its
130
+ # declaration - we can't just use the type of the
131
+ # method pin, as this might be a subclass of the
132
+ # place where the method is defined
133
+ self_type = name_pin.binder
134
+ end
135
+ # This same logic applies to the YARD work done by
136
+ # 'with_params()'.
137
+ #
138
+ # qualify(), however, happens in the namespace where
139
+ # the docs were written - from the method pin.
140
+ type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, p.namespace) if new_return_type.defined?
112
141
  type ||= ComplexType::UNDEFINED
113
142
  end
114
143
  break if type.defined?
@@ -124,13 +153,14 @@ module Solargraph
124
153
  end
125
154
  p
126
155
  end
127
- result.map do |pin|
128
- if pin.path == 'Class#new' && name_pin.context.tag != 'Class'
129
- reduced_context = name_pin.context.reduce_class_type
156
+ logger.debug { "Call#inferred_pins(name_pin.binder=#{name_pin.binder}, word=#{word}, pins=#{pins.map(&:desc)}, name_pin=#{name_pin}) - result=#{result}" }
157
+ out = result.map do |pin|
158
+ if pin.path == 'Class#new' && name_pin.binder.tag != 'Class'
159
+ reduced_context = name_pin.binder.reduce_class_type
130
160
  pin.proxy(reduced_context)
131
161
  else
132
162
  next pin if pin.return_type.undefined?
133
- selfy = pin.return_type.self_to_type(name_pin.context)
163
+ selfy = pin.return_type.self_to_type(name_pin.binder)
134
164
  selfy == pin.return_type ? pin : pin.proxy(selfy)
135
165
  end
136
166
  end
@@ -152,7 +182,7 @@ module Solargraph
152
182
  result = inner_process_macro(pin, macro, api_map, context, locals)
153
183
  return result unless result.return_type.undefined?
154
184
  end
155
- Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
185
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
156
186
  end
157
187
 
158
188
  # @param pin [Pin::Method]
@@ -167,7 +197,7 @@ module Solargraph
167
197
  result = inner_process_macro(pin, macro, api_map, context, locals)
168
198
  return result unless result.return_type.undefined?
169
199
  end
170
- Pin::ProxyType.anonymous ComplexType::UNDEFINED
200
+ Pin::ProxyType.anonymous ComplexType::UNDEFINED, source: :chain
171
201
  end
172
202
 
173
203
  # @param pin [Pin::Base]
@@ -177,7 +207,7 @@ module Solargraph
177
207
  # @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
178
208
  # @return [Pin::ProxyType]
179
209
  def inner_process_macro pin, macro, api_map, context, locals
180
- vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
210
+ vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
181
211
  txt = macro.tag.text.clone
182
212
  if txt.empty? && macro.tag.name
183
213
  named = api_map.named_macro(macro.tag.name)
@@ -191,9 +221,9 @@ module Solargraph
191
221
  docstring = Solargraph::Source.parse_docstring(txt).to_docstring
192
222
  tag = docstring.tag(:return)
193
223
  unless tag.nil? || tag.types.nil?
194
- return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types))
224
+ return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types), source: :chain)
195
225
  end
196
- Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
226
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
197
227
  end
198
228
 
199
229
  # @param docstring [YARD::Docstring]
@@ -41,7 +41,7 @@ module Solargraph
41
41
 
42
42
  private
43
43
 
44
- # @param pin [Pin::Base]
44
+ # @param pin [Pin::Closure]
45
45
  # @return [::Array<String>]
46
46
  def crawl_gates pin
47
47
  clos = pin
@@ -5,9 +5,10 @@ module Solargraph
5
5
  class Chain
6
6
  class Hash < Literal
7
7
  # @param type [String]
8
+ # @param node [Parser::AST::Node]
8
9
  # @param splatted [Boolean]
9
- def initialize type, splatted = false
10
- super(type)
10
+ def initialize type, node, splatted = false
11
+ super(type, node)
11
12
  @splatted = splatted
12
13
  end
13
14
 
@@ -21,7 +22,7 @@ module Solargraph
21
22
  end
22
23
 
23
24
  def resolve api_map, name_pin, locals
24
- [Pin::ProxyType.anonymous(@complex_type)]
25
+ [Pin::ProxyType.anonymous(@complex_type, source: :chain)]
25
26
  end
26
27
 
27
28
  def splatted?
@@ -9,7 +9,7 @@ module Solargraph
9
9
  # @note Chain::Head is only intended to handle `self` and `super`.
10
10
  class Head < Link
11
11
  def resolve api_map, name_pin, locals
12
- return [Pin::ProxyType.anonymous(name_pin.binder)] if word == 'self'
12
+ return [Pin::ProxyType.anonymous(name_pin.binder, source: :chain)] if word == 'self'
13
13
  # return super_pins(api_map, name_pin) if word == 'super'
14
14
  []
15
15
  end
@@ -20,7 +20,7 @@ module Solargraph
20
20
 
21
21
  def resolve api_map, name_pin, locals
22
22
  types = @links.map { |link| link.infer(api_map, name_pin, locals) }
23
- [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
23
+ [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')), source: :chain)]
24
24
  end
25
25
  end
26
26
  end