solargraph 0.60.4 → 0.62.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 +24 -2
- data/.github/workflows/plugins.yml +19 -1
- data/.github/workflows/rspec.yml +17 -2
- data/.github/workflows/typecheck.yml +6 -0
- data/CHANGELOG.md +54 -0
- data/Gemfile +0 -3
- data/lib/solargraph/api_map/index.rb +28 -4
- data/lib/solargraph/api_map/store.rb +19 -0
- data/lib/solargraph/api_map.rb +91 -80
- data/lib/solargraph/cache_dir.rb +58 -0
- data/lib/solargraph/collection/base.rb +50 -0
- data/lib/solargraph/collection/core.rb +17 -0
- data/lib/solargraph/collection/gem.rb +59 -0
- data/lib/solargraph/collection/stdlib.rb +25 -0
- data/lib/solargraph/collection.rb +30 -0
- data/lib/solargraph/complex_type/unique_type.rb +13 -0
- data/lib/solargraph/complex_type.rb +23 -3
- data/lib/solargraph/convention.rb +5 -7
- data/lib/solargraph/diagnostics/require_not_found.rb +0 -4
- data/lib/solargraph/diagnostics/type_check.rb +0 -1
- data/lib/solargraph/external.rb +187 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
- data/lib/solargraph/language_server/host/dispatch.rb +4 -2
- data/lib/solargraph/language_server/host.rb +10 -2
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +10 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +5 -2
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -2
- data/lib/solargraph/library.rb +26 -53
- data/lib/solargraph/metagem.rb +80 -0
- data/lib/solargraph/parser/node_processor/base.rb +6 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +22 -3
- data/lib/solargraph/parser/parser_gem/node_methods.rb +29 -6
- data/lib/solargraph/parser/parser_gem/node_processors/class_definition/class_assignment_node.rb +98 -0
- data/lib/solargraph/parser/parser_gem/node_processors/class_definition.rb +54 -0
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/data_definition/data_assignment_node.rb +65 -0
- data/lib/solargraph/parser/parser_gem/node_processors/data_definition/data_definition_node.rb +97 -0
- data/lib/solargraph/parser/parser_gem/node_processors/data_definition.rb +110 -0
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +185 -0
- data/lib/solargraph/parser/parser_gem/node_processors/struct_definition/struct_assignment_node.rb +66 -0
- data/lib/solargraph/parser/parser_gem/node_processors/struct_definition/struct_definition_node.rb +108 -0
- data/lib/solargraph/parser/parser_gem/node_processors/struct_definition.rb +170 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +33 -29
- data/lib/solargraph/pin/base.rb +25 -1
- data/lib/solargraph/pin/base_variable.rb +31 -1
- data/lib/solargraph/pin/callable.rb +11 -2
- data/lib/solargraph/pin/closure.rb +17 -0
- data/lib/solargraph/pin/delegated_method.rb +5 -0
- data/lib/solargraph/pin/duck_method.rb +36 -16
- data/lib/solargraph/pin/factory_parameter.rb +84 -0
- data/lib/solargraph/pin/instance_variable.rb +45 -0
- data/lib/solargraph/pin/method.rb +10 -0
- data/lib/solargraph/pin/method_alias.rb +4 -0
- data/lib/solargraph/pin/parameter.rb +1 -1
- data/lib/solargraph/pin/reference/included_mixin.rb +22 -0
- data/lib/solargraph/pin/reference.rb +1 -0
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/plugin/active_support.rb +100 -0
- data/lib/solargraph/plugin/addon.rb +16 -0
- data/lib/solargraph/plugin/base.rb +25 -0
- data/lib/solargraph/plugin/panel.rb +37 -0
- data/lib/solargraph/plugin.rb +26 -0
- data/lib/solargraph/rbs_collection.rb +119 -0
- data/lib/solargraph/rbs_map/base.rb +31 -0
- data/lib/solargraph/rbs_map/conversions.rb +109 -48
- data/lib/solargraph/rbs_map/{core_map.rb → core.rb} +18 -39
- data/lib/solargraph/rbs_map/core_fills.rb +1 -1
- data/lib/solargraph/rbs_map/gem.rb +16 -0
- data/lib/solargraph/rbs_map/helpers.rb +61 -0
- data/lib/solargraph/rbs_map/path.rb +19 -0
- data/lib/solargraph/rbs_map/stdlib.rb +24 -0
- data/lib/solargraph/rbs_map.rb +7 -198
- data/lib/solargraph/rbs_translator.rb +105 -70
- data/lib/solargraph/repo.rb +177 -0
- data/lib/solargraph/shell.rb +49 -99
- data/lib/solargraph/source/chain/call.rb +58 -14
- data/lib/solargraph/source/chain/literal.rb +17 -17
- data/lib/solargraph/source/chain/parameter.rb +79 -0
- data/lib/solargraph/source/chain.rb +8 -0
- data/lib/solargraph/source/node_map.rb +27 -0
- data/lib/solargraph/source/source_chainer.rb +40 -44
- data/lib/solargraph/source.rb +17 -0
- data/lib/solargraph/source_map/call.rb +18 -0
- data/lib/solargraph/source_map/clip.rb +5 -3
- data/lib/solargraph/source_map/mapper.rb +6 -2
- data/lib/solargraph/source_map.rb +28 -9
- data/lib/solargraph/type_checker/rules.rb +3 -2
- data/lib/solargraph/type_checker.rb +4 -1
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +0 -1
- data/lib/solargraph/yard_map/cache.rb +1 -1
- data/lib/solargraph/yard_map/directives/attribute_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/domain_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/method_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/override_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/parse_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/scope_directive.rb +178 -0
- data/lib/solargraph/yard_map/directives/visibility_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives.rb +5 -2
- data/lib/solargraph/yard_map/helpers.rb +1 -1
- data/lib/solargraph/yard_map/macro.rb +85 -6
- data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -1
- data/lib/solargraph/yard_map/mapper.rb +2 -2
- data/lib/solargraph/yard_map.rb +1 -1
- data/lib/solargraph/yardoc.rb +43 -60
- data/lib/solargraph.rb +8 -3
- data/rbs/fills/boolean/0/boolean.rbs +12 -0
- data/solargraph.gemspec +2 -2
- metadata +41 -18
- data/lib/solargraph/convention/active_support_concern.rb +0 -111
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +0 -61
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +0 -93
- data/lib/solargraph/convention/data_definition.rb +0 -108
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +0 -62
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +0 -103
- data/lib/solargraph/convention/struct_definition.rb +0 -168
- data/lib/solargraph/doc_map.rb +0 -439
- data/lib/solargraph/gem_pins.rb +0 -87
- data/lib/solargraph/pin_cache.rb +0 -248
- data/lib/solargraph/rbs_map/stdlib_map.rb +0 -71
- data/lib/solargraph/workspace/gemspecs.rb +0 -373
data/lib/solargraph/rbs_map.rb
CHANGED
|
@@ -1,207 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'digest'
|
|
4
|
-
require 'pathname'
|
|
5
3
|
require 'rbs'
|
|
6
4
|
|
|
7
5
|
module Solargraph
|
|
8
|
-
|
|
6
|
+
module RbsMap
|
|
7
|
+
autoload :Base, 'solargraph/rbs_map/base'
|
|
9
8
|
autoload :Conversions, 'solargraph/rbs_map/conversions'
|
|
10
|
-
autoload :
|
|
9
|
+
autoload :Core, 'solargraph/rbs_map/core'
|
|
11
10
|
autoload :CoreFills, 'solargraph/rbs_map/core_fills'
|
|
12
|
-
autoload :
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# @type [Hash{String => RbsMap}]
|
|
17
|
-
@@rbs_maps_hash = {}
|
|
18
|
-
|
|
19
|
-
attr_reader :library, :rbs_collection_paths, :rbs_collection_config_path
|
|
20
|
-
|
|
21
|
-
# @param library [String]
|
|
22
|
-
# @param version [String, nil]
|
|
23
|
-
# @param rbs_collection_config_path [String, Pathname, nil]
|
|
24
|
-
# @param rbs_collection_paths [Array<Pathname, String>]
|
|
25
|
-
# @param out [StringIO, IO, nil] where to log messages
|
|
26
|
-
def initialize library, version = nil, rbs_collection_config_path: nil, rbs_collection_paths: [], out: $stderr
|
|
27
|
-
if rbs_collection_config_path.nil? && !rbs_collection_paths.empty?
|
|
28
|
-
raise 'Please provide rbs_collection_config_path if you provide rbs_collection_paths'
|
|
29
|
-
end
|
|
30
|
-
@library = library
|
|
31
|
-
@version = version
|
|
32
|
-
@rbs_collection_config_path = rbs_collection_config_path
|
|
33
|
-
@rbs_collection_paths = rbs_collection_paths
|
|
34
|
-
add_library loader, library, version
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
CACHE_KEY_GEM_EXPORT = 'gem-export'
|
|
38
|
-
CACHE_KEY_UNRESOLVED = 'unresolved'
|
|
39
|
-
CACHE_KEY_STDLIB = 'stdlib'
|
|
40
|
-
CACHE_KEY_LOCAL = 'local'
|
|
41
|
-
|
|
42
|
-
# @param cache_key [String, nil]
|
|
43
|
-
# @return [String, nil] a description of the source of the RBS info
|
|
44
|
-
def self.rbs_source_desc cache_key
|
|
45
|
-
case cache_key
|
|
46
|
-
when CACHE_KEY_GEM_EXPORT
|
|
47
|
-
'RBS gem export'
|
|
48
|
-
when CACHE_KEY_UNRESOLVED
|
|
49
|
-
nil
|
|
50
|
-
when CACHE_KEY_STDLIB
|
|
51
|
-
'RBS standard library'
|
|
52
|
-
when CACHE_KEY_LOCAL
|
|
53
|
-
'local RBS shims'
|
|
54
|
-
else
|
|
55
|
-
'RBS collection'
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# @return [RBS::EnvironmentLoader]
|
|
60
|
-
def loader
|
|
61
|
-
@loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# @return [String] representing the version of the RBS info fetched
|
|
65
|
-
# for the given library. Must change when the RBS info is
|
|
66
|
-
# updated upstream for the same library and version. May change
|
|
67
|
-
# if the config for where information comes form changes.
|
|
68
|
-
def cache_key
|
|
69
|
-
return CACHE_KEY_UNRESOLVED unless resolved?
|
|
70
|
-
|
|
71
|
-
@cache_key ||= begin
|
|
72
|
-
# @type [String, nil]
|
|
73
|
-
data = nil
|
|
74
|
-
# @type gem_config [nil, Hash{String => Hash{String => String}}]
|
|
75
|
-
gem_config = nil
|
|
76
|
-
if rbs_collection_config_path
|
|
77
|
-
# @sg-ignore rbs_collection_config_path is not nil here
|
|
78
|
-
lockfile_path = RBS::Collection::Config.to_lockfile_path(Pathname.new(rbs_collection_config_path))
|
|
79
|
-
if lockfile_path.exist?
|
|
80
|
-
collection_config = RBS::Collection::Config.from_path lockfile_path
|
|
81
|
-
gem_config = collection_config.gem(library)
|
|
82
|
-
data = gem_config&.to_s
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
if gem_config.nil?
|
|
86
|
-
CACHE_KEY_STDLIB
|
|
87
|
-
else
|
|
88
|
-
# @type [String]
|
|
89
|
-
source = gem_config.dig('source', 'type')
|
|
90
|
-
case source
|
|
91
|
-
when 'rubygems'
|
|
92
|
-
CACHE_KEY_GEM_EXPORT
|
|
93
|
-
when 'local'
|
|
94
|
-
CACHE_KEY_LOCAL
|
|
95
|
-
when 'stdlib'
|
|
96
|
-
CACHE_KEY_STDLIB
|
|
97
|
-
else
|
|
98
|
-
Digest::SHA1.hexdigest(data || '')
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# @param gemspec [Gem::Specification, Bundler::LazySpecification]
|
|
105
|
-
# @param rbs_collection_path [String, Pathname, nil]
|
|
106
|
-
# @param rbs_collection_config_path [String, Pathname, nil]
|
|
107
|
-
# @return [RbsMap]
|
|
108
|
-
def self.from_gemspec gemspec, rbs_collection_path, rbs_collection_config_path
|
|
109
|
-
# prefers stdlib RBS if available
|
|
110
|
-
rbs_map = RbsMap::StdlibMap.new(gemspec.name)
|
|
111
|
-
return rbs_map if rbs_map.resolved?
|
|
112
|
-
|
|
113
|
-
rbs_map = RbsMap.new(gemspec.name, gemspec.version,
|
|
114
|
-
rbs_collection_paths: [rbs_collection_path].compact,
|
|
115
|
-
rbs_collection_config_path: rbs_collection_config_path)
|
|
116
|
-
return rbs_map if rbs_map.resolved?
|
|
117
|
-
|
|
118
|
-
# try any version of the gem in the collection
|
|
119
|
-
RbsMap.new(gemspec.name, nil,
|
|
120
|
-
rbs_collection_paths: [rbs_collection_path].compact,
|
|
121
|
-
rbs_collection_config_path: rbs_collection_config_path)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# @param out [IO, nil] where to log messages
|
|
125
|
-
# @return [Array<Pin::Base>]
|
|
126
|
-
def pins out: $stderr
|
|
127
|
-
@pins ||= if resolved?
|
|
128
|
-
conversions.pins
|
|
129
|
-
else
|
|
130
|
-
[]
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# @generic T
|
|
135
|
-
# @param path [String]
|
|
136
|
-
# @param klass [Class<generic<T>>]
|
|
137
|
-
#
|
|
138
|
-
# @sg-ignore Need to be able to resolve generics based on a
|
|
139
|
-
# Class<generic<T>> param
|
|
140
|
-
# @return [generic<T>, nil]
|
|
141
|
-
def path_pin path, klass = Pin::Base
|
|
142
|
-
pin = pins.find { |p| p.path == path }
|
|
143
|
-
pin if pin.is_a?(klass)
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
# @param path [String]
|
|
147
|
-
# @return [Array<Pin::Base>]
|
|
148
|
-
def path_pins path
|
|
149
|
-
pins.select { |p| p.path == path }
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def resolved?
|
|
153
|
-
@resolved
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# @return [RBS::Repository]
|
|
157
|
-
def repository
|
|
158
|
-
@repository ||= RBS::Repository.new(no_stdlib: false).tap do |repo|
|
|
159
|
-
@rbs_collection_paths.each do |dir|
|
|
160
|
-
dir_path = Pathname.new(dir)
|
|
161
|
-
repo.add(dir_path) if dir_path.exist? && dir_path.directory?
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
# @param library [String]
|
|
167
|
-
# @return [RbsMap]
|
|
168
|
-
def self.load library
|
|
169
|
-
@@rbs_maps_hash[library] ||= RbsMap.new(library)
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
private
|
|
173
|
-
|
|
174
|
-
# @return [Conversions]
|
|
175
|
-
def conversions
|
|
176
|
-
@conversions ||= Conversions.new(loader: loader)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def resolve_dependencies?
|
|
180
|
-
# we need to resolve dependencies via gemfile.lock manually for
|
|
181
|
-
# YARD regardless, so use same mechanism here so we don't
|
|
182
|
-
# duplicate work generating pins from dependencies
|
|
183
|
-
false
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
# @param loader [RBS::EnvironmentLoader]
|
|
187
|
-
# @param library [String]
|
|
188
|
-
# @param version [String, nil] the version of the library to load, or nil for any
|
|
189
|
-
# @param out [StringIO, IO, nil] where to log messages
|
|
190
|
-
# @return [Boolean] true if adding the library succeeded
|
|
191
|
-
def add_library loader, library, version, out: $stderr
|
|
192
|
-
@resolved = if loader.has_library?(library: library, version: version)
|
|
193
|
-
loader.add library: library, version: version, resolve_dependencies: resolve_dependencies?
|
|
194
|
-
logger.debug { "#{short_name} successfully loaded library #{library}:#{version}" }
|
|
195
|
-
true
|
|
196
|
-
else
|
|
197
|
-
logger.info { "#{short_name} did not find data for library #{library}:#{version}" }
|
|
198
|
-
false
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# @return [String]
|
|
203
|
-
def short_name
|
|
204
|
-
self.class.name.split('::').last
|
|
205
|
-
end
|
|
11
|
+
autoload :Gem, 'solargraph/rbs_map/gem'
|
|
12
|
+
autoload :Helpers, 'solargraph/rbs_map/helpers'
|
|
13
|
+
autoload :Path, 'solargraph/rbs_map/path'
|
|
14
|
+
autoload :Stdlib, 'solargraph/rbs_map/stdlib'
|
|
206
15
|
end
|
|
207
16
|
end
|
|
@@ -10,36 +10,43 @@ module Solargraph
|
|
|
10
10
|
'int' => 'Integer',
|
|
11
11
|
'untyped' => '',
|
|
12
12
|
'NilClass' => 'nil'
|
|
13
|
-
}
|
|
13
|
+
}.freeze
|
|
14
14
|
|
|
15
|
-
#
|
|
15
|
+
# Relative type names (e.g. `Bar` in an inline `#: () -> Bar`) stay
|
|
16
|
+
# unrooted so they resolve against the pin's namespace like YARD tags
|
|
17
|
+
# do. Absolute names (`::Bar`, or any name from an RBS environment
|
|
18
|
+
# after `resolve_type_names`) and RBS builtins stay rooted.
|
|
19
|
+
#
|
|
20
|
+
# @param type [RBS::Types::t]
|
|
21
|
+
# @param type_alias_decls [Hash{String => RBS::AST::Declarations::TypeAlias}]
|
|
16
22
|
# @return [ComplexType]
|
|
17
|
-
def self.to_complex_type
|
|
18
|
-
|
|
19
|
-
ComplexType.try_parse(tag).force_rooted
|
|
23
|
+
def self.to_complex_type type, type_alias_decls: {}
|
|
24
|
+
ComplexType.try_parse(type_to_tag(type, type_alias_decls))
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
# @param param_type [RBS::Types::Function::Param]
|
|
23
28
|
# @param name [String]
|
|
24
29
|
# @param decl [Symbol]
|
|
25
30
|
# @param closure [Pin::Closure]
|
|
31
|
+
# @param type_alias_decls [Hash{String => RBS::AST::Declarations::TypeAlias}]
|
|
26
32
|
# @return [Pin::Parameter]
|
|
27
|
-
def self.to_parameter_pin
|
|
33
|
+
def self.to_parameter_pin param_type, name, decl, closure, type_alias_decls: {}
|
|
28
34
|
return_type = if decl == :restarg
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
ComplexType.parse('Array')
|
|
36
|
+
elsif decl == :kwrestarg
|
|
37
|
+
ComplexType.parse('Hash{Symbol => Object}')
|
|
38
|
+
else
|
|
39
|
+
RbsTranslator.to_complex_type(param_type.type, type_alias_decls: type_alias_decls)
|
|
40
|
+
end
|
|
35
41
|
Solargraph::Pin::Parameter.new(decl: decl, name: name, closure: closure, return_type: return_type, source: :rbs, type_location: to_sg_location(param_type.location) || closure.type_location)
|
|
36
42
|
end
|
|
37
43
|
|
|
38
|
-
# @param method_type [RBS::MethodType]
|
|
44
|
+
# @param method_type [RBS::MethodType, RBS::Types::Block]
|
|
39
45
|
# @param closure [Pin::Closure]
|
|
40
46
|
# @param parameter_names [Array<String>]
|
|
47
|
+
# @param type_alias_decls [Hash{String => RBS::AST::Declarations::TypeAlias}]
|
|
41
48
|
# @return [Array<Pin::Parameter>]
|
|
42
|
-
def self.to_parameter_pins method_type, closure, parameter_names = []
|
|
49
|
+
def self.to_parameter_pins method_type, closure, parameter_names = [], type_alias_decls: {}
|
|
43
50
|
if defined?(RBS::Types::UntypedFunction) && method_type.type.is_a?(RBS::Types::UntypedFunction)
|
|
44
51
|
return [
|
|
45
52
|
Solargraph::Pin::Parameter.new(decl: :restarg, name: 'arg', closure: closure, source: :rbs)
|
|
@@ -49,27 +56,37 @@ module Solargraph
|
|
|
49
56
|
arg_num = 0
|
|
50
57
|
params = []
|
|
51
58
|
method_type.type.required_positionals.each do |param|
|
|
52
|
-
|
|
59
|
+
# @sg-ignore Unresolved call to name on RBS::Types::Function::Param
|
|
60
|
+
params.push RbsTranslator.to_parameter_pin(param, param.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}", :arg, closure, type_alias_decls: type_alias_decls)
|
|
53
61
|
arg_num += 1
|
|
54
62
|
end
|
|
55
63
|
method_type.type.optional_positionals.each do |param|
|
|
56
|
-
|
|
64
|
+
# @sg-ignore Unresolved call to name on RBS::Types::Function::Param
|
|
65
|
+
params.push RbsTranslator.to_parameter_pin(param, param.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}", :optarg, closure, type_alias_decls: type_alias_decls)
|
|
57
66
|
arg_num += 1
|
|
58
67
|
end
|
|
59
68
|
if method_type.type.rest_positionals
|
|
60
|
-
|
|
69
|
+
rest_positionals = method_type.type.rest_positionals
|
|
70
|
+
# @sg-ignore Unresolved call to name on RBS::Types::Function::Param
|
|
71
|
+
rest_name = rest_positionals.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}"
|
|
72
|
+
params.push RbsTranslator.to_parameter_pin(rest_positionals, rest_name, :restarg, closure, type_alias_decls: type_alias_decls)
|
|
61
73
|
arg_num += 1
|
|
62
74
|
end
|
|
63
75
|
method_type.type.required_keywords.each do |param|
|
|
64
|
-
|
|
76
|
+
# @sg-ignore Unresolved calls to last, first on generic<D>
|
|
77
|
+
params.push RbsTranslator.to_parameter_pin(param.last, param.first.to_s, :kwarg, closure, type_alias_decls: type_alias_decls)
|
|
65
78
|
arg_num += 1
|
|
66
79
|
end
|
|
67
80
|
method_type.type.optional_keywords.each do |param|
|
|
68
|
-
|
|
81
|
+
# @sg-ignore Unresolved calls to last, first on generic<D>
|
|
82
|
+
params.push RbsTranslator.to_parameter_pin(param.last, param.first.to_s, :kwoptarg, closure, type_alias_decls: type_alias_decls)
|
|
69
83
|
arg_num += 1
|
|
70
84
|
end
|
|
71
85
|
if method_type.type.rest_keywords
|
|
72
|
-
|
|
86
|
+
rest_keywords = method_type.type.rest_keywords
|
|
87
|
+
# @sg-ignore Unresolved call to name on RBS::Types::Function::Param
|
|
88
|
+
rest_keywords_name = rest_keywords.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}"
|
|
89
|
+
params.push RbsTranslator.to_parameter_pin(rest_keywords, rest_keywords_name, :kwrestarg, closure, type_alias_decls: type_alias_decls)
|
|
73
90
|
end
|
|
74
91
|
params
|
|
75
92
|
end
|
|
@@ -77,41 +94,29 @@ module Solargraph
|
|
|
77
94
|
# @param method_type [RBS::MethodType]
|
|
78
95
|
# @param closure [Pin::Closure]
|
|
79
96
|
# @param parameter_names [Array<String>]
|
|
97
|
+
# @param type_alias_decls [Hash{String => RBS::AST::Declarations::TypeAlias}]
|
|
80
98
|
# @return [Pin::Signature]
|
|
81
|
-
def self.to_signature method_type, closure, parameter_names = []
|
|
99
|
+
def self.to_signature method_type, closure, parameter_names = [], type_alias_decls: {}
|
|
82
100
|
# There may be edge cases here around different signatures
|
|
83
101
|
# having different type params / orders - we may need to match
|
|
84
102
|
# this data model and have generics live in signatures to
|
|
85
103
|
# handle those correctly
|
|
86
104
|
generics = method_type.type_params.map(&:name).map(&:to_s).uniq
|
|
87
|
-
parameters = to_parameter_pins(method_type, closure, parameter_names)
|
|
88
|
-
return_type = to_complex_type(method_type.type.return_type)
|
|
105
|
+
parameters = to_parameter_pins(method_type, closure, parameter_names, type_alias_decls: type_alias_decls)
|
|
106
|
+
return_type = to_complex_type(method_type.type.return_type, type_alias_decls: type_alias_decls)
|
|
89
107
|
block = if method_type.block
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
# @param type_name [RBS::TypeName]
|
|
98
|
-
# @param type_args [Enumerable<RBS::Types::Bases::Base>]
|
|
99
|
-
# @return [ComplexType::UniqueType]
|
|
100
|
-
def self.build_unique_type(type_name, type_args = [])
|
|
101
|
-
base = RBS_TO_YARD_TYPE[type_name.relative!.to_s] || type_name.relative!.to_s
|
|
102
|
-
params = type_args.map do |a|
|
|
103
|
-
RbsTranslator.to_complex_type(a)
|
|
104
|
-
end
|
|
105
|
-
if base == 'Hash' && params.length == 2
|
|
106
|
-
ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: true, parameters_type: :hash)
|
|
107
|
-
else
|
|
108
|
-
ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: true, parameters_type: :list)
|
|
109
|
-
end
|
|
108
|
+
# @sg-ignore https://github.com/castwide/solargraph/issues/1249
|
|
109
|
+
block_parameters = to_parameter_pins(method_type.block, closure, type_alias_decls: type_alias_decls)
|
|
110
|
+
block_return_type = to_complex_type(method_type.block.type.return_type, type_alias_decls: type_alias_decls)
|
|
111
|
+
Pin::Signature.new(generics: generics, parameters: block_parameters, return_type: block_return_type, source: :rbs, type_location: closure.location, closure: closure)
|
|
112
|
+
end
|
|
113
|
+
Pin::Signature.new(generics: generics, parameters: parameters, return_type: return_type, block: block,
|
|
114
|
+
block_required: method_type.block&.required || false, source: :rbs, type_location: closure.location, closure: closure)
|
|
110
115
|
end
|
|
111
116
|
|
|
112
117
|
# @param location [RBS::Location, nil]
|
|
113
118
|
# @return [Solargraph::Location, nil]
|
|
114
|
-
def self.to_sg_location
|
|
119
|
+
def self.to_sg_location location
|
|
115
120
|
return nil if location&.name.nil?
|
|
116
121
|
|
|
117
122
|
start_pos = Position.new(location.start_line - 1, location.start_column)
|
|
@@ -123,50 +128,74 @@ module Solargraph
|
|
|
123
128
|
class << self
|
|
124
129
|
private
|
|
125
130
|
|
|
126
|
-
# @param type [RBS::Types::
|
|
131
|
+
# @param type [RBS::Types::t]
|
|
132
|
+
# @param type_alias_decls [Hash{String => RBS::AST::Declarations::TypeAlias}]
|
|
133
|
+
# @param expanding_aliases [Array<String>] Names of aliases already
|
|
134
|
+
# being expanded in this call chain, to detect recursive aliases
|
|
127
135
|
# @return [String]
|
|
128
|
-
def type_to_tag type
|
|
136
|
+
def type_to_tag type, type_alias_decls = {}, expanding_aliases = []
|
|
129
137
|
case type
|
|
130
138
|
when RBS::Types::Optional
|
|
131
|
-
|
|
139
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
140
|
+
"#{type_to_tag(type.type, type_alias_decls, expanding_aliases)}, nil"
|
|
132
141
|
when RBS::Types::Bases::Bool
|
|
133
|
-
'Boolean'
|
|
142
|
+
'::Boolean'
|
|
134
143
|
when RBS::Types::Tuple
|
|
135
|
-
|
|
144
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
145
|
+
"::Array(#{type.types.map { |t| type_to_tag(t, type_alias_decls, expanding_aliases) }.join(', ')})"
|
|
136
146
|
when RBS::Types::Literal
|
|
147
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
137
148
|
type.literal.inspect
|
|
138
149
|
when RBS::Types::Union
|
|
139
|
-
|
|
150
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
151
|
+
type.types.map { |t| type_to_tag(t, type_alias_decls, expanding_aliases) }.join(', ')
|
|
140
152
|
when RBS::Types::Record
|
|
141
153
|
# @todo Better record support
|
|
142
|
-
'Hash'
|
|
154
|
+
'::Hash'
|
|
143
155
|
when RBS::Types::Bases::Nil
|
|
144
156
|
'nil'
|
|
145
157
|
when RBS::Types::Bases::Void
|
|
146
158
|
'void'
|
|
147
159
|
when RBS::Types::Variable
|
|
160
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
148
161
|
"#{Solargraph::ComplexType::GENERIC_TAG_NAME}<#{type.name}>"
|
|
149
162
|
when RBS::Types::Bases::Self, RBS::Types::Bases::Instance
|
|
150
163
|
'self'
|
|
151
164
|
when RBS::Types::Bases::Top
|
|
152
165
|
# `Top` is the most super superclass
|
|
153
|
-
'BasicObject'
|
|
166
|
+
'::BasicObject'
|
|
154
167
|
when RBS::Types::Intersection
|
|
155
|
-
|
|
168
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
169
|
+
type.types.map { |member| type_to_tag(member, type_alias_decls, expanding_aliases) }.join(', ')
|
|
156
170
|
when RBS::Types::Proc
|
|
157
|
-
'Proc'
|
|
158
|
-
when RBS::Types::
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
|
|
171
|
+
'::Proc'
|
|
172
|
+
when RBS::Types::Alias
|
|
173
|
+
# Expand so conformance checks see the members, not the name. A
|
|
174
|
+
# generic alias falls back: args are not substituted, so expanding
|
|
175
|
+
# would leak an unbound generic<T>.
|
|
176
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
177
|
+
alias_name = type.name.to_s
|
|
178
|
+
alias_decl = type_alias_decls[alias_name]
|
|
179
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
180
|
+
if alias_decl.nil? || expanding_aliases.include?(alias_name) || !type.args.empty?
|
|
181
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
182
|
+
type_tag(type.name, type.args, type_alias_decls, expanding_aliases)
|
|
183
|
+
else
|
|
184
|
+
# The alias body belongs to the alias's declaration, not the
|
|
185
|
+
# use site, so its names stay rooted even when a core-less
|
|
186
|
+
# environment left them relative.
|
|
187
|
+
expanded = type_to_tag(alias_decl.type, type_alias_decls, expanding_aliases + [alias_name])
|
|
188
|
+
ComplexType.try_parse(expanded).force_rooted.rooted_tags
|
|
189
|
+
end
|
|
190
|
+
when RBS::Types::ClassInstance, RBS::Types::Interface
|
|
191
|
+
# `Interface` represents a mix-in module which can be considered a
|
|
164
192
|
# subtype of a consumer of it
|
|
165
|
-
#
|
|
166
|
-
type_tag(type.name, type.args)
|
|
193
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
194
|
+
type_tag(type.name, type.args, type_alias_decls, expanding_aliases)
|
|
167
195
|
when RBS::Types::ClassSingleton
|
|
168
196
|
# e.g., singleton(String)
|
|
169
|
-
|
|
197
|
+
# @sg-ignore flow sensitive typing should support case/when
|
|
198
|
+
type_tag(type.name, [], type_alias_decls, expanding_aliases)
|
|
170
199
|
when RBS::Types::Bases::Any, RBS::Types::Bases::Bottom
|
|
171
200
|
# `Bottom`` is used in contexts where nothing will ever return
|
|
172
201
|
# - e.g., it could be the return type of 'exit()' or 'raise'
|
|
@@ -182,23 +211,29 @@ module Solargraph
|
|
|
182
211
|
|
|
183
212
|
# @param type_name [RBS::TypeName]
|
|
184
213
|
# @param type_args [Enumerable<RBS::Types::Bases::Base>]
|
|
214
|
+
# @param type_alias_decls [Hash{String => RBS::AST::Declarations::TypeAlias}]
|
|
215
|
+
# @param expanding_aliases [Array<String>]
|
|
185
216
|
# @return [String]
|
|
186
|
-
def type_tag
|
|
187
|
-
build_type(type_name, type_args).
|
|
217
|
+
def type_tag type_name, type_args = [], type_alias_decls = {}, expanding_aliases = []
|
|
218
|
+
build_type(type_name, type_args, type_alias_decls, expanding_aliases).rooted_tags
|
|
188
219
|
end
|
|
189
220
|
|
|
190
221
|
# @param type_name [RBS::TypeName]
|
|
191
222
|
# @param type_args [Enumerable<RBS::Types::Bases::Base>]
|
|
223
|
+
# @param type_alias_decls [Hash{String => RBS::AST::Declarations::TypeAlias}]
|
|
224
|
+
# @param expanding_aliases [Array<String>]
|
|
192
225
|
# @return [ComplexType::UniqueType]
|
|
193
|
-
def build_type
|
|
194
|
-
|
|
195
|
-
|
|
226
|
+
def build_type type_name, type_args = [], type_alias_decls = {}, expanding_aliases = []
|
|
227
|
+
yard_base = RBS_TO_YARD_TYPE[type_name.relative!.to_s]
|
|
228
|
+
base = yard_base || type_name.relative!.to_s
|
|
229
|
+
rooted = !yard_base.nil? || type_name.absolute?
|
|
230
|
+
params = type_args.map { |a| type_to_tag(a, type_alias_decls, expanding_aliases) }.map do |t|
|
|
196
231
|
ComplexType.try_parse(t)
|
|
197
232
|
end
|
|
198
233
|
if base == 'Hash' && params.length == 2
|
|
199
|
-
ComplexType::UniqueType.new(base, [params.first], [params.last], rooted:
|
|
234
|
+
ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: rooted, parameters_type: :hash)
|
|
200
235
|
else
|
|
201
|
-
ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted:
|
|
236
|
+
ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: rooted, parameters_type: :list)
|
|
202
237
|
end
|
|
203
238
|
end
|
|
204
239
|
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Solargraph
|
|
7
|
+
# A repository for the gems available in the specified directory. If the
|
|
8
|
+
# directory has a Gemfile, Repo will use its gem definitions. Otherwise it
|
|
9
|
+
# uses the system gems.
|
|
10
|
+
#
|
|
11
|
+
class Repo
|
|
12
|
+
# @return [String, nil]
|
|
13
|
+
attr_reader :directory
|
|
14
|
+
|
|
15
|
+
# @param directory [String, nil]
|
|
16
|
+
def initialize directory
|
|
17
|
+
@directory = File.expand_path(directory) if directory
|
|
18
|
+
build_from_directory
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Find a metagem by path from the directory's bundle definition or the
|
|
22
|
+
# system gems.
|
|
23
|
+
#
|
|
24
|
+
# @param path [String]
|
|
25
|
+
# @return [Metagem, nil]
|
|
26
|
+
def find_by_path path
|
|
27
|
+
return system_find_by_path(path) unless bundled?
|
|
28
|
+
|
|
29
|
+
bundled_metagem_path_map[path]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Find a metagem by name from the directory's bundle definition or the
|
|
33
|
+
# system gems.
|
|
34
|
+
#
|
|
35
|
+
# @param name [String]
|
|
36
|
+
# @return [Metagem, nil]
|
|
37
|
+
def find_by_name name
|
|
38
|
+
return system_find_by_name(name) unless bundled?
|
|
39
|
+
|
|
40
|
+
bundled_metagem_name_map[name]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Get an array of metagems by its bundle group name. Returns an empty array
|
|
44
|
+
# if the repo isn't bundled or the group doesn't exist.
|
|
45
|
+
#
|
|
46
|
+
# @param group [Symbol]
|
|
47
|
+
# @return [Array<Metagem>]
|
|
48
|
+
def find_by_group group
|
|
49
|
+
return system_find_by_group(group) unless bundled?
|
|
50
|
+
|
|
51
|
+
bundled_group_map[group] || []
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# True if the directory has a bundle definition.
|
|
55
|
+
#
|
|
56
|
+
# @note If Solargraph itself is running in this directory's bundled
|
|
57
|
+
# environment, `bundled?` is false.
|
|
58
|
+
#
|
|
59
|
+
def bundled?
|
|
60
|
+
!!@metagems
|
|
61
|
+
end
|
|
62
|
+
alias bundle? bundled?
|
|
63
|
+
|
|
64
|
+
# Metagems from the directory's bundle definition, or an empty array if a
|
|
65
|
+
# bundle definition does not exist.
|
|
66
|
+
#
|
|
67
|
+
# @return [Array<Solargraph::Metagem>]
|
|
68
|
+
def bundled
|
|
69
|
+
@metagems || []
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# @return [String, nil]
|
|
75
|
+
def gemfile
|
|
76
|
+
@gemfile ||= File.expand_path('Gemfile', directory) if directory
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @return [String, nil]
|
|
80
|
+
def lockfile
|
|
81
|
+
@lockfile ||= File.expand_path('Gemfile.lock', directory) if directory
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def bundled_directory?
|
|
85
|
+
directory && File.file?(gemfile) && File.file?(lockfile)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Load metagems from the directory's bundle definition if available.
|
|
89
|
+
#
|
|
90
|
+
# This method performs gem collection in a separate process to suppress
|
|
91
|
+
# output from the `Bundler.definition.specs` call.
|
|
92
|
+
#
|
|
93
|
+
# @return [Array<Metagem>, nil]
|
|
94
|
+
def build_from_directory
|
|
95
|
+
return unless bundled_directory? && ENV['BUNDLE_GEMFILE'] != gemfile
|
|
96
|
+
|
|
97
|
+
Solargraph.with_clean_env do
|
|
98
|
+
cmd = ['ruby', '-e', bundle_script]
|
|
99
|
+
o, e, s = Open3.capture3(*cmd, chdir: directory)
|
|
100
|
+
if s.success?
|
|
101
|
+
json = o && !o.empty? ? JSON.parse(o.strip.split("\n").last, symbolize_names: true) : []
|
|
102
|
+
@metagems = json[:metagems].map { |data| Metagem.new(**data) }
|
|
103
|
+
@bundled_group_map = json[:groups].transform_values { |names| names.map { |name| bundled_metagem_name_map[name] } }
|
|
104
|
+
else
|
|
105
|
+
Solargraph.logger.warn "Failed to load gems from bundle at #{directory}: #{e}"
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def bundle_script
|
|
112
|
+
"
|
|
113
|
+
require 'bundler/setup'
|
|
114
|
+
require 'json'
|
|
115
|
+
|
|
116
|
+
puts Bundler.definition.specs.length
|
|
117
|
+
metagems = Bundler.definition.specs.map do |spec|
|
|
118
|
+
{
|
|
119
|
+
name: spec.name,
|
|
120
|
+
full_path: spec.full_gem_path,
|
|
121
|
+
spec_file: spec.spec_file,
|
|
122
|
+
source: spec.source.to_s,
|
|
123
|
+
version: spec.version,
|
|
124
|
+
require_paths: spec.require_paths,
|
|
125
|
+
dependencies: spec.runtime_dependencies.map(&:name)
|
|
126
|
+
}
|
|
127
|
+
end
|
|
128
|
+
groups = Bundler.definition.groups.to_h do |group|
|
|
129
|
+
[group, Bundler.definition.specs_for([group]).map(&:name)]
|
|
130
|
+
end
|
|
131
|
+
puts({ groups: groups, metagems: metagems }.to_json)
|
|
132
|
+
"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @param path [String]
|
|
136
|
+
# @return [Metagem, nil]
|
|
137
|
+
def system_find_by_path path
|
|
138
|
+
gem = Gem::Specification.find_by_path(path)
|
|
139
|
+
gem && Metagem.from_specification(gem)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @param name [String]
|
|
143
|
+
# @return [Metagem, nil]
|
|
144
|
+
def system_find_by_name name
|
|
145
|
+
gem = Gem::Specification.find_by_name(name)
|
|
146
|
+
gem && Metagem.from_specification(gem)
|
|
147
|
+
rescue Gem::MissingSpecError => _e
|
|
148
|
+
nil
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @param group [Symbol]
|
|
152
|
+
# @return [Array<Metagem>]
|
|
153
|
+
def system_find_by_group group
|
|
154
|
+
return [] unless ENV['BUNDLE_GEMFILE']
|
|
155
|
+
|
|
156
|
+
Bundler.definition
|
|
157
|
+
.specs_for([group])
|
|
158
|
+
.map { |spec| Metagem.from_specification(spec) }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def bundled_metagem_name_map
|
|
162
|
+
@bundled_metagem_name_map ||= bundled.to_set
|
|
163
|
+
.classify(&:name)
|
|
164
|
+
.transform_values(&:first)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def bundled_metagem_path_map
|
|
168
|
+
@bundled_metagem_path_map ||= Hash.new do |hash, path|
|
|
169
|
+
hash[path] = bundled.find { |mg| mg.require?(path) }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def bundled_group_map
|
|
174
|
+
@bundled_group_map ||= {}
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|