solargraph 0.58.1 → 0.59.0.dev.1
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/.envrc +3 -0
- data/.github/workflows/linting.yml +4 -5
- data/.github/workflows/plugins.yml +40 -36
- data/.github/workflows/rspec.yml +45 -13
- data/.github/workflows/typecheck.yml +2 -2
- data/.rubocop_todo.yml +27 -49
- data/README.md +3 -3
- data/Rakefile +1 -0
- data/lib/solargraph/api_map/cache.rb +110 -110
- data/lib/solargraph/api_map/constants.rb +289 -279
- data/lib/solargraph/api_map/index.rb +204 -193
- data/lib/solargraph/api_map/source_to_yard.rb +109 -97
- data/lib/solargraph/api_map/store.rb +387 -384
- data/lib/solargraph/api_map.rb +1000 -945
- data/lib/solargraph/complex_type/conformance.rb +176 -0
- data/lib/solargraph/complex_type/type_methods.rb +242 -228
- data/lib/solargraph/complex_type/unique_type.rb +632 -482
- data/lib/solargraph/complex_type.rb +549 -444
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
- data/lib/solargraph/convention/data_definition.rb +108 -105
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
- data/lib/solargraph/convention/struct_definition.rb +168 -164
- data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
- data/lib/solargraph/diagnostics/rubocop.rb +119 -118
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
- data/lib/solargraph/diagnostics/type_check.rb +56 -55
- data/lib/solargraph/doc_map.rb +200 -439
- data/lib/solargraph/equality.rb +34 -34
- data/lib/solargraph/gem_pins.rb +97 -98
- data/lib/solargraph/language_server/host/dispatch.rb +131 -130
- data/lib/solargraph/language_server/host/message_worker.rb +113 -112
- data/lib/solargraph/language_server/host/sources.rb +100 -99
- data/lib/solargraph/language_server/host.rb +883 -878
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +109 -114
- data/lib/solargraph/language_server/message/extended/document.rb +24 -23
- data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
- data/lib/solargraph/language_server/message/text_document/definition.rb +42 -40
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +28 -26
- data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
- data/lib/solargraph/language_server/message/text_document/hover.rb +60 -58
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +27 -25
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +25 -23
- data/lib/solargraph/library.rb +729 -683
- data/lib/solargraph/location.rb +87 -82
- data/lib/solargraph/logging.rb +57 -37
- data/lib/solargraph/parser/comment_ripper.rb +76 -69
- data/lib/solargraph/parser/flow_sensitive_typing.rb +483 -255
- data/lib/solargraph/parser/node_processor/base.rb +122 -92
- data/lib/solargraph/parser/node_processor.rb +63 -62
- data/lib/solargraph/parser/parser_gem/class_methods.rb +167 -149
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
- data/lib/solargraph/parser/parser_gem/node_methods.rb +506 -486
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +41 -40
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
- data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +53 -52
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +296 -291
- data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
- data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
- data/lib/solargraph/parser/region.rb +75 -69
- data/lib/solargraph/parser/snippet.rb +17 -17
- data/lib/solargraph/pin/base.rb +761 -729
- data/lib/solargraph/pin/base_variable.rb +418 -126
- data/lib/solargraph/pin/block.rb +126 -104
- data/lib/solargraph/pin/breakable.rb +13 -9
- data/lib/solargraph/pin/callable.rb +278 -231
- data/lib/solargraph/pin/closure.rb +68 -72
- data/lib/solargraph/pin/common.rb +94 -79
- data/lib/solargraph/pin/compound_statement.rb +55 -0
- data/lib/solargraph/pin/conversions.rb +124 -123
- data/lib/solargraph/pin/delegated_method.rb +131 -120
- data/lib/solargraph/pin/documenting.rb +115 -114
- data/lib/solargraph/pin/instance_variable.rb +38 -34
- data/lib/solargraph/pin/keyword.rb +16 -20
- data/lib/solargraph/pin/local_variable.rb +31 -75
- data/lib/solargraph/pin/method.rb +720 -672
- data/lib/solargraph/pin/method_alias.rb +42 -34
- data/lib/solargraph/pin/namespace.rb +121 -115
- data/lib/solargraph/pin/parameter.rb +338 -275
- data/lib/solargraph/pin/proxy_type.rb +40 -39
- data/lib/solargraph/pin/reference/override.rb +47 -47
- data/lib/solargraph/pin/reference/superclass.rb +17 -15
- data/lib/solargraph/pin/reference.rb +41 -39
- data/lib/solargraph/pin/search.rb +62 -61
- data/lib/solargraph/pin/signature.rb +69 -61
- data/lib/solargraph/pin/symbol.rb +53 -53
- data/lib/solargraph/pin/until.rb +18 -18
- data/lib/solargraph/pin/while.rb +18 -18
- data/lib/solargraph/pin.rb +46 -44
- data/lib/solargraph/pin_cache.rb +665 -245
- data/lib/solargraph/position.rb +118 -119
- data/lib/solargraph/range.rb +112 -112
- data/lib/solargraph/rbs_map/conversions.rb +846 -823
- data/lib/solargraph/rbs_map/core_map.rb +65 -58
- data/lib/solargraph/rbs_map/stdlib_map.rb +72 -43
- data/lib/solargraph/rbs_map.rb +217 -163
- data/lib/solargraph/shell.rb +397 -352
- data/lib/solargraph/source/chain/call.rb +372 -337
- data/lib/solargraph/source/chain/constant.rb +28 -26
- data/lib/solargraph/source/chain/hash.rb +35 -34
- data/lib/solargraph/source/chain/if.rb +29 -28
- data/lib/solargraph/source/chain/instance_variable.rb +34 -13
- data/lib/solargraph/source/chain/literal.rb +53 -48
- data/lib/solargraph/source/chain/or.rb +31 -23
- data/lib/solargraph/source/chain.rb +294 -291
- data/lib/solargraph/source/change.rb +89 -82
- data/lib/solargraph/source/cursor.rb +172 -166
- data/lib/solargraph/source/source_chainer.rb +204 -194
- data/lib/solargraph/source/updater.rb +59 -55
- data/lib/solargraph/source.rb +524 -498
- data/lib/solargraph/source_map/clip.rb +237 -226
- data/lib/solargraph/source_map/data.rb +37 -34
- data/lib/solargraph/source_map/mapper.rb +282 -259
- data/lib/solargraph/source_map.rb +220 -212
- data/lib/solargraph/type_checker/problem.rb +34 -32
- data/lib/solargraph/type_checker/rules.rb +157 -84
- data/lib/solargraph/type_checker.rb +895 -814
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +257 -255
- data/lib/solargraph/workspace/gemspecs.rb +367 -0
- data/lib/solargraph/workspace/require_paths.rb +98 -97
- data/lib/solargraph/workspace.rb +362 -220
- data/lib/solargraph/yard_map/helpers.rb +45 -44
- data/lib/solargraph/yard_map/mapper/to_method.rb +134 -130
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
- data/lib/solargraph/yard_map/mapper.rb +84 -79
- data/lib/solargraph/yardoc.rb +97 -87
- data/lib/solargraph.rb +126 -105
- data/rbs/fills/rubygems/0/dependency.rbs +193 -0
- data/rbs/fills/tuple/tuple.rbs +28 -0
- data/rbs/shims/ast/0/node.rbs +5 -0
- data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
- data/rbs_collection.yaml +1 -1
- data/solargraph.gemspec +2 -1
- metadata +22 -17
- data/lib/solargraph/type_checker/checks.rb +0 -124
- data/lib/solargraph/type_checker/param_def.rb +0 -37
- data/lib/solargraph/yard_map/to_method.rb +0 -89
- data/sig/shims/ast/0/node.rbs +0 -5
- /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
data/lib/solargraph/api_map.rb
CHANGED
|
@@ -1,945 +1,1000 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'pathname'
|
|
4
|
-
require 'yard'
|
|
5
|
-
require 'solargraph/yard_tags'
|
|
6
|
-
|
|
7
|
-
module Solargraph
|
|
8
|
-
# An aggregate provider for information about Workspaces, Sources, gems, and
|
|
9
|
-
# the Ruby core.
|
|
10
|
-
#
|
|
11
|
-
class ApiMap
|
|
12
|
-
autoload :Cache, 'solargraph/api_map/cache'
|
|
13
|
-
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
|
14
|
-
autoload :Store, 'solargraph/api_map/store'
|
|
15
|
-
autoload :Index, 'solargraph/api_map/index'
|
|
16
|
-
autoload :Constants, 'solargraph/api_map/constants'
|
|
17
|
-
|
|
18
|
-
# @return [Array<String>]
|
|
19
|
-
attr_reader :unresolved_requires
|
|
20
|
-
|
|
21
|
-
@@core_map = RbsMap::CoreMap.new
|
|
22
|
-
|
|
23
|
-
# @return [Array<String>]
|
|
24
|
-
attr_reader :missing_docs
|
|
25
|
-
|
|
26
|
-
# @param pins [Array<Solargraph::Pin::Base>]
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
# @return [
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
self
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
# @
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
# @
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
# @
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
#
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
#
|
|
256
|
-
#
|
|
257
|
-
# @param
|
|
258
|
-
# @
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
#
|
|
282
|
-
#
|
|
283
|
-
#
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
#
|
|
289
|
-
#
|
|
290
|
-
#
|
|
291
|
-
#
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
# @
|
|
297
|
-
#
|
|
298
|
-
#
|
|
299
|
-
# @param gates [Array<String
|
|
300
|
-
#
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
# @
|
|
308
|
-
#
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
# @
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
#
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
# @
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
#
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
# @
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
#
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
#
|
|
496
|
-
#
|
|
497
|
-
#
|
|
498
|
-
#
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
#
|
|
530
|
-
#
|
|
531
|
-
#
|
|
532
|
-
#
|
|
533
|
-
# @param
|
|
534
|
-
# @
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
# @deprecated
|
|
562
|
-
#
|
|
563
|
-
#
|
|
564
|
-
# @
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
get_path_pins(path)
|
|
568
|
-
end
|
|
569
|
-
|
|
570
|
-
# Get an array of
|
|
571
|
-
#
|
|
572
|
-
# @param
|
|
573
|
-
# @return [Array<Pin::Base>]
|
|
574
|
-
def
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
#
|
|
582
|
-
#
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
#
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
end
|
|
610
|
-
|
|
611
|
-
#
|
|
612
|
-
#
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
#
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
end
|
|
627
|
-
|
|
628
|
-
#
|
|
629
|
-
#
|
|
630
|
-
# @param
|
|
631
|
-
# @
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
#
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
#
|
|
660
|
-
#
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
#
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
#
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
#
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
# @param
|
|
730
|
-
#
|
|
731
|
-
# @param
|
|
732
|
-
# @
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
# @param
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'yard'
|
|
5
|
+
require 'solargraph/yard_tags'
|
|
6
|
+
|
|
7
|
+
module Solargraph
|
|
8
|
+
# An aggregate provider for information about Workspaces, Sources, gems, and
|
|
9
|
+
# the Ruby core.
|
|
10
|
+
#
|
|
11
|
+
class ApiMap
|
|
12
|
+
autoload :Cache, 'solargraph/api_map/cache'
|
|
13
|
+
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
|
14
|
+
autoload :Store, 'solargraph/api_map/store'
|
|
15
|
+
autoload :Index, 'solargraph/api_map/index'
|
|
16
|
+
autoload :Constants, 'solargraph/api_map/constants'
|
|
17
|
+
|
|
18
|
+
# @return [Array<String>]
|
|
19
|
+
attr_reader :unresolved_requires
|
|
20
|
+
|
|
21
|
+
@@core_map = RbsMap::CoreMap.new
|
|
22
|
+
|
|
23
|
+
# @return [Array<String>]
|
|
24
|
+
attr_reader :missing_docs
|
|
25
|
+
|
|
26
|
+
# @param pins [Array<Solargraph::Pin::Base>]
|
|
27
|
+
# @param loose_unions [Boolean] if true, a potential type can be
|
|
28
|
+
# inferred if ANY of the UniqueTypes in the base chain's
|
|
29
|
+
# ComplexType match it. If false, every single UniqueTypes in
|
|
30
|
+
# the base must be ALL able to independently provide this
|
|
31
|
+
# type. The former is useful during completion, but the
|
|
32
|
+
# latter is best for typechecking at higher levels.
|
|
33
|
+
#
|
|
34
|
+
def initialize pins: [], loose_unions: true
|
|
35
|
+
@source_map_hash = {}
|
|
36
|
+
@cache = Cache.new
|
|
37
|
+
@loose_unions = loose_unions
|
|
38
|
+
index pins
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @param out [StringIO, IO, nil] output stream for logging
|
|
42
|
+
# @return [void]
|
|
43
|
+
def self.reset_core out: nil
|
|
44
|
+
@@core_map = RbsMap::CoreMap.new
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# This is a mutable object, which is cached in the Chain class -
|
|
49
|
+
# if you add any fields which change the results of calls (not
|
|
50
|
+
# just caches), please also change `equality_fields` below.
|
|
51
|
+
#
|
|
52
|
+
|
|
53
|
+
# @param other [Object]
|
|
54
|
+
def eql?(other)
|
|
55
|
+
self.class == other.class &&
|
|
56
|
+
# @sg-ignore flow sensitive typing needs to handle self.class == other.class
|
|
57
|
+
equality_fields == other.equality_fields
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @param other [Object]
|
|
61
|
+
def ==(other)
|
|
62
|
+
self.eql?(other)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [Integer]
|
|
66
|
+
def hash
|
|
67
|
+
equality_fields.hash
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
attr_reader :loose_unions
|
|
71
|
+
|
|
72
|
+
def to_s
|
|
73
|
+
self.class.to_s
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# avoid enormous dump
|
|
77
|
+
def inspect
|
|
78
|
+
to_s
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @param pins [Array<Pin::Base>]
|
|
82
|
+
# @return [self]
|
|
83
|
+
def index pins
|
|
84
|
+
# @todo This implementation is incomplete. It should probably create a
|
|
85
|
+
# Bench.
|
|
86
|
+
@source_map_hash = {}
|
|
87
|
+
conventions_environ.clear
|
|
88
|
+
cache.clear
|
|
89
|
+
store.update @@core_map.pins, pins
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Map a single source.
|
|
94
|
+
#
|
|
95
|
+
# @param source [Source]
|
|
96
|
+
# @param live [Boolean] True for live source map (active editor file)
|
|
97
|
+
# @return [self]
|
|
98
|
+
def map source, live: false
|
|
99
|
+
map = Solargraph::SourceMap.map(source)
|
|
100
|
+
catalog Bench.new(source_maps: [map], live_map: live ? map : nil)
|
|
101
|
+
self
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Catalog a bench.
|
|
105
|
+
#
|
|
106
|
+
# @param bench [Bench]
|
|
107
|
+
# @return [self]
|
|
108
|
+
def catalog bench
|
|
109
|
+
@source_map_hash = bench.source_map_hash
|
|
110
|
+
iced_pins = bench.icebox.flat_map(&:pins)
|
|
111
|
+
live_pins = bench.live_map&.all_pins || []
|
|
112
|
+
conventions_environ.clear
|
|
113
|
+
source_map_hash.each_value do |map|
|
|
114
|
+
conventions_environ.merge map.conventions_environ
|
|
115
|
+
end
|
|
116
|
+
unresolved_requires = (bench.external_requires + conventions_environ.requires + bench.workspace.config.required).to_a.compact.uniq
|
|
117
|
+
recreate_docmap = @unresolved_requires != unresolved_requires ||
|
|
118
|
+
workspace.rbs_collection_path != bench.workspace.rbs_collection_path ||
|
|
119
|
+
@doc_map.any_uncached?
|
|
120
|
+
|
|
121
|
+
if recreate_docmap
|
|
122
|
+
@doc_map = DocMap.new(unresolved_requires, bench.workspace, out: nil) # @todo Implement gem preferences
|
|
123
|
+
@unresolved_requires = @doc_map.unresolved_requires
|
|
124
|
+
end
|
|
125
|
+
@cache.clear if store.update(@@core_map.pins, @doc_map.pins, conventions_environ.pins, iced_pins, live_pins)
|
|
126
|
+
@missing_docs = [] # @todo Implement missing docs
|
|
127
|
+
self
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @todo need to model type def statement in chains as a symbol so
|
|
131
|
+
# that this overload of 'protected' will typecheck @sg-ignore
|
|
132
|
+
# @sg-ignore
|
|
133
|
+
protected def equality_fields
|
|
134
|
+
[self.class, @source_map_hash, conventions_environ, @doc_map, @unresolved_requires, @missing_docs, @loose_unions]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# @return [DocMap]
|
|
138
|
+
def doc_map
|
|
139
|
+
@doc_map ||= DocMap.new([], Workspace.new('.'))
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @return [::Array<Gem::Specification>]
|
|
143
|
+
def uncached_gemspecs
|
|
144
|
+
doc_map.uncached_gemspecs || []
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @return [Enumerable<Pin::Base>]
|
|
148
|
+
def core_pins
|
|
149
|
+
@@core_map.pins
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# @param name [String, nil]
|
|
153
|
+
# @return [YARD::Tags::MacroDirective, nil]
|
|
154
|
+
def named_macro name
|
|
155
|
+
# @sg-ignore Need to add nil check here
|
|
156
|
+
store.named_macros[name]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @return [Set<String>]
|
|
160
|
+
def required
|
|
161
|
+
@required ||= Set.new
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @return [Environ]
|
|
165
|
+
def conventions_environ
|
|
166
|
+
@conventions_environ ||= Environ.new
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @param filename [String]
|
|
170
|
+
# @param position [Position, Array(Integer, Integer)]
|
|
171
|
+
# @return [Source::Cursor]
|
|
172
|
+
def cursor_at filename, position
|
|
173
|
+
position = Position.normalize(position)
|
|
174
|
+
raise FileNotFoundError, "File not found: #{filename}" unless source_map_hash.key?(filename)
|
|
175
|
+
source_map_hash[filename].cursor_at(position)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Get a clip by filename and position.
|
|
179
|
+
#
|
|
180
|
+
# @param filename [String]
|
|
181
|
+
# @param position [Position, Array(Integer, Integer)]
|
|
182
|
+
# @return [SourceMap::Clip]
|
|
183
|
+
def clip_at filename, position
|
|
184
|
+
position = Position.normalize(position)
|
|
185
|
+
clip(cursor_at(filename, position))
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Create an ApiMap with a workspace in the specified directory.
|
|
189
|
+
#
|
|
190
|
+
# @param directory [String]
|
|
191
|
+
# @param loose_unions [Boolean] See #initialize
|
|
192
|
+
#
|
|
193
|
+
# @return [ApiMap]
|
|
194
|
+
def self.load directory, loose_unions: true
|
|
195
|
+
api_map = new(loose_unions: loose_unions)
|
|
196
|
+
workspace = Solargraph::Workspace.new(directory)
|
|
197
|
+
# api_map.catalog Bench.new(workspace: workspace)
|
|
198
|
+
library = Library.new(workspace)
|
|
199
|
+
library.map!
|
|
200
|
+
api_map.catalog library.bench
|
|
201
|
+
api_map
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# @param out [StringIO, IO, nil]
|
|
205
|
+
# @param rebuild [Boolean] whether to rebuild the pins even if they are cached
|
|
206
|
+
# @return [void]
|
|
207
|
+
def cache_all_for_doc_map! out: $stderr, rebuild: false
|
|
208
|
+
doc_map.cache_doc_map_gems!(out, rebuild: rebuild)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @param gemspec [Gem::Specification]
|
|
212
|
+
# @param rebuild [Boolean]
|
|
213
|
+
# @param out [StringIO, IO, nil]
|
|
214
|
+
# @return [void]
|
|
215
|
+
def cache_gem(gemspec, rebuild: false, out: nil)
|
|
216
|
+
doc_map.cache(gemspec, rebuild: rebuild, out: out)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
class << self
|
|
220
|
+
include Logging
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Create an ApiMap with a workspace in the specified directory and cache
|
|
224
|
+
# any missing gems.
|
|
225
|
+
#
|
|
226
|
+
#
|
|
227
|
+
# @param directory [String]
|
|
228
|
+
# @param out [IO, StringIO, nil] The output stream for messages
|
|
229
|
+
# @param loose_unions [Boolean] See #initialize
|
|
230
|
+
#
|
|
231
|
+
# @return [ApiMap]
|
|
232
|
+
def self.load_with_cache directory, out = $stderr, loose_unions: true
|
|
233
|
+
api_map = load(directory, loose_unions: loose_unions)
|
|
234
|
+
if api_map.uncached_gemspecs.empty?
|
|
235
|
+
logger.info { "All gems cached for #{directory}" }
|
|
236
|
+
return api_map
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
api_map.cache_all_for_doc_map!(out: out)
|
|
240
|
+
load(directory, loose_unions: loose_unions)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
244
|
+
def pins
|
|
245
|
+
store.pins.clone.freeze
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# An array of pins based on Ruby keywords (`if`, `end`, etc.).
|
|
249
|
+
#
|
|
250
|
+
# @return [Enumerable<Solargraph::Pin::Keyword>]
|
|
251
|
+
def keyword_pins
|
|
252
|
+
store.pins_by_class(Pin::Keyword)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# True if the namespace exists.
|
|
256
|
+
#
|
|
257
|
+
# @param name [String] The namespace to match
|
|
258
|
+
# @param context [String] The context to search
|
|
259
|
+
# @return [Boolean]
|
|
260
|
+
def namespace_exists? name, context = ''
|
|
261
|
+
!qualify(name, context).nil?
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Get suggestions for constants in the specified namespace. The result
|
|
265
|
+
# may contain both constant and namespace pins.
|
|
266
|
+
#
|
|
267
|
+
# @param namespace [String] The namespace
|
|
268
|
+
# @param contexts [Array<String>] The contexts
|
|
269
|
+
# @return [Array<Solargraph::Pin::Constant, Solargraph::Pin::Namespace>]
|
|
270
|
+
def get_constants namespace, *contexts
|
|
271
|
+
namespace ||= ''
|
|
272
|
+
gates = contexts.clone
|
|
273
|
+
gates.push '' if contexts.empty? && namespace.empty?
|
|
274
|
+
gates.push namespace unless namespace.empty?
|
|
275
|
+
store.constants
|
|
276
|
+
.collect(gates)
|
|
277
|
+
.select { |pin| namespace.empty? || contexts.empty? || pin.namespace == namespace }
|
|
278
|
+
.select { |pin| pin.visibility == :public || pin.namespace == namespace }
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# @param namespace [String]
|
|
282
|
+
# @param context [String]
|
|
283
|
+
# @return [Array<Pin::Namespace>]
|
|
284
|
+
def get_namespace_pins namespace, context
|
|
285
|
+
store.fqns_pins(qualify(namespace, context))
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Determine fully qualified tag for a given tag used inside the
|
|
289
|
+
# definition of another tag ("context"). This method will start
|
|
290
|
+
# the search in the specified context until it finds a match for
|
|
291
|
+
# the tag.
|
|
292
|
+
#
|
|
293
|
+
# Does not recurse into qualifying the type parameters, but
|
|
294
|
+
# returns any which were passed in unchanged.
|
|
295
|
+
#
|
|
296
|
+
# @param tag [String, nil] The namespace to
|
|
297
|
+
# match, complete with generic parameters set to appropriate
|
|
298
|
+
# values if available
|
|
299
|
+
# @param gates [Array<String>] The fully qualified context in which
|
|
300
|
+
# the tag was referenced; start from here to resolve the name.
|
|
301
|
+
# Should not be prefixed with '::'.
|
|
302
|
+
# @return [String, nil] fully qualified tag
|
|
303
|
+
def qualify tag, *gates
|
|
304
|
+
store.constants.qualify(tag, *gates)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# @see Store::Constants#resolve
|
|
308
|
+
#
|
|
309
|
+
# @param name [String]
|
|
310
|
+
# @param gates [Array<String, Array<String>>]
|
|
311
|
+
# @return [String, nil]
|
|
312
|
+
def resolve name, *gates
|
|
313
|
+
store.constants.resolve(name, *gates)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Get a fully qualified namespace from a reference pin.
|
|
317
|
+
#
|
|
318
|
+
# @param pin [Pin::Reference]
|
|
319
|
+
# @return [String, nil]
|
|
320
|
+
def dereference(pin)
|
|
321
|
+
store.constants.dereference(pin)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# @param fqns [String]
|
|
325
|
+
# @return [Array<Pin::Reference::Extend>]
|
|
326
|
+
def get_extends(fqns)
|
|
327
|
+
store.get_extends(fqns)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# @param fqns [String]
|
|
331
|
+
# @return [Array<Pin::Reference::Include>]
|
|
332
|
+
def get_includes(fqns)
|
|
333
|
+
store.get_includes(fqns)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Get an array of instance variable pins defined in specified namespace
|
|
337
|
+
# and scope.
|
|
338
|
+
#
|
|
339
|
+
# @param namespace [String] A fully qualified namespace
|
|
340
|
+
# @param scope [Symbol] :instance or :class
|
|
341
|
+
# @return [Array<Solargraph::Pin::InstanceVariable>]
|
|
342
|
+
def get_instance_variable_pins namespace, scope = :instance
|
|
343
|
+
result = []
|
|
344
|
+
used = [namespace]
|
|
345
|
+
result.concat store.get_instance_variables(namespace, scope)
|
|
346
|
+
sc_fqns = namespace
|
|
347
|
+
while (sc = store.get_superclass(sc_fqns))
|
|
348
|
+
# @sg-ignore flow sensitive typing needs to handle "if foo = bar"
|
|
349
|
+
sc_fqns = store.constants.dereference(sc)
|
|
350
|
+
result.concat store.get_instance_variables(sc_fqns, scope)
|
|
351
|
+
end
|
|
352
|
+
result
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Find a variable pin by name and where it is used.
|
|
356
|
+
#
|
|
357
|
+
# Resolves our most specific view of this variable's type by
|
|
358
|
+
# preferring pins created by flow-sensitive typing when we have
|
|
359
|
+
# them based on the Closure and Location.
|
|
360
|
+
#
|
|
361
|
+
# @param candidates [Array<Pin::BaseVariable>]
|
|
362
|
+
# @param name [String]
|
|
363
|
+
# @param closure [Pin::Closure]
|
|
364
|
+
# @param location [Location]
|
|
365
|
+
#
|
|
366
|
+
# @return [Pin::BaseVariable, nil]
|
|
367
|
+
def var_at_location(candidates, name, closure, location)
|
|
368
|
+
with_correct_name = candidates.select { |pin| pin.name == name}
|
|
369
|
+
vars_at_location = with_correct_name.reject do |pin|
|
|
370
|
+
# visible_at? excludes the starting position, but we want to
|
|
371
|
+
# include it for this purpose
|
|
372
|
+
(!pin.visible_at?(closure, location) && !pin.starts_at?(location))
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
vars_at_location.inject(&:combine_with)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# Get an array of class variable pins for a namespace.
|
|
379
|
+
#
|
|
380
|
+
# @param namespace [String] A fully qualified namespace
|
|
381
|
+
# @return [Enumerable<Solargraph::Pin::ClassVariable>]
|
|
382
|
+
def get_class_variable_pins namespace
|
|
383
|
+
prefer_non_nil_variables(store.get_class_variables(namespace))
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# @return [Enumerable<Solargraph::Pin::Base>]
|
|
387
|
+
def get_symbols
|
|
388
|
+
store.get_symbols
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# @return [Enumerable<Solargraph::Pin::GlobalVariable>]
|
|
392
|
+
def get_global_variable_pins
|
|
393
|
+
store.pins_by_class(Pin::GlobalVariable)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# @return [Enumerable<Solargraph::Pin::Block>]
|
|
397
|
+
def get_block_pins
|
|
398
|
+
store.pins_by_class(Pin::Block)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# Get an array of methods available in a particular context.
|
|
402
|
+
#
|
|
403
|
+
# @param rooted_tag [String] The fully qualified namespace to search for methods
|
|
404
|
+
# @param scope [Symbol] :class or :instance
|
|
405
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
|
406
|
+
# @param deep [Boolean] True to include superclasses, mixins, etc.
|
|
407
|
+
# @return [Array<Solargraph::Pin::Method>]
|
|
408
|
+
def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
|
|
409
|
+
if rooted_tag.start_with? 'Array('
|
|
410
|
+
# Array() are really tuples - use our fill, as the RBS repo
|
|
411
|
+
# does not give us definitions for it
|
|
412
|
+
rooted_tag = "Solargraph::Fills::Tuple(#{rooted_tag[6..-2]})"
|
|
413
|
+
end
|
|
414
|
+
rooted_type = ComplexType.try_parse(rooted_tag)
|
|
415
|
+
fqns = rooted_type.namespace
|
|
416
|
+
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
|
417
|
+
cached = cache.get_methods(rooted_tag, scope, visibility, deep)
|
|
418
|
+
return cached.clone unless cached.nil?
|
|
419
|
+
# @type [Array<Solargraph::Pin::Method>]
|
|
420
|
+
result = []
|
|
421
|
+
skip = Set.new
|
|
422
|
+
if rooted_tag == ''
|
|
423
|
+
# @todo Implement domains
|
|
424
|
+
conventions_environ.domains.each do |domain|
|
|
425
|
+
type = ComplexType.try_parse(domain)
|
|
426
|
+
next if type.undefined?
|
|
427
|
+
result.concat inner_get_methods(type.name, type.scope, visibility, deep, skip)
|
|
428
|
+
end
|
|
429
|
+
result.concat inner_get_methods(rooted_tag, :class, visibility, deep, skip)
|
|
430
|
+
result.concat inner_get_methods(rooted_tag, :instance, visibility, deep, skip)
|
|
431
|
+
result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
|
|
432
|
+
else
|
|
433
|
+
result.concat inner_get_methods(rooted_tag, scope, visibility, deep, skip)
|
|
434
|
+
unless %w[Class Class<Class>].include?(rooted_tag)
|
|
435
|
+
result.map! do |pin|
|
|
436
|
+
next pin unless pin.path == 'Class#new'
|
|
437
|
+
init_pin = get_method_stack(rooted_tag, 'initialize').first
|
|
438
|
+
next pin unless init_pin
|
|
439
|
+
|
|
440
|
+
type = ComplexType::SELF
|
|
441
|
+
new_pin = Pin::Method.new(
|
|
442
|
+
name: 'new',
|
|
443
|
+
scope: :class,
|
|
444
|
+
location: init_pin.location,
|
|
445
|
+
return_type: type,
|
|
446
|
+
comments: init_pin.comments,
|
|
447
|
+
closure: init_pin.closure,
|
|
448
|
+
source: init_pin.source,
|
|
449
|
+
type_location: init_pin.type_location,
|
|
450
|
+
)
|
|
451
|
+
new_pin.parameters = init_pin.parameters.map do |init_param|
|
|
452
|
+
param = init_param.clone
|
|
453
|
+
param.closure = new_pin
|
|
454
|
+
param.reset_generated!
|
|
455
|
+
param
|
|
456
|
+
end.freeze
|
|
457
|
+
new_pin.signatures = init_pin.signatures.map do |init_sig|
|
|
458
|
+
sig = init_sig.proxy(type)
|
|
459
|
+
sig.parameters = init_sig.parameters.map do |param|
|
|
460
|
+
param = param.clone
|
|
461
|
+
param.closure = new_pin
|
|
462
|
+
param.reset_generated!
|
|
463
|
+
param
|
|
464
|
+
end.freeze
|
|
465
|
+
sig.closure = new_pin
|
|
466
|
+
sig.reset_generated!
|
|
467
|
+
sig
|
|
468
|
+
end.freeze
|
|
469
|
+
new_pin
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
|
|
473
|
+
result.concat inner_get_methods('Module', scope, visibility, deep, skip) if scope == :module
|
|
474
|
+
end
|
|
475
|
+
result = resolve_method_aliases(result, visibility)
|
|
476
|
+
if namespace_pin && rooted_tag != rooted_type.name
|
|
477
|
+
result = result.map { |method_pin| method_pin.resolve_generics(namespace_pin, rooted_type) }
|
|
478
|
+
end
|
|
479
|
+
cache.set_methods(rooted_tag, scope, visibility, deep, result)
|
|
480
|
+
result
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Get an array of method pins for a complex type.
|
|
484
|
+
#
|
|
485
|
+
# The type's namespace and the context should be fully qualified. If the
|
|
486
|
+
# context matches the namespace type or is a subclass of the type,
|
|
487
|
+
# protected methods are included in the results. If protected methods are
|
|
488
|
+
# included and internal is true, private methods are also included.
|
|
489
|
+
#
|
|
490
|
+
# @example
|
|
491
|
+
# api_map = Solargraph::ApiMap.new
|
|
492
|
+
# type = Solargraph::ComplexType.parse('String')
|
|
493
|
+
# api_map.get_complex_type_methods(type)
|
|
494
|
+
#
|
|
495
|
+
# @param complex_type [Solargraph::ComplexType] The complex type of the namespace
|
|
496
|
+
# @param context [String] The context from which the type is referenced
|
|
497
|
+
# @param internal [Boolean] True to include private methods
|
|
498
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
499
|
+
def get_complex_type_methods complex_type, context = '', internal = false
|
|
500
|
+
# This method does not qualify the complex type's namespace because
|
|
501
|
+
# it can cause conflicts between similar names, e.g., `Foo` vs.
|
|
502
|
+
# `Other::Foo`. It still takes a context argument to determine whether
|
|
503
|
+
# protected and private methods are visible.
|
|
504
|
+
return [] if complex_type.undefined? || complex_type.void?
|
|
505
|
+
result = Set.new
|
|
506
|
+
complex_type.each do |type|
|
|
507
|
+
if type.duck_type?
|
|
508
|
+
result.add Pin::DuckMethod.new(name: type.to_s[1..-1], source: :api_map)
|
|
509
|
+
result.merge get_methods('Object')
|
|
510
|
+
else
|
|
511
|
+
unless type.nil? || type.name == 'void'
|
|
512
|
+
visibility = [:public]
|
|
513
|
+
if type.namespace == context || super_and_sub?(type.namespace, context)
|
|
514
|
+
visibility.push :protected
|
|
515
|
+
visibility.push :private if internal
|
|
516
|
+
end
|
|
517
|
+
result.merge get_methods(type.tag, scope: type.scope, visibility: visibility)
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
result.to_a
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# Get a stack of method pins for a method name in a potentially
|
|
525
|
+
# parameterized namespace. The order of the pins corresponds to
|
|
526
|
+
# the ancestry chain, with highest precedence first.
|
|
527
|
+
#
|
|
528
|
+
# @example
|
|
529
|
+
# api_map.get_method_stack('Subclass', 'method_name')
|
|
530
|
+
# #=> [ <Subclass#method_name pin>, <Superclass#method_name pin> ]
|
|
531
|
+
#
|
|
532
|
+
# @param rooted_tag [String] Parameterized namespace, fully qualified
|
|
533
|
+
# @param name [String] Method name to look up
|
|
534
|
+
# @param scope [Symbol] :instance or :class
|
|
535
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
|
536
|
+
# @param preserve_generics [Boolean] True to preserve any
|
|
537
|
+
# unresolved generic parameters, false to erase them
|
|
538
|
+
# @return [Array<Solargraph::Pin::Method>]
|
|
539
|
+
def get_method_stack rooted_tag, name, scope: :instance, visibility: [:private, :protected, :public], preserve_generics: false
|
|
540
|
+
rooted_type = ComplexType.parse(rooted_tag)
|
|
541
|
+
fqns = rooted_type.namespace
|
|
542
|
+
namespace_pin = store.get_path_pins(fqns).first
|
|
543
|
+
methods = if namespace_pin.is_a?(Pin::Constant)
|
|
544
|
+
type = namespace_pin.typify(self)
|
|
545
|
+
type = namespace_pin.probe(self) unless type.defined?
|
|
546
|
+
if type.defined?
|
|
547
|
+
namespace_pin = store.get_path_pins(type.namespace).first
|
|
548
|
+
get_methods(type.namespace, scope: scope, visibility: visibility).select { |p| p.name == name }
|
|
549
|
+
else
|
|
550
|
+
[]
|
|
551
|
+
end
|
|
552
|
+
else
|
|
553
|
+
get_methods(rooted_tag, scope: scope, visibility: visibility).select { |p| p.name == name }
|
|
554
|
+
end
|
|
555
|
+
methods = erase_generics(namespace_pin, rooted_type, methods) unless preserve_generics
|
|
556
|
+
methods
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
# Get an array of all suggestions that match the specified path.
|
|
560
|
+
#
|
|
561
|
+
# @deprecated Use #get_path_pins instead.
|
|
562
|
+
#
|
|
563
|
+
# @param path [String] The path to find
|
|
564
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
565
|
+
def get_path_suggestions path
|
|
566
|
+
return [] if path.nil?
|
|
567
|
+
resolve_method_aliases store.get_path_pins(path)
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
# Get an array of pins that match the specified path.
|
|
571
|
+
#
|
|
572
|
+
# @param path [String]
|
|
573
|
+
# @return [Array<Pin::Base>]
|
|
574
|
+
def get_path_pins path
|
|
575
|
+
get_path_suggestions(path)
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
# Get a list of documented paths that match the query.
|
|
579
|
+
#
|
|
580
|
+
# @example
|
|
581
|
+
# api_map.query('str') # Results will include `String` and `Struct`
|
|
582
|
+
#
|
|
583
|
+
# @param query [String] The text to match
|
|
584
|
+
# @return [Array<String>]
|
|
585
|
+
def search query
|
|
586
|
+
pins.map(&:path)
|
|
587
|
+
.compact
|
|
588
|
+
.select { |path| path.downcase.include?(query.downcase) }
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# @deprecated This method is likely superfluous. Calling #get_path_pins
|
|
592
|
+
# directly should be sufficient.
|
|
593
|
+
#
|
|
594
|
+
# @param path [String] The path to find
|
|
595
|
+
# @return [Enumerable<Pin::Base>]
|
|
596
|
+
def document path
|
|
597
|
+
get_path_pins(path)
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
# Get an array of all symbols in the workspace that match the query.
|
|
601
|
+
#
|
|
602
|
+
# @param query [String]
|
|
603
|
+
# @return [Array<Pin::Base>]
|
|
604
|
+
def query_symbols query
|
|
605
|
+
Pin::Search.new(
|
|
606
|
+
source_map_hash.values.flat_map(&:document_symbols),
|
|
607
|
+
query
|
|
608
|
+
).results
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
# @param location [Solargraph::Location]
|
|
612
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
613
|
+
def locate_pins location
|
|
614
|
+
return [] if location.nil? || !source_map_hash.key?(location.filename)
|
|
615
|
+
resolve_method_aliases source_map_hash[location.filename].locate_pins(location)
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
# @raise [FileNotFoundError] if the cursor's file is not in the ApiMap
|
|
619
|
+
# @param cursor [Source::Cursor]
|
|
620
|
+
# @return [SourceMap::Clip]
|
|
621
|
+
def clip cursor
|
|
622
|
+
# @sg-ignore Need to add nil check here
|
|
623
|
+
raise FileNotFoundError, "ApiMap did not catalog #{cursor.filename}" unless source_map_hash.key?(cursor.filename)
|
|
624
|
+
|
|
625
|
+
SourceMap::Clip.new(self, cursor)
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
# Get an array of document symbols from a file.
|
|
629
|
+
#
|
|
630
|
+
# @param filename [String]
|
|
631
|
+
# @return [Array<Pin::Symbol>]
|
|
632
|
+
def document_symbols filename
|
|
633
|
+
return [] unless source_map_hash.key?(filename) # @todo Raise error?
|
|
634
|
+
resolve_method_aliases source_map_hash[filename].document_symbols
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# @return [Array<SourceMap>]
|
|
638
|
+
def source_maps
|
|
639
|
+
source_map_hash.values
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
# Get a source map by filename.
|
|
643
|
+
#
|
|
644
|
+
# @param filename [String]
|
|
645
|
+
# @return [SourceMap]
|
|
646
|
+
def source_map filename
|
|
647
|
+
raise FileNotFoundError, "Source map for `#{filename}` not found" unless source_map_hash.key?(filename)
|
|
648
|
+
source_map_hash[filename]
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
# True if the specified file was included in a bundle, i.e., it's either
|
|
652
|
+
# included in a workspace or open in a library.
|
|
653
|
+
#
|
|
654
|
+
# @param filename [String]
|
|
655
|
+
def bundled? filename
|
|
656
|
+
source_map_hash.keys.include?(filename)
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
# Check if a class is a superclass of another class.
|
|
660
|
+
#
|
|
661
|
+
# @param sup [String] The superclass
|
|
662
|
+
# @param sub [String] The subclass
|
|
663
|
+
# @return [Boolean]
|
|
664
|
+
def super_and_sub?(sup, sub)
|
|
665
|
+
sup = ComplexType.try_parse(sup)
|
|
666
|
+
sub = ComplexType.try_parse(sub)
|
|
667
|
+
# @todo If two literals are different values of the same type, it would
|
|
668
|
+
# make more sense for super_and_sub? to return true, but there are a
|
|
669
|
+
# few callers that currently expect this to be false.
|
|
670
|
+
# @sg-ignore flow-sensitive typing should be able to handle redefinition
|
|
671
|
+
return false if sup.literal? && sub.literal? && sup.to_s != sub.to_s
|
|
672
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
673
|
+
sup = sup.simplify_literals.to_s
|
|
674
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
675
|
+
sub = sub.simplify_literals.to_s
|
|
676
|
+
return true if sup == sub
|
|
677
|
+
sc_fqns = sub
|
|
678
|
+
while (sc = store.get_superclass(sc_fqns))
|
|
679
|
+
# @sg-ignore flow sensitive typing needs to handle "if foo = bar"
|
|
680
|
+
sc_new = store.constants.dereference(sc)
|
|
681
|
+
# Cyclical inheritance is invalid
|
|
682
|
+
return false if sc_new == sc_fqns
|
|
683
|
+
sc_fqns = sc_new
|
|
684
|
+
return true if sc_fqns == sup
|
|
685
|
+
end
|
|
686
|
+
false
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
# Check if the host class includes the specified module, ignoring
|
|
690
|
+
# type parameters used.
|
|
691
|
+
#
|
|
692
|
+
# @param host_ns [String] The class namesapce (no type parameters)
|
|
693
|
+
# @param module_ns [String] The module namespace (no type parameters)
|
|
694
|
+
#
|
|
695
|
+
# @return [Boolean]
|
|
696
|
+
def type_include?(host_ns, module_ns)
|
|
697
|
+
store.get_includes(host_ns).map { |inc_tag| inc_tag.type.name }.include?(module_ns)
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
# @param pins [Enumerable<Pin::Base>]
|
|
701
|
+
# @param visibility [Enumerable<Symbol>]
|
|
702
|
+
# @return [Array<Pin::Base>]
|
|
703
|
+
def resolve_method_aliases pins, visibility = [:public, :private, :protected]
|
|
704
|
+
with_resolved_aliases = pins.map do |pin|
|
|
705
|
+
next pin unless pin.is_a?(Pin::MethodAlias)
|
|
706
|
+
resolved = resolve_method_alias(pin)
|
|
707
|
+
# @sg-ignore Need to add nil check here
|
|
708
|
+
next nil if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
|
|
709
|
+
resolved
|
|
710
|
+
end.compact
|
|
711
|
+
logger.debug do
|
|
712
|
+
"ApiMap#resolve_method_aliases(pins=#{pins.map(&:name)}, visibility=#{visibility}) => #{with_resolved_aliases.map(&:name)}"
|
|
713
|
+
end
|
|
714
|
+
GemPins.combine_method_pins_by_path(with_resolved_aliases)
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
# @return [Workspace]
|
|
718
|
+
def workspace
|
|
719
|
+
doc_map.workspace
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
# @param fq_reference_tag [String] A fully qualified whose method should be pulled in
|
|
723
|
+
# @param namespace_pin [Pin::Base] Namespace pin for the rooted_type
|
|
724
|
+
# parameter - used to pull generics information
|
|
725
|
+
# @param type [ComplexType] The type which is having its
|
|
726
|
+
# methods supplemented from fq_reference_tag
|
|
727
|
+
# @param scope [Symbol] :class or :instance
|
|
728
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
|
729
|
+
# @param deep [Boolean]
|
|
730
|
+
# @param skip [Set<String>]
|
|
731
|
+
# @param no_core [Boolean] Skip core classes if true
|
|
732
|
+
# @return [Array<Pin::Base>]
|
|
733
|
+
def inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core)
|
|
734
|
+
logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) starting" }
|
|
735
|
+
|
|
736
|
+
# Ensure the types returned by the methods in the referenced
|
|
737
|
+
# type are relative to the generic values passed in the
|
|
738
|
+
# reference. e.g., Foo<String> might include Enumerable<String>
|
|
739
|
+
#
|
|
740
|
+
# @todo perform the same translation in the other areas
|
|
741
|
+
# here after adding a spec and handling things correctly
|
|
742
|
+
# in ApiMap::Store and RbsMap::Conversions for each
|
|
743
|
+
resolved_reference_type = ComplexType.parse(fq_reference_tag).force_rooted.resolve_generics(namespace_pin, type)
|
|
744
|
+
# @todo Can inner_get_methods be cached? Lots of lookups of base types going on.
|
|
745
|
+
methods = inner_get_methods(resolved_reference_type.tag, scope, visibility, deep, skip, no_core)
|
|
746
|
+
if namespace_pin && !resolved_reference_type.all_params.empty?
|
|
747
|
+
reference_pin = store.get_path_pins(resolved_reference_type.name).select { |p| p.is_a?(Pin::Namespace) }.first
|
|
748
|
+
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolving generics with #{reference_pin.generics}, #{resolved_reference_type.rooted_tags}" }
|
|
749
|
+
methods = methods.map do |method_pin|
|
|
750
|
+
method_pin.resolve_generics(reference_pin, resolved_reference_type)
|
|
751
|
+
end
|
|
752
|
+
end
|
|
753
|
+
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolved_reference_type: #{resolved_reference_type} for type=#{type}: #{methods.map(&:name)}" }
|
|
754
|
+
methods
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
# @param fq_sub_tag [String]
|
|
758
|
+
# @return [String, nil]
|
|
759
|
+
def qualify_superclass fq_sub_tag
|
|
760
|
+
store.qualify_superclass fq_sub_tag
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
private
|
|
764
|
+
|
|
765
|
+
# A hash of source maps with filename keys.
|
|
766
|
+
#
|
|
767
|
+
# @return [Hash{String => SourceMap}]
|
|
768
|
+
attr_reader :source_map_hash
|
|
769
|
+
|
|
770
|
+
# @return [ApiMap::Store]
|
|
771
|
+
def store
|
|
772
|
+
@store ||= Store.new
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
# @return [Solargraph::ApiMap::Cache]
|
|
776
|
+
attr_reader :cache
|
|
777
|
+
|
|
778
|
+
# @param rooted_tag [String] A fully qualified namespace, with
|
|
779
|
+
# generic parameter values if applicable
|
|
780
|
+
# @param scope [Symbol] :class or :instance
|
|
781
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
|
782
|
+
# @param deep [Boolean]
|
|
783
|
+
# @param skip [Set<String>]
|
|
784
|
+
# @param no_core [Boolean] Skip core classes if true
|
|
785
|
+
# @return [Array<Pin::Base>]
|
|
786
|
+
def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
|
|
787
|
+
rooted_type = ComplexType.parse(rooted_tag).force_rooted
|
|
788
|
+
fqns = rooted_type.namespace
|
|
789
|
+
fqns_generic_params = rooted_type.all_params
|
|
790
|
+
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
|
791
|
+
return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module)$/
|
|
792
|
+
reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
|
|
793
|
+
return [] if skip.include?(reqstr)
|
|
794
|
+
skip.add reqstr
|
|
795
|
+
result = []
|
|
796
|
+
environ = Convention.for_object(self, rooted_tag, scope, visibility, deep, skip, no_core)
|
|
797
|
+
# ensure we start out with any immediate methods in this
|
|
798
|
+
# namespace so we roughly match the same ordering of get_methods
|
|
799
|
+
# and obey the 'deep' instruction
|
|
800
|
+
direct_convention_methods, convention_methods_by_reference = environ.pins.partition { |p| p.namespace == rooted_tag }
|
|
801
|
+
result.concat direct_convention_methods
|
|
802
|
+
|
|
803
|
+
if deep && scope == :instance
|
|
804
|
+
store.get_prepends(fqns).reverse.each do |im|
|
|
805
|
+
fqim = store.constants.dereference(im)
|
|
806
|
+
result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
|
|
807
|
+
end
|
|
808
|
+
end
|
|
809
|
+
# Store#get_methods doesn't know about full tags, just
|
|
810
|
+
# namespaces; resolving the generics in the method pins is this
|
|
811
|
+
# class' responsibility
|
|
812
|
+
methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
|
|
813
|
+
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}" }
|
|
814
|
+
result.concat methods
|
|
815
|
+
if deep
|
|
816
|
+
result.concat convention_methods_by_reference
|
|
817
|
+
|
|
818
|
+
if scope == :instance
|
|
819
|
+
store.get_includes(fqns).reverse.each do |ref|
|
|
820
|
+
in_tag = dereference(ref)
|
|
821
|
+
# @sg-ignore Need to add nil check here
|
|
822
|
+
result.concat inner_get_methods_from_reference(in_tag, namespace_pin, rooted_type, scope, visibility, deep, skip, true)
|
|
823
|
+
end
|
|
824
|
+
rooted_sc_tag = qualify_superclass(rooted_tag)
|
|
825
|
+
unless rooted_sc_tag.nil?
|
|
826
|
+
result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope,
|
|
827
|
+
visibility, true, skip, no_core)
|
|
828
|
+
end
|
|
829
|
+
else
|
|
830
|
+
logger.info { "ApiMap#inner_get_methods(#{fqns}, #{scope}, #{visibility}, #{deep}, #{skip}) - looking for get_extends() from #{fqns}" }
|
|
831
|
+
store.get_extends(fqns).reverse.each do |em|
|
|
832
|
+
fqem = dereference(em)
|
|
833
|
+
result.concat inner_get_methods(fqem, :instance, visibility, deep, skip, true) unless fqem.nil?
|
|
834
|
+
end
|
|
835
|
+
rooted_sc_tag = qualify_superclass(rooted_tag)
|
|
836
|
+
unless rooted_sc_tag.nil?
|
|
837
|
+
result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope,
|
|
838
|
+
visibility, true, skip, true)
|
|
839
|
+
end
|
|
840
|
+
unless no_core || fqns.empty?
|
|
841
|
+
type = get_namespace_type(fqns)
|
|
842
|
+
result.concat inner_get_methods('Class', :instance, visibility, deep, skip, no_core) if type == :class
|
|
843
|
+
result.concat inner_get_methods('Module', :instance, visibility, deep, skip, no_core)
|
|
844
|
+
end
|
|
845
|
+
end
|
|
846
|
+
store.domains(fqns).each do |d|
|
|
847
|
+
dt = ComplexType.try_parse(d)
|
|
848
|
+
result.concat inner_get_methods(dt.namespace, dt.scope, visibility, deep, skip)
|
|
849
|
+
end
|
|
850
|
+
end
|
|
851
|
+
result
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
# @return [Hash]
|
|
855
|
+
def path_macros
|
|
856
|
+
@path_macros ||= {}
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
# Get the namespace's type (Class or Module).
|
|
860
|
+
#
|
|
861
|
+
# @param fqns [String] A fully qualified namespace
|
|
862
|
+
# @return [Symbol, nil] :class, :module, or nil
|
|
863
|
+
def get_namespace_type fqns
|
|
864
|
+
return nil if fqns.nil?
|
|
865
|
+
# @type [Pin::Namespace, nil]
|
|
866
|
+
pin = store.get_path_pins(fqns).select{|p| p.is_a?(Pin::Namespace)}.first
|
|
867
|
+
return nil if pin.nil?
|
|
868
|
+
pin.type
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
# Sort an array of pins to put nil or undefined variables last.
|
|
872
|
+
#
|
|
873
|
+
# @param pins [Enumerable<Pin::BaseVariable>]
|
|
874
|
+
# @return [Enumerable<Pin::BaseVariable>]
|
|
875
|
+
def prefer_non_nil_variables pins
|
|
876
|
+
result = []
|
|
877
|
+
nil_pins = []
|
|
878
|
+
pins.each do |pin|
|
|
879
|
+
if pin.variable? && pin.nil_assignment?
|
|
880
|
+
nil_pins.push pin
|
|
881
|
+
else
|
|
882
|
+
result.push pin
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
result + nil_pins
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
include Logging
|
|
889
|
+
|
|
890
|
+
# @param alias_pin [Pin::MethodAlias]
|
|
891
|
+
# @return [Pin::Method, nil]
|
|
892
|
+
def resolve_method_alias(alias_pin)
|
|
893
|
+
ancestors = store.get_ancestors(alias_pin.full_context.reduce_class_type.tag)
|
|
894
|
+
# @type [Pin::Method, nil]
|
|
895
|
+
original = nil
|
|
896
|
+
|
|
897
|
+
# Search each ancestor for the original method
|
|
898
|
+
ancestors.each do |ancestor_fqns|
|
|
899
|
+
next if ancestor_fqns.nil?
|
|
900
|
+
ancestor_method_path = if alias_pin.original == 'new' && alias_pin.scope == :class
|
|
901
|
+
"#{ancestor_fqns}#initialize"
|
|
902
|
+
else
|
|
903
|
+
"#{ancestor_fqns}#{alias_pin.scope == :instance ? '#' : '.'}#{alias_pin.original}"
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
# Search for the original method in the ancestor
|
|
907
|
+
original = store.get_path_pins(ancestor_method_path).find do |candidate_pin|
|
|
908
|
+
next if candidate_pin == alias_pin
|
|
909
|
+
|
|
910
|
+
if candidate_pin.is_a?(Pin::MethodAlias)
|
|
911
|
+
# recursively resolve method aliases
|
|
912
|
+
resolved = resolve_method_alias(candidate_pin)
|
|
913
|
+
break resolved if resolved
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
candidate_pin.is_a?(Pin::Method)
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
break if original
|
|
920
|
+
end
|
|
921
|
+
if original.nil?
|
|
922
|
+
# :nocov:
|
|
923
|
+
Solargraph.assert_or_log(:alias_target_missing) { "Rejecting alias - target is missing while looking for #{alias_pin.full_context.tag} #{alias_pin.original} in #{alias_pin.scope} scope = #{alias_pin.inspect}" }
|
|
924
|
+
return nil
|
|
925
|
+
# :nocov:
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
# @sg-ignore ignore `received nil` for original
|
|
929
|
+
create_resolved_alias_pin(alias_pin, original)
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
# Fast path for creating resolved alias pins without individual method stack lookups
|
|
933
|
+
# @param alias_pin [Pin::MethodAlias] The alias pin to resolve
|
|
934
|
+
# @param original [Pin::Method] The original method pin that was already found
|
|
935
|
+
# @return [Pin::Method] The resolved method pin
|
|
936
|
+
def create_resolved_alias_pin(alias_pin, original)
|
|
937
|
+
# Build the resolved method pin directly (same logic as resolve_method_alias but without lookup)
|
|
938
|
+
args = {
|
|
939
|
+
location: alias_pin.location,
|
|
940
|
+
type_location: original.type_location,
|
|
941
|
+
closure: alias_pin.closure,
|
|
942
|
+
name: alias_pin.name,
|
|
943
|
+
comments: original.comments,
|
|
944
|
+
scope: original.scope,
|
|
945
|
+
visibility: original.visibility,
|
|
946
|
+
signatures: original.signatures.map(&:clone).freeze,
|
|
947
|
+
attribute: original.attribute?,
|
|
948
|
+
generics: original.generics.clone,
|
|
949
|
+
return_type: original.return_type,
|
|
950
|
+
source: :resolve_method_alias
|
|
951
|
+
}
|
|
952
|
+
resolved_pin = Pin::Method.new **args
|
|
953
|
+
|
|
954
|
+
# Clone signatures and parameters
|
|
955
|
+
resolved_pin.signatures.each do |sig|
|
|
956
|
+
sig.parameters = sig.parameters.map(&:clone).freeze
|
|
957
|
+
sig.source = :resolve_method_alias
|
|
958
|
+
sig.parameters.each do |param|
|
|
959
|
+
param.closure = resolved_pin
|
|
960
|
+
param.source = :resolve_method_alias
|
|
961
|
+
param.reset_generated!
|
|
962
|
+
end
|
|
963
|
+
sig.closure = resolved_pin
|
|
964
|
+
sig.reset_generated!
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
resolved_pin
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
# @param namespace_pin [Pin::Namespace]
|
|
971
|
+
# @param rooted_type [ComplexType]
|
|
972
|
+
# @param pins [Enumerable<Pin::Base>]
|
|
973
|
+
# @return [Array<Pin::Base>]
|
|
974
|
+
def erase_generics namespace_pin, rooted_type, pins
|
|
975
|
+
return pins unless should_erase_generics_when_done?(namespace_pin, rooted_type)
|
|
976
|
+
|
|
977
|
+
logger.debug("Erasing generics on namespace_pin=#{namespace_pin} / rooted_type=#{rooted_type}")
|
|
978
|
+
pins.map do |method_pin|
|
|
979
|
+
method_pin.erase_generics(namespace_pin.generics)
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
# @param namespace_pin [Pin::Namespace]
|
|
984
|
+
# @param rooted_type [ComplexType]
|
|
985
|
+
def should_erase_generics_when_done? namespace_pin, rooted_type
|
|
986
|
+
has_generics?(namespace_pin) && !can_resolve_generics?(namespace_pin, rooted_type)
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
# @param namespace_pin [Pin::Namespace, Pin::Constant]
|
|
990
|
+
def has_generics?(namespace_pin)
|
|
991
|
+
namespace_pin.is_a?(Pin::Namespace) && !namespace_pin.generics.empty?
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
# @param namespace_pin [Pin::Namespace]
|
|
995
|
+
# @param rooted_type [ComplexType]
|
|
996
|
+
def can_resolve_generics? namespace_pin, rooted_type
|
|
997
|
+
has_generics?(namespace_pin) && !rooted_type.all_params.empty?
|
|
998
|
+
end
|
|
999
|
+
end
|
|
1000
|
+
end
|