solargraph 0.56.2 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/linting.yml +125 -0
- data/.github/workflows/plugins.yml +148 -6
- data/.github/workflows/rspec.yml +39 -4
- data/.github/workflows/typecheck.yml +5 -2
- data/.gitignore +5 -0
- data/.overcommit.yml +72 -0
- data/.rspec +1 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +2627 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +42 -0
- data/README.md +8 -4
- data/Rakefile +125 -13
- data/lib/solargraph/api_map/cache.rb +3 -2
- data/lib/solargraph/api_map/constants.rb +218 -0
- data/lib/solargraph/api_map/index.rb +20 -26
- data/lib/solargraph/api_map/source_to_yard.rb +10 -4
- data/lib/solargraph/api_map/store.rb +126 -18
- data/lib/solargraph/api_map.rb +212 -234
- data/lib/solargraph/bench.rb +1 -0
- data/lib/solargraph/complex_type/type_methods.rb +1 -0
- data/lib/solargraph/complex_type/unique_type.rb +7 -7
- data/lib/solargraph/complex_type.rb +5 -1
- data/lib/solargraph/convention/active_support_concern.rb +111 -0
- data/lib/solargraph/convention/base.rb +17 -0
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -0
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
- data/lib/solargraph/convention/data_definition.rb +2 -1
- data/lib/solargraph/convention/gemspec.rb +1 -1
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +3 -1
- data/lib/solargraph/convention/struct_definition.rb +36 -13
- data/lib/solargraph/convention.rb +31 -2
- data/lib/solargraph/diagnostics/rubocop.rb +6 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
- data/lib/solargraph/doc_map.rb +40 -12
- data/lib/solargraph/environ.rb +9 -2
- data/lib/solargraph/gem_pins.rb +17 -11
- data/lib/solargraph/language_server/host/dispatch.rb +2 -0
- data/lib/solargraph/language_server/host/message_worker.rb +3 -0
- data/lib/solargraph/language_server/host.rb +2 -1
- data/lib/solargraph/language_server/message/base.rb +2 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
- data/lib/solargraph/language_server/progress.rb +8 -0
- data/lib/solargraph/language_server/request.rb +1 -0
- data/lib/solargraph/library.rb +8 -15
- data/lib/solargraph/location.rb +2 -0
- data/lib/solargraph/logging.rb +11 -2
- data/lib/solargraph/page.rb +4 -0
- data/lib/solargraph/parser/comment_ripper.rb +8 -1
- data/lib/solargraph/parser/flow_sensitive_typing.rb +32 -4
- data/lib/solargraph/parser/node_methods.rb +2 -2
- data/lib/solargraph/parser/node_processor/base.rb +1 -1
- data/lib/solargraph/parser/node_processor.rb +6 -2
- data/lib/solargraph/parser/parser_gem/class_methods.rb +1 -1
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_methods.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +35 -14
- data/lib/solargraph/parser/region.rb +3 -0
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/pin/base.rb +50 -8
- data/lib/solargraph/pin/base_variable.rb +1 -2
- data/lib/solargraph/pin/callable.rb +9 -0
- data/lib/solargraph/pin/closure.rb +2 -0
- data/lib/solargraph/pin/common.rb +6 -2
- data/lib/solargraph/pin/constant.rb +2 -0
- data/lib/solargraph/pin/delegated_method.rb +1 -0
- data/lib/solargraph/pin/local_variable.rb +4 -1
- data/lib/solargraph/pin/method.rb +8 -5
- data/lib/solargraph/pin/method_alias.rb +3 -0
- data/lib/solargraph/pin/parameter.rb +18 -8
- data/lib/solargraph/pin/proxy_type.rb +1 -0
- data/lib/solargraph/pin/reference/override.rb +15 -1
- data/lib/solargraph/pin/reference/superclass.rb +5 -0
- data/lib/solargraph/pin/reference.rb +26 -0
- data/lib/solargraph/pin/search.rb +3 -1
- data/lib/solargraph/pin/signature.rb +2 -0
- data/lib/solargraph/pin/symbol.rb +5 -0
- data/lib/solargraph/pin_cache.rb +64 -4
- data/lib/solargraph/position.rb +2 -0
- data/lib/solargraph/range.rb +1 -0
- data/lib/solargraph/rbs_map/conversions.rb +7 -5
- data/lib/solargraph/rbs_map/core_map.rb +3 -0
- data/lib/solargraph/rbs_map.rb +15 -2
- data/lib/solargraph/shell.rb +3 -0
- data/lib/solargraph/source/chain/link.rb +10 -1
- data/lib/solargraph/source/chain.rb +9 -2
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/cursor.rb +2 -3
- data/lib/solargraph/source/source_chainer.rb +1 -1
- data/lib/solargraph/source.rb +5 -2
- data/lib/solargraph/source_map/clip.rb +1 -1
- data/lib/solargraph/source_map/data.rb +4 -0
- data/lib/solargraph/source_map/mapper.rb +4 -2
- data/lib/solargraph/source_map.rb +21 -14
- data/lib/solargraph/type_checker/param_def.rb +2 -0
- data/lib/solargraph/type_checker/rules.rb +8 -0
- data/lib/solargraph/type_checker.rb +173 -120
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +0 -2
- data/lib/solargraph/workspace/require_paths.rb +98 -0
- data/lib/solargraph/workspace.rb +16 -48
- data/lib/solargraph/yard_map/mapper/to_method.rb +2 -2
- data/lib/solargraph/yardoc.rb +16 -3
- data/lib/solargraph.rb +2 -0
- data/rbs/fills/tuple.rbs +2 -3
- data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
- data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
- data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
- data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
- data/solargraph.gemspec +14 -4
- metadata +123 -9
- data/lib/.rubocop.yml +0 -22
data/lib/solargraph/api_map.rb
CHANGED
@@ -13,6 +13,7 @@ module Solargraph
|
|
13
13
|
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
14
14
|
autoload :Store, 'solargraph/api_map/store'
|
15
15
|
autoload :Index, 'solargraph/api_map/index'
|
16
|
+
autoload :Constants, 'solargraph/api_map/constants'
|
16
17
|
|
17
18
|
# @return [Array<String>]
|
18
19
|
attr_reader :unresolved_requires
|
@@ -26,7 +27,6 @@ module Solargraph
|
|
26
27
|
def initialize pins: []
|
27
28
|
@source_map_hash = {}
|
28
29
|
@cache = Cache.new
|
29
|
-
@method_alias_stack = []
|
30
30
|
index pins
|
31
31
|
end
|
32
32
|
|
@@ -36,11 +36,13 @@ module Solargraph
|
|
36
36
|
# just caches), please also change `equality_fields` below.
|
37
37
|
#
|
38
38
|
|
39
|
+
# @param other [Object]
|
39
40
|
def eql?(other)
|
40
41
|
self.class == other.class &&
|
41
42
|
equality_fields == other.equality_fields
|
42
43
|
end
|
43
44
|
|
45
|
+
# @param other [Object]
|
44
46
|
def ==(other)
|
45
47
|
self.eql?(other)
|
46
48
|
end
|
@@ -64,7 +66,7 @@ module Solargraph
|
|
64
66
|
# @todo This implementation is incomplete. It should probably create a
|
65
67
|
# Bench.
|
66
68
|
@source_map_hash = {}
|
67
|
-
|
69
|
+
conventions_environ.clear
|
68
70
|
cache.clear
|
69
71
|
store.update @@core_map.pins, pins
|
70
72
|
self
|
@@ -73,10 +75,11 @@ module Solargraph
|
|
73
75
|
# Map a single source.
|
74
76
|
#
|
75
77
|
# @param source [Source]
|
78
|
+
# @param live [Boolean] True for live source map (active editor file)
|
76
79
|
# @return [self]
|
77
|
-
def map source
|
80
|
+
def map source, live: false
|
78
81
|
map = Solargraph::SourceMap.map(source)
|
79
|
-
catalog Bench.new(source_maps: [map])
|
82
|
+
catalog Bench.new(source_maps: [map], live_map: live ? map : nil)
|
80
83
|
self
|
81
84
|
end
|
82
85
|
|
@@ -87,12 +90,12 @@ module Solargraph
|
|
87
90
|
def catalog bench
|
88
91
|
@source_map_hash = bench.source_map_hash
|
89
92
|
iced_pins = bench.icebox.flat_map(&:pins)
|
90
|
-
live_pins = bench.live_map&.
|
91
|
-
|
93
|
+
live_pins = bench.live_map&.all_pins || []
|
94
|
+
conventions_environ.clear
|
92
95
|
source_map_hash.each_value do |map|
|
93
|
-
|
96
|
+
conventions_environ.merge map.conventions_environ
|
94
97
|
end
|
95
|
-
unresolved_requires = (bench.external_requires +
|
98
|
+
unresolved_requires = (bench.external_requires + conventions_environ.requires + bench.workspace.config.required).to_a.compact.uniq
|
96
99
|
recreate_docmap = @unresolved_requires != unresolved_requires ||
|
97
100
|
@doc_map&.uncached_yard_gemspecs&.any? ||
|
98
101
|
@doc_map&.uncached_rbs_collection_gemspecs&.any? ||
|
@@ -101,7 +104,7 @@ module Solargraph
|
|
101
104
|
@doc_map = DocMap.new(unresolved_requires, [], bench.workspace) # @todo Implement gem preferences
|
102
105
|
@unresolved_requires = @doc_map.unresolved_requires
|
103
106
|
end
|
104
|
-
@cache.clear if store.update(@@core_map.pins, @doc_map.pins,
|
107
|
+
@cache.clear if store.update(@@core_map.pins, @doc_map.pins, conventions_environ.pins, iced_pins, live_pins)
|
105
108
|
@missing_docs = [] # @todo Implement missing docs
|
106
109
|
self
|
107
110
|
end
|
@@ -110,9 +113,10 @@ module Solargraph
|
|
110
113
|
# that this overload of 'protected' will typecheck @sg-ignore
|
111
114
|
# @sg-ignore
|
112
115
|
protected def equality_fields
|
113
|
-
[self.class, @source_map_hash,
|
116
|
+
[self.class, @source_map_hash, conventions_environ, @doc_map, @unresolved_requires]
|
114
117
|
end
|
115
118
|
|
119
|
+
# @return [DocMap]
|
116
120
|
def doc_map
|
117
121
|
@doc_map ||= DocMap.new([], [])
|
118
122
|
end
|
@@ -132,7 +136,7 @@ module Solargraph
|
|
132
136
|
@doc_map.uncached_yard_gemspecs
|
133
137
|
end
|
134
138
|
|
135
|
-
# @return [
|
139
|
+
# @return [Enumerable<Pin::Base>]
|
136
140
|
def core_pins
|
137
141
|
@@core_map.pins
|
138
142
|
end
|
@@ -149,8 +153,8 @@ module Solargraph
|
|
149
153
|
end
|
150
154
|
|
151
155
|
# @return [Environ]
|
152
|
-
def
|
153
|
-
@
|
156
|
+
def conventions_environ
|
157
|
+
@conventions_environ ||= Environ.new
|
154
158
|
end
|
155
159
|
|
156
160
|
# @param filename [String]
|
@@ -186,10 +190,16 @@ module Solargraph
|
|
186
190
|
api_map
|
187
191
|
end
|
188
192
|
|
193
|
+
# @param out [IO, nil]
|
194
|
+
# @return [void]
|
189
195
|
def cache_all!(out)
|
190
196
|
@doc_map.cache_all!(out)
|
191
197
|
end
|
192
198
|
|
199
|
+
# @param gemspec [Gem::Specification]
|
200
|
+
# @param rebuild [Boolean]
|
201
|
+
# @param out [IO, nil]
|
202
|
+
# @return [void]
|
193
203
|
def cache_gem(gemspec, rebuild: false, out: nil)
|
194
204
|
@doc_map.cache(gemspec, rebuild: rebuild, out: out)
|
195
205
|
end
|
@@ -202,9 +212,6 @@ module Solargraph
|
|
202
212
|
# any missing gems.
|
203
213
|
#
|
204
214
|
#
|
205
|
-
# @todo IO::NULL is incorrectly inferred to be a String.
|
206
|
-
# @sg-ignore
|
207
|
-
#
|
208
215
|
# @param directory [String]
|
209
216
|
# @param out [IO] The output stream for messages
|
210
217
|
# @return [ApiMap]
|
@@ -255,19 +262,13 @@ module Solargraph
|
|
255
262
|
# @return [Array<Solargraph::Pin::Base>]
|
256
263
|
def get_constants namespace, *contexts
|
257
264
|
namespace ||= ''
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
visibility = [:public]
|
266
|
-
visibility.push :private if fqns == context
|
267
|
-
result.concat inner_get_constants(fqns, visibility, skip)
|
268
|
-
end
|
269
|
-
cache.set_constants(namespace, contexts, result)
|
270
|
-
result
|
265
|
+
gates = contexts.clone
|
266
|
+
gates.push '' if contexts.empty? && namespace.empty?
|
267
|
+
gates.push namespace unless namespace.empty?
|
268
|
+
store.constants
|
269
|
+
.collect(gates)
|
270
|
+
.select { |pin| namespace.empty? || contexts.empty? || pin.namespace == namespace }
|
271
|
+
.select { |pin| pin.visibility == :public || pin.namespace == namespace }
|
271
272
|
end
|
272
273
|
|
273
274
|
# @param namespace [String]
|
@@ -293,44 +294,27 @@ module Solargraph
|
|
293
294
|
# Should not be prefixed with '::'.
|
294
295
|
# @return [String, nil] fully qualified tag
|
295
296
|
def qualify tag, context_tag = ''
|
296
|
-
|
297
|
-
|
298
|
-
context_type = ComplexType.try_parse(context_tag).force_rooted
|
299
|
-
return unless context_type
|
300
|
-
|
301
|
-
type = ComplexType.try_parse(tag)
|
302
|
-
return unless type
|
303
|
-
return tag if type.literal?
|
304
|
-
|
305
|
-
context_type = ComplexType.try_parse(context_tag)
|
306
|
-
return unless context_type
|
297
|
+
store.constants.qualify(tag, context_tag)
|
298
|
+
end
|
307
299
|
|
308
|
-
|
309
|
-
|
300
|
+
# Get a fully qualified namespace from a reference pin.
|
301
|
+
#
|
302
|
+
# @param pin [Pin::Reference]
|
303
|
+
# @return [String, nil]
|
304
|
+
def dereference(pin)
|
305
|
+
store.constants.dereference(pin)
|
306
|
+
end
|
310
307
|
|
311
|
-
|
308
|
+
# @param fqns [String]
|
309
|
+
# @return [Array<String>]
|
310
|
+
def get_extends(fqns)
|
311
|
+
store.get_extends(fqns)
|
312
312
|
end
|
313
313
|
|
314
|
-
#
|
315
|
-
#
|
316
|
-
|
317
|
-
|
318
|
-
#
|
319
|
-
# @param namespace [String, nil] The namespace to
|
320
|
-
# match
|
321
|
-
# @param context_namespace [String] The context namespace in which the
|
322
|
-
# tag was referenced; start from here to resolve the name
|
323
|
-
# @return [String, nil] fully qualified namespace
|
324
|
-
def qualify_namespace(namespace, context_namespace = '')
|
325
|
-
cached = cache.get_qualified_namespace(namespace, context_namespace)
|
326
|
-
return cached.clone unless cached.nil?
|
327
|
-
result = if namespace.start_with?('::')
|
328
|
-
inner_qualify(namespace[2..-1], '', Set.new)
|
329
|
-
else
|
330
|
-
inner_qualify(namespace, context_namespace, Set.new)
|
331
|
-
end
|
332
|
-
cache.set_qualified_namespace(namespace, context_namespace, result)
|
333
|
-
result
|
314
|
+
# @param fqns [String]
|
315
|
+
# @return [Array<String>]
|
316
|
+
def get_includes(fqns)
|
317
|
+
store.get_includes(fqns)
|
334
318
|
end
|
335
319
|
|
336
320
|
# Get an array of instance variable pins defined in specified namespace
|
@@ -343,15 +327,15 @@ module Solargraph
|
|
343
327
|
result = []
|
344
328
|
used = [namespace]
|
345
329
|
result.concat store.get_instance_variables(namespace, scope)
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
result.concat store.get_instance_variables(
|
350
|
-
sc = qualify_lower(store.get_superclass(sc), sc)
|
330
|
+
sc_fqns = namespace
|
331
|
+
while (sc = store.get_superclass(sc_fqns))
|
332
|
+
sc_fqns = store.constants.dereference(sc)
|
333
|
+
result.concat store.get_instance_variables(sc_fqns, scope)
|
351
334
|
end
|
352
335
|
result
|
353
336
|
end
|
354
337
|
|
338
|
+
# @sg-ignore Missing @return tag for Solargraph::ApiMap#visible_pins
|
355
339
|
# @see Solargraph::Parser::FlowSensitiveTyping#visible_pins
|
356
340
|
def visible_pins(*args, **kwargs, &blk)
|
357
341
|
Solargraph::Parser::FlowSensitiveTyping.visible_pins(*args, **kwargs, &blk)
|
@@ -403,7 +387,7 @@ module Solargraph
|
|
403
387
|
skip = Set.new
|
404
388
|
if rooted_tag == ''
|
405
389
|
# @todo Implement domains
|
406
|
-
|
390
|
+
conventions_environ.domains.each do |domain|
|
407
391
|
type = ComplexType.try_parse(domain)
|
408
392
|
next if type.undefined?
|
409
393
|
result.concat inner_get_methods(type.name, type.scope, visibility, deep, skip)
|
@@ -514,12 +498,24 @@ module Solargraph
|
|
514
498
|
# @param rooted_tag [String] Parameterized namespace, fully qualified
|
515
499
|
# @param name [String] Method name to look up
|
516
500
|
# @param scope [Symbol] :instance or :class
|
501
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
502
|
+
# @param preserve_generics [Boolean]
|
517
503
|
# @return [Array<Solargraph::Pin::Method>]
|
518
504
|
def get_method_stack rooted_tag, name, scope: :instance, visibility: [:private, :protected, :public], preserve_generics: false
|
519
505
|
rooted_type = ComplexType.parse(rooted_tag)
|
520
506
|
fqns = rooted_type.namespace
|
521
|
-
namespace_pin = store.get_path_pins(fqns).
|
522
|
-
methods =
|
507
|
+
namespace_pin = store.get_path_pins(fqns).first
|
508
|
+
methods = if namespace_pin.is_a?(Pin::Constant)
|
509
|
+
type = namespace_pin.infer(self)
|
510
|
+
if type.defined?
|
511
|
+
namespace_pin = store.get_path_pins(type.namespace).first
|
512
|
+
get_methods(type.namespace, scope: scope, visibility: visibility).select { |p| p.name == name }
|
513
|
+
else
|
514
|
+
[]
|
515
|
+
end
|
516
|
+
else
|
517
|
+
get_methods(rooted_tag, scope: scope, visibility: visibility).select { |p| p.name == name }
|
518
|
+
end
|
523
519
|
methods = erase_generics(namespace_pin, rooted_type, methods) unless preserve_generics
|
524
520
|
methods
|
525
521
|
end
|
@@ -629,13 +625,22 @@ module Solargraph
|
|
629
625
|
# @param sub [String] The subclass
|
630
626
|
# @return [Boolean]
|
631
627
|
def super_and_sub?(sup, sub)
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
628
|
+
sup = ComplexType.try_parse(sup)
|
629
|
+
sub = ComplexType.try_parse(sub)
|
630
|
+
# @todo If two literals are different values of the same type, it would
|
631
|
+
# make more sense for super_and_sub? to return true, but there are a
|
632
|
+
# few callers that currently expect this to be false.
|
633
|
+
return false if sup.literal? && sub.literal? && sup.to_s != sub.to_s
|
634
|
+
sup = sup.simplify_literals.to_s
|
635
|
+
sub = sub.simplify_literals.to_s
|
636
|
+
return true if sup == sub
|
637
|
+
sc_fqns = sub
|
638
|
+
while (sc = store.get_superclass(sc_fqns))
|
639
|
+
sc_new = store.constants.dereference(sc)
|
640
|
+
# Cyclical inheritance is invalid
|
641
|
+
return false if sc_new == sc_fqns
|
642
|
+
sc_fqns = sc_new
|
643
|
+
return true if sc_fqns == sup
|
639
644
|
end
|
640
645
|
false
|
641
646
|
end
|
@@ -648,7 +653,7 @@ module Solargraph
|
|
648
653
|
#
|
649
654
|
# @return [Boolean]
|
650
655
|
def type_include?(host_ns, module_ns)
|
651
|
-
store.get_includes(host_ns).map { |inc_tag|
|
656
|
+
store.get_includes(host_ns).map { |inc_tag| inc_tag.parametrized_tag.name }.include?(module_ns)
|
652
657
|
end
|
653
658
|
|
654
659
|
# @param pins [Enumerable<Pin::Base>]
|
@@ -656,6 +661,7 @@ module Solargraph
|
|
656
661
|
# @return [Array<Pin::Base>]
|
657
662
|
def resolve_method_aliases pins, visibility = [:public, :private, :protected]
|
658
663
|
with_resolved_aliases = pins.map do |pin|
|
664
|
+
next pin unless pin.is_a?(Pin::MethodAlias)
|
659
665
|
resolved = resolve_method_alias(pin)
|
660
666
|
next nil if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
|
661
667
|
resolved
|
@@ -664,6 +670,41 @@ module Solargraph
|
|
664
670
|
GemPins.combine_method_pins_by_path(with_resolved_aliases)
|
665
671
|
end
|
666
672
|
|
673
|
+
# @param fq_reference_tag [String] A fully qualified whose method should be pulled in
|
674
|
+
# @param namespace_pin [Pin::Base] Namespace pin for the rooted_type
|
675
|
+
# parameter - used to pull generics information
|
676
|
+
# @param type [ComplexType] The type which is having its
|
677
|
+
# methods supplemented from fq_reference_tag
|
678
|
+
# @param scope [Symbol] :class or :instance
|
679
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
680
|
+
# @param deep [Boolean]
|
681
|
+
# @param skip [Set<String>]
|
682
|
+
# @param no_core [Boolean] Skip core classes if true
|
683
|
+
# @return [Array<Pin::Base>]
|
684
|
+
def inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core)
|
685
|
+
logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) starting" }
|
686
|
+
|
687
|
+
# Ensure the types returned by the methods in the referenced
|
688
|
+
# type are relative to the generic values passed in the
|
689
|
+
# reference. e.g., Foo<String> might include Enumerable<String>
|
690
|
+
#
|
691
|
+
# @todo perform the same translation in the other areas
|
692
|
+
# here after adding a spec and handling things correctly
|
693
|
+
# in ApiMap::Store and RbsMap::Conversions for each
|
694
|
+
resolved_reference_type = ComplexType.parse(fq_reference_tag).force_rooted.resolve_generics(namespace_pin, type)
|
695
|
+
# @todo Can inner_get_methods be cached? Lots of lookups of base types going on.
|
696
|
+
methods = inner_get_methods(resolved_reference_type.tag, scope, visibility, deep, skip, no_core)
|
697
|
+
if namespace_pin && !resolved_reference_type.all_params.empty?
|
698
|
+
reference_pin = store.get_path_pins(resolved_reference_type.name).select { |p| p.is_a?(Pin::Namespace) }.first
|
699
|
+
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolving generics with #{reference_pin.generics}, #{resolved_reference_type.rooted_tags}" }
|
700
|
+
methods = methods.map do |method_pin|
|
701
|
+
method_pin.resolve_generics(reference_pin, resolved_reference_type)
|
702
|
+
end
|
703
|
+
end
|
704
|
+
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolved_reference_type: #{resolved_reference_type} for type=#{type}: #{methods.map(&:name)}" }
|
705
|
+
methods
|
706
|
+
end
|
707
|
+
|
667
708
|
private
|
668
709
|
|
669
710
|
# A hash of source maps with filename keys.
|
@@ -687,6 +728,7 @@ module Solargraph
|
|
687
728
|
# @param skip [Set<String>]
|
688
729
|
# @param no_core [Boolean] Skip core classes if true
|
689
730
|
# @return [Array<Pin::Base>]
|
731
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
690
732
|
def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
|
691
733
|
rooted_type = ComplexType.parse(rooted_tag).force_rooted
|
692
734
|
fqns = rooted_type.namespace
|
@@ -697,9 +739,16 @@ module Solargraph
|
|
697
739
|
return [] if skip.include?(reqstr)
|
698
740
|
skip.add reqstr
|
699
741
|
result = []
|
742
|
+
environ = Convention.for_object(self, rooted_tag, scope, visibility, deep, skip, no_core)
|
743
|
+
# ensure we start out with any immediate methods in this
|
744
|
+
# namespace so we roughly match the same ordering of get_methods
|
745
|
+
# and obey the 'deep' instruction
|
746
|
+
direct_convention_methods, convention_methods_by_reference = environ.pins.partition { |p| p.namespace == rooted_tag }
|
747
|
+
result.concat direct_convention_methods
|
748
|
+
|
700
749
|
if deep && scope == :instance
|
701
750
|
store.get_prepends(fqns).reverse.each do |im|
|
702
|
-
fqim =
|
751
|
+
fqim = store.constants.dereference(im)
|
703
752
|
result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
|
704
753
|
end
|
705
754
|
end
|
@@ -707,20 +756,33 @@ module Solargraph
|
|
707
756
|
# namespaces; resolving the generics in the method pins is this
|
708
757
|
# class' responsibility
|
709
758
|
methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
|
759
|
+
logger.info { "ApiMap#inner_get_methods(rooted_tag=#{rooted_tag.inspect}, scope=#{scope.inspect}, visibility=#{visibility.inspect}, deep=#{deep.inspect}, skip=#{skip.inspect}, fqns=#{fqns}) - added from store: #{methods}" }
|
710
760
|
result.concat methods
|
711
761
|
if deep
|
762
|
+
result.concat convention_methods_by_reference
|
763
|
+
|
712
764
|
if scope == :instance
|
713
|
-
store.get_includes(fqns).reverse.each do |
|
714
|
-
|
715
|
-
|
765
|
+
store.get_includes(fqns).reverse.each do |ref|
|
766
|
+
const = get_constants('', *ref.closure.gates).find { |pin| pin.path.end_with? ref.name }
|
767
|
+
if const.is_a?(Pin::Namespace)
|
768
|
+
result.concat inner_get_methods(const.path, scope, visibility, deep, skip, true)
|
769
|
+
elsif const.is_a?(Pin::Constant)
|
770
|
+
type = const.infer(self)
|
771
|
+
result.concat inner_get_methods(type.namespace, scope, visibility, deep, skip, true) if type.defined?
|
772
|
+
else
|
773
|
+
referenced_tag = ref.parametrized_tag
|
774
|
+
next unless referenced_tag.defined?
|
775
|
+
result.concat inner_get_methods_from_reference(referenced_tag.to_s, namespace_pin, rooted_type, scope, visibility, deep, skip, true)
|
776
|
+
end
|
716
777
|
end
|
717
778
|
rooted_sc_tag = qualify_superclass(rooted_tag)
|
718
779
|
unless rooted_sc_tag.nil?
|
719
780
|
result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope, visibility, true, skip, no_core)
|
720
781
|
end
|
721
782
|
else
|
783
|
+
logger.info { "ApiMap#inner_get_methods(#{fqns}, #{scope}, #{visibility}, #{deep}, #{skip}) - looking for get_extends() from #{fqns}" }
|
722
784
|
store.get_extends(fqns).reverse.each do |em|
|
723
|
-
fqem =
|
785
|
+
fqem = store.constants.dereference(em)
|
724
786
|
result.concat inner_get_methods(fqem, :instance, visibility, deep, skip, true) unless fqem.nil?
|
725
787
|
end
|
726
788
|
rooted_sc_tag = qualify_superclass(rooted_tag)
|
@@ -740,131 +802,17 @@ module Solargraph
|
|
740
802
|
end
|
741
803
|
result
|
742
804
|
end
|
743
|
-
|
744
|
-
# @param fq_reference_tag [String] A fully qualified whose method should be pulled in
|
745
|
-
# @param namespace_pin [Pin::Base] Namespace pin for the rooted_type
|
746
|
-
# parameter - used to pull generics information
|
747
|
-
# @param type [ComplexType] The type which is having its
|
748
|
-
# methods supplemented from fq_reference_tag
|
749
|
-
# @param scope [Symbol] :class or :instance
|
750
|
-
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
751
|
-
# @param deep [Boolean]
|
752
|
-
# @param skip [Set<String>]
|
753
|
-
# @param no_core [Boolean] Skip core classes if true
|
754
|
-
# @return [Array<Pin::Base>]
|
755
|
-
def inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core)
|
756
|
-
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) starting" }
|
757
|
-
|
758
|
-
# Ensure the types returned by the methods in the referenced
|
759
|
-
# type are relative to the generic values passed in the
|
760
|
-
# reference. e.g., Foo<String> might include Enumerable<String>
|
761
|
-
#
|
762
|
-
# @todo perform the same translation in the other areas
|
763
|
-
# here after adding a spec and handling things correctly
|
764
|
-
# in ApiMap::Store and RbsMap::Conversions for each
|
765
|
-
resolved_reference_type = ComplexType.parse(fq_reference_tag).force_rooted.resolve_generics(namespace_pin, type)
|
766
|
-
# @todo Can inner_get_methods be cached? Lots of lookups of base types going on.
|
767
|
-
methods = inner_get_methods(resolved_reference_type.tag, scope, visibility, deep, skip, no_core)
|
768
|
-
if namespace_pin && !resolved_reference_type.all_params.empty?
|
769
|
-
reference_pin = store.get_path_pins(resolved_reference_type.name).select { |p| p.is_a?(Pin::Namespace) }.first
|
770
|
-
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolving generics with #{reference_pin.generics}, #{resolved_reference_type.rooted_tags}" }
|
771
|
-
methods = methods.map do |method_pin|
|
772
|
-
method_pin.resolve_generics(reference_pin, resolved_reference_type)
|
773
|
-
end
|
774
|
-
end
|
775
|
-
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolved_reference_type: #{resolved_reference_type} for type=#{type}: #{methods.map(&:name)}" }
|
776
|
-
methods
|
777
|
-
end
|
778
|
-
|
779
|
-
# @param fqns [String]
|
780
|
-
# @param visibility [Array<Symbol>]
|
781
|
-
# @param skip [Set<String>]
|
782
|
-
# @return [Array<Pin::Base>]
|
783
|
-
def inner_get_constants fqns, visibility, skip
|
784
|
-
return [] if fqns.nil? || skip.include?(fqns)
|
785
|
-
skip.add fqns
|
786
|
-
result = []
|
787
|
-
store.get_prepends(fqns).each do |is|
|
788
|
-
result.concat inner_get_constants(qualify(is, fqns), [:public], skip)
|
789
|
-
end
|
790
|
-
result.concat store.get_constants(fqns, visibility)
|
791
|
-
.sort { |a, b| a.name <=> b.name }
|
792
|
-
store.get_includes(fqns).each do |is|
|
793
|
-
result.concat inner_get_constants(qualify(is, fqns), [:public], skip)
|
794
|
-
end
|
795
|
-
fqsc = qualify_superclass(fqns)
|
796
|
-
unless %w[Object BasicObject].include?(fqsc)
|
797
|
-
result.concat inner_get_constants(fqsc, [:public], skip)
|
798
|
-
end
|
799
|
-
result
|
800
|
-
end
|
805
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
801
806
|
|
802
807
|
# @return [Hash]
|
803
808
|
def path_macros
|
804
809
|
@path_macros ||= {}
|
805
810
|
end
|
806
811
|
|
807
|
-
# @param
|
808
|
-
# @param context [String]
|
809
|
-
# @return [String, nil]
|
810
|
-
def qualify_lower namespace, context
|
811
|
-
qualify namespace, context.split('::')[0..-2].join('::')
|
812
|
-
end
|
813
|
-
|
814
|
-
# @param fq_tag [String]
|
812
|
+
# @param fq_sub_tag [String]
|
815
813
|
# @return [String, nil]
|
816
814
|
def qualify_superclass fq_sub_tag
|
817
|
-
|
818
|
-
fq_sub_ns = fq_sub_type.name
|
819
|
-
sup_tag = store.get_superclass(fq_sub_tag)
|
820
|
-
sup_type = ComplexType.try_parse(sup_tag)
|
821
|
-
sup_ns = sup_type.name
|
822
|
-
return nil if sup_tag.nil?
|
823
|
-
parts = fq_sub_ns.split('::')
|
824
|
-
last = parts.pop
|
825
|
-
parts.pop if last == sup_ns
|
826
|
-
qualify(sup_tag, parts.join('::'))
|
827
|
-
end
|
828
|
-
|
829
|
-
# @param name [String] Namespace to fully qualify
|
830
|
-
# @param root [String] The context to search
|
831
|
-
# @param skip [Set<String>] Contexts already searched
|
832
|
-
# @return [String, nil] Fully qualified ("rooted") namespace
|
833
|
-
def inner_qualify name, root, skip
|
834
|
-
return name if name == ComplexType::GENERIC_TAG_NAME
|
835
|
-
return nil if name.nil?
|
836
|
-
return nil if skip.include?(root)
|
837
|
-
skip.add root
|
838
|
-
possibles = []
|
839
|
-
if name == ''
|
840
|
-
if root == ''
|
841
|
-
return ''
|
842
|
-
else
|
843
|
-
return inner_qualify(root, '', skip)
|
844
|
-
end
|
845
|
-
else
|
846
|
-
return name if root == '' && store.namespace_exists?(name)
|
847
|
-
roots = root.to_s.split('::')
|
848
|
-
while roots.length > 0
|
849
|
-
fqns = roots.join('::') + '::' + name
|
850
|
-
return fqns if store.namespace_exists?(fqns)
|
851
|
-
incs = store.get_includes(roots.join('::'))
|
852
|
-
incs.each do |inc|
|
853
|
-
foundinc = inner_qualify(name, inc, skip)
|
854
|
-
possibles.push foundinc unless foundinc.nil?
|
855
|
-
end
|
856
|
-
roots.pop
|
857
|
-
end
|
858
|
-
if possibles.empty?
|
859
|
-
incs = store.get_includes('')
|
860
|
-
incs.each do |inc|
|
861
|
-
foundinc = inner_qualify(name, inc, skip)
|
862
|
-
possibles.push foundinc unless foundinc.nil?
|
863
|
-
end
|
864
|
-
end
|
865
|
-
return name if store.namespace_exists?(name)
|
866
|
-
return possibles.last
|
867
|
-
end
|
815
|
+
store.qualify_superclass fq_sub_tag
|
868
816
|
end
|
869
817
|
|
870
818
|
# Get the namespace's type (Class or Module).
|
@@ -896,49 +844,79 @@ module Solargraph
|
|
896
844
|
result + nil_pins
|
897
845
|
end
|
898
846
|
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
847
|
+
include Logging
|
848
|
+
|
849
|
+
private
|
850
|
+
|
851
|
+
# @param alias_pin [Pin::MethodAlias]
|
852
|
+
# @return [Pin::Method, nil]
|
853
|
+
def resolve_method_alias(alias_pin)
|
854
|
+
ancestors = store.get_ancestors(alias_pin.full_context.tag)
|
855
|
+
original = nil
|
856
|
+
|
857
|
+
# Search each ancestor for the original method
|
858
|
+
ancestors.each do |ancestor_fqns|
|
859
|
+
ancestor_fqns = ComplexType.try_parse(ancestor_fqns).force_rooted.namespace
|
860
|
+
next if ancestor_fqns.nil?
|
861
|
+
ancestor_method_path = "#{ancestor_fqns}#{alias_pin.scope == :instance ? '#' : '.'}#{alias_pin.original}"
|
862
|
+
|
863
|
+
# Search for the original method in the ancestor
|
864
|
+
original = store.get_path_pins(ancestor_method_path).find do |candidate_pin|
|
865
|
+
next if candidate_pin == alias_pin
|
866
|
+
|
867
|
+
if candidate_pin.is_a?(Pin::MethodAlias)
|
868
|
+
# recursively resolve method aliases
|
869
|
+
resolved = resolve_method_alias(candidate_pin)
|
870
|
+
break resolved if resolved
|
871
|
+
end
|
872
|
+
|
873
|
+
candidate_pin.is_a?(Pin::Method) && candidate_pin.scope == alias_pin.scope
|
874
|
+
end
|
875
|
+
|
876
|
+
break if original
|
877
|
+
end
|
878
|
+
|
879
|
+
# @sg-ignore ignore `received nil` for original
|
880
|
+
create_resolved_alias_pin(alias_pin, original) if original
|
881
|
+
end
|
882
|
+
|
883
|
+
# Fast path for creating resolved alias pins without individual method stack lookups
|
884
|
+
# @param alias_pin [Pin::MethodAlias] The alias pin to resolve
|
885
|
+
# @param original [Pin::Method] The original method pin that was already found
|
886
|
+
# @return [Pin::Method] The resolved method pin
|
887
|
+
def create_resolved_alias_pin(alias_pin, original)
|
888
|
+
# Build the resolved method pin directly (same logic as resolve_method_alias but without lookup)
|
908
889
|
args = {
|
909
|
-
location:
|
910
|
-
type_location:
|
911
|
-
closure:
|
912
|
-
name:
|
913
|
-
comments:
|
914
|
-
scope:
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
return_type: origin.return_type,
|
890
|
+
location: alias_pin.location,
|
891
|
+
type_location: original.type_location,
|
892
|
+
closure: alias_pin.closure,
|
893
|
+
name: alias_pin.name,
|
894
|
+
comments: original.comments,
|
895
|
+
scope: original.scope,
|
896
|
+
visibility: original.visibility,
|
897
|
+
signatures: original.signatures.map(&:clone).freeze,
|
898
|
+
attribute: original.attribute?,
|
899
|
+
generics: original.generics.clone,
|
900
|
+
return_type: original.return_type,
|
921
901
|
source: :resolve_method_alias
|
922
902
|
}
|
923
|
-
|
924
|
-
|
903
|
+
resolved_pin = Pin::Method.new **args
|
904
|
+
|
905
|
+
# Clone signatures and parameters
|
906
|
+
resolved_pin.signatures.each do |sig|
|
925
907
|
sig.parameters = sig.parameters.map(&:clone).freeze
|
926
908
|
sig.source = :resolve_method_alias
|
927
909
|
sig.parameters.each do |param|
|
928
|
-
param.closure =
|
910
|
+
param.closure = resolved_pin
|
929
911
|
param.source = :resolve_method_alias
|
930
912
|
param.reset_generated!
|
931
913
|
end
|
932
|
-
sig.closure =
|
914
|
+
sig.closure = resolved_pin
|
933
915
|
sig.reset_generated!
|
934
916
|
end
|
935
|
-
logger.debug { "ApiMap#resolve_method_alias(pin=#{pin}) - returning #{out} from #{origin}" }
|
936
|
-
out
|
937
|
-
end
|
938
|
-
|
939
|
-
include Logging
|
940
917
|
|
941
|
-
|
918
|
+
resolved_pin
|
919
|
+
end
|
942
920
|
|
943
921
|
# @param namespace_pin [Pin::Namespace]
|
944
922
|
# @param rooted_type [ComplexType]
|
@@ -959,9 +937,9 @@ module Solargraph
|
|
959
937
|
has_generics?(namespace_pin) && !can_resolve_generics?(namespace_pin, rooted_type)
|
960
938
|
end
|
961
939
|
|
962
|
-
# @param namespace_pin [Pin::Namespace]
|
940
|
+
# @param namespace_pin [Pin::Namespace, Pin::Constant]
|
963
941
|
def has_generics?(namespace_pin)
|
964
|
-
namespace_pin && !namespace_pin.generics.empty?
|
942
|
+
namespace_pin.is_a?(Pin::Namespace) && !namespace_pin.generics.empty?
|
965
943
|
end
|
966
944
|
|
967
945
|
# @param namespace_pin [Pin::Namespace]
|