solargraph 0.60.3 → 0.61.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 +1 -5
- data/.github/workflows/rspec.yml +3 -1
- data/CHANGELOG.md +26 -0
- data/Gemfile +0 -3
- data/lib/solargraph/api_map/index.rb +15 -2
- data/lib/solargraph/api_map/store.rb +13 -0
- data/lib/solargraph/api_map.rb +60 -81
- data/lib/solargraph/cache_dir.rb +58 -0
- data/lib/solargraph/collection/base.rb +50 -0
- data/lib/solargraph/collection/core.rb +17 -0
- data/lib/solargraph/collection/gem.rb +57 -0
- data/lib/solargraph/collection/rbs.rb +49 -0
- data/lib/solargraph/collection/stdlib.rb +25 -0
- data/lib/solargraph/collection.rb +31 -0
- data/lib/solargraph/complex_type.rb +18 -5
- data/lib/solargraph/convention.rb +5 -3
- data/lib/solargraph/diagnostics/require_not_found.rb +0 -4
- data/lib/solargraph/external.rb +159 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +4 -1
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -2
- data/lib/solargraph/library.rb +11 -24
- data/lib/solargraph/metagem.rb +80 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +22 -3
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +14 -5
- data/lib/solargraph/pin/closure.rb +17 -0
- data/lib/solargraph/pin/factory_parameter.rb +84 -0
- data/lib/solargraph/pin/method.rb +7 -4
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/rbs_map/base.rb +31 -0
- data/lib/solargraph/rbs_map/conversions.rb +3 -1
- data/lib/solargraph/rbs_map/{core_map.rb → core.rb} +18 -39
- data/lib/solargraph/rbs_map/core_fills.rb +1 -1
- data/lib/solargraph/rbs_map/gem.rb +13 -0
- data/lib/solargraph/rbs_map/helpers.rb +60 -0
- data/lib/solargraph/rbs_map/path.rb +19 -0
- data/lib/solargraph/rbs_map/stdlib.rb +24 -0
- data/lib/solargraph/rbs_map.rb +7 -198
- data/lib/solargraph/repo.rb +177 -0
- data/lib/solargraph/shell.rb +49 -99
- data/lib/solargraph/source/chain/call.rb +190 -67
- data/lib/solargraph/source/chain/literal.rb +17 -17
- data/lib/solargraph/source/chain/parameter.rb +79 -0
- data/lib/solargraph/source/chain.rb +44 -5
- data/lib/solargraph/source/source_chainer.rb +40 -44
- data/lib/solargraph/source_map/clip.rb +5 -3
- data/lib/solargraph/source_map/mapper.rb +6 -2
- data/lib/solargraph/source_map.rb +10 -5
- data/lib/solargraph/type_checker/rules.rb +2 -1
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +0 -1
- data/lib/solargraph/yard_map/cache.rb +1 -1
- data/lib/solargraph/yard_map/directives/attribute_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/domain_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/method_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/override_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/parse_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/scope_directive.rb +178 -0
- data/lib/solargraph/yard_map/directives/visibility_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives.rb +5 -2
- data/lib/solargraph/yard_map/helpers.rb +1 -1
- data/lib/solargraph/yard_map/macro.rb +34 -5
- data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -1
- data/lib/solargraph/yard_map/mapper.rb +37 -4
- data/lib/solargraph/yard_map.rb +1 -1
- data/lib/solargraph/yardoc.rb +43 -60
- data/lib/solargraph.rb +6 -3
- data/solargraph.gemspec +1 -1
- metadata +22 -9
- data/lib/solargraph/doc_map.rb +0 -439
- data/lib/solargraph/gem_pins.rb +0 -87
- data/lib/solargraph/pin_cache.rb +0 -248
- data/lib/solargraph/rbs_map/stdlib_map.rb +0 -71
- data/lib/solargraph/workspace/gemspecs.rb +0 -373
|
@@ -227,7 +227,7 @@ module Solargraph
|
|
|
227
227
|
expected = expected.downcast_to_literal_if_possible
|
|
228
228
|
inferred = downcast_to_literal_if_possible
|
|
229
229
|
|
|
230
|
-
return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
|
|
230
|
+
return duck_types_match?(api_map, expected, inferred, rules) if expected.duck_type?
|
|
231
231
|
|
|
232
232
|
if rules.include? :allow_any_match
|
|
233
233
|
inferred.any? do |inf|
|
|
@@ -245,18 +245,31 @@ module Solargraph
|
|
|
245
245
|
# @param api_map [ApiMap]
|
|
246
246
|
# @param expected [ComplexType, UniqueType]
|
|
247
247
|
# @param inferred [ComplexType, UniqueType]
|
|
248
|
+
# @param rules [Array<Symbol>]
|
|
248
249
|
# @return [Boolean]
|
|
249
|
-
def duck_types_match? api_map, expected, inferred
|
|
250
|
+
def duck_types_match? api_map, expected, inferred, rules = []
|
|
250
251
|
raise ArgumentError, 'Expected type must be duck type' unless expected.duck_type?
|
|
252
|
+
allow_any_match = rules.include?(:allow_any_match)
|
|
251
253
|
expected.each do |exp|
|
|
252
254
|
next unless exp.duck_type?
|
|
253
|
-
quack = exp.to_s[1..]
|
|
254
|
-
|
|
255
|
-
return false
|
|
255
|
+
quack = exp.to_s[1..] || ''
|
|
256
|
+
matched = allow_any_match ? inferred.any? { |inf| duck_type_provides?(api_map, inf, quack) } : inferred.all? { |inf| duck_type_provides?(api_map, inf, quack) }
|
|
257
|
+
return false unless matched
|
|
256
258
|
end
|
|
257
259
|
true
|
|
258
260
|
end
|
|
259
261
|
|
|
262
|
+
# @param api_map [ApiMap]
|
|
263
|
+
# @param inf [UniqueType]
|
|
264
|
+
# @param quack [String]
|
|
265
|
+
# @return [Boolean]
|
|
266
|
+
def duck_type_provides? api_map, inf, quack
|
|
267
|
+
return true if inf.duck_type? && inf.to_s[1..] == quack
|
|
268
|
+
|
|
269
|
+
!api_map.get_method_stack(inf.namespace, quack, scope: inf.scope).empty?
|
|
270
|
+
end
|
|
271
|
+
private :duck_type_provides?
|
|
272
|
+
|
|
260
273
|
# @return [String]
|
|
261
274
|
def rooted_tags
|
|
262
275
|
map(&:rooted_tag).join(', ')
|
|
@@ -38,12 +38,14 @@ module Solargraph
|
|
|
38
38
|
result
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
# @
|
|
41
|
+
# @todo Determine what argument needs to be passed here
|
|
42
|
+
#
|
|
43
|
+
# @param object [Object]
|
|
42
44
|
# @return [Environ]
|
|
43
|
-
def self.for_global
|
|
45
|
+
def self.for_global object
|
|
44
46
|
result = Environ.new
|
|
45
47
|
@@conventions.each do |conv|
|
|
46
|
-
result.merge conv.global(
|
|
48
|
+
result.merge conv.global(object)
|
|
47
49
|
end
|
|
48
50
|
result
|
|
49
51
|
end
|
|
@@ -13,10 +13,6 @@ module Solargraph
|
|
|
13
13
|
# @sg-ignore Need to add nil check here
|
|
14
14
|
map = api_map.source_map(source.filename)
|
|
15
15
|
map.requires.each { |ref| refs[ref.name] = ref }
|
|
16
|
-
api_map.missing_docs.each do |r|
|
|
17
|
-
next unless refs.key?(r)
|
|
18
|
-
result.push docs_error(r, refs[r].location)
|
|
19
|
-
end
|
|
20
16
|
api_map.unresolved_requires.each do |r|
|
|
21
17
|
next unless refs.key?(r)
|
|
22
18
|
result.push require_error(r, refs[r].location)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
module Solargraph
|
|
6
|
+
# @todo This class might need a way to track changes to the repo, e.g.,
|
|
7
|
+
# bundle or dependency updates
|
|
8
|
+
#
|
|
9
|
+
class External
|
|
10
|
+
# @return [String]
|
|
11
|
+
attr_reader :directory
|
|
12
|
+
|
|
13
|
+
# @return [Array<String>]
|
|
14
|
+
attr_reader :requires
|
|
15
|
+
|
|
16
|
+
# @param directory [String]
|
|
17
|
+
# @param requires [Array<String>]
|
|
18
|
+
def initialize directory, requires
|
|
19
|
+
@repo = Repo.new(directory)
|
|
20
|
+
@directory = directory
|
|
21
|
+
@requires = requires
|
|
22
|
+
update!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def unresolved_requires
|
|
26
|
+
@unresolved_requires ||= []
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def unresolved_dependencies
|
|
30
|
+
@unresolved_dependencies ||= []
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def loaded_gems
|
|
34
|
+
@loaded_gems ||= Set.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def unloaded_gems
|
|
38
|
+
@unloaded_gems ||= Set.new
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def pins
|
|
42
|
+
@pins ||= []
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Integer] incremented whenever the external pin set is rebuilt
|
|
46
|
+
def generation
|
|
47
|
+
@generation ||= 0
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @param new_requires [Array<String>]
|
|
51
|
+
# @return [Boolean]
|
|
52
|
+
def update new_requires
|
|
53
|
+
return false if requires == new_requires && !cache_changed?
|
|
54
|
+
|
|
55
|
+
requires.replace new_requires
|
|
56
|
+
update!
|
|
57
|
+
true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Array<String>]
|
|
61
|
+
def rbs_collection_paths
|
|
62
|
+
@rbs_collection_paths ||= read_rbs_collection_paths
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [String, nil]
|
|
66
|
+
def rbs_collection_config_path
|
|
67
|
+
# @todo Get rid of the '*' case
|
|
68
|
+
@rbs_collection_config_path ||= unless directory.nil? || directory.empty? || directory == '*'
|
|
69
|
+
yaml_file = File.join(directory, 'rbs_collection.yaml')
|
|
70
|
+
yaml_file if File.file?(yaml_file)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def update!
|
|
77
|
+
@generation = generation + 1
|
|
78
|
+
clear_all
|
|
79
|
+
load_requires
|
|
80
|
+
load_rbs_collection
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def cache_changed?
|
|
84
|
+
unloaded_gems.any? { |gem| Collection::Gem.cached?(gem) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def load_requires
|
|
88
|
+
bundler_require = false
|
|
89
|
+
|
|
90
|
+
requires.uniq.each do |path|
|
|
91
|
+
if path == 'bundler/require'
|
|
92
|
+
bundler_require = true
|
|
93
|
+
end
|
|
94
|
+
if RbsMap::Stdlib.has?(path)
|
|
95
|
+
pins.concat Collection::Stdlib.load(path)
|
|
96
|
+
else
|
|
97
|
+
metagem = @repo.find_by_path(path)
|
|
98
|
+
next unresolved_requires.push(path) unless metagem
|
|
99
|
+
process_gem metagem
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
return unless bundler_require
|
|
104
|
+
|
|
105
|
+
@repo.find_by_group(:default).each { |metagem| process_gem metagem }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def load_rbs_collection
|
|
109
|
+
rbs_collection_pins = rbs_collection_paths.flat_map { |path| Collection::Rbs.load(path) }
|
|
110
|
+
pins.replace RbsMap::Helpers.combine(pins, rbs_collection_pins)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def clear_all
|
|
114
|
+
pins.clear
|
|
115
|
+
unresolved_requires.clear
|
|
116
|
+
unresolved_dependencies.clear
|
|
117
|
+
loaded_gems.clear
|
|
118
|
+
unloaded_gems.clear
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def process_gem metagem
|
|
122
|
+
return if loaded_gems.include?(metagem) || unloaded_gems.include?(metagem)
|
|
123
|
+
|
|
124
|
+
if metagem.cacheable?
|
|
125
|
+
if Collection::Gem.cached?(metagem)
|
|
126
|
+
loaded_gems.add metagem
|
|
127
|
+
pins.concat Collection::Gem.load(metagem)
|
|
128
|
+
else
|
|
129
|
+
unloaded_gems.add metagem
|
|
130
|
+
end
|
|
131
|
+
else
|
|
132
|
+
loaded_gems.add metagem
|
|
133
|
+
pins.concat Collection::Gem.load(metagem)
|
|
134
|
+
end
|
|
135
|
+
load_dependencies metagem
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def load_dependencies parent
|
|
139
|
+
parent.dependencies.each do |name|
|
|
140
|
+
next if loaded_gems.map(&:name).include?(name) || unloaded_gems.map(&:name).include?(name)
|
|
141
|
+
metagem = @repo.find_by_name(name)
|
|
142
|
+
next unresolved_dependencies.push(name) unless metagem
|
|
143
|
+
process_gem metagem
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @return [Array<String>]
|
|
148
|
+
def read_rbs_collection_paths
|
|
149
|
+
return [] unless rbs_collection_config_path
|
|
150
|
+
|
|
151
|
+
yaml = YAML.load_file(rbs_collection_config_path)
|
|
152
|
+
[File.expand_path(yaml.fetch('path'), directory)].concat(
|
|
153
|
+
yaml.fetch('sources', [])
|
|
154
|
+
.select { |source| source['type'] == 'local' && source['path'] }
|
|
155
|
+
.map { |source| File.expand_path(source['path'], directory) }
|
|
156
|
+
).compact
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -29,7 +29,10 @@ module Solargraph
|
|
|
29
29
|
|
|
30
30
|
# @return [Array<Hash>, nil]
|
|
31
31
|
def require_location
|
|
32
|
-
# @todo Terrible hack
|
|
32
|
+
# @todo Terrible hack - move this logic to [Solargraph::Source::Chain::Parameter]
|
|
33
|
+
# @example
|
|
34
|
+
# require 'click_me'
|
|
35
|
+
# ^^^^^^^^^^
|
|
33
36
|
lib = host.library_for(params['textDocument']['uri'])
|
|
34
37
|
rloc = Solargraph::Location.new(uri_to_file(params['textDocument']['uri']),
|
|
35
38
|
Solargraph::Range.from_to(@line, @column, @line, @column))
|
|
@@ -11,8 +11,7 @@ module Solargraph
|
|
|
11
11
|
contents = []
|
|
12
12
|
suggestions = host.definitions_at(params['textDocument']['uri'], line, col)
|
|
13
13
|
last_link = nil
|
|
14
|
-
|
|
15
|
-
suggestions.each do |pin|
|
|
14
|
+
suggestions&.each do |pin|
|
|
16
15
|
parts = []
|
|
17
16
|
this_link = host.options['enablePages'] ? pin.link_documentation : pin.text_documentation
|
|
18
17
|
parts.push this_link if !this_link.nil? && this_link != last_link
|
data/lib/solargraph/library.rb
CHANGED
|
@@ -576,14 +576,8 @@ module Solargraph
|
|
|
576
576
|
return unless source
|
|
577
577
|
# @sg-ignore Wrong argument type for Solargraph::Workspace#has_file?: filename expected String, received String, nil
|
|
578
578
|
return unless @current == source || workspace.has_file?(source.filename)
|
|
579
|
-
if
|
|
580
|
-
|
|
581
|
-
# @sg-ignore OK if source.filename is nil
|
|
582
|
-
source_map_hash[source.filename] = new_map
|
|
583
|
-
else
|
|
584
|
-
# @sg-ignore OK if source.filename is nil
|
|
585
|
-
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
|
586
|
-
end
|
|
579
|
+
# @sg-ignore OK if source.filename is nil
|
|
580
|
+
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
|
587
581
|
end
|
|
588
582
|
|
|
589
583
|
# @return [Set<Gem::Specification>]
|
|
@@ -595,10 +589,10 @@ module Solargraph
|
|
|
595
589
|
def cache_next_gemspec
|
|
596
590
|
return if @cache_progress
|
|
597
591
|
|
|
598
|
-
spec =
|
|
592
|
+
spec = api_map.unloaded_gems.first
|
|
599
593
|
return end_cache_progress unless spec
|
|
600
594
|
|
|
601
|
-
pending = api_map.
|
|
595
|
+
pending = api_map.unloaded_gems.length - cache_errors.length - 1
|
|
602
596
|
|
|
603
597
|
if Yardoc.processing?(spec)
|
|
604
598
|
logger.info "Enqueuing cache of #{spec.name} #{spec.version} (already being processed)"
|
|
@@ -615,7 +609,10 @@ module Solargraph
|
|
|
615
609
|
logger.info "Caching #{spec.name} #{spec.version}"
|
|
616
610
|
Thread.new do
|
|
617
611
|
report_cache_progress spec.name, pending
|
|
618
|
-
|
|
612
|
+
|
|
613
|
+
cmd = [workspace.command_path, 'cache', spec.name]
|
|
614
|
+
cmd.push('--directory', workspace.directory) if workspace.directory
|
|
615
|
+
_o, e, s = Open3.capture3(*cmd)
|
|
619
616
|
if s.success?
|
|
620
617
|
logger.info "Cached #{spec.name} #{spec.version}"
|
|
621
618
|
else
|
|
@@ -630,17 +627,6 @@ module Solargraph
|
|
|
630
627
|
end
|
|
631
628
|
end
|
|
632
629
|
|
|
633
|
-
# @return [Array<Gem::Specification>]
|
|
634
|
-
def cacheable_specs
|
|
635
|
-
cacheable = api_map.uncached_yard_gemspecs +
|
|
636
|
-
api_map.uncached_rbs_collection_gemspecs -
|
|
637
|
-
queued_gemspec_cache -
|
|
638
|
-
cache_errors.to_a
|
|
639
|
-
return cacheable unless cacheable.empty?
|
|
640
|
-
|
|
641
|
-
queued_gemspec_cache
|
|
642
|
-
end
|
|
643
|
-
|
|
644
630
|
# @return [Array<Gem::Specification>]
|
|
645
631
|
def queued_gemspec_cache
|
|
646
632
|
@queued_gemspec_cache ||= []
|
|
@@ -696,8 +682,9 @@ module Solargraph
|
|
|
696
682
|
source_map_hash.each_value { |map| find_external_requires(map) }
|
|
697
683
|
api_map.catalog bench
|
|
698
684
|
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
|
699
|
-
|
|
700
|
-
logger.info "#{api_map.
|
|
685
|
+
# @todo This needs work
|
|
686
|
+
# logger.info "#{api_map.uncached_yard_gemspecs.length} uncached YARD gemspecs"
|
|
687
|
+
# logger.info "#{api_map.uncached_rbs_collection_gemspecs.length} uncached RBS collection gemspecs"
|
|
701
688
|
cache_next_gemspec
|
|
702
689
|
@sync_count = 0
|
|
703
690
|
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
class Metagem
|
|
5
|
+
include Equality
|
|
6
|
+
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_reader :name
|
|
9
|
+
|
|
10
|
+
# @return [String]
|
|
11
|
+
attr_reader :full_path
|
|
12
|
+
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_reader :spec_file
|
|
15
|
+
|
|
16
|
+
# @return [String]
|
|
17
|
+
attr_reader :source
|
|
18
|
+
|
|
19
|
+
# @return [String]
|
|
20
|
+
attr_reader :version
|
|
21
|
+
|
|
22
|
+
# @return [Array<String>]
|
|
23
|
+
attr_reader :require_paths
|
|
24
|
+
|
|
25
|
+
# @return [Array<String>]
|
|
26
|
+
attr_reader :dependencies
|
|
27
|
+
|
|
28
|
+
# @return [String]
|
|
29
|
+
attr_reader :cache_name
|
|
30
|
+
|
|
31
|
+
def initialize name:, full_path:, spec_file:, source:, version:, require_paths:, dependencies:
|
|
32
|
+
@name = name
|
|
33
|
+
@full_path = full_path
|
|
34
|
+
@spec_file = spec_file
|
|
35
|
+
@source = source
|
|
36
|
+
@version = version
|
|
37
|
+
@require_paths = require_paths
|
|
38
|
+
@dependencies = dependencies
|
|
39
|
+
# @todo Possible change to cache names to make them more specific to sources
|
|
40
|
+
# @cache_name = "#{File.basename(full_path)}__#{source.gsub(/[^a-z0-9\-_]/i, '_')}" unless source.end_with?('Path')
|
|
41
|
+
# @todo Better path source detection
|
|
42
|
+
@cache_name = File.basename(full_path) unless source.start_with?('source at') || source.to_s.end_with?('::Path')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def cacheable?
|
|
46
|
+
!!@cache_name
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def require? path
|
|
50
|
+
require_paths.any? do |req|
|
|
51
|
+
File.file?(File.join(full_path, req, "#{path}.rb"))
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_specification
|
|
56
|
+
Gem::Specification.load(spec_file)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
alias full_gem_path full_path
|
|
60
|
+
|
|
61
|
+
# @return [Array]
|
|
62
|
+
def equality_fields
|
|
63
|
+
# A version arrives as a String from a bundle definition and as a
|
|
64
|
+
# Gem::Version from a specification, so compare its string form.
|
|
65
|
+
[name, version.to_s, full_path, source]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param gem [Gem::Specification]
|
|
69
|
+
# @return [Metagem]
|
|
70
|
+
def self.from_specification gem
|
|
71
|
+
Metagem.new(name: gem.name,
|
|
72
|
+
full_path: gem.full_gem_path,
|
|
73
|
+
spec_file: gem.spec_file,
|
|
74
|
+
source: gem.source.to_s,
|
|
75
|
+
version: gem.version,
|
|
76
|
+
require_paths: gem.require_paths,
|
|
77
|
+
dependencies: gem.runtime_dependencies.map(&:name))
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -13,10 +13,12 @@ module Solargraph
|
|
|
13
13
|
# @param node [Parser::AST::Node]
|
|
14
14
|
# @param filename [String, nil]
|
|
15
15
|
# @param parent [Parser::AST::Node, nil]
|
|
16
|
-
|
|
16
|
+
# @param tree [Array<Parser::AST::Node>, nil]
|
|
17
|
+
def initialize node, filename = nil, parent = nil, tree = nil
|
|
17
18
|
@node = node
|
|
18
19
|
@filename = filename
|
|
19
20
|
@parent = parent
|
|
21
|
+
@tree = tree
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
# @return [Source::Chain]
|
|
@@ -29,9 +31,10 @@ module Solargraph
|
|
|
29
31
|
# @param node [Parser::AST::Node]
|
|
30
32
|
# @param filename [String, nil]
|
|
31
33
|
# @param parent [Parser::AST::Node, nil]
|
|
34
|
+
# @param tree [Parser::AST::Node, nil]
|
|
32
35
|
# @return [Source::Chain]
|
|
33
|
-
def chain node, filename = nil, parent = nil
|
|
34
|
-
NodeChainer.new(node, filename, parent).chain
|
|
36
|
+
def chain node, filename = nil, parent = nil, tree = nil
|
|
37
|
+
NodeChainer.new(node, filename, parent, tree).chain
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
# @param code [String]
|
|
@@ -150,6 +153,13 @@ module Solargraph
|
|
|
150
153
|
elsif n.type == :array
|
|
151
154
|
chained_children = n.children.map { |c| NodeChainer.chain(c) }
|
|
152
155
|
result.push Source::Chain::Array.new(chained_children, n)
|
|
156
|
+
elsif inside_method_call? # If the node is inside a method call, it may be a parameter.
|
|
157
|
+
lit = infer_literal_node_type(n)
|
|
158
|
+
if lit
|
|
159
|
+
method_call_chain = NodeChainer.chain(send_node, @filename, nil, [])
|
|
160
|
+
literal = Chain::Literal.new(lit, n)
|
|
161
|
+
result.push Chain::Parameter.new(literal, method_call_chain)
|
|
162
|
+
end
|
|
153
163
|
else
|
|
154
164
|
lit = infer_literal_node_type(n)
|
|
155
165
|
result.push(lit ? Chain::Literal.new(lit, n) : Chain::Link.new)
|
|
@@ -158,6 +168,15 @@ module Solargraph
|
|
|
158
168
|
result
|
|
159
169
|
end
|
|
160
170
|
|
|
171
|
+
def inside_method_call?
|
|
172
|
+
!send_node.nil? && send_node != @node
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @return [Parser::AST::Node, nil]
|
|
176
|
+
def send_node
|
|
177
|
+
@send_node ||= @tree&.find { |n| n.type == :send }
|
|
178
|
+
end
|
|
179
|
+
|
|
161
180
|
# @param node [Parser::AST::Node]
|
|
162
181
|
def hash_is_splatted? node
|
|
163
182
|
return false unless Parser.is_ast_node?(node) && node.type == :hash
|
|
@@ -27,7 +27,6 @@ module Solargraph
|
|
|
27
27
|
source: :parser
|
|
28
28
|
)
|
|
29
29
|
pins.push nspin
|
|
30
|
-
Solargraph.logger.warn "Superclass: #{superclass_name}" if superclass_name&.start_with?('Array')
|
|
31
30
|
if superclass_name
|
|
32
31
|
pins.push Pin::Reference::Superclass.new(
|
|
33
32
|
location: loc,
|
|
@@ -41,12 +40,22 @@ module Solargraph
|
|
|
41
40
|
|
|
42
41
|
private
|
|
43
42
|
|
|
44
|
-
#
|
|
43
|
+
# Type arguments for a generic superclass in inline RBS syntax, e.g.,
|
|
44
|
+
# `class Foo < Array #[String]`. Only recognized where RBS defines
|
|
45
|
+
# it: directly after the superclass, on the same line, with no space
|
|
46
|
+
# between `#` and `[`. Anything else is an ordinary comment.
|
|
47
|
+
#
|
|
45
48
|
# @return [String, nil]
|
|
46
49
|
def parameters_from_inline_rbs
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
superclass = node.children[1]
|
|
51
|
+
return unless superclass
|
|
52
|
+
|
|
53
|
+
source = region.source.code
|
|
54
|
+
pos = get_node_end_position(superclass)
|
|
55
|
+
offset = Position.line_char_to_offset(source, pos.line, pos.character)
|
|
56
|
+
eol = source.index("\n", offset) || source.length
|
|
57
|
+
match = source[offset...eol].to_s.match(/\A\s*#\[([^\]]*)\]/)
|
|
58
|
+
return unless match
|
|
50
59
|
|
|
51
60
|
code = match[1].strip
|
|
52
61
|
return if code.empty?
|
|
@@ -6,6 +6,23 @@ module Solargraph
|
|
|
6
6
|
# @return [::Symbol] :class or :instance
|
|
7
7
|
attr_reader :scope
|
|
8
8
|
|
|
9
|
+
# Override the pin's scope.
|
|
10
|
+
#
|
|
11
|
+
# Scope is normally determined by the syntax that declared the pin, but
|
|
12
|
+
# YARD's `@!scope` directive can change it after the fact. Any values
|
|
13
|
+
# derived from the scope, such as the pin's path and context, are
|
|
14
|
+
# recalculated.
|
|
15
|
+
#
|
|
16
|
+
# @param scope [::Symbol] :class or :instance
|
|
17
|
+
# @return [void]
|
|
18
|
+
def scope= scope
|
|
19
|
+
return if @scope == scope
|
|
20
|
+
|
|
21
|
+
@scope = scope
|
|
22
|
+
# remove cached values generated from scope
|
|
23
|
+
reset_generated!
|
|
24
|
+
end
|
|
25
|
+
|
|
9
26
|
# @param scope [::Symbol] :class or :instance
|
|
10
27
|
# @param generics [::Array<Pin::String>, nil]
|
|
11
28
|
# @param generic_defaults [Hash{String => ComplexType}]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module Pin
|
|
5
|
+
# A method parameter with a literal value used in a factory method.
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# RSpec.shared_examples 'some examples'
|
|
9
|
+
#
|
|
10
|
+
# FactoryParameter.new(
|
|
11
|
+
# method_name: 'shared_examples',
|
|
12
|
+
# method_namespace: 'RSpec',
|
|
13
|
+
# method_scope: :class,
|
|
14
|
+
# param_name: 'name',
|
|
15
|
+
# value: 'some examples',
|
|
16
|
+
# decl: :arg,
|
|
17
|
+
# return_type: 'void'
|
|
18
|
+
# )
|
|
19
|
+
class FactoryParameter < Base
|
|
20
|
+
# @return [String]
|
|
21
|
+
attr_reader :method_name
|
|
22
|
+
# @return [String]
|
|
23
|
+
attr_reader :method_namespace
|
|
24
|
+
# @return [Symbol] :class or :instance
|
|
25
|
+
attr_reader :method_scope
|
|
26
|
+
# @return [String, nil]
|
|
27
|
+
attr_reader :param_name
|
|
28
|
+
# @return [::String, ::Symbol] The literal value
|
|
29
|
+
attr_reader :value
|
|
30
|
+
# @return [::Symbol] :arg, :optarg, :kwarg, :kwoptarg, :restarg, :kwrestarg, :block, :blockarg
|
|
31
|
+
attr_reader :decl
|
|
32
|
+
# @return [Location, nil]
|
|
33
|
+
attr_reader :location
|
|
34
|
+
|
|
35
|
+
# @param method_name [String] The name of the method that this parameter belongs to
|
|
36
|
+
# @param method_namespace [String] The class of the method that this parameter belongs to
|
|
37
|
+
# @param method_scope [Symbol] The scope of the method, either :class or :instance
|
|
38
|
+
# @param param_name [String, nil] The name of the parameter
|
|
39
|
+
# @param value [String, Symbol] The value of the parameter
|
|
40
|
+
# @param decl [::Symbol] :arg, :kwarg
|
|
41
|
+
# @param location [Location, nil] The location of the parameter in the source code
|
|
42
|
+
# @param return_type [String, nil] The return type of the method that this parameter belongs to
|
|
43
|
+
def initialize method_name:,
|
|
44
|
+
method_namespace:,
|
|
45
|
+
method_scope:,
|
|
46
|
+
param_name:,
|
|
47
|
+
value:,
|
|
48
|
+
return_type:,
|
|
49
|
+
decl: :arg,
|
|
50
|
+
location: nil
|
|
51
|
+
super(location: location)
|
|
52
|
+
@method_name = method_name
|
|
53
|
+
@method_namespace = method_namespace
|
|
54
|
+
@method_scope = method_scope
|
|
55
|
+
@param_name = param_name
|
|
56
|
+
@value = value
|
|
57
|
+
@decl = decl
|
|
58
|
+
@return_type = return_type
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def name
|
|
62
|
+
param_name
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def text_documentation
|
|
66
|
+
"#{method_path}(#{param_name}) = #{value.inspect}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [String]
|
|
70
|
+
def method_path
|
|
71
|
+
# @sg-ignore false failure on method_scope "Wrong argument type for Solargraph::Pin::Base#==: other expected
|
|
72
|
+
# Solargraph::Pin::Base, received :instance"
|
|
73
|
+
@method_path ||= "#{method_namespace}#{method_scope == :instance ? '#' : '.'}#{method_name}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def inner_desc
|
|
79
|
+
"method_path=#{method_path}, value=#{value.inspect}, decl=#{decl.inspect}, " \
|
|
80
|
+
"return_type=#{return_type&.to_s || 'nil'}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -148,12 +148,13 @@ module Solargraph
|
|
|
148
148
|
|
|
149
149
|
# @param parameters [::Array<Parameter>]
|
|
150
150
|
# @param return_type [ComplexType, nil]
|
|
151
|
+
# @param tag_docstring [YARD::Docstring] source of @yieldparam/@yieldreturn tags; pass an @overload tag's own docstring here
|
|
151
152
|
# @return [Signature]
|
|
152
|
-
def generate_signature parameters, return_type
|
|
153
|
+
def generate_signature parameters, return_type, tag_docstring = docstring
|
|
153
154
|
# @type [Pin::Signature, nil]
|
|
154
155
|
block = nil
|
|
155
|
-
yieldparam_tags =
|
|
156
|
-
yieldreturn_tags =
|
|
156
|
+
yieldparam_tags = tag_docstring.tags(:yieldparam)
|
|
157
|
+
yieldreturn_tags = tag_docstring.tags(:yieldreturn)
|
|
157
158
|
generics = docstring.tags(:generic).map(&:name)
|
|
158
159
|
needs_block_param_signature =
|
|
159
160
|
parameters.last&.block? || !yieldreturn_tags.empty? || !yieldparam_tags.empty?
|
|
@@ -747,7 +748,9 @@ module Solargraph
|
|
|
747
748
|
top_type = generate_complex_type
|
|
748
749
|
result = []
|
|
749
750
|
result.push generate_signature(parameters, top_type) if top_type.defined?
|
|
750
|
-
|
|
751
|
+
# @param meth [Pin::Signature]
|
|
752
|
+
# @param tag [YARD::Tags::OverloadTag]
|
|
753
|
+
result.concat(overloads.zip(docstring.tags(:overload).select(&:parameters)).map { |meth, tag| generate_signature(meth.parameters, meth.return_type, tag.docstring) }) unless overloads.empty?
|
|
751
754
|
result.push generate_signature(parameters, @return_type || ComplexType::UNDEFINED) if result.empty?
|
|
752
755
|
result
|
|
753
756
|
end
|
data/lib/solargraph/pin.rb
CHANGED
|
@@ -38,6 +38,7 @@ module Solargraph
|
|
|
38
38
|
autoload :Until, 'solargraph/pin/until'
|
|
39
39
|
autoload :While, 'solargraph/pin/while'
|
|
40
40
|
autoload :Callable, 'solargraph/pin/callable'
|
|
41
|
+
autoload :FactoryParameter, 'solargraph/pin/factory_parameter'
|
|
41
42
|
autoload :CompoundStatement,
|
|
42
43
|
'solargraph/pin/compound_statement'
|
|
43
44
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module RbsMap
|
|
5
|
+
class Base
|
|
6
|
+
def pins
|
|
7
|
+
@pins ||= RbsMap::Conversions.new(loader: loader).pins
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [RBS::Repository]
|
|
11
|
+
def repository
|
|
12
|
+
@repository ||= RBS::Repository.new(no_stdlib: true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [RBS::EnvironmentLoader]
|
|
16
|
+
def loader
|
|
17
|
+
@loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @param path [String]
|
|
21
|
+
# @return [Array<Pin::Base>]
|
|
22
|
+
def path_pins path
|
|
23
|
+
pins.select { |p| p.path == path }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.pins(...)
|
|
27
|
+
new(...).pins
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|