solargraph 0.51.2 → 0.54.2
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/plugins.yml +40 -0
- data/.github/workflows/rspec.yml +1 -3
- data/.github/workflows/typecheck.yml +34 -0
- data/.yardopts +2 -2
- data/CHANGELOG.md +127 -5
- data/README.md +13 -16
- data/SPONSORS.md +1 -7
- data/lib/solargraph/api_map/cache.rb +50 -20
- data/lib/solargraph/api_map/source_to_yard.rb +17 -10
- data/lib/solargraph/api_map/store.rb +60 -15
- data/lib/solargraph/api_map.rb +282 -123
- data/lib/solargraph/bench.rb +3 -2
- data/lib/solargraph/cache.rb +29 -5
- data/lib/solargraph/complex_type/type_methods.rb +122 -39
- data/lib/solargraph/complex_type/unique_type.rb +310 -76
- data/lib/solargraph/complex_type.rb +166 -44
- data/lib/solargraph/convention.rb +0 -1
- data/lib/solargraph/converters/dd.rb +5 -0
- data/lib/solargraph/converters/dl.rb +3 -0
- data/lib/solargraph/converters/dt.rb +3 -0
- data/lib/solargraph/diagnostics/rubocop.rb +8 -7
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
- data/lib/solargraph/diagnostics/type_check.rb +1 -0
- data/lib/solargraph/diagnostics.rb +2 -2
- data/lib/solargraph/doc_map.rb +187 -0
- data/lib/solargraph/gem_pins.rb +72 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
- data/lib/solargraph/language_server/host/dispatch.rb +22 -5
- data/lib/solargraph/language_server/host/message_worker.rb +49 -5
- data/lib/solargraph/language_server/host/sources.rb +8 -65
- data/lib/solargraph/language_server/host.rb +65 -84
- data/lib/solargraph/language_server/message/base.rb +19 -12
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
- data/lib/solargraph/language_server/message/initialize.rb +19 -2
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +3 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document.rb +0 -1
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +135 -0
- data/lib/solargraph/language_server/transport/adapter.rb +16 -1
- data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +207 -111
- data/lib/solargraph/location.rb +15 -1
- data/lib/solargraph/page.rb +6 -0
- data/lib/solargraph/parser/comment_ripper.rb +4 -0
- data/lib/solargraph/parser/node_methods.rb +47 -7
- data/lib/solargraph/parser/node_processor/base.rb +11 -1
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
- data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +62 -43
- data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +57 -0
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +7 -20
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +4 -4
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +8 -6
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
- data/lib/solargraph/parser/parser_gem.rb +12 -0
- data/lib/solargraph/parser/region.rb +1 -1
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/parser.rb +8 -12
- data/lib/solargraph/pin/base.rb +78 -10
- data/lib/solargraph/pin/base_variable.rb +40 -7
- data/lib/solargraph/pin/block.rb +69 -46
- data/lib/solargraph/pin/callable.rb +147 -0
- data/lib/solargraph/pin/closure.rb +23 -3
- data/lib/solargraph/pin/common.rb +6 -6
- data/lib/solargraph/pin/conversions.rb +36 -5
- data/lib/solargraph/pin/delegated_method.rb +6 -2
- data/lib/solargraph/pin/documenting.rb +25 -32
- data/lib/solargraph/pin/instance_variable.rb +6 -2
- data/lib/solargraph/pin/local_variable.rb +13 -1
- data/lib/solargraph/pin/method.rb +205 -32
- data/lib/solargraph/pin/namespace.rb +20 -7
- data/lib/solargraph/pin/parameter.rb +41 -36
- data/lib/solargraph/pin/proxy_type.rb +1 -1
- data/lib/solargraph/pin/reference/override.rb +2 -2
- data/lib/solargraph/pin/reference.rb +8 -0
- data/lib/solargraph/pin/search.rb +3 -3
- data/lib/solargraph/pin/signature.rb +8 -14
- data/lib/solargraph/pin.rb +4 -2
- data/lib/solargraph/range.rb +4 -6
- data/lib/solargraph/rbs_map/conversions.rb +326 -76
- data/lib/solargraph/rbs_map/core_fills.rb +16 -33
- data/lib/solargraph/rbs_map/core_map.rb +3 -13
- data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
- data/lib/solargraph/rbs_map.rb +32 -13
- data/lib/solargraph/shell.rb +95 -72
- data/lib/solargraph/source/chain/array.rb +33 -0
- data/lib/solargraph/source/chain/block_symbol.rb +13 -0
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +152 -69
- data/lib/solargraph/source/chain/constant.rb +15 -1
- data/lib/solargraph/source/chain/if.rb +23 -0
- data/lib/solargraph/source/chain/link.rb +17 -2
- data/lib/solargraph/source/chain/or.rb +2 -2
- data/lib/solargraph/source/chain/z_super.rb +3 -3
- data/lib/solargraph/source/chain.rb +85 -26
- data/lib/solargraph/source/change.rb +3 -0
- data/lib/solargraph/source/cursor.rb +16 -2
- data/lib/solargraph/source/source_chainer.rb +8 -5
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +120 -148
- data/lib/solargraph/source_map/clip.rb +16 -27
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map/mapper.rb +15 -3
- data/lib/solargraph/source_map.rb +48 -24
- data/lib/solargraph/type_checker/checks.rb +10 -2
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +150 -39
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- data/lib/solargraph/workspace/config.rb +9 -6
- data/lib/solargraph/workspace.rb +30 -3
- data/lib/solargraph/yard_map/cache.rb +6 -0
- data/lib/solargraph/yard_map/helpers.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +16 -3
- data/lib/solargraph/yard_map/mapper.rb +1 -1
- data/lib/solargraph/yard_map/to_method.rb +11 -4
- data/lib/solargraph/yard_map.rb +1 -292
- data/lib/solargraph/yard_tags.rb +20 -0
- data/lib/solargraph/yardoc.rb +52 -0
- data/lib/solargraph.rb +6 -4
- data/solargraph.gemspec +7 -6
- metadata +71 -82
- data/lib/solargraph/api_map/bundler_methods.rb +0 -22
- data/lib/solargraph/documentor.rb +0 -76
- data/lib/solargraph/language_server/host/cataloger.rb +0 -56
- data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
- data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
- data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -50
- data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
- data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
- data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
- data/lib/solargraph/parser/legacy.rb +0 -12
- data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -153
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
- data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
- data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
- data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
- data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
- data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
- data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
- data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
- data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
- data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
- data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
- data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
- data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
- data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
- data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
- data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
- data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
- data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
- data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
- data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
- data/lib/solargraph/parser/rubyvm.rb +0 -40
- data/lib/solargraph/rbs_map/core_signs.rb +0 -33
- data/lib/yard-solargraph.rb +0 -33
@@ -64,6 +64,10 @@ module Solargraph
|
|
64
64
|
pins.select{|pin| pin.is_a?(Pin::Closure) and pin.location.range.contain?(position)}.last
|
65
65
|
end
|
66
66
|
|
67
|
+
# @param source_position [Position]
|
68
|
+
# @param comment_position [Position]
|
69
|
+
# @param comment [String]
|
70
|
+
# @return [void]
|
67
71
|
def process_comment source_position, comment_position, comment
|
68
72
|
return unless comment.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
|
69
73
|
cmnt = remove_inline_comment_hashes(comment)
|
@@ -79,6 +83,8 @@ module Solargraph
|
|
79
83
|
end
|
80
84
|
|
81
85
|
# @param comment [String]
|
86
|
+
# @param tag [String]
|
87
|
+
# @param start [Integer]
|
82
88
|
# @return [Integer]
|
83
89
|
def find_directive_line_number comment, tag, start
|
84
90
|
# Avoid overruning the index
|
@@ -107,7 +113,8 @@ module Solargraph
|
|
107
113
|
begin
|
108
114
|
src = Solargraph::Source.load_string("def #{directive.tag.name};end", @source.filename)
|
109
115
|
region = Parser::Region.new(source: src, closure: namespace)
|
110
|
-
|
116
|
+
method_gen_pins = Parser.process_node(src.node, region).first.select { |pin| pin.is_a?(Pin::Method) }
|
117
|
+
gen_pin = method_gen_pins.last
|
111
118
|
return if gen_pin.nil?
|
112
119
|
# Move the location to the end of the line so it gets recognized
|
113
120
|
# as originating from a comment
|
@@ -137,7 +144,7 @@ module Solargraph
|
|
137
144
|
)
|
138
145
|
end
|
139
146
|
if t.nil? || t.include?('w')
|
140
|
-
|
147
|
+
method_pin = Solargraph::Pin::Method.new(
|
141
148
|
location: location,
|
142
149
|
closure: namespace,
|
143
150
|
name: "#{directive.tag.name}=",
|
@@ -146,7 +153,8 @@ module Solargraph
|
|
146
153
|
visibility: :public,
|
147
154
|
attribute: true
|
148
155
|
)
|
149
|
-
pins.
|
156
|
+
pins.push method_pin
|
157
|
+
method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
|
150
158
|
if pins.last.return_type.defined?
|
151
159
|
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
|
152
160
|
end
|
@@ -203,10 +211,14 @@ module Solargraph
|
|
203
211
|
end
|
204
212
|
end
|
205
213
|
|
214
|
+
# @param line1 [Integer]
|
215
|
+
# @param line2 [Integer]
|
206
216
|
def no_empty_lines?(line1, line2)
|
207
217
|
@code.lines[line1..line2].none? { |line| line.strip.empty? }
|
208
218
|
end
|
209
219
|
|
220
|
+
# @param comment [String]
|
221
|
+
# @return [String]
|
210
222
|
def remove_inline_comment_hashes comment
|
211
223
|
ctxt = ''
|
212
224
|
num = nil
|
@@ -1,49 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'yard'
|
4
|
-
require '
|
5
|
-
require 'set'
|
4
|
+
require 'solargraph/yard_tags'
|
6
5
|
|
7
6
|
module Solargraph
|
8
|
-
# An index of
|
7
|
+
# An index of Pins and other ApiMap-related data for a single Source
|
8
|
+
# that can be queried.
|
9
9
|
#
|
10
10
|
class SourceMap
|
11
11
|
autoload :Mapper, 'solargraph/source_map/mapper'
|
12
12
|
autoload :Clip, 'solargraph/source_map/clip'
|
13
13
|
autoload :Completion, 'solargraph/source_map/completion'
|
14
|
+
autoload :Data, 'solargraph/source_map/data'
|
14
15
|
|
15
16
|
# @return [Source]
|
16
17
|
attr_reader :source
|
17
18
|
|
18
19
|
# @return [Array<Pin::Base>]
|
19
|
-
|
20
|
+
def pins
|
21
|
+
data.pins
|
22
|
+
end
|
20
23
|
|
21
|
-
# @return [Array<Pin::
|
22
|
-
|
24
|
+
# @return [Array<Pin::LocalVariable>]
|
25
|
+
def locals
|
26
|
+
data.locals
|
27
|
+
end
|
23
28
|
|
24
29
|
# @param source [Source]
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
# HACK: Keep the library from changing this
|
29
|
-
@source = source.dup
|
30
|
-
@pins = pins
|
31
|
-
@locals = locals
|
30
|
+
def initialize source
|
31
|
+
@source = source
|
32
|
+
|
32
33
|
environ.merge Convention.for_local(self) unless filename.nil?
|
33
34
|
self.convention_pins = environ.pins
|
34
|
-
@pin_class_hash = pins.to_set.classify(&:class).transform_values(&:to_a)
|
35
35
|
@pin_select_cache = {}
|
36
36
|
end
|
37
37
|
|
38
|
+
# @param klass [Class]
|
39
|
+
# @return [Array<Pin::Base>]
|
38
40
|
def pins_by_class klass
|
39
|
-
@pin_select_cache[klass] ||=
|
41
|
+
@pin_select_cache[klass] ||= pin_class_hash.select { |key, _| key <= klass }.values.flatten
|
40
42
|
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
# A hash representing the state of the source map's API.
|
45
|
+
#
|
46
|
+
# ApiMap#catalog uses this value to determine whether it needs to clear its
|
47
|
+
# cache.
|
48
|
+
#
|
49
|
+
# @return [Integer]
|
50
|
+
def api_hash
|
51
|
+
@api_hash ||= (pins_by_class(Pin::Constant) + pins_by_class(Pin::Namespace).select { |pin| pin.namespace.to_s > '' } + pins_by_class(Pin::Reference) + pins_by_class(Pin::Method).map(&:node) + locals).hash
|
47
52
|
end
|
48
53
|
|
49
54
|
# @return [String]
|
@@ -99,18 +104,27 @@ module Solargraph
|
|
99
104
|
(pins + locals).select { |pin| pin.location == location }
|
100
105
|
end
|
101
106
|
|
107
|
+
# @param line [Integer]
|
108
|
+
# @param character [Integer]
|
109
|
+
# @return [Pin::Method,Pin::Namespace]
|
102
110
|
def locate_named_path_pin line, character
|
103
111
|
_locate_pin line, character, Pin::Namespace, Pin::Method
|
104
112
|
end
|
105
113
|
|
114
|
+
# @param line [Integer]
|
115
|
+
# @param character [Integer]
|
116
|
+
# @return [Pin::Namespace,Pin::Method,Pin::Block]
|
106
117
|
def locate_block_pin line, character
|
107
118
|
_locate_pin line, character, Pin::Namespace, Pin::Method, Pin::Block
|
108
119
|
end
|
109
120
|
|
121
|
+
# @todo Candidate for deprecation
|
122
|
+
#
|
110
123
|
# @param other_map [SourceMap]
|
111
124
|
# @return [Boolean]
|
112
125
|
def try_merge! other_map
|
113
126
|
return false if pins.length != other_map.pins.length || locals.length != other_map.locals.length || requires.map(&:name).uniq.sort != other_map.requires.map(&:name).uniq.sort
|
127
|
+
|
114
128
|
pins.each_index do |i|
|
115
129
|
return false unless pins[i].try_merge!(other_map.pins[i])
|
116
130
|
end
|
@@ -151,23 +165,33 @@ module Solargraph
|
|
151
165
|
SourceMap.map(source)
|
152
166
|
end
|
153
167
|
|
168
|
+
# @deprecated
|
154
169
|
# @param source [Source]
|
155
170
|
# @return [SourceMap]
|
156
171
|
def map source
|
157
|
-
|
158
|
-
new(source, *result)
|
172
|
+
new(source)
|
159
173
|
end
|
160
174
|
end
|
161
175
|
|
162
176
|
private
|
163
177
|
|
178
|
+
def pin_class_hash
|
179
|
+
@pin_class_hash ||= pins.to_set.classify(&:class).transform_values(&:to_a)
|
180
|
+
end
|
181
|
+
|
182
|
+
def data
|
183
|
+
@data ||= Data.new(source)
|
184
|
+
end
|
185
|
+
|
164
186
|
# @return [Array<Pin::Base>]
|
165
187
|
def convention_pins
|
166
188
|
@convention_pins || []
|
167
189
|
end
|
168
190
|
|
191
|
+
# @param pins [Array<Pin::Base>]
|
192
|
+
# @return [Array<Pin::Base>]
|
169
193
|
def convention_pins=(pins)
|
170
|
-
# unmemoizing the document_symbols in case it was called from any of
|
194
|
+
# unmemoizing the document_symbols in case it was called from any of conventions
|
171
195
|
@document_symbols = nil
|
172
196
|
@convention_pins = pins
|
173
197
|
end
|
@@ -175,7 +199,7 @@ module Solargraph
|
|
175
199
|
# @param line [Integer]
|
176
200
|
# @param character [Integer]
|
177
201
|
# @param klasses [Array<Class>]
|
178
|
-
# @return [Pin::Base]
|
202
|
+
# @return [Pin::Base, nil]
|
179
203
|
def _locate_pin line, character, *klasses
|
180
204
|
position = Position.new(line, character)
|
181
205
|
found = nil
|
@@ -51,8 +51,13 @@ module Solargraph
|
|
51
51
|
# @return [Boolean]
|
52
52
|
def any_types_match? api_map, expected, inferred
|
53
53
|
return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
|
54
|
+
# walk through the union expected type and see if any members
|
55
|
+
# of the union match the inferred type
|
54
56
|
expected.each do |exp|
|
55
57
|
next if exp.duck_type?
|
58
|
+
# @todo: there should be a level of typechecking where all
|
59
|
+
# unique types in the inferred must match one of the
|
60
|
+
# expected unique types
|
56
61
|
inferred.each do |inf|
|
57
62
|
# return true if exp == inf || api_map.super_and_sub?(fuzz(inf), fuzz(exp))
|
58
63
|
return true if exp == inf || either_way?(api_map, inf, exp)
|
@@ -103,9 +108,12 @@ module Solargraph
|
|
103
108
|
# @param cls2 [ComplexType::UniqueType]
|
104
109
|
# @return [Boolean]
|
105
110
|
def either_way?(api_map, cls1, cls2)
|
106
|
-
|
107
|
-
|
111
|
+
# @todo there should be a level of typechecking which uses the
|
112
|
+
# full tag with parameters to determine compatibility
|
113
|
+
f1 = cls1.name
|
114
|
+
f2 = cls2.name
|
108
115
|
api_map.type_include?(f1, f2) || api_map.super_and_sub?(f1, f2) || api_map.super_and_sub?(f2, f1)
|
116
|
+
# api_map.type_include?(f1, f2) || api_map.super_and_sub?(f1, f2) || api_map.super_and_sub?(f2, f1)
|
109
117
|
end
|
110
118
|
end
|
111
119
|
end
|
@@ -9,7 +9,8 @@ module Solargraph
|
|
9
9
|
normal: 0,
|
10
10
|
typed: 1,
|
11
11
|
strict: 2,
|
12
|
-
strong: 3
|
12
|
+
strong: 3,
|
13
|
+
alpha: 4
|
13
14
|
}.freeze
|
14
15
|
|
15
16
|
# @return [Symbol]
|
@@ -52,6 +53,10 @@ module Solargraph
|
|
52
53
|
def validate_tags?
|
53
54
|
rank > LEVELS[:normal]
|
54
55
|
end
|
56
|
+
|
57
|
+
def require_all_return_types_match_inferred?
|
58
|
+
rank >= LEVELS[:alpha]
|
59
|
+
end
|
55
60
|
end
|
56
61
|
end
|
57
62
|
end
|
@@ -22,7 +22,7 @@ module Solargraph
|
|
22
22
|
attr_reader :api_map
|
23
23
|
|
24
24
|
# @param filename [String]
|
25
|
-
# @param api_map [ApiMap]
|
25
|
+
# @param api_map [ApiMap, nil]
|
26
26
|
# @param level [Symbol]
|
27
27
|
def initialize filename, api_map: nil, level: :normal
|
28
28
|
@filename = filename
|
@@ -51,6 +51,7 @@ module Solargraph
|
|
51
51
|
|
52
52
|
class << self
|
53
53
|
# @param filename [String]
|
54
|
+
# @param level [Symbol]
|
54
55
|
# @return [self]
|
55
56
|
def load filename, level = :normal
|
56
57
|
source = Solargraph::Source.load(filename)
|
@@ -61,6 +62,7 @@ module Solargraph
|
|
61
62
|
|
62
63
|
# @param code [String]
|
63
64
|
# @param filename [String, nil]
|
65
|
+
# @param level [Symbol]
|
64
66
|
# @return [self]
|
65
67
|
def load_string code, filename = nil, level = :normal
|
66
68
|
source = Solargraph::Source.load_string(code, filename)
|
@@ -88,10 +90,15 @@ module Solargraph
|
|
88
90
|
def method_return_type_problems_for pin
|
89
91
|
return [] if pin.is_a?(Pin::MethodAlias)
|
90
92
|
result = []
|
91
|
-
declared = pin.typify(api_map).
|
93
|
+
declared = pin.typify(api_map).self_to_type(pin.full_context).qualify(api_map, pin.full_context.tag)
|
92
94
|
if declared.undefined?
|
93
95
|
if pin.return_type.undefined? && rules.require_type_tags?
|
94
|
-
|
96
|
+
if pin.attribute?
|
97
|
+
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
98
|
+
result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin) unless inferred.defined?
|
99
|
+
else
|
100
|
+
result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
|
101
|
+
end
|
95
102
|
elsif pin.return_type.defined? && !resolved_constant?(pin)
|
96
103
|
result.push Problem.new(pin.location, "Unresolved return type #{pin.return_type} for #{pin.path}", pin: pin)
|
97
104
|
elsif rules.must_tag_or_infer? && pin.probe(api_map).undefined?
|
@@ -99,14 +106,14 @@ module Solargraph
|
|
99
106
|
end
|
100
107
|
elsif rules.validate_tags?
|
101
108
|
unless pin.node.nil? || declared.void? || virtual_pin?(pin) || abstract?(pin)
|
102
|
-
inferred = pin.probe(api_map).
|
109
|
+
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
103
110
|
if inferred.undefined?
|
104
111
|
unless rules.ignore_all_undefined? || external?(pin)
|
105
112
|
result.push Problem.new(pin.location, "#{pin.path} return type could not be inferred", pin: pin)
|
106
113
|
end
|
107
114
|
else
|
108
|
-
unless (rules.
|
109
|
-
result.push Problem.new(pin.location, "Declared return type #{declared} does not match inferred type #{inferred} for #{pin.path}", pin: pin)
|
115
|
+
unless (rules.require_all_return_types_match_inferred? ? all_types_match?(api_map, inferred, declared) : any_types_match?(api_map, declared, inferred))
|
116
|
+
result.push Problem.new(pin.location, "Declared return type #{declared.rooted_tags} does not match inferred type #{inferred.rooted_tags} for #{pin.path}", pin: pin)
|
110
117
|
end
|
111
118
|
end
|
112
119
|
end
|
@@ -121,11 +128,16 @@ module Solargraph
|
|
121
128
|
# @return [Boolean]
|
122
129
|
def resolved_constant? pin
|
123
130
|
return true if pin.typify(api_map).defined?
|
124
|
-
api_map.get_constants('', *pin.closure.gates)
|
125
|
-
|
126
|
-
|
131
|
+
constant_pins = api_map.get_constants('', *pin.closure.gates)
|
132
|
+
.select { |p| p.name == pin.return_type.namespace }
|
133
|
+
return true if constant_pins.find { |p| p.typify(api_map).defined? }
|
134
|
+
# will need to probe when a constant name is assigned to a
|
135
|
+
# class/module (alias)
|
136
|
+
return true if constant_pins.find { |p| p.probe(api_map).defined? }
|
137
|
+
false
|
127
138
|
end
|
128
139
|
|
140
|
+
# @param pin [Pin::Base]
|
129
141
|
def virtual_pin? pin
|
130
142
|
pin.location && source_map.source.comment_at?(pin.location.range.ending)
|
131
143
|
end
|
@@ -141,12 +153,23 @@ module Solargraph
|
|
141
153
|
sig.parameters.each do |par|
|
142
154
|
break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
|
143
155
|
unless params[par.name]
|
144
|
-
|
156
|
+
if pin.attribute?
|
157
|
+
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
158
|
+
if inferred.undefined?
|
159
|
+
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
160
|
+
end
|
161
|
+
else
|
162
|
+
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
163
|
+
end
|
145
164
|
end
|
146
165
|
end
|
147
166
|
end
|
148
167
|
end
|
168
|
+
# @todo Should be able to probe type of name and data here
|
169
|
+
# @param name [String]
|
170
|
+
# @param data [Hash{Symbol => BasicObject}]
|
149
171
|
params.each_pair do |name, data|
|
172
|
+
# @type [ComplexType]
|
150
173
|
type = data[:qualified]
|
151
174
|
if type.undefined?
|
152
175
|
result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
|
@@ -155,6 +178,7 @@ module Solargraph
|
|
155
178
|
result
|
156
179
|
end
|
157
180
|
|
181
|
+
# @return [Array<Pin::Base>]
|
158
182
|
def ignored_pins
|
159
183
|
@ignored_pins ||= []
|
160
184
|
end
|
@@ -202,6 +226,7 @@ module Solargraph
|
|
202
226
|
source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.select { |pin| pin.is_a?(Pin::LocalVariable) }
|
203
227
|
end
|
204
228
|
|
229
|
+
# @return [Array<Problem>]
|
205
230
|
def const_problems
|
206
231
|
return [] unless rules.validate_consts?
|
207
232
|
result = []
|
@@ -220,6 +245,7 @@ module Solargraph
|
|
220
245
|
result
|
221
246
|
end
|
222
247
|
|
248
|
+
# @return [Array<Problem>]
|
223
249
|
def call_problems
|
224
250
|
result = []
|
225
251
|
Solargraph::Parser::NodeMethods.call_nodes_from(source_map.source.node).each do |call|
|
@@ -242,8 +268,9 @@ module Solargraph
|
|
242
268
|
base = base.base
|
243
269
|
end
|
244
270
|
closest = found.typify(api_map) if found
|
271
|
+
# @todo remove the internal_or_core? check at a higher-than-strict level
|
245
272
|
if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
|
246
|
-
unless closest.
|
273
|
+
unless closest.generic? || ignored_pins.include?(found)
|
247
274
|
result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
|
248
275
|
@marked_ranges.push rng
|
249
276
|
end
|
@@ -259,49 +286,98 @@ module Solargraph
|
|
259
286
|
# @param block_pin [Solargraph::Pin::Base]
|
260
287
|
# @param locals [Array<Solargraph::Pin::Base>]
|
261
288
|
# @param location [Solargraph::Location]
|
289
|
+
# @return [Array<Problem>]
|
262
290
|
def argument_problems_for chain, api_map, block_pin, locals, location
|
263
291
|
result = []
|
264
292
|
base = chain
|
265
293
|
until base.links.length == 1 && base.undefined?
|
294
|
+
last_base_link = base.links.last
|
295
|
+
break unless last_base_link.is_a?(Solargraph::Source::Chain::Call)
|
296
|
+
|
297
|
+
arguments = last_base_link.arguments
|
298
|
+
|
266
299
|
pins = base.define(api_map, block_pin, locals)
|
267
300
|
|
268
|
-
|
301
|
+
first_pin = pins.first
|
302
|
+
if first_pin.is_a?(Pin::DelegatedMethod) && !first_pin.resolvable?(api_map)
|
269
303
|
# Do nothing, as we can't find the actual method implementation
|
270
|
-
elsif
|
304
|
+
elsif first_pin.is_a?(Pin::Method)
|
271
305
|
# @type [Pin::Method]
|
272
|
-
pin =
|
306
|
+
pin = first_pin
|
273
307
|
ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
|
274
308
|
arity_problems_for(pin, fake_args_for(block_pin), location)
|
309
|
+
elsif pin.path == 'Class#new'
|
310
|
+
fqns = if base.links.one?
|
311
|
+
block_pin.namespace
|
312
|
+
else
|
313
|
+
base.base.infer(api_map, block_pin, locals).namespace
|
314
|
+
end
|
315
|
+
init = api_map.get_method_stack(fqns, 'initialize').first
|
316
|
+
init ? arity_problems_for(init, arguments, location) : []
|
275
317
|
else
|
276
|
-
arity_problems_for(pin,
|
318
|
+
arity_problems_for(pin, arguments, location)
|
277
319
|
end
|
278
320
|
unless ap.empty?
|
279
321
|
result.concat ap
|
280
322
|
break
|
281
323
|
end
|
282
|
-
break
|
324
|
+
break if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
|
325
|
+
|
283
326
|
params = first_param_hash(pins)
|
284
327
|
|
285
328
|
all_errors = []
|
286
329
|
pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
|
287
330
|
errors = []
|
288
331
|
sig.parameters.each_with_index do |par, idx|
|
289
|
-
|
332
|
+
# @todo add logic mapping up restarg parameters with
|
333
|
+
# arguments (including restarg arguments). Use tuples
|
334
|
+
# when possible, and when not, ensure provably
|
335
|
+
# incorrect situations are detected.
|
336
|
+
break if par.decl == :restarg # bail out pending better arg processing
|
337
|
+
argchain = arguments[idx]
|
290
338
|
if argchain.nil?
|
291
339
|
if par.decl == :arg
|
292
|
-
|
293
|
-
|
340
|
+
final_arg = arguments.last
|
341
|
+
if final_arg && final_arg.node.type == :splat
|
342
|
+
argchain = final_arg
|
343
|
+
next # don't try to apply the type of the splat - unlikely to be specific enough
|
344
|
+
else
|
345
|
+
errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
|
346
|
+
next
|
347
|
+
end
|
294
348
|
else
|
295
|
-
|
296
|
-
argchain =
|
349
|
+
final_arg = arguments.last
|
350
|
+
argchain = final_arg if final_arg && [:kwsplat, :hash].include?(final_arg.node.type)
|
297
351
|
end
|
298
352
|
end
|
299
353
|
if argchain
|
300
354
|
if par.decl != :arg
|
301
|
-
errors.concat kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, idx
|
355
|
+
errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
|
302
356
|
next
|
303
357
|
else
|
358
|
+
if argchain.node.type == :splat && argchain == arguments.last
|
359
|
+
final_arg = argchain
|
360
|
+
end
|
361
|
+
if (final_arg && final_arg.node.type == :splat)
|
362
|
+
# The final argument given has been seen and was a
|
363
|
+
# splat, which doesn't give us useful types or
|
364
|
+
# arities against positional parameters, so let's
|
365
|
+
# continue on in case there are any required
|
366
|
+
# kwargs we should warn about
|
367
|
+
next
|
368
|
+
end
|
369
|
+
|
370
|
+
if argchain.node.type == :splat && par != sig.parameters.last
|
371
|
+
# we have been given a splat and there are more
|
372
|
+
# arguments to come.
|
373
|
+
|
374
|
+
# @todo Improve this so that we can skip past the
|
375
|
+
# rest of the positional parameters here but still
|
376
|
+
# process the kwargs
|
377
|
+
break
|
378
|
+
end
|
304
379
|
ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
|
380
|
+
ptype = ptype.self_to_type(par.context)
|
305
381
|
if ptype.nil?
|
306
382
|
# @todo Some level (strong, I guess) should require the param here
|
307
383
|
else
|
@@ -330,10 +406,21 @@ module Solargraph
|
|
330
406
|
result
|
331
407
|
end
|
332
408
|
|
333
|
-
|
409
|
+
# @param sig [Pin::Signature]
|
410
|
+
# @param argchain [Source::Chain]
|
411
|
+
# @param api_map [ApiMap]
|
412
|
+
# @param block_pin [Pin::Block]
|
413
|
+
# @param locals [Array<Pin::LocalVariable>]
|
414
|
+
# @param location [Location]
|
415
|
+
# @param pin [Pin::Method]
|
416
|
+
# @param params [Hash{String => [nil, Hash]}]
|
417
|
+
# @param idx [Integer]
|
418
|
+
#
|
419
|
+
# @return [Array<Problem>]
|
420
|
+
def kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
|
334
421
|
result = []
|
335
422
|
kwargs = convert_hash(argchain.node)
|
336
|
-
par =
|
423
|
+
par = sig.parameters[idx]
|
337
424
|
argchain = kwargs[par.name.to_sym]
|
338
425
|
if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
|
339
426
|
result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
|
@@ -358,6 +445,14 @@ module Solargraph
|
|
358
445
|
result
|
359
446
|
end
|
360
447
|
|
448
|
+
# @param api_map [ApiMap]
|
449
|
+
# @param block_pin [Pin::Block]
|
450
|
+
# @param locals [Array<Pin::LocalVariable>]
|
451
|
+
# @param location [Location]
|
452
|
+
# @param pin [Pin::Method]
|
453
|
+
# @param params [Hash{String => [nil, Hash]}]
|
454
|
+
# @param kwargs [Hash{Symbol => Source::Chain}]
|
455
|
+
# @return [Array<Problem>]
|
361
456
|
def kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
|
362
457
|
result = []
|
363
458
|
kwargs.each_pair do |pname, argchain|
|
@@ -371,8 +466,8 @@ module Solargraph
|
|
371
466
|
result
|
372
467
|
end
|
373
468
|
|
374
|
-
# @param [Pin::Method]
|
375
|
-
# @return [Hash]
|
469
|
+
# @param pin [Pin::Method]
|
470
|
+
# @return [Hash{String => Hash{Symbol => BaseObject}}]
|
376
471
|
def param_hash(pin)
|
377
472
|
tags = pin.docstring.tags(:param)
|
378
473
|
return {} if tags.empty?
|
@@ -387,10 +482,12 @@ module Solargraph
|
|
387
482
|
result
|
388
483
|
end
|
389
484
|
|
390
|
-
# @param [Array<Pin::Method>]
|
391
|
-
# @return [Hash]
|
485
|
+
# @param pins [Array<Pin::Method>]
|
486
|
+
# @return [Hash{String => Hash{Symbol => BasicObject}}]
|
392
487
|
def first_param_hash(pins)
|
393
488
|
pins.each do |pin|
|
489
|
+
# @todo this assignment from parametric use of Hash should not lose its generic
|
490
|
+
# @type [Hash{String => Hash{Symbol => BasicObject}}]
|
394
491
|
result = param_hash(pin)
|
395
492
|
return result unless result.empty?
|
396
493
|
end
|
@@ -404,6 +501,7 @@ module Solargraph
|
|
404
501
|
end
|
405
502
|
|
406
503
|
# True if the pin is either internal (part of the workspace) or from the core/stdlib
|
504
|
+
# @param pin [Pin::Base]
|
407
505
|
def internal_or_core? pin
|
408
506
|
# @todo RBS pins are not necessarily core/stdlib pins
|
409
507
|
internal?(pin) || pin.source == :rbs
|
@@ -414,6 +512,7 @@ module Solargraph
|
|
414
512
|
!internal? pin
|
415
513
|
end
|
416
514
|
|
515
|
+
# @param pin [Pin::Base]
|
417
516
|
def declared_externally? pin
|
418
517
|
return true if pin.assignment.nil?
|
419
518
|
chain = Solargraph::Parser.chain(pin.assignment, filename)
|
@@ -441,6 +540,10 @@ module Solargraph
|
|
441
540
|
true
|
442
541
|
end
|
443
542
|
|
543
|
+
# @param pin [Pin::Method]
|
544
|
+
# @param arguments [Array<Source::Chain>]
|
545
|
+
# @param location [Location]
|
546
|
+
# @return [Array<Problem>]
|
444
547
|
def arity_problems_for pin, arguments, location
|
445
548
|
results = pin.signatures.map do |sig|
|
446
549
|
r = parameterized_arity_problems_for(pin, sig.parameters, arguments, location)
|
@@ -450,16 +553,15 @@ module Solargraph
|
|
450
553
|
results.first
|
451
554
|
end
|
452
555
|
|
556
|
+
# @param pin [Pin::Method]
|
557
|
+
# @param parameters [Array<Pin::Parameter>]
|
558
|
+
# @param arguments [Array<Source::Chain>]
|
559
|
+
# @param location [Location]
|
560
|
+
# @return [Array<Problem>]
|
453
561
|
def parameterized_arity_problems_for(pin, parameters, arguments, location)
|
454
562
|
return [] unless pin.explicit?
|
455
563
|
return [] if parameters.empty? && arguments.empty?
|
456
564
|
return [] if pin.anon_splat?
|
457
|
-
if parameters.empty?
|
458
|
-
# Functions tagged param_tuple accepts two arguments (e.g., Hash#[]=)
|
459
|
-
return [] if pin.docstring.tag(:param_tuple) && arguments.length == 2
|
460
|
-
return [] if arguments.length == 1 && arguments.last.links.last.is_a?(Source::Chain::BlockVariable)
|
461
|
-
return [Problem.new(location, "Too many arguments to #{pin.path}")]
|
462
|
-
end
|
463
565
|
unchecked = arguments.clone
|
464
566
|
add_params = 0
|
465
567
|
if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
|
@@ -499,9 +601,6 @@ module Solargraph
|
|
499
601
|
return [] if parameters.any?(&:rest?)
|
500
602
|
opt = optional_param_count(parameters)
|
501
603
|
return [] if unchecked.length <= req + opt
|
502
|
-
if unchecked.length == req + opt + 1 && unchecked.last.links.last.is_a?(Source::Chain::BlockVariable)
|
503
|
-
return []
|
504
|
-
end
|
505
604
|
if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
|
506
605
|
return []
|
507
606
|
end
|
@@ -517,20 +616,30 @@ module Solargraph
|
|
517
616
|
[]
|
518
617
|
end
|
519
618
|
|
619
|
+
# @param parameters [Enumerable<Pin::Parameter>]
|
620
|
+
# @todo need to use generic types in method to choose correct
|
621
|
+
# signature and generate Integer as return type
|
622
|
+
# @sg-ignore
|
623
|
+
# @return [Integer]
|
520
624
|
def required_param_count(parameters)
|
521
625
|
parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
|
522
626
|
end
|
523
627
|
|
628
|
+
# @param parameters [Enumerable<Pin::Parameter>]
|
524
629
|
# @param pin [Pin::Method]
|
630
|
+
# @return [Integer]
|
525
631
|
def optional_param_count(parameters)
|
526
632
|
parameters.select { |p| p.decl == :optarg }.length
|
527
633
|
end
|
528
634
|
|
635
|
+
# @param pin [Pin::Method]
|
529
636
|
def abstract? pin
|
530
|
-
pin.docstring.has_tag?(
|
531
|
-
(pin.closure && pin.closure.docstring.has_tag?(
|
637
|
+
pin.docstring.has_tag?('abstract') ||
|
638
|
+
(pin.closure && pin.closure.docstring.has_tag?('abstract'))
|
532
639
|
end
|
533
640
|
|
641
|
+
# @param pin [Pin::Base]
|
642
|
+
# @return [Array<Source::Chain>]
|
534
643
|
def fake_args_for(pin)
|
535
644
|
args = []
|
536
645
|
with_opts = false
|
@@ -551,6 +660,8 @@ module Solargraph
|
|
551
660
|
args
|
552
661
|
end
|
553
662
|
|
663
|
+
# @param problems [Array<Problem>]
|
664
|
+
# @return [Array<Problem>]
|
554
665
|
def without_ignored problems
|
555
666
|
problems.reject do |problem|
|
556
667
|
node = source_map.source.node_at(problem.location.range.start.line, problem.location.range.start.column)
|
data/lib/solargraph/version.rb
CHANGED