solargraph 0.50.0 → 0.53.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/plugins.yml +40 -0
- data/.github/workflows/rspec.yml +4 -8
- data/.github/workflows/typecheck.yml +34 -0
- data/.yardopts +2 -2
- data/CHANGELOG.md +81 -3
- data/README.md +13 -16
- data/SPONSORS.md +2 -9
- data/lib/solargraph/api_map/cache.rb +60 -20
- data/lib/solargraph/api_map/store.rb +47 -11
- data/lib/solargraph/api_map.rb +161 -95
- data/lib/solargraph/bench.rb +2 -2
- data/lib/solargraph/cache.rb +30 -6
- data/lib/solargraph/complex_type/type_methods.rb +54 -9
- data/lib/solargraph/complex_type/unique_type.rb +154 -57
- data/lib/solargraph/complex_type.rb +91 -17
- data/lib/solargraph/convention.rb +0 -3
- 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 +146 -0
- data/lib/solargraph/gem_pins.rb +64 -0
- data/lib/solargraph/language_server/host/cataloger.rb +1 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
- data/lib/solargraph/language_server/host/dispatch.rb +10 -4
- data/lib/solargraph/language_server/host/message_worker.rb +4 -0
- data/lib/solargraph/language_server/host/sources.rb +7 -4
- data/lib/solargraph/language_server/host.rb +26 -7
- 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 +11 -0
- data/lib/solargraph/language_server/message/initialized.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
- data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
- data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
- data/lib/solargraph/language_server/message/text_document.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
- data/lib/solargraph/language_server/message.rb +1 -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/library.rb +86 -16
- data/lib/solargraph/location.rb +1 -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 +9 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
- data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
- data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -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 +53 -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/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
- data/lib/solargraph/parser/{rubyvm → 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 +2 -2
- 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 +2 -2
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -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 +9 -10
- data/lib/solargraph/pin/base.rb +64 -9
- data/lib/solargraph/pin/base_variable.rb +6 -2
- data/lib/solargraph/pin/block.rb +19 -9
- data/lib/solargraph/pin/closure.rb +17 -2
- data/lib/solargraph/pin/common.rb +7 -3
- data/lib/solargraph/pin/conversions.rb +33 -3
- data/lib/solargraph/pin/delegated_method.rb +97 -0
- data/lib/solargraph/pin/documenting.rb +25 -34
- data/lib/solargraph/pin/instance_variable.rb +4 -0
- data/lib/solargraph/pin/local_variable.rb +13 -1
- data/lib/solargraph/pin/method.rb +182 -18
- data/lib/solargraph/pin/namespace.rb +18 -5
- data/lib/solargraph/pin/parameter.rb +44 -14
- data/lib/solargraph/pin/reference/override.rb +2 -2
- data/lib/solargraph/pin/reference.rb +8 -0
- data/lib/solargraph/pin/search.rb +4 -4
- data/lib/solargraph/pin/signature.rb +123 -3
- data/lib/solargraph/pin.rb +1 -1
- data/lib/solargraph/range.rb +4 -6
- data/lib/solargraph/rbs_map/conversions.rb +294 -50
- data/lib/solargraph/rbs_map/core_fills.rb +7 -24
- data/lib/solargraph/rbs_map/core_map.rb +3 -2
- data/lib/solargraph/rbs_map/core_signs.rb +2 -0
- data/lib/solargraph/rbs_map/stdlib_map.rb +2 -5
- data/lib/solargraph/rbs_map.rb +20 -11
- data/lib/solargraph/shell.rb +62 -59
- data/lib/solargraph/source/chain/array.rb +32 -0
- data/lib/solargraph/source/chain/block_symbol.rb +13 -0
- data/lib/solargraph/source/chain/call.rb +99 -46
- 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 +8 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain/z_super.rb +3 -3
- data/lib/solargraph/source/chain.rb +29 -14
- data/lib/solargraph/source/change.rb +3 -0
- data/lib/solargraph/source/cursor.rb +2 -0
- data/lib/solargraph/source/source_chainer.rb +8 -5
- data/lib/solargraph/source.rb +18 -19
- data/lib/solargraph/source_map/clip.rb +25 -23
- data/lib/solargraph/source_map/mapper.rb +12 -1
- data/lib/solargraph/source_map.rb +30 -7
- data/lib/solargraph/type_checker/checks.rb +10 -2
- data/lib/solargraph/type_checker.rb +123 -45
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +14 -11
- data/lib/solargraph/workspace.rb +3 -2
- 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 +11 -1
- 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 -284
- data/lib/solargraph/yard_tags.rb +20 -0
- data/lib/solargraph/yardoc.rb +52 -0
- data/lib/solargraph.rb +6 -4
- data/solargraph.gemspec +11 -5
- metadata +131 -75
- data/lib/solargraph/api_map/bundler_methods.rb +0 -22
- data/lib/solargraph/convention/rspec.rb +0 -30
- data/lib/solargraph/documentor.rb +0 -76
- 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 -35
- data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
- data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
- data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +0 -23
- data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
- data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
- data/lib/solargraph/parser/legacy.rb +0 -12
- data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -149
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
- data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
- 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/def_node.rb +0 -75
- data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
- 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 -45
- 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 -63
- data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
- data/lib/solargraph/parser/rubyvm.rb +0 -40
- data/lib/yard-solargraph.rb +0 -33
|
@@ -1,8 +1,7 @@
|
|
|
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
7
|
# An index of pins and other ApiMap-related data for a Source.
|
|
@@ -18,7 +17,7 @@ module Solargraph
|
|
|
18
17
|
# @return [Array<Pin::Base>]
|
|
19
18
|
attr_reader :pins
|
|
20
19
|
|
|
21
|
-
# @return [Array<Pin::
|
|
20
|
+
# @return [Array<Pin::LocalVariable>]
|
|
22
21
|
attr_reader :locals
|
|
23
22
|
|
|
24
23
|
# @param source [Source]
|
|
@@ -30,17 +29,21 @@ module Solargraph
|
|
|
30
29
|
@pins = pins
|
|
31
30
|
@locals = locals
|
|
32
31
|
environ.merge Convention.for_local(self) unless filename.nil?
|
|
32
|
+
self.convention_pins = environ.pins
|
|
33
33
|
@pin_class_hash = pins.to_set.classify(&:class).transform_values(&:to_a)
|
|
34
34
|
@pin_select_cache = {}
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# @param klass [Class]
|
|
38
|
+
# @return [Array<Pin::Base>]
|
|
37
39
|
def pins_by_class klass
|
|
38
40
|
@pin_select_cache[klass] ||= @pin_class_hash.select { |key, _| key <= klass }.values.flatten
|
|
39
41
|
end
|
|
40
42
|
|
|
43
|
+
# @return [Set<String>]
|
|
41
44
|
def rebindable_method_names
|
|
42
45
|
@rebindable_method_names ||= pins_by_class(Pin::Method)
|
|
43
|
-
.select { |pin| pin.comments && pin.comments.include?('@
|
|
46
|
+
.select { |pin| pin.comments && pin.comments.include?('@yieldreceiver') }
|
|
44
47
|
.map(&:name)
|
|
45
48
|
.to_set
|
|
46
49
|
end
|
|
@@ -65,11 +68,12 @@ module Solargraph
|
|
|
65
68
|
@environ ||= Environ.new
|
|
66
69
|
end
|
|
67
70
|
|
|
71
|
+
# all pins except Solargraph::Pin::Reference::Reference
|
|
68
72
|
# @return [Array<Pin::Base>]
|
|
69
73
|
def document_symbols
|
|
70
|
-
@document_symbols ||= pins.select
|
|
74
|
+
@document_symbols ||= (pins + convention_pins).select do |pin|
|
|
71
75
|
pin.path && !pin.path.empty?
|
|
72
|
-
|
|
76
|
+
end
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
# @param query [String]
|
|
@@ -97,10 +101,16 @@ module Solargraph
|
|
|
97
101
|
(pins + locals).select { |pin| pin.location == location }
|
|
98
102
|
end
|
|
99
103
|
|
|
104
|
+
# @param line [Integer]
|
|
105
|
+
# @param character [Integer]
|
|
106
|
+
# @return [Pin::Method,Pin::Namespace]
|
|
100
107
|
def locate_named_path_pin line, character
|
|
101
108
|
_locate_pin line, character, Pin::Namespace, Pin::Method
|
|
102
109
|
end
|
|
103
110
|
|
|
111
|
+
# @param line [Integer]
|
|
112
|
+
# @param character [Integer]
|
|
113
|
+
# @return [Pin::Namespace,Pin::Method,Pin::Block]
|
|
104
114
|
def locate_block_pin line, character
|
|
105
115
|
_locate_pin line, character, Pin::Namespace, Pin::Method, Pin::Block
|
|
106
116
|
end
|
|
@@ -159,10 +169,23 @@ module Solargraph
|
|
|
159
169
|
|
|
160
170
|
private
|
|
161
171
|
|
|
172
|
+
# @return [Array<Pin::Base>]
|
|
173
|
+
def convention_pins
|
|
174
|
+
@convention_pins || []
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# @param pins [Array<Pin::Base>]
|
|
178
|
+
# @return [Array<Pin::Base>]
|
|
179
|
+
def convention_pins=(pins)
|
|
180
|
+
# unmemoizing the document_symbols in case it was called from any of convnetions
|
|
181
|
+
@document_symbols = nil
|
|
182
|
+
@convention_pins = pins
|
|
183
|
+
end
|
|
184
|
+
|
|
162
185
|
# @param line [Integer]
|
|
163
186
|
# @param character [Integer]
|
|
164
187
|
# @param klasses [Array<Class>]
|
|
165
|
-
# @return [Pin::Base]
|
|
188
|
+
# @return [Pin::Base, nil]
|
|
166
189
|
def _locate_pin line, character, *klasses
|
|
167
190
|
position = Position.new(line, character)
|
|
168
191
|
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
|
|
@@ -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)
|
|
@@ -91,7 +93,12 @@ module Solargraph
|
|
|
91
93
|
declared = pin.typify(api_map).self_to(pin.full_context.namespace)
|
|
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(pin.full_context.namespace)
|
|
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?
|
|
@@ -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(pin.full_context.namespace)
|
|
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|
|
|
@@ -243,7 +269,7 @@ module Solargraph
|
|
|
243
269
|
end
|
|
244
270
|
closest = found.typify(api_map) if found
|
|
245
271
|
if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
|
|
246
|
-
unless closest.
|
|
272
|
+
unless closest.generic? || ignored_pins.include?(found)
|
|
247
273
|
result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
|
|
248
274
|
@marked_ranges.push rng
|
|
249
275
|
end
|
|
@@ -254,12 +280,21 @@ module Solargraph
|
|
|
254
280
|
result
|
|
255
281
|
end
|
|
256
282
|
|
|
283
|
+
# @param chain [Solargraph::Source::Chain]
|
|
284
|
+
# @param api_map [Solargraph::ApiMap]
|
|
285
|
+
# @param block_pin [Solargraph::Pin::Base]
|
|
286
|
+
# @param locals [Array<Solargraph::Pin::Base>]
|
|
287
|
+
# @param location [Solargraph::Location]
|
|
288
|
+
# @return [Array<Problem>]
|
|
257
289
|
def argument_problems_for chain, api_map, block_pin, locals, location
|
|
258
290
|
result = []
|
|
259
291
|
base = chain
|
|
260
292
|
until base.links.length == 1 && base.undefined?
|
|
261
293
|
pins = base.define(api_map, block_pin, locals)
|
|
262
|
-
|
|
294
|
+
|
|
295
|
+
if pins.first.is_a?(Pin::DelegatedMethod) && !pins.first.resolvable?(api_map)
|
|
296
|
+
# Do nothing, as we can't find the actual method implementation
|
|
297
|
+
elsif pins.first.is_a?(Pin::Method)
|
|
263
298
|
# @type [Pin::Method]
|
|
264
299
|
pin = pins.first
|
|
265
300
|
ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
|
|
@@ -271,21 +306,30 @@ module Solargraph
|
|
|
271
306
|
result.concat ap
|
|
272
307
|
break
|
|
273
308
|
end
|
|
274
|
-
break
|
|
309
|
+
break if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
|
|
310
|
+
|
|
275
311
|
params = first_param_hash(pins)
|
|
276
312
|
|
|
277
313
|
all_errors = []
|
|
278
314
|
pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
|
|
279
315
|
errors = []
|
|
316
|
+
# @todo these should be able to be probed
|
|
317
|
+
# @param par [Parameter]
|
|
318
|
+
# @param idx [Integer]
|
|
280
319
|
sig.parameters.each_with_index do |par, idx|
|
|
281
320
|
argchain = base.links.last.arguments[idx]
|
|
282
|
-
if argchain.nil?
|
|
283
|
-
|
|
284
|
-
|
|
321
|
+
if argchain.nil?
|
|
322
|
+
if par.decl == :arg
|
|
323
|
+
errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
|
|
324
|
+
next
|
|
325
|
+
else
|
|
326
|
+
last = base.links.last.arguments.last
|
|
327
|
+
argchain = last if last && [:kwsplat, :hash].include?(last.node.type)
|
|
328
|
+
end
|
|
285
329
|
end
|
|
286
330
|
if argchain
|
|
287
331
|
if par.decl != :arg
|
|
288
|
-
errors.concat kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, idx
|
|
332
|
+
errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
|
|
289
333
|
next
|
|
290
334
|
else
|
|
291
335
|
ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
|
|
@@ -317,35 +361,53 @@ module Solargraph
|
|
|
317
361
|
result
|
|
318
362
|
end
|
|
319
363
|
|
|
320
|
-
|
|
364
|
+
# @param sig [Pin::Signature]
|
|
365
|
+
# @param argchain [Source::Chain]
|
|
366
|
+
# @param api_map [ApiMap]
|
|
367
|
+
# @param block_pin [Pin::Block]
|
|
368
|
+
# @param locals [Array<Pin::LocalVariable>]
|
|
369
|
+
# @param location [Location]
|
|
370
|
+
# @param pin [Pin::Method]
|
|
371
|
+
# @param params [Hash{String => [nil, Hash]}]
|
|
372
|
+
# @param idx [Integer]
|
|
373
|
+
#
|
|
374
|
+
# @return [Array<Problem>]
|
|
375
|
+
def kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
|
|
321
376
|
result = []
|
|
322
377
|
kwargs = convert_hash(argchain.node)
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
next if ptype.undefined?
|
|
378
|
+
par = sig.parameters[idx]
|
|
379
|
+
argchain = kwargs[par.name.to_sym]
|
|
380
|
+
if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
|
|
381
|
+
result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
|
|
382
|
+
else
|
|
383
|
+
if argchain
|
|
384
|
+
data = params[par.name]
|
|
385
|
+
if data.nil?
|
|
386
|
+
# @todo Some level (strong, I guess) should require the param here
|
|
387
|
+
else
|
|
388
|
+
ptype = data[:qualified]
|
|
389
|
+
unless ptype.undefined?
|
|
336
390
|
argtype = argchain.infer(api_map, block_pin, locals)
|
|
337
391
|
if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
|
|
338
392
|
result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
|
339
393
|
end
|
|
340
394
|
end
|
|
341
|
-
elsif par.decl == :kwarg
|
|
342
|
-
result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
|
343
395
|
end
|
|
396
|
+
elsif par.decl == :kwarg
|
|
397
|
+
result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
|
344
398
|
end
|
|
345
399
|
end
|
|
346
400
|
result
|
|
347
401
|
end
|
|
348
402
|
|
|
403
|
+
# @param api_map [ApiMap]
|
|
404
|
+
# @param block_pin [Pin::Block]
|
|
405
|
+
# @param locals [Array<Pin::LocalVariable>]
|
|
406
|
+
# @param location [Location]
|
|
407
|
+
# @param pin [Pin::Method]
|
|
408
|
+
# @param params [Hash{String => [nil, Hash]}]
|
|
409
|
+
# @param kwargs [Hash{Symbol => Source::Chain}]
|
|
410
|
+
# @return [Array<Problem>]
|
|
349
411
|
def kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
|
|
350
412
|
result = []
|
|
351
413
|
kwargs.each_pair do |pname, argchain|
|
|
@@ -359,8 +421,8 @@ module Solargraph
|
|
|
359
421
|
result
|
|
360
422
|
end
|
|
361
423
|
|
|
362
|
-
# @param [Pin::Method]
|
|
363
|
-
# @return [Hash]
|
|
424
|
+
# @param pin [Pin::Method]
|
|
425
|
+
# @return [Hash{String => Hash{Symbol => BaseObject}}]
|
|
364
426
|
def param_hash(pin)
|
|
365
427
|
tags = pin.docstring.tags(:param)
|
|
366
428
|
return {} if tags.empty?
|
|
@@ -375,10 +437,12 @@ module Solargraph
|
|
|
375
437
|
result
|
|
376
438
|
end
|
|
377
439
|
|
|
378
|
-
# @param [Array<Pin::Method>]
|
|
379
|
-
# @return [Hash]
|
|
440
|
+
# @param pins [Array<Pin::Method>]
|
|
441
|
+
# @return [Hash{String => Hash{Symbol => BasicObject}}]
|
|
380
442
|
def first_param_hash(pins)
|
|
381
443
|
pins.each do |pin|
|
|
444
|
+
# @todo this assignment from parametric use of Hash should not lose its generic
|
|
445
|
+
# @type [Hash{String => Hash{Symbol => BasicObject}]
|
|
382
446
|
result = param_hash(pin)
|
|
383
447
|
return result unless result.empty?
|
|
384
448
|
end
|
|
@@ -392,6 +456,7 @@ module Solargraph
|
|
|
392
456
|
end
|
|
393
457
|
|
|
394
458
|
# True if the pin is either internal (part of the workspace) or from the core/stdlib
|
|
459
|
+
# @param pin [Pin::Base]
|
|
395
460
|
def internal_or_core? pin
|
|
396
461
|
# @todo RBS pins are not necessarily core/stdlib pins
|
|
397
462
|
internal?(pin) || pin.source == :rbs
|
|
@@ -402,6 +467,7 @@ module Solargraph
|
|
|
402
467
|
!internal? pin
|
|
403
468
|
end
|
|
404
469
|
|
|
470
|
+
# @param pin [Pin::Base]
|
|
405
471
|
def declared_externally? pin
|
|
406
472
|
return true if pin.assignment.nil?
|
|
407
473
|
chain = Solargraph::Parser.chain(pin.assignment, filename)
|
|
@@ -429,6 +495,10 @@ module Solargraph
|
|
|
429
495
|
true
|
|
430
496
|
end
|
|
431
497
|
|
|
498
|
+
# @param pin [Pin::Method]
|
|
499
|
+
# @param arguments [Array<Source::Chain>]
|
|
500
|
+
# @param location [Location]
|
|
501
|
+
# @return [Array<Problem>]
|
|
432
502
|
def arity_problems_for pin, arguments, location
|
|
433
503
|
results = pin.signatures.map do |sig|
|
|
434
504
|
r = parameterized_arity_problems_for(pin, sig.parameters, arguments, location)
|
|
@@ -438,16 +508,15 @@ module Solargraph
|
|
|
438
508
|
results.first
|
|
439
509
|
end
|
|
440
510
|
|
|
511
|
+
# @param pin [Pin::Method]
|
|
512
|
+
# @param parameters [Array<Pin::Parameter>]
|
|
513
|
+
# @param arguments [Array<Source::Chain>]
|
|
514
|
+
# @param location [Location]
|
|
515
|
+
# @return [Array<Problem>]
|
|
441
516
|
def parameterized_arity_problems_for(pin, parameters, arguments, location)
|
|
442
517
|
return [] unless pin.explicit?
|
|
443
518
|
return [] if parameters.empty? && arguments.empty?
|
|
444
519
|
return [] if pin.anon_splat?
|
|
445
|
-
if parameters.empty?
|
|
446
|
-
# Functions tagged param_tuple accepts two arguments (e.g., Hash#[]=)
|
|
447
|
-
return [] if pin.docstring.tag(:param_tuple) && arguments.length == 2
|
|
448
|
-
return [] if arguments.length == 1 && arguments.last.links.last.is_a?(Source::Chain::BlockVariable)
|
|
449
|
-
return [Problem.new(location, "Too many arguments to #{pin.path}")]
|
|
450
|
-
end
|
|
451
520
|
unchecked = arguments.clone
|
|
452
521
|
add_params = 0
|
|
453
522
|
if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
|
|
@@ -487,9 +556,6 @@ module Solargraph
|
|
|
487
556
|
return [] if parameters.any?(&:rest?)
|
|
488
557
|
opt = optional_param_count(parameters)
|
|
489
558
|
return [] if unchecked.length <= req + opt
|
|
490
|
-
if unchecked.length == req + opt + 1 && unchecked.last.links.last.is_a?(Source::Chain::BlockVariable)
|
|
491
|
-
return []
|
|
492
|
-
end
|
|
493
559
|
if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
|
|
494
560
|
return []
|
|
495
561
|
end
|
|
@@ -505,20 +571,30 @@ module Solargraph
|
|
|
505
571
|
[]
|
|
506
572
|
end
|
|
507
573
|
|
|
574
|
+
# @param parameters [Enumerable<Pin::Parameter>]
|
|
575
|
+
# @todo need to use generic types in method to choose correct
|
|
576
|
+
# signature and generate Integer as return type
|
|
577
|
+
# @sg-ignore
|
|
578
|
+
# @return [Integer]
|
|
508
579
|
def required_param_count(parameters)
|
|
509
580
|
parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
|
|
510
581
|
end
|
|
511
582
|
|
|
583
|
+
# @param parameters [Enumerable<Pin::Parameter>]
|
|
512
584
|
# @param pin [Pin::Method]
|
|
585
|
+
# @return [Integer]
|
|
513
586
|
def optional_param_count(parameters)
|
|
514
587
|
parameters.select { |p| p.decl == :optarg }.length
|
|
515
588
|
end
|
|
516
589
|
|
|
590
|
+
# @param pin [Pin::Method]
|
|
517
591
|
def abstract? pin
|
|
518
|
-
pin.docstring.has_tag?(
|
|
519
|
-
(pin.closure && pin.closure.docstring.has_tag?(
|
|
592
|
+
pin.docstring.has_tag?('abstract') ||
|
|
593
|
+
(pin.closure && pin.closure.docstring.has_tag?('abstract'))
|
|
520
594
|
end
|
|
521
595
|
|
|
596
|
+
# @param pin [Pin::Base]
|
|
597
|
+
# @return [Array<Source::Chain>]
|
|
522
598
|
def fake_args_for(pin)
|
|
523
599
|
args = []
|
|
524
600
|
with_opts = false
|
|
@@ -539,10 +615,12 @@ module Solargraph
|
|
|
539
615
|
args
|
|
540
616
|
end
|
|
541
617
|
|
|
618
|
+
# @param problems [Array<Problem>]
|
|
619
|
+
# @return [Array<Problem>]
|
|
542
620
|
def without_ignored problems
|
|
543
621
|
problems.reject do |problem|
|
|
544
622
|
node = source_map.source.node_at(problem.location.range.start.line, problem.location.range.start.column)
|
|
545
|
-
source_map.source.comments_for(node)&.include?('@sg-ignore')
|
|
623
|
+
node && source_map.source.comments_for(node)&.include?('@sg-ignore')
|
|
546
624
|
end
|
|
547
625
|
end
|
|
548
626
|
end
|
data/lib/solargraph/version.rb
CHANGED
|
@@ -14,12 +14,12 @@ module Solargraph
|
|
|
14
14
|
# @return [String]
|
|
15
15
|
attr_reader :directory
|
|
16
16
|
|
|
17
|
-
# @return [Hash]
|
|
17
|
+
# @return [Hash{String => BasicObject}]
|
|
18
18
|
attr_reader :raw_data
|
|
19
19
|
|
|
20
20
|
# @param directory [String]
|
|
21
21
|
def initialize directory = ''
|
|
22
|
-
@directory = directory
|
|
22
|
+
@directory = File.absolute_path(directory)
|
|
23
23
|
@raw_data = config_data
|
|
24
24
|
included
|
|
25
25
|
excluded
|
|
@@ -41,8 +41,10 @@ module Solargraph
|
|
|
41
41
|
@excluded ||= process_exclusions(@raw_data['exclude'])
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# @param filename [String]
|
|
44
45
|
def allow? filename
|
|
45
|
-
filename.
|
|
46
|
+
filename = File.absolute_path(filename, directory)
|
|
47
|
+
filename.start_with?(directory) &&
|
|
46
48
|
!excluded.include?(filename) &&
|
|
47
49
|
excluded_directories.none? { |d| filename.start_with?(d) }
|
|
48
50
|
end
|
|
@@ -110,7 +112,7 @@ module Solargraph
|
|
|
110
112
|
|
|
111
113
|
# @return [String]
|
|
112
114
|
def global_config_path
|
|
113
|
-
ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
|
|
115
|
+
ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
|
|
114
116
|
File.join(Dir.home, '.config', 'solargraph', 'config.yml')
|
|
115
117
|
end
|
|
116
118
|
|
|
@@ -120,7 +122,7 @@ module Solargraph
|
|
|
120
122
|
File.join(@directory, '.solargraph.yml')
|
|
121
123
|
end
|
|
122
124
|
|
|
123
|
-
# @return [Hash]
|
|
125
|
+
# @return [Hash{String => Array, Hash, Integer}]
|
|
124
126
|
def config_data
|
|
125
127
|
workspace_config = read_config(workspace_config_path)
|
|
126
128
|
global_config = read_config(global_config_path)
|
|
@@ -135,15 +137,15 @@ module Solargraph
|
|
|
135
137
|
|
|
136
138
|
# Read a .solargraph yaml config
|
|
137
139
|
#
|
|
138
|
-
# @param
|
|
139
|
-
# @return [Hash, nil]
|
|
140
|
+
# @param config_path [String]
|
|
141
|
+
# @return [Hash{String => Array, Hash, Integer}, nil]
|
|
140
142
|
def read_config config_path = ''
|
|
141
143
|
return nil if config_path.empty?
|
|
142
144
|
return nil unless File.file?(config_path)
|
|
143
145
|
YAML.safe_load(File.read(config_path))
|
|
144
146
|
end
|
|
145
147
|
|
|
146
|
-
# @return [Hash]
|
|
148
|
+
# @return [Hash{String => Array, Hash, Integer}]
|
|
147
149
|
def default_config
|
|
148
150
|
{
|
|
149
151
|
'include' => ['**/*.rb'],
|
|
@@ -171,7 +173,7 @@ module Solargraph
|
|
|
171
173
|
# @return [Array<String>]
|
|
172
174
|
def process_globs globs
|
|
173
175
|
result = globs.flat_map do |glob|
|
|
174
|
-
Dir[File.
|
|
176
|
+
Dir[File.absolute_path(glob, directory)]
|
|
175
177
|
.map{ |f| f.gsub(/\\/, '/') }
|
|
176
178
|
.select { |f| File.file?(f) }
|
|
177
179
|
end
|
|
@@ -186,7 +188,7 @@ module Solargraph
|
|
|
186
188
|
def process_exclusions globs
|
|
187
189
|
remainder = globs.select do |glob|
|
|
188
190
|
if glob_is_directory?(glob)
|
|
189
|
-
exdir = File.
|
|
191
|
+
exdir = File.absolute_path(glob_to_directory(glob), directory)
|
|
190
192
|
included.delete_if { |file| file.start_with?(exdir) }
|
|
191
193
|
false
|
|
192
194
|
else
|
|
@@ -221,10 +223,11 @@ module Solargraph
|
|
|
221
223
|
glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
|
|
222
224
|
end
|
|
223
225
|
|
|
226
|
+
# @return [Array<String>]
|
|
224
227
|
def excluded_directories
|
|
225
228
|
@raw_data['exclude']
|
|
226
229
|
.select { |g| glob_is_directory?(g) }
|
|
227
|
-
.map { |g| File.
|
|
230
|
+
.map { |g| File.absolute_path(glob_to_directory(g), directory) }
|
|
228
231
|
end
|
|
229
232
|
end
|
|
230
233
|
end
|
data/lib/solargraph/workspace.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'open3'
|
|
4
|
-
require 'rubygems'
|
|
5
4
|
require 'json'
|
|
6
5
|
|
|
7
6
|
module Solargraph
|
|
@@ -104,7 +103,8 @@ module Solargraph
|
|
|
104
103
|
# @return [Boolean]
|
|
105
104
|
def would_require? path
|
|
106
105
|
require_paths.each do |rp|
|
|
107
|
-
|
|
106
|
+
full = File.join rp, path
|
|
107
|
+
return true if File.exist?(full) or File.exist?(full << ".rb")
|
|
108
108
|
end
|
|
109
109
|
false
|
|
110
110
|
end
|
|
@@ -199,6 +199,7 @@ module Solargraph
|
|
|
199
199
|
config.require_paths.map{|p| File.join(directory, p)}
|
|
200
200
|
end
|
|
201
201
|
|
|
202
|
+
# @return [void]
|
|
202
203
|
def require_plugins
|
|
203
204
|
config.plugins.each do |plugin|
|
|
204
205
|
begin
|
|
@@ -4,13 +4,19 @@ module Solargraph
|
|
|
4
4
|
class YardMap
|
|
5
5
|
class Cache
|
|
6
6
|
def initialize
|
|
7
|
+
# @type [Hash{String => Array<Solargraph::Pin::Base>}]
|
|
7
8
|
@path_pins = {}
|
|
8
9
|
end
|
|
9
10
|
|
|
11
|
+
# @param path [String]
|
|
12
|
+
# @param pins [Array<Solargraph::Pin::Base>]
|
|
13
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
10
14
|
def set_path_pins path, pins
|
|
11
15
|
@path_pins[path] = pins
|
|
12
16
|
end
|
|
13
17
|
|
|
18
|
+
# @param path [String]
|
|
19
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
14
20
|
def get_path_pins path
|
|
15
21
|
@path_pins[path]
|
|
16
22
|
end
|
|
@@ -4,7 +4,7 @@ module Solargraph
|
|
|
4
4
|
module_function
|
|
5
5
|
|
|
6
6
|
# @param code_object [YARD::CodeObjects::Base]
|
|
7
|
-
# @param spec [Gem::Specification]
|
|
7
|
+
# @param spec [Gem::Specification, nil]
|
|
8
8
|
# @return [Solargraph::Location, nil]
|
|
9
9
|
def object_location code_object, spec
|
|
10
10
|
return nil if spec.nil? || code_object.nil? || code_object.file.nil? || code_object.line.nil?
|