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.
- checksums.yaml +4 -4
- data/.github/workflows/linting.yml +125 -0
- data/.github/workflows/plugins.yml +149 -5
- data/.github/workflows/rspec.yml +39 -4
- data/.github/workflows/typecheck.yml +8 -3
- data/.gitignore +7 -0
- data/.overcommit.yml +72 -0
- data/.rspec +1 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +2627 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +104 -0
- data/README.md +20 -6
- data/Rakefile +125 -13
- data/lib/solargraph/api_map/cache.rb +3 -2
- data/lib/solargraph/api_map/constants.rb +218 -0
- data/lib/solargraph/api_map/index.rb +44 -42
- data/lib/solargraph/api_map/source_to_yard.rb +10 -4
- data/lib/solargraph/api_map/store.rb +165 -32
- data/lib/solargraph/api_map.rb +319 -243
- data/lib/solargraph/bench.rb +18 -1
- data/lib/solargraph/complex_type/type_methods.rb +7 -1
- data/lib/solargraph/complex_type/unique_type.rb +105 -16
- data/lib/solargraph/complex_type.rb +40 -7
- data/lib/solargraph/convention/active_support_concern.rb +111 -0
- data/lib/solargraph/convention/base.rb +20 -3
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
- data/lib/solargraph/convention/data_definition.rb +105 -0
- data/lib/solargraph/convention/gemspec.rb +3 -2
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
- data/lib/solargraph/convention/struct_definition.rb +164 -0
- data/lib/solargraph/convention.rb +35 -4
- data/lib/solargraph/diagnostics/rubocop.rb +6 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
- data/lib/solargraph/doc_map.rb +313 -65
- data/lib/solargraph/environ.rb +9 -2
- data/lib/solargraph/gem_pins.rb +60 -38
- data/lib/solargraph/language_server/host/dispatch.rb +2 -0
- data/lib/solargraph/language_server/host/message_worker.rb +13 -7
- data/lib/solargraph/language_server/host.rb +14 -3
- data/lib/solargraph/language_server/message/base.rb +2 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
- data/lib/solargraph/language_server/message/extended/document.rb +5 -2
- data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
- data/lib/solargraph/language_server/progress.rb +8 -0
- data/lib/solargraph/language_server/request.rb +1 -0
- data/lib/solargraph/library.rb +53 -32
- data/lib/solargraph/location.rb +23 -0
- data/lib/solargraph/logging.rb +12 -2
- data/lib/solargraph/page.rb +4 -0
- data/lib/solargraph/parser/comment_ripper.rb +20 -7
- data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
- data/lib/solargraph/parser/node_methods.rb +16 -2
- data/lib/solargraph/parser/node_processor/base.rb +10 -5
- data/lib/solargraph/parser/node_processor.rb +26 -9
- data/lib/solargraph/parser/parser_gem/class_methods.rb +17 -15
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
- data/lib/solargraph/parser/parser_gem/node_methods.rb +8 -4
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +63 -30
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
- data/lib/solargraph/parser/region.rb +4 -1
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/parser.rb +1 -0
- data/lib/solargraph/pin/base.rb +360 -30
- data/lib/solargraph/pin/base_variable.rb +16 -10
- data/lib/solargraph/pin/block.rb +2 -0
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +83 -3
- data/lib/solargraph/pin/closure.rb +20 -1
- data/lib/solargraph/pin/common.rb +10 -1
- data/lib/solargraph/pin/constant.rb +2 -0
- data/lib/solargraph/pin/delegated_method.rb +21 -1
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +18 -6
- data/lib/solargraph/pin/method.rb +175 -46
- data/lib/solargraph/pin/method_alias.rb +3 -0
- data/lib/solargraph/pin/namespace.rb +17 -9
- data/lib/solargraph/pin/parameter.rb +78 -19
- data/lib/solargraph/pin/proxy_type.rb +13 -6
- data/lib/solargraph/pin/reference/override.rb +24 -6
- data/lib/solargraph/pin/reference/require.rb +2 -2
- data/lib/solargraph/pin/reference/superclass.rb +5 -0
- data/lib/solargraph/pin/reference.rb +26 -0
- data/lib/solargraph/pin/search.rb +3 -1
- data/lib/solargraph/pin/signature.rb +44 -0
- data/lib/solargraph/pin/singleton.rb +1 -1
- data/lib/solargraph/pin/symbol.rb +8 -2
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/pin_cache.rb +245 -0
- data/lib/solargraph/position.rb +11 -0
- data/lib/solargraph/range.rb +10 -0
- data/lib/solargraph/rbs_map/conversions.rb +226 -70
- data/lib/solargraph/rbs_map/core_fills.rb +32 -16
- data/lib/solargraph/rbs_map/core_map.rb +37 -11
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +88 -18
- data/lib/solargraph/shell.rb +20 -18
- data/lib/solargraph/source/chain/array.rb +11 -7
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +53 -23
- data/lib/solargraph/source/chain/constant.rb +1 -1
- data/lib/solargraph/source/chain/hash.rb +4 -3
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +12 -1
- data/lib/solargraph/source/chain/literal.rb +22 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain/z_super.rb +1 -1
- data/lib/solargraph/source/chain.rb +84 -47
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/cursor.rb +2 -3
- data/lib/solargraph/source/source_chainer.rb +3 -3
- data/lib/solargraph/source.rb +5 -2
- data/lib/solargraph/source_map/clip.rb +4 -2
- data/lib/solargraph/source_map/data.rb +4 -0
- data/lib/solargraph/source_map/mapper.rb +13 -7
- data/lib/solargraph/source_map.rb +21 -31
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker/param_def.rb +2 -0
- data/lib/solargraph/type_checker/rules.rb +8 -0
- data/lib/solargraph/type_checker.rb +208 -128
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +10 -10
- data/lib/solargraph/views/_namespace.erb +3 -3
- data/lib/solargraph/views/document.erb +10 -10
- data/lib/solargraph/workspace/config.rb +1 -3
- data/lib/solargraph/workspace/require_paths.rb +98 -0
- data/lib/solargraph/workspace.rb +38 -52
- data/lib/solargraph/yard_map/helpers.rb +29 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
- data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
- data/lib/solargraph/yard_map/mapper.rb +4 -3
- data/lib/solargraph/yard_map/to_method.rb +4 -2
- data/lib/solargraph/yardoc.rb +22 -10
- data/lib/solargraph.rb +34 -1
- data/rbs/fills/tuple.rbs +149 -0
- data/rbs_collection.yaml +19 -0
- data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
- data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
- data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
- data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
- data/solargraph.gemspec +15 -4
- metadata +157 -15
- data/lib/.rubocop.yml +0 -22
- data/lib/solargraph/cache.rb +0 -77
data/lib/solargraph/doc_map.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pathname'
|
4
|
+
require 'benchmark'
|
5
|
+
require 'open3'
|
6
|
+
|
3
7
|
module Solargraph
|
4
8
|
# A collection of pins generated from required gems.
|
5
9
|
#
|
6
10
|
class DocMap
|
11
|
+
include Logging
|
12
|
+
|
7
13
|
# @return [Array<String>]
|
8
14
|
attr_reader :requires
|
15
|
+
alias required requires
|
9
16
|
|
10
17
|
# @return [Array<Gem::Specification>]
|
11
18
|
attr_reader :preferences
|
@@ -14,31 +21,147 @@ module Solargraph
|
|
14
21
|
attr_reader :pins
|
15
22
|
|
16
23
|
# @return [Array<Gem::Specification>]
|
17
|
-
|
24
|
+
def uncached_gemspecs
|
25
|
+
uncached_yard_gemspecs.concat(uncached_rbs_collection_gemspecs)
|
26
|
+
.sort
|
27
|
+
.uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Array<Gem::Specification>]
|
31
|
+
attr_reader :uncached_yard_gemspecs
|
32
|
+
|
33
|
+
# @return [Array<Gem::Specification>]
|
34
|
+
attr_reader :uncached_rbs_collection_gemspecs
|
35
|
+
|
36
|
+
# @return [String, nil]
|
37
|
+
attr_reader :rbs_collection_path
|
38
|
+
|
39
|
+
# @return [String, nil]
|
40
|
+
attr_reader :rbs_collection_config_path
|
41
|
+
|
42
|
+
# @return [Workspace, nil]
|
43
|
+
attr_reader :workspace
|
44
|
+
|
45
|
+
# @return [Environ]
|
46
|
+
attr_reader :environ
|
18
47
|
|
19
48
|
# @param requires [Array<String>]
|
20
49
|
# @param preferences [Array<Gem::Specification>]
|
21
|
-
# @param
|
22
|
-
def initialize(requires, preferences,
|
50
|
+
# @param workspace [Workspace, nil]
|
51
|
+
def initialize(requires, preferences, workspace = nil)
|
23
52
|
@requires = requires.compact
|
24
53
|
@preferences = preferences.compact
|
25
|
-
@
|
26
|
-
|
54
|
+
@workspace = workspace
|
55
|
+
@rbs_collection_path = workspace&.rbs_collection_path
|
56
|
+
@rbs_collection_config_path = workspace&.rbs_collection_config_path
|
57
|
+
@environ = Convention.for_global(self)
|
58
|
+
@requires.concat @environ.requires if @environ
|
59
|
+
load_serialized_gem_pins
|
60
|
+
pins.concat @environ.pins
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param out [IO]
|
64
|
+
# @return [void]
|
65
|
+
def cache_all!(out)
|
66
|
+
# if we log at debug level:
|
67
|
+
if logger.info?
|
68
|
+
gem_desc = uncached_gemspecs.map { |gemspec| "#{gemspec.name}:#{gemspec.version}" }.join(', ')
|
69
|
+
logger.info "Caching pins for gems: #{gem_desc}" unless uncached_gemspecs.empty?
|
70
|
+
end
|
71
|
+
logger.debug { "Caching for YARD: #{uncached_yard_gemspecs.map(&:name)}" }
|
72
|
+
logger.debug { "Caching for RBS collection: #{uncached_rbs_collection_gemspecs.map(&:name)}" }
|
73
|
+
load_serialized_gem_pins
|
74
|
+
uncached_gemspecs.each do |gemspec|
|
75
|
+
cache(gemspec, out: out)
|
76
|
+
end
|
77
|
+
load_serialized_gem_pins
|
78
|
+
@uncached_rbs_collection_gemspecs = []
|
79
|
+
@uncached_yard_gemspecs = []
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param gemspec [Gem::Specification]
|
83
|
+
# @param out [IO]
|
84
|
+
# @return [void]
|
85
|
+
def cache_yard_pins(gemspec, out)
|
86
|
+
pins = GemPins.build_yard_pins(yard_plugins, gemspec)
|
87
|
+
PinCache.serialize_yard_gem(gemspec, pins)
|
88
|
+
logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param gemspec [Gem::Specification]
|
92
|
+
# @param out [IO]
|
93
|
+
# @return [void]
|
94
|
+
def cache_rbs_collection_pins(gemspec, out)
|
95
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
96
|
+
pins = rbs_map.pins
|
97
|
+
rbs_version_cache_key = rbs_map.cache_key
|
98
|
+
# cache pins even if result is zero, so we don't retry building pins
|
99
|
+
pins ||= []
|
100
|
+
PinCache.serialize_rbs_collection_gem(gemspec, rbs_version_cache_key, pins)
|
101
|
+
logger.info { "Cached #{pins.length} RBS collection pins for gem #{gemspec.name} #{gemspec.version} with cache_key #{rbs_version_cache_key.inspect}" unless pins.empty? }
|
102
|
+
end
|
103
|
+
|
104
|
+
# @param gemspec [Gem::Specification]
|
105
|
+
# @param rebuild [Boolean] whether to rebuild the pins even if they are cached
|
106
|
+
# @param out [IO, nil] output stream for logging
|
107
|
+
# @return [void]
|
108
|
+
def cache(gemspec, rebuild: false, out: nil)
|
109
|
+
build_yard = uncached_yard_gemspecs.include?(gemspec) || rebuild
|
110
|
+
build_rbs_collection = uncached_rbs_collection_gemspecs.include?(gemspec) || rebuild
|
111
|
+
if build_yard || build_rbs_collection
|
112
|
+
type = []
|
113
|
+
type << 'YARD' if build_yard
|
114
|
+
type << 'RBS collection' if build_rbs_collection
|
115
|
+
out.puts("Caching #{type.join(' and ')} pins for gem #{gemspec.name}:#{gemspec.version}") if out
|
116
|
+
end
|
117
|
+
cache_yard_pins(gemspec, out) if build_yard
|
118
|
+
cache_rbs_collection_pins(gemspec, out) if build_rbs_collection
|
27
119
|
end
|
28
120
|
|
29
121
|
# @return [Array<Gem::Specification>]
|
30
122
|
def gemspecs
|
31
|
-
@gemspecs ||=
|
123
|
+
@gemspecs ||= required_gems_map.values.compact.flatten
|
32
124
|
end
|
33
125
|
|
34
126
|
# @return [Array<String>]
|
35
127
|
def unresolved_requires
|
36
|
-
@unresolved_requires ||=
|
128
|
+
@unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [Hash{Array(String, String) => Array<Gem::Specification>}] Indexed by gemspec name and version
|
132
|
+
def self.all_yard_gems_in_memory
|
133
|
+
@yard_gems_in_memory ||= {}
|
134
|
+
end
|
135
|
+
|
136
|
+
# @return [Hash{String => Hash{Array(String, String) => Array<Pin::Base>}}] stored by RBS collection path
|
137
|
+
def self.all_rbs_collection_gems_in_memory
|
138
|
+
@rbs_collection_gems_in_memory ||= {}
|
37
139
|
end
|
38
140
|
|
39
|
-
# @return [Hash{
|
40
|
-
def
|
41
|
-
|
141
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
142
|
+
def yard_pins_in_memory
|
143
|
+
self.class.all_yard_gems_in_memory
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
147
|
+
def rbs_collection_pins_in_memory
|
148
|
+
self.class.all_rbs_collection_gems_in_memory[rbs_collection_path] ||= {}
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
152
|
+
def self.all_combined_pins_in_memory
|
153
|
+
@combined_pins_in_memory ||= {}
|
154
|
+
end
|
155
|
+
|
156
|
+
# @todo this should also include an index by the hash of the RBS collection
|
157
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
158
|
+
def combined_pins_in_memory
|
159
|
+
self.class.all_combined_pins_in_memory
|
160
|
+
end
|
161
|
+
|
162
|
+
# @return [Array<String>]
|
163
|
+
def yard_plugins
|
164
|
+
@environ.yard_plugins
|
42
165
|
end
|
43
166
|
|
44
167
|
# @return [Set<Gem::Specification>]
|
@@ -49,23 +172,38 @@ module Solargraph
|
|
49
172
|
private
|
50
173
|
|
51
174
|
# @return [void]
|
52
|
-
def
|
175
|
+
def load_serialized_gem_pins
|
53
176
|
@pins = []
|
54
|
-
@
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
177
|
+
@uncached_yard_gemspecs = []
|
178
|
+
@uncached_rbs_collection_gemspecs = []
|
179
|
+
with_gemspecs, without_gemspecs = required_gems_map.partition { |_, v| v }
|
180
|
+
# @sg-ignore Wrong argument type for Hash.[]: arg_0 expected _ToHash<Array(String, Array<Gem::Specification>), undefined>, received Array<Array(String, Array<Gem::Specification>)>
|
181
|
+
# @type [Array<String>]
|
182
|
+
paths = Hash[without_gemspecs].keys
|
183
|
+
# @sg-ignore Wrong argument type for Hash.[]: arg_0 expected _ToHash<Array(String, Array<Gem::Specification>), undefined>, received Array<Array(String, Array<Gem::Specification>)>
|
184
|
+
# @type [Array<Gem::Specification>]
|
185
|
+
gemspecs = Hash[with_gemspecs].values.flatten.compact + dependencies.to_a
|
186
|
+
|
187
|
+
paths.each do |path|
|
188
|
+
rbs_pins = deserialize_stdlib_rbs_map path
|
189
|
+
end
|
190
|
+
|
191
|
+
logger.debug { "DocMap#load_serialized_gem_pins: Combining pins..." }
|
192
|
+
time = Benchmark.measure do
|
193
|
+
gemspecs.each do |gemspec|
|
194
|
+
pins = deserialize_combined_pin_cache gemspec
|
195
|
+
@pins.concat pins if pins
|
60
196
|
end
|
61
197
|
end
|
62
|
-
|
63
|
-
@
|
198
|
+
logger.info { "DocMap#load_serialized_gem_pins: Loaded and processed serialized pins together in #{time.real} seconds" }
|
199
|
+
@uncached_yard_gemspecs.uniq!
|
200
|
+
@uncached_rbs_collection_gemspecs.uniq!
|
201
|
+
nil
|
64
202
|
end
|
65
203
|
|
66
|
-
# @return [Hash{String => Gem::Specification
|
67
|
-
def
|
68
|
-
@
|
204
|
+
# @return [Hash{String => Array<Gem::Specification>}]
|
205
|
+
def required_gems_map
|
206
|
+
@required_gems_map ||= requires.to_h { |path| [path, resolve_path_to_gemspecs(path)] }
|
69
207
|
end
|
70
208
|
|
71
209
|
# @return [Hash{String => Gem::Specification}]
|
@@ -73,62 +211,109 @@ module Solargraph
|
|
73
211
|
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
74
212
|
end
|
75
213
|
|
214
|
+
# @param gemspec [Gem::Specification]
|
215
|
+
# @return [Array<Pin::Base>]
|
216
|
+
def deserialize_yard_pin_cache gemspec
|
217
|
+
if yard_pins_in_memory.key?([gemspec.name, gemspec.version])
|
218
|
+
return yard_pins_in_memory[[gemspec.name, gemspec.version]]
|
219
|
+
end
|
220
|
+
|
221
|
+
cached = PinCache.deserialize_yard_gem(gemspec)
|
222
|
+
if cached
|
223
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
224
|
+
yard_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
225
|
+
cached
|
226
|
+
else
|
227
|
+
logger.debug "No YARD pin cache for #{gemspec.name}:#{gemspec.version}"
|
228
|
+
@uncached_yard_gemspecs.push gemspec
|
229
|
+
nil
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
76
233
|
# @param gemspec [Gem::Specification]
|
77
234
|
# @return [void]
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
235
|
+
def deserialize_combined_pin_cache(gemspec)
|
236
|
+
unless combined_pins_in_memory[[gemspec.name, gemspec.version]].nil?
|
237
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
238
|
+
end
|
239
|
+
|
240
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
241
|
+
rbs_version_cache_key = rbs_map.cache_key
|
242
|
+
|
243
|
+
cached = PinCache.deserialize_combined_gem(gemspec, rbs_version_cache_key)
|
244
|
+
if cached
|
245
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
246
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
247
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
248
|
+
end
|
249
|
+
|
250
|
+
rbs_collection_pins = deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
251
|
+
|
252
|
+
yard_pins = deserialize_yard_pin_cache gemspec
|
253
|
+
|
254
|
+
if !rbs_collection_pins.nil? && !yard_pins.nil?
|
255
|
+
logger.debug { "Combining pins for #{gemspec.name}:#{gemspec.version}" }
|
256
|
+
combined_pins = GemPins.combine(yard_pins, rbs_collection_pins)
|
257
|
+
PinCache.serialize_combined_gem(gemspec, rbs_version_cache_key, combined_pins)
|
258
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = combined_pins
|
259
|
+
logger.info { "Generated #{combined_pins_in_memory[[gemspec.name, gemspec.version]].length} combined pins for #{gemspec.name} #{gemspec.version}" }
|
260
|
+
return combined_pins
|
261
|
+
end
|
262
|
+
|
263
|
+
if !yard_pins.nil?
|
264
|
+
logger.debug { "Using only YARD pins for #{gemspec.name}:#{gemspec.version}" }
|
265
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = yard_pins
|
266
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
267
|
+
elsif !rbs_collection_pins.nil?
|
268
|
+
logger.debug { "Using only RBS collection pins for #{gemspec.name}:#{gemspec.version}" }
|
269
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = rbs_collection_pins
|
270
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
86
271
|
else
|
87
|
-
|
88
|
-
|
272
|
+
logger.debug { "Pins not yet cached for #{gemspec.name}:#{gemspec.version}" }
|
273
|
+
return nil
|
89
274
|
end
|
90
275
|
end
|
91
276
|
|
92
277
|
# @param path [String] require path that might be in the RBS stdlib collection
|
93
278
|
# @return [void]
|
94
|
-
def
|
279
|
+
def deserialize_stdlib_rbs_map path
|
95
280
|
map = RbsMap::StdlibMap.load(path)
|
96
281
|
if map.resolved?
|
97
|
-
|
282
|
+
logger.debug { "Loading stdlib pins for #{path}" }
|
98
283
|
@pins.concat map.pins
|
284
|
+
logger.debug { "Loaded #{map.pins.length} stdlib pins for #{path}" }
|
285
|
+
map.pins
|
99
286
|
else
|
100
287
|
# @todo Temporarily ignoring unresolved `require 'set'`
|
101
|
-
|
288
|
+
logger.debug { "Require path #{path} could not be resolved in RBS" } unless path == 'set'
|
289
|
+
nil
|
102
290
|
end
|
103
291
|
end
|
104
292
|
|
105
293
|
# @param gemspec [Gem::Specification]
|
106
|
-
# @
|
107
|
-
|
108
|
-
|
109
|
-
return
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
rbs_map = RbsMap.new(gemspec.name, gemspec.version, directories: [@rbs_path])
|
121
|
-
return gempins unless rbs_map.resolved?
|
122
|
-
|
123
|
-
Solargraph.logger.info "Updating #{gemspec.name} #{gemspec.version} from collection"
|
124
|
-
GemPins.combine(gempins, rbs_map)
|
294
|
+
# @param rbs_version_cache_key [String]
|
295
|
+
# @return [Array<Pin::Base>, nil]
|
296
|
+
def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
297
|
+
return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
|
298
|
+
cached = PinCache.deserialize_rbs_collection_gem(gemspec, rbs_version_cache_key)
|
299
|
+
if cached
|
300
|
+
logger.info { "Loaded #{cached.length} pins from RBS collection cache for #{gemspec.name}:#{gemspec.version}" } unless cached.empty?
|
301
|
+
rbs_collection_pins_in_memory[[gemspec, rbs_version_cache_key]] = cached
|
302
|
+
cached
|
303
|
+
else
|
304
|
+
logger.debug "No RBS collection pin cache for #{gemspec.name} #{gemspec.version}"
|
305
|
+
@uncached_rbs_collection_gemspecs.push gemspec
|
306
|
+
nil
|
307
|
+
end
|
125
308
|
end
|
126
309
|
|
127
310
|
# @param path [String]
|
128
|
-
# @return [Gem::Specification
|
129
|
-
def
|
311
|
+
# @return [::Array<Gem::Specification>, nil]
|
312
|
+
def resolve_path_to_gemspecs path
|
130
313
|
return nil if path.empty?
|
314
|
+
return gemspecs_required_from_bundler if path == 'bundler/require'
|
131
315
|
|
316
|
+
# @type [Gem::Specification, nil]
|
132
317
|
gemspec = Gem::Specification.find_by_path(path)
|
133
318
|
if gemspec.nil?
|
134
319
|
gem_name_guess = path.split('/').first
|
@@ -141,20 +326,23 @@ module Solargraph
|
|
141
326
|
file = "lib/#{path}.rb"
|
142
327
|
gemspec = potential_gemspec if potential_gemspec.files.any? { |gemspec_file| file == gemspec_file }
|
143
328
|
rescue Gem::MissingSpecError
|
144
|
-
|
145
|
-
|
329
|
+
logger.debug { "Require path #{path} could not be resolved to a gem via find_by_path or guess of #{gem_name_guess}" }
|
330
|
+
[]
|
146
331
|
end
|
147
332
|
end
|
148
|
-
|
333
|
+
return nil if gemspec.nil?
|
334
|
+
[gemspec_or_preference(gemspec)]
|
149
335
|
end
|
150
336
|
|
151
|
-
# @param gemspec [Gem::Specification
|
152
|
-
# @return [Gem::Specification
|
337
|
+
# @param gemspec [Gem::Specification]
|
338
|
+
# @return [Gem::Specification]
|
153
339
|
def gemspec_or_preference gemspec
|
154
|
-
|
340
|
+
# :nocov: dormant feature
|
341
|
+
return gemspec unless preference_map.key?(gemspec.name)
|
155
342
|
return gemspec if gemspec.version == preference_map[gemspec.name].version
|
156
343
|
|
157
|
-
change_gemspec_version gemspec, preference_map[
|
344
|
+
change_gemspec_version gemspec, preference_map[gemspec.name].version
|
345
|
+
# :nocov:
|
158
346
|
end
|
159
347
|
|
160
348
|
# @param gemspec [Gem::Specification]
|
@@ -170,12 +358,15 @@ module Solargraph
|
|
170
358
|
# @param gemspec [Gem::Specification]
|
171
359
|
# @return [Array<Gem::Specification>]
|
172
360
|
def fetch_dependencies gemspec
|
361
|
+
# @param spec [Gem::Dependency]
|
173
362
|
only_runtime_dependencies(gemspec).each_with_object(Set.new) do |spec, deps|
|
174
363
|
Solargraph.logger.info "Adding #{spec.name} dependency for #{gemspec.name}"
|
175
|
-
dep = Gem
|
364
|
+
dep = Gem.loaded_specs[spec.name]
|
365
|
+
# @todo is next line necessary?
|
366
|
+
dep ||= Gem::Specification.find_by_name(spec.name, spec.requirement)
|
176
367
|
deps.merge fetch_dependencies(dep) if deps.add?(dep)
|
177
368
|
rescue Gem::MissingSpecError
|
178
|
-
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.
|
369
|
+
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirement} for #{gemspec.name} not found in RubyGems."
|
179
370
|
end.to_a
|
180
371
|
end
|
181
372
|
|
@@ -184,5 +375,62 @@ module Solargraph
|
|
184
375
|
def only_runtime_dependencies gemspec
|
185
376
|
gemspec.dependencies - gemspec.development_dependencies
|
186
377
|
end
|
378
|
+
|
379
|
+
|
380
|
+
def inspect
|
381
|
+
self.class.inspect
|
382
|
+
end
|
383
|
+
|
384
|
+
# @return [Array<Gem::Specification>]
|
385
|
+
def gemspecs_required_from_bundler
|
386
|
+
# @todo Handle projects with custom Bundler/Gemfile setups
|
387
|
+
return unless workspace.gemfile?
|
388
|
+
|
389
|
+
if workspace.gemfile? && Bundler.definition&.lockfile&.to_s&.start_with?(workspace.directory)
|
390
|
+
# Find only the gems bundler is now using
|
391
|
+
Bundler.definition.locked_gems.specs.flat_map do |lazy_spec|
|
392
|
+
logger.info "Handling #{lazy_spec.name}:#{lazy_spec.version}"
|
393
|
+
[Gem::Specification.find_by_name(lazy_spec.name, lazy_spec.version)]
|
394
|
+
rescue Gem::MissingSpecError => e
|
395
|
+
logger.info("Could not find #{lazy_spec.name}:#{lazy_spec.version} with find_by_name, falling back to guess")
|
396
|
+
# can happen in local filesystem references
|
397
|
+
specs = resolve_path_to_gemspecs lazy_spec.name
|
398
|
+
logger.warn "Gem #{lazy_spec.name} #{lazy_spec.version} from bundle not found: #{e}" if specs.nil?
|
399
|
+
next specs
|
400
|
+
end.compact
|
401
|
+
else
|
402
|
+
logger.info 'Fetching gemspecs required from Bundler (bundler/require)'
|
403
|
+
gemspecs_required_from_external_bundle
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# @return [Array<Gem::Specification>]
|
408
|
+
def gemspecs_required_from_external_bundle
|
409
|
+
logger.info 'Fetching gemspecs required from external bundle'
|
410
|
+
return [] unless workspace&.directory
|
411
|
+
|
412
|
+
Solargraph.with_clean_env do
|
413
|
+
cmd = [
|
414
|
+
'ruby', '-e',
|
415
|
+
"require 'bundler'; require 'json'; Dir.chdir('#{workspace&.directory}') { puts Bundler.definition.locked_gems.specs.map { |spec| [spec.name, spec.version] }.to_h.to_json }"
|
416
|
+
]
|
417
|
+
o, e, s = Open3.capture3(*cmd)
|
418
|
+
if s.success?
|
419
|
+
Solargraph.logger.debug "External bundle: #{o}"
|
420
|
+
hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
|
421
|
+
hash.flat_map do |name, version|
|
422
|
+
Gem::Specification.find_by_name(name, version)
|
423
|
+
rescue Gem::MissingSpecError => e
|
424
|
+
logger.info("Could not find #{name}:#{version} with find_by_name, falling back to guess")
|
425
|
+
# can happen in local filesystem references
|
426
|
+
specs = resolve_path_to_gemspecs name
|
427
|
+
logger.warn "Gem #{name} #{version} from bundle not found: #{e}" if specs.nil?
|
428
|
+
next specs
|
429
|
+
end.compact
|
430
|
+
else
|
431
|
+
Solargraph.logger.warn "Failed to load gems from bundle at #{workspace&.directory}: #{e}"
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
187
435
|
end
|
188
436
|
end
|
data/lib/solargraph/environ.rb
CHANGED
@@ -13,16 +13,21 @@ module Solargraph
|
|
13
13
|
# @return [Array<String>]
|
14
14
|
attr_reader :domains
|
15
15
|
|
16
|
-
# @return [Array<Pin::
|
16
|
+
# @return [Array<Pin::Base>]
|
17
17
|
attr_reader :pins
|
18
18
|
|
19
|
+
# @return [Array<String>]
|
20
|
+
attr_reader :yard_plugins
|
21
|
+
|
19
22
|
# @param requires [Array<String>]
|
20
23
|
# @param domains [Array<String>]
|
21
24
|
# @param pins [Array<Pin::Base>]
|
22
|
-
|
25
|
+
# @param yard_plugins[Array<String>]
|
26
|
+
def initialize requires: [], domains: [], pins: [], yard_plugins: []
|
23
27
|
@requires = requires
|
24
28
|
@domains = domains
|
25
29
|
@pins = pins
|
30
|
+
@yard_plugins = yard_plugins
|
26
31
|
end
|
27
32
|
|
28
33
|
# @return [self]
|
@@ -30,6 +35,7 @@ module Solargraph
|
|
30
35
|
domains.clear
|
31
36
|
requires.clear
|
32
37
|
pins.clear
|
38
|
+
yard_plugins.clear
|
33
39
|
self
|
34
40
|
end
|
35
41
|
|
@@ -39,6 +45,7 @@ module Solargraph
|
|
39
45
|
domains.concat other.domains
|
40
46
|
requires.concat other.requires
|
41
47
|
pins.concat other.pins
|
48
|
+
yard_plugins.concat other.yard_plugins
|
42
49
|
self
|
43
50
|
end
|
44
51
|
end
|
data/lib/solargraph/gem_pins.rb
CHANGED
@@ -7,59 +7,81 @@ module Solargraph
|
|
7
7
|
# documentation.
|
8
8
|
#
|
9
9
|
module GemPins
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
class << self
|
11
|
+
include Logging
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param pins [Array<Pin::Base>]
|
15
|
+
# @return [Array<Pin::Base>]
|
16
|
+
def self.combine_method_pins_by_path(pins)
|
17
|
+
method_pins, alias_pins = pins.partition { |pin| pin.class == Pin::Method }
|
18
|
+
by_path = method_pins.group_by(&:path)
|
19
|
+
by_path.transform_values! do |pins|
|
20
|
+
GemPins.combine_method_pins(*pins)
|
21
|
+
end
|
22
|
+
by_path.values + alias_pins
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param pins [Array<Pin::Method>]
|
26
|
+
# @return [Pin::Method, nil]
|
27
|
+
def self.combine_method_pins(*pins)
|
28
|
+
# @type [Pin::Method, nil]
|
29
|
+
combined_pin = nil
|
30
|
+
out = pins.reduce(combined_pin) do |memo, pin|
|
31
|
+
next pin if memo.nil?
|
32
|
+
if memo == pin && memo.source != :combined
|
33
|
+
# @todo we should track down situations where we are handled
|
34
|
+
# the same pin from the same source here and eliminate them -
|
35
|
+
# this is an efficiency workaround for now
|
36
|
+
next memo
|
37
|
+
end
|
38
|
+
memo.combine_with(pin)
|
39
|
+
end
|
40
|
+
logger.debug { "GemPins.combine_method_pins(pins.length=#{pins.length}, pins=#{pins}) => #{out.inspect}" }
|
41
|
+
out
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param yard_plugins [Array<String>] The names of YARD plugins to use.
|
14
45
|
# @param gemspec [Gem::Specification]
|
15
46
|
# @return [Array<Pin::Base>]
|
16
|
-
def self.
|
17
|
-
|
18
|
-
|
19
|
-
|
47
|
+
def self.build_yard_pins(yard_plugins, gemspec)
|
48
|
+
Yardoc.cache(yard_plugins, gemspec) unless Yardoc.cached?(gemspec)
|
49
|
+
yardoc = Yardoc.load!(gemspec)
|
50
|
+
YardMap::Mapper.new(yardoc, gemspec).map
|
20
51
|
end
|
21
52
|
|
22
53
|
# @param yard_pins [Array<Pin::Base>]
|
23
|
-
# @param
|
54
|
+
# @param rbs_pins [Array<Pin::Base>]
|
55
|
+
#
|
24
56
|
# @return [Array<Pin::Base>]
|
25
|
-
def self.combine(yard_pins,
|
57
|
+
def self.combine(yard_pins, rbs_pins)
|
26
58
|
in_yard = Set.new
|
27
|
-
|
28
|
-
|
29
|
-
|
59
|
+
rbs_api_map = Solargraph::ApiMap.new(pins: rbs_pins)
|
60
|
+
combined = yard_pins.map do |yard_pin|
|
61
|
+
in_yard.add yard_pin.path
|
62
|
+
rbs_pin = rbs_api_map.get_path_pins(yard_pin.path).filter { |pin| pin.is_a? Pin::Method }.first
|
63
|
+
next yard_pin unless rbs_pin && yard_pin.class == Pin::Method
|
30
64
|
|
31
|
-
|
32
|
-
|
65
|
+
unless rbs_pin
|
66
|
+
logger.debug { "GemPins.combine: No rbs pin for #{yard_pin.path} - using YARD's '#{yard_pin.inspect} (return_type=#{yard_pin.return_type}; signatures=#{yard_pin.signatures})" }
|
67
|
+
next yard_pin
|
68
|
+
end
|
33
69
|
|
34
|
-
|
35
|
-
yard.
|
36
|
-
|
37
|
-
closure: yard.closure,
|
38
|
-
name: yard.name,
|
39
|
-
comments: yard.comments,
|
40
|
-
scope: yard.scope,
|
41
|
-
parameters: rbs.parameters,
|
42
|
-
generics: rbs.generics,
|
43
|
-
node: yard.node,
|
44
|
-
signatures: yard.signatures,
|
45
|
-
return_type: best_return_type(rbs.return_type, yard.return_type)
|
46
|
-
)
|
70
|
+
out = combine_method_pins(rbs_pin, yard_pin)
|
71
|
+
logger.debug { "GemPins.combine: Combining yard.path=#{yard_pin.path} - rbs=#{rbs_pin.inspect} with yard=#{yard_pin.inspect} into #{out}" }
|
72
|
+
out
|
47
73
|
end
|
48
|
-
|
49
|
-
|
74
|
+
in_rbs_only = rbs_pins.select do |pin|
|
75
|
+
pin.path.nil? || !in_yard.include?(pin.path)
|
76
|
+
end
|
77
|
+
out = combined + in_rbs_only
|
78
|
+
logger.debug { "GemPins#combine: Returning #{out.length} combined pins" }
|
79
|
+
out
|
50
80
|
end
|
51
81
|
|
52
82
|
class << self
|
53
83
|
private
|
54
84
|
|
55
|
-
# @param gemspec [Gem::Specification]
|
56
|
-
# @return [Array<Pin::Base>]
|
57
|
-
def build_yard_pins(gemspec)
|
58
|
-
Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
|
59
|
-
yardoc = Yardoc.load!(gemspec)
|
60
|
-
YardMap::Mapper.new(yardoc, gemspec).map
|
61
|
-
end
|
62
|
-
|
63
85
|
# Select the first defined type.
|
64
86
|
#
|
65
87
|
# @param choices [Array<ComplexType>]
|
@@ -95,6 +95,7 @@ module Solargraph
|
|
95
95
|
nil
|
96
96
|
end
|
97
97
|
|
98
|
+
# @return [Hash{String => undefined}]
|
98
99
|
def options
|
99
100
|
@options ||= {}.freeze
|
100
101
|
end
|
@@ -118,6 +119,7 @@ module Solargraph
|
|
118
119
|
end
|
119
120
|
|
120
121
|
# @param library [Solargraph::Library]
|
122
|
+
# @param progress [Solargraph::LanguageServer::Progress, nil]
|
121
123
|
# @return [void]
|
122
124
|
def update progress
|
123
125
|
progress&.send(self)
|