solargraph 0.61.0 → 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 +18 -0
- data/.github/workflows/rspec.yml +14 -1
- data/.github/workflows/typecheck.yml +6 -0
- data/CHANGELOG.md +38 -0
- data/lib/solargraph/api_map/index.rb +14 -3
- data/lib/solargraph/api_map/store.rb +6 -0
- data/lib/solargraph/api_map.rb +34 -2
- data/lib/solargraph/collection/gem.rb +12 -10
- data/lib/solargraph/collection.rb +0 -1
- data/lib/solargraph/complex_type/unique_type.rb +13 -0
- data/lib/solargraph/complex_type.rb +23 -3
- data/lib/solargraph/convention.rb +0 -4
- data/lib/solargraph/diagnostics/type_check.rb +0 -1
- data/lib/solargraph/external.rb +56 -28
- 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 +1 -1
- data/lib/solargraph/library.rb +19 -33
- data/lib/solargraph/parser/node_processor/base.rb +6 -0
- 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/delegated_method.rb +5 -0
- data/lib/solargraph/pin/duck_method.rb +36 -16
- 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/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/conversions.rb +106 -47
- data/lib/solargraph/rbs_map/gem.rb +4 -1
- data/lib/solargraph/rbs_map/helpers.rb +7 -6
- data/lib/solargraph/rbs_translator.rb +105 -70
- data/lib/solargraph/repo.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +32 -13
- data/lib/solargraph/source/node_map.rb +27 -0
- data/lib/solargraph/source.rb +17 -0
- data/lib/solargraph/source_map/call.rb +18 -0
- data/lib/solargraph/source_map/mapper.rb +1 -1
- data/lib/solargraph/source_map.rb +18 -4
- data/lib/solargraph/type_checker/rules.rb +2 -2
- data/lib/solargraph/type_checker.rb +4 -1
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map/macro.rb +51 -1
- data/lib/solargraph.rb +2 -0
- data/rbs/fills/boolean/0/boolean.rbs +12 -0
- data/solargraph.gemspec +1 -1
- metadata +21 -11
- data/lib/solargraph/collection/rbs.rb +0 -49
- 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
|
@@ -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
|
data/lib/solargraph/repo.rb
CHANGED
|
@@ -122,7 +122,7 @@ module Solargraph
|
|
|
122
122
|
source: spec.source.to_s,
|
|
123
123
|
version: spec.version,
|
|
124
124
|
require_paths: spec.require_paths,
|
|
125
|
-
dependencies: spec.
|
|
125
|
+
dependencies: spec.runtime_dependencies.map(&:name)
|
|
126
126
|
}
|
|
127
127
|
end
|
|
128
128
|
groups = Bundler.definition.groups.to_h do |group|
|
|
@@ -55,20 +55,39 @@ module Solargraph
|
|
|
55
55
|
# chain.rb#maybe_nil will add the nil type later, we just
|
|
56
56
|
# need to worry about the not-nil case
|
|
57
57
|
|
|
58
|
-
# @sg-ignore Need to handle duck-typed method calls on union types
|
|
59
58
|
binder = binder.without_nil if nullable?
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
# Resolve one unique type at a time, so a `self` return type narrows to the one that supplied the pin.
|
|
60
|
+
# @type [::Array<Pin::Base>]
|
|
61
|
+
resolved = []
|
|
62
|
+
unresolved_type = false
|
|
63
|
+
binder.each_unique_type do |context|
|
|
64
|
+
if context.duck_type? && context.name[1..] == word
|
|
65
|
+
# explicit: false skips arity checking; the duck type
|
|
66
|
+
# only tells us the method exists, not its signature
|
|
67
|
+
pin = Pin::DuckMethod.new(name: word, source: :chain, explicit: false)
|
|
68
|
+
else
|
|
69
|
+
ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
|
|
70
|
+
stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
|
|
71
|
+
pin = stack.first
|
|
72
|
+
end
|
|
73
|
+
if pin.nil?
|
|
74
|
+
unresolved_type = true
|
|
75
|
+
next
|
|
76
|
+
end
|
|
77
|
+
# Bind name_pin to this type alone, so #inferred_pins (incl. Class#new) cannot see the others.
|
|
78
|
+
type_name_pin = Pin::ProxyType.anonymous(name_pin.context,
|
|
79
|
+
closure: name_pin.closure,
|
|
80
|
+
gates: name_pin.gates,
|
|
81
|
+
binder: context,
|
|
82
|
+
source: :chain)
|
|
83
|
+
resolved.concat inferred_pins([pin], api_map, type_name_pin, locals)
|
|
65
84
|
end
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
return [] if unresolved_type && !api_map.loose_unions
|
|
86
|
+
return [] if resolved.empty?
|
|
87
|
+
# Accumulating every type's result treats the binder as a union, which is the only
|
|
88
|
+
# multi-type binder ComplexType builds; dedup on rooted_tags rather than #tag, which
|
|
89
|
+
# reports only the first member and so collapses two distinct unions.
|
|
90
|
+
resolved.uniq { |pin| [pin.path, pin.return_type.rooted_tags] }
|
|
72
91
|
end
|
|
73
92
|
|
|
74
93
|
private
|
|
@@ -166,7 +185,7 @@ module Solargraph
|
|
|
166
185
|
|
|
167
186
|
# @param pins [::Enumerable<Pin::Base>]
|
|
168
187
|
# @param api_map [ApiMap]
|
|
169
|
-
# @param name_pin [Pin::Base]
|
|
188
|
+
# @param name_pin [Pin::Base] its #binder resolves `self` in the declarations of `pins`
|
|
170
189
|
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
171
190
|
# @return [::Array<Pin::Base>]
|
|
172
191
|
def inferred_pins pins, api_map, name_pin, locals
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
class Source
|
|
5
|
+
class NodeMap
|
|
6
|
+
# @param node [Parser::AST::Node]
|
|
7
|
+
def initialize node
|
|
8
|
+
@node = node
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find_by_type type
|
|
12
|
+
node_map[type] || []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def node_map
|
|
18
|
+
@node_map ||= flatten(@node).to_set.classify(&:type)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def flatten from
|
|
22
|
+
return [] unless from.is_a?(::Parser::AST::Node)
|
|
23
|
+
[from].concat(from.children.flat_map { |child| flatten child })
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/solargraph/source.rb
CHANGED
|
@@ -12,6 +12,7 @@ module Solargraph
|
|
|
12
12
|
autoload :Cursor, 'solargraph/source/cursor'
|
|
13
13
|
autoload :Chain, 'solargraph/source/chain'
|
|
14
14
|
autoload :SourceChainer, 'solargraph/source/source_chainer'
|
|
15
|
+
autoload :NodeMap, 'solargraph/source/node_map'
|
|
15
16
|
|
|
16
17
|
include EncodingFixes
|
|
17
18
|
|
|
@@ -213,6 +214,21 @@ module Solargraph
|
|
|
213
214
|
end
|
|
214
215
|
end
|
|
215
216
|
|
|
217
|
+
# The RBS type in an rbs-inline type assertion, i.e., a `#: TYPE`
|
|
218
|
+
# comment that trails the node on its last line.
|
|
219
|
+
#
|
|
220
|
+
# @example
|
|
221
|
+
# x = [] #: Array[String]
|
|
222
|
+
#
|
|
223
|
+
# @param node [AST::Node]
|
|
224
|
+
# @return [String, nil]
|
|
225
|
+
def type_assertion_for node
|
|
226
|
+
rng = Range.from_node(node)
|
|
227
|
+
return nil if rng.nil?
|
|
228
|
+
rest = code_lines[rng.ending.line]&.[](rng.ending.column..)
|
|
229
|
+
rest&.[](/\A\s*#:(.*)$/, 1)&.strip
|
|
230
|
+
end
|
|
231
|
+
|
|
216
232
|
# A location representing the file in its entirety.
|
|
217
233
|
#
|
|
218
234
|
# @return [Location]
|
|
@@ -457,6 +473,7 @@ module Solargraph
|
|
|
457
473
|
# @return [String]
|
|
458
474
|
def code= val
|
|
459
475
|
@code_lines = nil
|
|
476
|
+
@node_map = nil
|
|
460
477
|
@finalized = false
|
|
461
478
|
@code = val
|
|
462
479
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
class SourceMap
|
|
5
|
+
class Call
|
|
6
|
+
attr_reader :source_map, :chain, :closure
|
|
7
|
+
|
|
8
|
+
# @param source_map [SourceMap]
|
|
9
|
+
# @param chain [Source::Chain]
|
|
10
|
+
# @param closure [Pin::Closure]
|
|
11
|
+
def initialize source_map, chain, closure
|
|
12
|
+
@source_map = source_map
|
|
13
|
+
@chain = chain
|
|
14
|
+
@closure = closure
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -12,7 +12,7 @@ module Solargraph
|
|
|
12
12
|
|
|
13
13
|
private_class_method :new
|
|
14
14
|
|
|
15
|
-
DIRECTIVE_REGEXP = /(@!method|@!attribute|@!visibility|@!scope|@!domain|@!macro|@!parse|@!override)/
|
|
15
|
+
DIRECTIVE_REGEXP = /(@!method|@method|@!attribute|@!visibility|@!scope|@!domain|@!macro|@!parse|@!override)/
|
|
16
16
|
|
|
17
17
|
# Generate the data.
|
|
18
18
|
#
|
|
@@ -12,6 +12,7 @@ module Solargraph
|
|
|
12
12
|
autoload :Clip, 'solargraph/source_map/clip'
|
|
13
13
|
autoload :Completion, 'solargraph/source_map/completion'
|
|
14
14
|
autoload :Data, 'solargraph/source_map/data'
|
|
15
|
+
autoload :Call, 'solargraph/source_map/call'
|
|
15
16
|
|
|
16
17
|
# @return [Source]
|
|
17
18
|
attr_reader :source
|
|
@@ -82,6 +83,16 @@ module Solargraph
|
|
|
82
83
|
pins_by_class(Pin::Reference::Require)
|
|
83
84
|
end
|
|
84
85
|
|
|
86
|
+
def calls *method_names
|
|
87
|
+
symbolized = method_names.map(&:to_sym)
|
|
88
|
+
node_map.find_by_type(:send).select { |node| node.children[0].nil? && symbolized.include?(node.children[1].to_sym) }
|
|
89
|
+
.map { |node| Call.new(self, Parser.chain(node), locate_namespace_pin(node.loc.line, node.loc.column)) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def node_map
|
|
93
|
+
@node_map ||= Source::NodeMap.new(source.node)
|
|
94
|
+
end
|
|
95
|
+
|
|
85
96
|
# @return [Environ]
|
|
86
97
|
def conventions_environ
|
|
87
98
|
@conventions_environ ||= Environ.new
|
|
@@ -128,6 +139,10 @@ module Solargraph
|
|
|
128
139
|
_locate_pin line, character, Pin::Namespace, Pin::Method
|
|
129
140
|
end
|
|
130
141
|
|
|
142
|
+
def locate_namespace_pin line, character
|
|
143
|
+
_locate_pin line, character, Pin::Namespace, Pin::Singleton
|
|
144
|
+
end
|
|
145
|
+
|
|
131
146
|
# @param line [Integer]
|
|
132
147
|
# @param character [Integer]
|
|
133
148
|
# @return [Pin::Closure]
|
|
@@ -197,7 +212,7 @@ module Solargraph
|
|
|
197
212
|
|
|
198
213
|
private
|
|
199
214
|
|
|
200
|
-
# @return [Hash{Class
|
|
215
|
+
# @return [Hash{Class, Pin::Base => Array<Pin::Base>}]
|
|
201
216
|
def pin_class_hash
|
|
202
217
|
# @todo Need to support generic resolution in classify and transform_values
|
|
203
218
|
@pin_class_hash ||= pins.to_set.classify(&:class).transform_values(&:to_a)
|
|
@@ -226,9 +241,8 @@ module Solargraph
|
|
|
226
241
|
position = Position.new(line, character)
|
|
227
242
|
found = nil
|
|
228
243
|
pins.each do |pin|
|
|
229
|
-
#
|
|
230
|
-
|
|
231
|
-
next if pin.is_a?(Pin::Method) && pin.attribute?
|
|
244
|
+
# A bodyless method pin covers its declaring statement's range but isn't a closure.
|
|
245
|
+
next if pin.is_a?(Pin::Method) && !pin.body?
|
|
232
246
|
found = pin if (klasses.empty? || klasses.any? do |kls|
|
|
233
247
|
pin.is_a?(kls)
|
|
234
248
|
# @sg-ignore Need to add nil check here
|
|
@@ -75,11 +75,11 @@ module Solargraph
|
|
|
75
75
|
# @todo 22: Translate to something flow sensitive typing understands
|
|
76
76
|
# @todo 3: Need a downcast here
|
|
77
77
|
#
|
|
78
|
-
# flow sensitive typing could handle (
|
|
78
|
+
# flow sensitive typing could handle (99):
|
|
79
79
|
#
|
|
80
80
|
# @todo 36: flow sensitive typing needs to handle attrs
|
|
81
81
|
# @todo 29: flow sensitive typing should be able to handle redefinition
|
|
82
|
-
# @todo
|
|
82
|
+
# @todo 21: flow sensitive typing needs to narrow down type with an if is_a? check
|
|
83
83
|
# @todo 13: Need to validate config
|
|
84
84
|
# @todo 8: flow sensitive typing should support .class == .class
|
|
85
85
|
# @todo 6: need boolish support for ? methods
|
|
@@ -141,6 +141,8 @@ module Solargraph
|
|
|
141
141
|
# @return [Array<Problem>]
|
|
142
142
|
def method_return_type_problems_for pin
|
|
143
143
|
return [] if pin.is_a?(Pin::MethodAlias)
|
|
144
|
+
# An unresolvable DelegatedMethod's type comes from its @!method directive, not a @return tag.
|
|
145
|
+
return [] if pin.is_a?(Pin::DelegatedMethod) && !pin.resolvable?(api_map)
|
|
144
146
|
result = []
|
|
145
147
|
declared = pin.typify(api_map).self_to_type(pin.full_context).qualify(api_map, *pin.gates)
|
|
146
148
|
if declared.undefined?
|
|
@@ -219,7 +221,7 @@ module Solargraph
|
|
|
219
221
|
params = param_details_from_stack(sig, stack)
|
|
220
222
|
if rules.require_type_tags?
|
|
221
223
|
sig.parameters.each do |par|
|
|
222
|
-
break if %i[restarg kwrestarg blockarg].include?(par.decl)
|
|
224
|
+
break if %i[restarg kwrestarg blockarg forward_args].include?(par.decl)
|
|
223
225
|
unless params[par.name]
|
|
224
226
|
if pin.attribute?
|
|
225
227
|
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
|
@@ -388,6 +390,7 @@ module Solargraph
|
|
|
388
390
|
return [] unless last_base_link.is_a?(Solargraph::Source::Chain::Call)
|
|
389
391
|
|
|
390
392
|
arguments = last_base_link.arguments
|
|
393
|
+
return [] if any_forwarded_args?(arguments.map(&:node))
|
|
391
394
|
|
|
392
395
|
pins = base.define(api_map, closure_pin, locals)
|
|
393
396
|
|
data/lib/solargraph/version.rb
CHANGED
|
@@ -11,6 +11,17 @@ module Solargraph
|
|
|
11
11
|
# its content.
|
|
12
12
|
VALUE_DIRECTIVES = %w[parse scope].freeze
|
|
13
13
|
|
|
14
|
+
# Directives that define an object capable of owning @overload tags.
|
|
15
|
+
OVERLOAD_OWNERS = %w[method attribute parse].freeze
|
|
16
|
+
|
|
17
|
+
# The directive used to generate a pin for the @overload tags a macro
|
|
18
|
+
# declares without an owning @!method directive. Its arguments are
|
|
19
|
+
# represented by (...) so that any of the overloads remains valid.
|
|
20
|
+
OVERLOAD_METHOD_DIRECTIVE = '@!method $1(...)'
|
|
21
|
+
|
|
22
|
+
# An @overload tag that starts a line of a macro's text.
|
|
23
|
+
OVERLOAD_TAG_LINE = /^\s*@overload(\s|$)/
|
|
24
|
+
|
|
14
25
|
class << self
|
|
15
26
|
# @param directive [YARD::Tags::Directive]
|
|
16
27
|
# @param method_pin [Pin::Method]
|
|
@@ -123,9 +134,17 @@ module Solargraph
|
|
|
123
134
|
code = source_map.source.code_for(chain.node)
|
|
124
135
|
expanded_comment = macro_object.expand([name, *values], code)
|
|
125
136
|
.gsub(/\n(?!@!|\s)/, "\n ")
|
|
126
|
-
|
|
137
|
+
parsed_docstring = Solargraph::Source.parse_docstring(expanded_comment)
|
|
138
|
+
directives = parsed_docstring.directives.select do |directive|
|
|
127
139
|
PROCESSABLE_DIRECTIVES.include?(directive.tag.tag_name)
|
|
128
140
|
end
|
|
141
|
+
# A macro can document the methods it generates with bare @overload
|
|
142
|
+
# tags instead of wrapping them in a @!method directive. Those overloads
|
|
143
|
+
# have no pin to attach to and would otherwise be discarded, so
|
|
144
|
+
# generate the pin they describe.
|
|
145
|
+
if declares_overloads? && directives.none? { |directive| OVERLOAD_OWNERS.include?(directive.tag.tag_name) }
|
|
146
|
+
directives += generate_overload_directives([name, *values], code)
|
|
147
|
+
end
|
|
129
148
|
directives.each do |directive|
|
|
130
149
|
next if VALUE_DIRECTIVES.include? directive.tag.tag_name
|
|
131
150
|
|
|
@@ -137,6 +156,37 @@ module Solargraph
|
|
|
137
156
|
end
|
|
138
157
|
directives
|
|
139
158
|
end
|
|
159
|
+
|
|
160
|
+
# True if the macro declares @overload tags. The tags are read from the
|
|
161
|
+
# macro's text and not from its parsed docstring because the indentation
|
|
162
|
+
# a macro's content ends up with can nest the tags inside other objects.
|
|
163
|
+
#
|
|
164
|
+
# @return [Boolean]
|
|
165
|
+
def declares_overloads?
|
|
166
|
+
text.match?(OVERLOAD_TAG_LINE)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Generates the @!method directive for a macro's bare @overload tags. The
|
|
170
|
+
# pin takes the name the macro generates, that is, the pin a
|
|
171
|
+
# @!method $1(...) directive would produce, and keeps the overloads in
|
|
172
|
+
# its comments.
|
|
173
|
+
#
|
|
174
|
+
# The macro's unprocessed text is used here and not its macro data. The
|
|
175
|
+
# data is re-indented for @! directives, which flattens the nesting that
|
|
176
|
+
# keeps a @param attached to the @overload it describes.
|
|
177
|
+
#
|
|
178
|
+
# @param call_params [Array<String>]
|
|
179
|
+
# @param code [String]
|
|
180
|
+
# @return [Array<YARD::Tags::Directive>]
|
|
181
|
+
def generate_overload_directives call_params, code
|
|
182
|
+
body = text.each_line.map { |line| " #{line}" }.join
|
|
183
|
+
expanded = YARD::CodeObjects::MacroObject.expand(
|
|
184
|
+
"#{OVERLOAD_METHOD_DIRECTIVE}\n#{body}", call_params, code
|
|
185
|
+
)
|
|
186
|
+
Solargraph::Source.parse_docstring(expanded).directives.select do |directive|
|
|
187
|
+
directive.tag.tag_name == 'method'
|
|
188
|
+
end
|
|
189
|
+
end
|
|
140
190
|
end
|
|
141
191
|
end
|
|
142
192
|
end
|
data/lib/solargraph.rb
CHANGED
|
@@ -53,6 +53,8 @@ module Solargraph
|
|
|
53
53
|
autoload :RbsMap, 'solargraph/rbs_map'
|
|
54
54
|
autoload :CacheDir, 'solargraph/cache_dir'
|
|
55
55
|
autoload :RbsTranslator, 'solargraph/rbs_translator'
|
|
56
|
+
autoload :RbsCollection, 'solargraph/rbs_collection'
|
|
57
|
+
autoload :Plugin, 'solargraph/plugin'
|
|
56
58
|
|
|
57
59
|
dir = File.dirname(__FILE__)
|
|
58
60
|
VIEWS_PATH = File.join(dir, 'solargraph', 'views')
|