solargraph 0.54.1 → 0.56.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 +2 -0
- data/.github/workflows/typecheck.yml +3 -1
- data/.gitignore +2 -0
- data/CHANGELOG.md +70 -0
- data/README.md +13 -3
- data/lib/solargraph/api_map/cache.rb +10 -1
- data/lib/solargraph/api_map/index.rb +175 -0
- data/lib/solargraph/api_map/store.rb +79 -126
- data/lib/solargraph/api_map.rb +247 -93
- data/lib/solargraph/bench.rb +17 -1
- data/lib/solargraph/complex_type/type_methods.rb +13 -1
- data/lib/solargraph/complex_type/unique_type.rb +118 -9
- data/lib/solargraph/complex_type.rb +48 -18
- data/lib/solargraph/convention/base.rb +3 -3
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +60 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +100 -0
- data/lib/solargraph/convention/struct_definition.rb +101 -0
- data/lib/solargraph/convention.rb +5 -3
- data/lib/solargraph/doc_map.rb +274 -56
- data/lib/solargraph/equality.rb +33 -0
- data/lib/solargraph/gem_pins.rb +53 -37
- data/lib/solargraph/language_server/host/message_worker.rb +31 -11
- data/lib/solargraph/language_server/host.rb +24 -13
- data/lib/solargraph/language_server/message/base.rb +19 -12
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
- data/lib/solargraph/language_server/message/extended/document.rb +5 -2
- data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
- data/lib/solargraph/language_server/message/initialize.rb +3 -1
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
- data/lib/solargraph/library.rb +13 -11
- data/lib/solargraph/location.rb +28 -0
- data/lib/solargraph/logging.rb +1 -0
- data/lib/solargraph/parser/comment_ripper.rb +12 -6
- data/lib/solargraph/parser/flow_sensitive_typing.rb +227 -0
- data/lib/solargraph/parser/node_methods.rb +15 -1
- data/lib/solargraph/parser/node_processor.rb +3 -1
- data/lib/solargraph/parser/parser_gem/class_methods.rb +16 -14
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +17 -23
- data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -3
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +23 -2
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +4 -3
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +29 -6
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +41 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +28 -16
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +10 -0
- data/lib/solargraph/parser/region.rb +1 -1
- data/lib/solargraph/parser.rb +1 -0
- data/lib/solargraph/pin/base.rb +326 -43
- data/lib/solargraph/pin/base_variable.rb +18 -10
- data/lib/solargraph/pin/block.rb +3 -3
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +77 -6
- data/lib/solargraph/pin/closure.rb +18 -1
- data/lib/solargraph/pin/common.rb +5 -0
- data/lib/solargraph/pin/delegated_method.rb +20 -1
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +15 -6
- data/lib/solargraph/pin/method.rb +172 -42
- data/lib/solargraph/pin/namespace.rb +17 -9
- data/lib/solargraph/pin/parameter.rb +61 -11
- data/lib/solargraph/pin/proxy_type.rb +12 -6
- data/lib/solargraph/pin/reference/override.rb +10 -6
- data/lib/solargraph/pin/reference/require.rb +2 -2
- data/lib/solargraph/pin/signature.rb +42 -0
- data/lib/solargraph/pin/singleton.rb +1 -1
- data/lib/solargraph/pin/symbol.rb +3 -2
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/pin_cache.rb +185 -0
- data/lib/solargraph/position.rb +16 -0
- data/lib/solargraph/range.rb +16 -0
- data/lib/solargraph/rbs_map/conversions.rb +199 -66
- data/lib/solargraph/rbs_map/core_fills.rb +32 -16
- data/lib/solargraph/rbs_map/core_map.rb +34 -11
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +74 -16
- data/lib/solargraph/shell.rb +19 -18
- data/lib/solargraph/source/chain/array.rb +12 -8
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +62 -25
- data/lib/solargraph/source/chain/constant.rb +1 -1
- data/lib/solargraph/source/chain/hash.rb +9 -3
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +6 -1
- data/lib/solargraph/source/chain/link.rb +19 -5
- data/lib/solargraph/source/chain/literal.rb +27 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain/z_super.rb +1 -1
- data/lib/solargraph/source/chain.rb +106 -62
- data/lib/solargraph/source/cursor.rb +1 -11
- data/lib/solargraph/source/source_chainer.rb +2 -2
- data/lib/solargraph/source.rb +2 -1
- data/lib/solargraph/source_map/clip.rb +4 -2
- data/lib/solargraph/source_map/mapper.rb +9 -5
- data/lib/solargraph/source_map.rb +0 -17
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker.rb +41 -14
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +10 -10
- data/lib/solargraph/views/_namespace.erb +3 -3
- data/lib/solargraph/views/document.erb +10 -10
- data/lib/solargraph/workspace/config.rb +7 -3
- data/lib/solargraph/workspace.rb +16 -6
- data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -2
- data/lib/solargraph/yard_map/mapper/to_method.rb +55 -15
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +5 -2
- data/lib/solargraph/yard_map/mapper.rb +5 -3
- data/lib/solargraph/yard_map/to_method.rb +4 -2
- data/lib/solargraph/yardoc.rb +6 -9
- data/lib/solargraph.rb +20 -1
- data/rbs/fills/tuple.rbs +150 -0
- data/rbs_collection.yaml +19 -0
- data/solargraph.gemspec +6 -5
- metadata +56 -29
- data/lib/solargraph/cache.rb +0 -77
|
@@ -7,19 +7,29 @@ module Solargraph
|
|
|
7
7
|
# Ruby stdlib pins
|
|
8
8
|
#
|
|
9
9
|
class StdlibMap < RbsMap
|
|
10
|
+
include Logging
|
|
11
|
+
|
|
10
12
|
# @type [Hash{String => RbsMap}]
|
|
11
13
|
@stdlib_maps_hash = {}
|
|
12
14
|
|
|
13
15
|
# @param library [String]
|
|
14
16
|
def initialize library
|
|
15
|
-
|
|
16
|
-
if
|
|
17
|
-
pins
|
|
17
|
+
cached_pins = PinCache.deserialize_stdlib_require library
|
|
18
|
+
if cached_pins
|
|
19
|
+
@pins = cached_pins
|
|
18
20
|
@resolved = true
|
|
21
|
+
@loaded = true
|
|
22
|
+
logger.debug { "Deserialized #{cached_pins.length} cached pins for stdlib require #{library.inspect}" }
|
|
19
23
|
else
|
|
20
24
|
super
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
unless resolved?
|
|
26
|
+
@pins = []
|
|
27
|
+
logger.info { "Could not resolve #{library.inspect}" }
|
|
28
|
+
return
|
|
29
|
+
end
|
|
30
|
+
generated_pins = pins
|
|
31
|
+
logger.debug { "Found #{generated_pins.length} pins for stdlib library #{library}" }
|
|
32
|
+
PinCache.serialize_stdlib_require library, generated_pins
|
|
23
33
|
end
|
|
24
34
|
end
|
|
25
35
|
|
data/lib/solargraph/rbs_map.rb
CHANGED
|
@@ -10,25 +10,78 @@ module Solargraph
|
|
|
10
10
|
autoload :CoreFills, 'solargraph/rbs_map/core_fills'
|
|
11
11
|
autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
|
|
12
12
|
|
|
13
|
-
include
|
|
13
|
+
include Logging
|
|
14
14
|
|
|
15
15
|
# @type [Hash{String => RbsMap}]
|
|
16
16
|
@@rbs_maps_hash = {}
|
|
17
17
|
|
|
18
18
|
attr_reader :library
|
|
19
19
|
|
|
20
|
+
attr_reader :rbs_collection_paths
|
|
21
|
+
|
|
22
|
+
attr_reader :rbs_collection_config_path
|
|
23
|
+
|
|
20
24
|
# @param library [String]
|
|
21
25
|
# @param version [String, nil]
|
|
22
|
-
# @param
|
|
23
|
-
def initialize library, version = nil,
|
|
26
|
+
# @param rbs_collection_paths [Array<Pathname, String>]
|
|
27
|
+
def initialize library, version = nil, rbs_collection_config_path: nil, rbs_collection_paths: []
|
|
28
|
+
if rbs_collection_config_path.nil? && !rbs_collection_paths.empty?
|
|
29
|
+
raise 'Please provide rbs_collection_config_path if you provide rbs_collection_paths'
|
|
30
|
+
end
|
|
24
31
|
@library = library
|
|
25
32
|
@version = version
|
|
26
|
-
@
|
|
27
|
-
@
|
|
28
|
-
loader = RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
|
|
33
|
+
@rbs_collection_config_path = rbs_collection_config_path
|
|
34
|
+
@rbs_collection_paths = rbs_collection_paths
|
|
29
35
|
add_library loader, library, version
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def loader
|
|
39
|
+
@loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return string representing the version of the RBS info fetched
|
|
43
|
+
# for the given library. Must change when the RBS info is
|
|
44
|
+
# updated upstream for the same library and version. May change
|
|
45
|
+
# if the config for where information comes form changes.
|
|
46
|
+
def cache_key
|
|
47
|
+
@hextdigest ||= begin
|
|
48
|
+
data = nil
|
|
49
|
+
if rbs_collection_config_path
|
|
50
|
+
lockfile_path = RBS::Collection::Config.to_lockfile_path(Pathname.new(rbs_collection_config_path))
|
|
51
|
+
if lockfile_path.exist?
|
|
52
|
+
collection_config = RBS::Collection::Config.from_path lockfile_path
|
|
53
|
+
gem_config = collection_config.gem(library)
|
|
54
|
+
data = gem_config&.to_s
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
if data.nil? || data.empty?
|
|
58
|
+
if resolved?
|
|
59
|
+
# definitely came from the gem itself and not elsewhere -
|
|
60
|
+
# only one version per gem
|
|
61
|
+
'gem-export'
|
|
62
|
+
else
|
|
63
|
+
'unresolved'
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
Digest::SHA1.hexdigest(data)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.from_gemspec gemspec, rbs_collection_path, rbs_collection_config_path
|
|
72
|
+
rbs_map = RbsMap.new(gemspec.name, gemspec.version,
|
|
73
|
+
rbs_collection_paths: [rbs_collection_path].compact,
|
|
74
|
+
rbs_collection_config_path: rbs_collection_config_path)
|
|
75
|
+
return rbs_map if rbs_map.resolved?
|
|
76
|
+
|
|
77
|
+
# try any version of the gem in the collection
|
|
78
|
+
RbsMap.new(gemspec.name, nil,
|
|
79
|
+
rbs_collection_paths: [rbs_collection_path].compact,
|
|
80
|
+
rbs_collection_config_path: rbs_collection_config_path)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def pins
|
|
84
|
+
@pins ||= resolved? ? conversions.pins : []
|
|
32
85
|
end
|
|
33
86
|
|
|
34
87
|
# @generic T
|
|
@@ -52,9 +105,10 @@ module Solargraph
|
|
|
52
105
|
|
|
53
106
|
def repository
|
|
54
107
|
@repository ||= RBS::Repository.new(no_stdlib: false).tap do |repo|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
108
|
+
@rbs_collection_paths.each do |dir|
|
|
109
|
+
dir_path = Pathname.new(dir)
|
|
110
|
+
repo.add(dir_path) if dir_path.exist? && dir_path.directory?
|
|
111
|
+
end
|
|
58
112
|
end
|
|
59
113
|
end
|
|
60
114
|
|
|
@@ -64,11 +118,15 @@ module Solargraph
|
|
|
64
118
|
@@rbs_maps_hash[library] ||= RbsMap.new(library)
|
|
65
119
|
end
|
|
66
120
|
|
|
67
|
-
|
|
68
|
-
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def loader
|
|
124
|
+
@loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
|
|
69
125
|
end
|
|
70
126
|
|
|
71
|
-
|
|
127
|
+
def conversions
|
|
128
|
+
@conversions ||= Conversions.new(loader: loader)
|
|
129
|
+
end
|
|
72
130
|
|
|
73
131
|
# @param loader [RBS::EnvironmentLoader]
|
|
74
132
|
# @param library [String]
|
|
@@ -76,10 +134,10 @@ module Solargraph
|
|
|
76
134
|
def add_library loader, library, version
|
|
77
135
|
@resolved = if loader.has_library?(library: library, version: version)
|
|
78
136
|
loader.add library: library, version: version
|
|
79
|
-
|
|
137
|
+
logger.debug { "#{short_name} successfully loaded library #{library}:#{version}" }
|
|
80
138
|
true
|
|
81
139
|
else
|
|
82
|
-
|
|
140
|
+
logger.info { "#{short_name} did not find data for library #{library}:#{version}" }
|
|
83
141
|
false
|
|
84
142
|
end
|
|
85
143
|
end
|
data/lib/solargraph/shell.rb
CHANGED
|
@@ -90,19 +90,20 @@ module Solargraph
|
|
|
90
90
|
# @return [void]
|
|
91
91
|
def clear
|
|
92
92
|
puts "Deleting all cached documentation (gems, core and stdlib)"
|
|
93
|
-
Solargraph::
|
|
93
|
+
Solargraph::PinCache.clear
|
|
94
94
|
end
|
|
95
95
|
map 'clear-cache' => :clear
|
|
96
96
|
map 'clear-cores' => :clear
|
|
97
97
|
|
|
98
98
|
desc 'cache', 'Cache a gem', hide: true
|
|
99
|
+
option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
|
|
99
100
|
# @return [void]
|
|
100
101
|
# @param gem [String]
|
|
101
102
|
# @param version [String, nil]
|
|
102
103
|
def cache gem, version = nil
|
|
104
|
+
api_map = Solargraph::ApiMap.load(Dir.pwd)
|
|
103
105
|
spec = Gem::Specification.find_by_name(gem, version)
|
|
104
|
-
|
|
105
|
-
Cache.save('gems', "#{spec.name}-#{spec.version}.ser", pins)
|
|
106
|
+
api_map.cache_gem(spec, rebuild: options[:rebuild], out: $stdout)
|
|
106
107
|
end
|
|
107
108
|
|
|
108
109
|
desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
|
|
@@ -111,39 +112,43 @@ module Solargraph
|
|
|
111
112
|
also be specified to clear cached system documentation.
|
|
112
113
|
Documentation will be regenerated as needed.
|
|
113
114
|
)
|
|
115
|
+
# @param gems [Array<String>]
|
|
114
116
|
# @return [void]
|
|
115
117
|
def uncache *gems
|
|
116
118
|
raise ArgumentError, 'No gems specified.' if gems.empty?
|
|
117
119
|
gems.each do |gem|
|
|
118
120
|
if gem == 'core'
|
|
119
|
-
|
|
121
|
+
PinCache.uncache_core
|
|
120
122
|
next
|
|
121
123
|
end
|
|
122
124
|
|
|
123
125
|
if gem == 'stdlib'
|
|
124
|
-
|
|
126
|
+
PinCache.uncache_stdlib
|
|
125
127
|
next
|
|
126
128
|
end
|
|
127
129
|
|
|
128
130
|
spec = Gem::Specification.find_by_name(gem)
|
|
129
|
-
|
|
130
|
-
Cache.uncache('gems', "#{spec.name}-#{spec.version}.yardoc")
|
|
131
|
+
PinCache.uncache_gem(spec, out: $stdout)
|
|
131
132
|
end
|
|
132
133
|
end
|
|
133
134
|
|
|
134
135
|
desc 'gems [GEM[=VERSION]]', 'Cache documentation for installed gems'
|
|
135
136
|
option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
|
|
137
|
+
# @param names [Array<String>]
|
|
136
138
|
# @return [void]
|
|
137
139
|
def gems *names
|
|
140
|
+
api_map = ApiMap.load('.')
|
|
138
141
|
if names.empty?
|
|
139
|
-
Gem::Specification.to_a.each { |spec| do_cache spec }
|
|
142
|
+
Gem::Specification.to_a.each { |spec| do_cache spec, api_map }
|
|
143
|
+
STDERR.puts "Documentation cached for all #{Gem::Specification.count} gems."
|
|
140
144
|
else
|
|
141
145
|
names.each do |name|
|
|
142
146
|
spec = Gem::Specification.find_by_name(*name.split('='))
|
|
143
|
-
do_cache spec
|
|
147
|
+
do_cache spec, api_map
|
|
144
148
|
rescue Gem::MissingSpecError
|
|
145
149
|
warn "Gem '#{name}' not found"
|
|
146
150
|
end
|
|
151
|
+
STDERR.puts "Documentation cached for #{names.count} gems."
|
|
147
152
|
end
|
|
148
153
|
end
|
|
149
154
|
|
|
@@ -204,6 +209,7 @@ module Solargraph
|
|
|
204
209
|
# @return [void]
|
|
205
210
|
def scan
|
|
206
211
|
directory = File.realpath(options[:directory])
|
|
212
|
+
# @type [Solargraph::ApiMap, nil]
|
|
207
213
|
api_map = nil
|
|
208
214
|
time = Benchmark.measure {
|
|
209
215
|
api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
|
|
@@ -253,15 +259,10 @@ module Solargraph
|
|
|
253
259
|
|
|
254
260
|
# @param gemspec [Gem::Specification]
|
|
255
261
|
# @return [void]
|
|
256
|
-
def do_cache gemspec
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
else
|
|
261
|
-
puts "#{cached ? 'Rebuilding' : 'Caching'} gem documentation for #{gemspec.name} #{gemspec.version}"
|
|
262
|
-
pins = GemPins.build(gemspec)
|
|
263
|
-
Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
|
|
264
|
-
end
|
|
262
|
+
def do_cache gemspec, api_map
|
|
263
|
+
# @todo if the rebuild: option is passed as a positional arg,
|
|
264
|
+
# typecheck doesn't complain on the below line
|
|
265
|
+
api_map.cache_gem(gemspec, rebuild: options.rebuild, out: $stdout)
|
|
265
266
|
end
|
|
266
267
|
end
|
|
267
268
|
end
|
|
@@ -3,8 +3,9 @@ module Solargraph
|
|
|
3
3
|
class Chain
|
|
4
4
|
class Array < Literal
|
|
5
5
|
# @param children [::Array<Chain>]
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
# @param node [Parser::AST::Node]
|
|
7
|
+
def initialize children, node
|
|
8
|
+
super('::Array', node)
|
|
8
9
|
@children = children
|
|
9
10
|
end
|
|
10
11
|
|
|
@@ -14,18 +15,21 @@ module Solargraph
|
|
|
14
15
|
|
|
15
16
|
# @param api_map [ApiMap]
|
|
16
17
|
# @param name_pin [Pin::Base]
|
|
17
|
-
# @param locals [
|
|
18
|
+
# @param locals [::Array<Pin::Parameter, Pin::LocalVariable>]
|
|
18
19
|
def resolve api_map, name_pin, locals
|
|
19
20
|
child_types = @children.map do |child|
|
|
20
|
-
child.infer(api_map, name_pin, locals)
|
|
21
|
+
child.infer(api_map, name_pin, locals).simplify_literals
|
|
21
22
|
end
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
type = if child_types.length == 0 || child_types.any?(&:undefined?)
|
|
24
|
+
ComplexType::UniqueType.new('Array', rooted: true)
|
|
25
|
+
elsif child_types.uniq.length == 1 && child_types.first.defined?
|
|
24
26
|
ComplexType::UniqueType.new('Array', [], child_types.uniq, rooted: true, parameters_type: :list)
|
|
27
|
+
elsif child_types.length == 0
|
|
28
|
+
ComplexType::UniqueType.new('Array', rooted: true, parameters_type: :list)
|
|
25
29
|
else
|
|
26
|
-
ComplexType::UniqueType.new('Array', rooted: true)
|
|
30
|
+
ComplexType::UniqueType.new('Array', [], child_types, rooted: true, parameters_type: :fixed)
|
|
27
31
|
end
|
|
28
|
-
[Pin::ProxyType.anonymous(type)]
|
|
32
|
+
[Pin::ProxyType.anonymous(type, source: :chain)]
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
end
|
|
@@ -3,12 +3,20 @@
|
|
|
3
3
|
module Solargraph
|
|
4
4
|
class Source
|
|
5
5
|
class Chain
|
|
6
|
+
#
|
|
7
|
+
# Handles both method calls and local variable references by
|
|
8
|
+
# first looking for a variable with the name 'word', then
|
|
9
|
+
# proceeding to method signature resolution if not found.
|
|
10
|
+
#
|
|
6
11
|
class Call < Chain::Link
|
|
7
12
|
include Solargraph::Parser::NodeMethods
|
|
8
13
|
|
|
9
14
|
# @return [String]
|
|
10
15
|
attr_reader :word
|
|
11
16
|
|
|
17
|
+
# @return [Location]
|
|
18
|
+
attr_reader :location
|
|
19
|
+
|
|
12
20
|
# @return [::Array<Chain>]
|
|
13
21
|
attr_reader :arguments
|
|
14
22
|
|
|
@@ -16,34 +24,42 @@ module Solargraph
|
|
|
16
24
|
attr_reader :block
|
|
17
25
|
|
|
18
26
|
# @param word [String]
|
|
27
|
+
# @param location [Location, nil]
|
|
19
28
|
# @param arguments [::Array<Chain>]
|
|
20
29
|
# @param block [Chain, nil]
|
|
21
|
-
def initialize word, arguments = [], block = nil
|
|
30
|
+
def initialize word, location = nil, arguments = [], block = nil
|
|
22
31
|
@word = word
|
|
32
|
+
@location = location
|
|
23
33
|
@arguments = arguments
|
|
24
34
|
@block = block
|
|
25
35
|
fix_block_pass
|
|
26
36
|
end
|
|
27
37
|
|
|
38
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
39
|
+
protected def equality_fields
|
|
40
|
+
super + [arguments, block]
|
|
41
|
+
end
|
|
42
|
+
|
|
28
43
|
def with_block?
|
|
29
44
|
!!@block
|
|
30
45
|
end
|
|
31
46
|
|
|
32
47
|
# @param api_map [ApiMap]
|
|
33
|
-
# @param name_pin [Pin::Closure] name_pin.binder should give us the object on which 'word' will be invoked
|
|
48
|
+
# @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
|
|
34
49
|
# @param locals [::Array<Pin::LocalVariable>]
|
|
35
50
|
def resolve api_map, name_pin, locals
|
|
36
51
|
return super_pins(api_map, name_pin) if word == 'super'
|
|
37
52
|
return yield_pins(api_map, name_pin) if word == 'yield'
|
|
38
53
|
found = if head?
|
|
39
|
-
locals
|
|
54
|
+
api_map.visible_pins(locals, word, name_pin, location)
|
|
40
55
|
else
|
|
41
56
|
[]
|
|
42
57
|
end
|
|
43
58
|
return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
|
|
44
59
|
pins = name_pin.binder.each_unique_type.flat_map do |context|
|
|
45
|
-
|
|
46
|
-
api_map.get_method_stack(
|
|
60
|
+
ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
|
|
61
|
+
stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
|
|
62
|
+
[stack.first].compact
|
|
47
63
|
end
|
|
48
64
|
return [] if pins.empty?
|
|
49
65
|
inferred_pins(pins, api_map, name_pin, locals)
|
|
@@ -54,7 +70,7 @@ module Solargraph
|
|
|
54
70
|
# @param pins [::Enumerable<Pin::Method>]
|
|
55
71
|
# @param api_map [ApiMap]
|
|
56
72
|
# @param name_pin [Pin::Base]
|
|
57
|
-
# @param locals [::Array<Pin::LocalVariable>]
|
|
73
|
+
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
58
74
|
# @return [::Array<Pin::Base>]
|
|
59
75
|
def inferred_pins pins, api_map, name_pin, locals
|
|
60
76
|
result = pins.map do |p|
|
|
@@ -67,7 +83,9 @@ module Solargraph
|
|
|
67
83
|
# use it. If we didn't pass a block, the logic below will
|
|
68
84
|
# reject it regardless
|
|
69
85
|
|
|
70
|
-
|
|
86
|
+
with_block, without_block = overloads.partition(&:block?)
|
|
87
|
+
sorted_overloads = with_block + without_block
|
|
88
|
+
# @type [Pin::Signature, nil]
|
|
71
89
|
new_signature_pin = nil
|
|
72
90
|
sorted_overloads.each do |ol|
|
|
73
91
|
next unless ol.arity_matches?(arguments, with_block?)
|
|
@@ -80,11 +98,8 @@ module Solargraph
|
|
|
80
98
|
match = ol.parameters.any?(&:restarg?)
|
|
81
99
|
break
|
|
82
100
|
end
|
|
83
|
-
atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context), locals)
|
|
84
|
-
|
|
85
|
-
# @todo Weak type comparison
|
|
86
|
-
# unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
|
|
87
|
-
unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name) || param.return_type.generic?
|
|
101
|
+
atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context, source: :chain), locals)
|
|
102
|
+
unless param.compatible_arg?(atype, api_map) || param.restarg?
|
|
88
103
|
match = false
|
|
89
104
|
break
|
|
90
105
|
end
|
|
@@ -99,9 +114,30 @@ module Solargraph
|
|
|
99
114
|
blocktype = block_call_type(api_map, name_pin, locals)
|
|
100
115
|
end
|
|
101
116
|
end
|
|
117
|
+
# @type new_signature_pin [Pin::Signature]
|
|
102
118
|
new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
|
|
103
119
|
new_return_type = new_signature_pin.return_type
|
|
104
|
-
|
|
120
|
+
if head?
|
|
121
|
+
# If we're at the head of the chain, we called a
|
|
122
|
+
# method somewhere that marked itself as returning
|
|
123
|
+
# self. Given we didn't invoke this on an object,
|
|
124
|
+
# this must be a method in this same class - so we
|
|
125
|
+
# use our own self type
|
|
126
|
+
self_type = name_pin.context
|
|
127
|
+
else
|
|
128
|
+
# if we're past the head in the chain, whatever the
|
|
129
|
+
# type of the lhs side is what 'self' will be in its
|
|
130
|
+
# declaration - we can't just use the type of the
|
|
131
|
+
# method pin, as this might be a subclass of the
|
|
132
|
+
# place where the method is defined
|
|
133
|
+
self_type = name_pin.binder
|
|
134
|
+
end
|
|
135
|
+
# This same logic applies to the YARD work done by
|
|
136
|
+
# 'with_params()'.
|
|
137
|
+
#
|
|
138
|
+
# qualify(), however, happens in the namespace where
|
|
139
|
+
# the docs were written - from the method pin.
|
|
140
|
+
type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, p.namespace) if new_return_type.defined?
|
|
105
141
|
type ||= ComplexType::UNDEFINED
|
|
106
142
|
end
|
|
107
143
|
break if type.defined?
|
|
@@ -117,13 +153,14 @@ module Solargraph
|
|
|
117
153
|
end
|
|
118
154
|
p
|
|
119
155
|
end
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
156
|
+
logger.debug { "Call#inferred_pins(name_pin.binder=#{name_pin.binder}, word=#{word}, pins=#{pins.map(&:desc)}, name_pin=#{name_pin}) - result=#{result}" }
|
|
157
|
+
out = result.map do |pin|
|
|
158
|
+
if pin.path == 'Class#new' && name_pin.binder.tag != 'Class'
|
|
159
|
+
reduced_context = name_pin.binder.reduce_class_type
|
|
123
160
|
pin.proxy(reduced_context)
|
|
124
161
|
else
|
|
125
162
|
next pin if pin.return_type.undefined?
|
|
126
|
-
selfy = pin.return_type.self_to_type(name_pin.
|
|
163
|
+
selfy = pin.return_type.self_to_type(name_pin.binder)
|
|
127
164
|
selfy == pin.return_type ? pin : pin.proxy(selfy)
|
|
128
165
|
end
|
|
129
166
|
end
|
|
@@ -132,7 +169,7 @@ module Solargraph
|
|
|
132
169
|
# @param pin [Pin::Base]
|
|
133
170
|
# @param api_map [ApiMap]
|
|
134
171
|
# @param context [ComplexType]
|
|
135
|
-
# @param locals [
|
|
172
|
+
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
136
173
|
# @return [Pin::Base]
|
|
137
174
|
def process_macro pin, api_map, context, locals
|
|
138
175
|
pin.macros.each do |macro|
|
|
@@ -145,13 +182,13 @@ module Solargraph
|
|
|
145
182
|
result = inner_process_macro(pin, macro, api_map, context, locals)
|
|
146
183
|
return result unless result.return_type.undefined?
|
|
147
184
|
end
|
|
148
|
-
Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
|
|
185
|
+
Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
|
|
149
186
|
end
|
|
150
187
|
|
|
151
188
|
# @param pin [Pin::Method]
|
|
152
189
|
# @param api_map [ApiMap]
|
|
153
190
|
# @param context [ComplexType]
|
|
154
|
-
# @param locals [
|
|
191
|
+
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
155
192
|
# @return [Pin::ProxyType]
|
|
156
193
|
def process_directive pin, api_map, context, locals
|
|
157
194
|
pin.directives.each do |dir|
|
|
@@ -160,17 +197,17 @@ module Solargraph
|
|
|
160
197
|
result = inner_process_macro(pin, macro, api_map, context, locals)
|
|
161
198
|
return result unless result.return_type.undefined?
|
|
162
199
|
end
|
|
163
|
-
Pin::ProxyType.anonymous ComplexType::UNDEFINED
|
|
200
|
+
Pin::ProxyType.anonymous ComplexType::UNDEFINED, source: :chain
|
|
164
201
|
end
|
|
165
202
|
|
|
166
203
|
# @param pin [Pin::Base]
|
|
167
204
|
# @param macro [YARD::Tags::MacroDirective]
|
|
168
205
|
# @param api_map [ApiMap]
|
|
169
206
|
# @param context [ComplexType]
|
|
170
|
-
# @param locals [
|
|
207
|
+
# @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
|
|
171
208
|
# @return [Pin::ProxyType]
|
|
172
209
|
def inner_process_macro pin, macro, api_map, context, locals
|
|
173
|
-
vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
|
|
210
|
+
vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
|
|
174
211
|
txt = macro.tag.text.clone
|
|
175
212
|
if txt.empty? && macro.tag.name
|
|
176
213
|
named = api_map.named_macro(macro.tag.name)
|
|
@@ -184,9 +221,9 @@ module Solargraph
|
|
|
184
221
|
docstring = Solargraph::Source.parse_docstring(txt).to_docstring
|
|
185
222
|
tag = docstring.tag(:return)
|
|
186
223
|
unless tag.nil? || tag.types.nil?
|
|
187
|
-
return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types))
|
|
224
|
+
return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types), source: :chain)
|
|
188
225
|
end
|
|
189
|
-
Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
|
|
226
|
+
Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
|
|
190
227
|
end
|
|
191
228
|
|
|
192
229
|
# @param docstring [YARD::Docstring]
|
|
@@ -5,18 +5,24 @@ module Solargraph
|
|
|
5
5
|
class Chain
|
|
6
6
|
class Hash < Literal
|
|
7
7
|
# @param type [String]
|
|
8
|
+
# @param node [Parser::AST::Node]
|
|
8
9
|
# @param splatted [Boolean]
|
|
9
|
-
def initialize type, splatted = false
|
|
10
|
-
super(type)
|
|
10
|
+
def initialize type, node, splatted = false
|
|
11
|
+
super(type, node)
|
|
11
12
|
@splatted = splatted
|
|
12
13
|
end
|
|
13
14
|
|
|
15
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
16
|
+
protected def equality_fields
|
|
17
|
+
super + [@splatted]
|
|
18
|
+
end
|
|
19
|
+
|
|
14
20
|
def word
|
|
15
21
|
@word ||= "<#{@type}>"
|
|
16
22
|
end
|
|
17
23
|
|
|
18
24
|
def resolve api_map, name_pin, locals
|
|
19
|
-
[Pin::ProxyType.anonymous(@complex_type)]
|
|
25
|
+
[Pin::ProxyType.anonymous(@complex_type, source: :chain)]
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
def splatted?
|
|
@@ -9,7 +9,7 @@ module Solargraph
|
|
|
9
9
|
# @note Chain::Head is only intended to handle `self` and `super`.
|
|
10
10
|
class Head < Link
|
|
11
11
|
def resolve api_map, name_pin, locals
|
|
12
|
-
return [Pin::ProxyType.anonymous(name_pin.binder)] if word == 'self'
|
|
12
|
+
return [Pin::ProxyType.anonymous(name_pin.binder, source: :chain)] if word == 'self'
|
|
13
13
|
# return super_pins(api_map, name_pin) if word == 'super'
|
|
14
14
|
[]
|
|
15
15
|
end
|
|
@@ -13,9 +13,14 @@ module Solargraph
|
|
|
13
13
|
@links = links
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
17
|
+
protected def equality_fields
|
|
18
|
+
super + [@links]
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
def resolve api_map, name_pin, locals
|
|
17
22
|
types = @links.map { |link| link.infer(api_map, name_pin, locals) }
|
|
18
|
-
[Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
|
|
23
|
+
[Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')), source: :chain)]
|
|
19
24
|
end
|
|
20
25
|
end
|
|
21
26
|
end
|
|
@@ -4,6 +4,8 @@ module Solargraph
|
|
|
4
4
|
class Source
|
|
5
5
|
class Chain
|
|
6
6
|
class Link
|
|
7
|
+
include Equality
|
|
8
|
+
|
|
7
9
|
# @return [String]
|
|
8
10
|
attr_reader :word
|
|
9
11
|
|
|
@@ -15,6 +17,11 @@ module Solargraph
|
|
|
15
17
|
@word = word
|
|
16
18
|
end
|
|
17
19
|
|
|
20
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
21
|
+
protected def equality_fields
|
|
22
|
+
[self.class, word]
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
def undefined?
|
|
19
26
|
word == '<undefined>'
|
|
20
27
|
end
|
|
@@ -31,18 +38,23 @@ module Solargraph
|
|
|
31
38
|
[]
|
|
32
39
|
end
|
|
33
40
|
|
|
41
|
+
# debugging description of contents; not for machine use
|
|
42
|
+
def desc
|
|
43
|
+
word
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_s
|
|
47
|
+
desc
|
|
48
|
+
end
|
|
49
|
+
|
|
34
50
|
def inspect
|
|
35
|
-
"
|
|
51
|
+
"#<#{self.class} - `#{self.desc}`>"
|
|
36
52
|
end
|
|
37
53
|
|
|
38
54
|
def head?
|
|
39
55
|
@head ||= false
|
|
40
56
|
end
|
|
41
57
|
|
|
42
|
-
def == other
|
|
43
|
-
self.class == other.class and word == other.word
|
|
44
|
-
end
|
|
45
|
-
|
|
46
58
|
# Make a copy of this link marked as the head of a chain
|
|
47
59
|
#
|
|
48
60
|
# @return [self]
|
|
@@ -70,6 +82,8 @@ module Solargraph
|
|
|
70
82
|
"#<#{self.class} - `#{self.desc}`>"
|
|
71
83
|
end
|
|
72
84
|
|
|
85
|
+
include Logging
|
|
86
|
+
|
|
73
87
|
protected
|
|
74
88
|
|
|
75
89
|
# Mark whether this link is the head of a chain
|