solargraph 0.57.0 → 0.58.3

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.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/linting.yml +4 -2
  4. data/.github/workflows/plugins.yml +63 -28
  5. data/.github/workflows/rspec.yml +19 -4
  6. data/.github/workflows/typecheck.yml +2 -2
  7. data/.gitignore +1 -0
  8. data/.rubocop.yml +1 -1
  9. data/.rubocop_todo.yml +90 -1438
  10. data/CHANGELOG.md +39 -0
  11. data/Rakefile +1 -1
  12. data/bin/solargraph +3 -0
  13. data/lib/solargraph/api_map/cache.rb +110 -110
  14. data/lib/solargraph/api_map/constants.rb +279 -218
  15. data/lib/solargraph/api_map/index.rb +193 -169
  16. data/lib/solargraph/api_map/source_to_yard.rb +97 -94
  17. data/lib/solargraph/api_map/store.rb +384 -374
  18. data/lib/solargraph/api_map.rb +945 -951
  19. data/lib/solargraph/bench.rb +45 -45
  20. data/lib/solargraph/complex_type/type_methods.rb +228 -223
  21. data/lib/solargraph/complex_type/unique_type.rb +482 -475
  22. data/lib/solargraph/complex_type.rb +444 -427
  23. data/lib/solargraph/convention/active_support_concern.rb +1 -1
  24. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  25. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -91
  26. data/lib/solargraph/convention/data_definition.rb +105 -105
  27. data/lib/solargraph/convention/gemfile.rb +15 -15
  28. data/lib/solargraph/convention/gemspec.rb +23 -23
  29. data/lib/solargraph/convention/rakefile.rb +17 -17
  30. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -61
  31. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -102
  32. data/lib/solargraph/convention/struct_definition.rb +164 -164
  33. data/lib/solargraph/convention.rb +78 -78
  34. data/lib/solargraph/converters/dd.rb +17 -17
  35. data/lib/solargraph/converters/dl.rb +15 -15
  36. data/lib/solargraph/converters/dt.rb +15 -15
  37. data/lib/solargraph/converters/misc.rb +1 -1
  38. data/lib/solargraph/diagnostics/require_not_found.rb +53 -53
  39. data/lib/solargraph/diagnostics/rubocop.rb +118 -118
  40. data/lib/solargraph/diagnostics/rubocop_helpers.rb +68 -66
  41. data/lib/solargraph/diagnostics/type_check.rb +55 -55
  42. data/lib/solargraph/diagnostics/update_errors.rb +41 -41
  43. data/lib/solargraph/doc_map.rb +439 -436
  44. data/lib/solargraph/environ.rb +1 -1
  45. data/lib/solargraph/equality.rb +34 -33
  46. data/lib/solargraph/gem_pins.rb +98 -94
  47. data/lib/solargraph/language_server/error_codes.rb +20 -20
  48. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  49. data/lib/solargraph/language_server/host/dispatch.rb +130 -130
  50. data/lib/solargraph/language_server/host/message_worker.rb +112 -112
  51. data/lib/solargraph/language_server/host/sources.rb +99 -99
  52. data/lib/solargraph/language_server/host.rb +878 -872
  53. data/lib/solargraph/language_server/message/base.rb +97 -97
  54. data/lib/solargraph/language_server/message/client/register_capability.rb +15 -15
  55. data/lib/solargraph/language_server/message/completion_item/resolve.rb +60 -60
  56. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +114 -114
  57. data/lib/solargraph/language_server/message/extended/document.rb +23 -23
  58. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  59. data/lib/solargraph/language_server/message/extended/download_core.rb +19 -19
  60. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  61. data/lib/solargraph/language_server/message/initialize.rb +191 -191
  62. data/lib/solargraph/language_server/message/text_document/completion.rb +56 -56
  63. data/lib/solargraph/language_server/message/text_document/definition.rb +40 -40
  64. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +16 -16
  65. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +26 -26
  66. data/lib/solargraph/language_server/message/text_document/formatting.rb +148 -145
  67. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  68. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +11 -11
  69. data/lib/solargraph/language_server/message/text_document/references.rb +16 -16
  70. data/lib/solargraph/language_server/message/text_document/rename.rb +19 -19
  71. data/lib/solargraph/language_server/message/text_document/signature_help.rb +24 -24
  72. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -25
  73. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +35 -35
  74. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +40 -40
  75. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +26 -26
  76. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -23
  77. data/lib/solargraph/language_server/message.rb +94 -94
  78. data/lib/solargraph/language_server/progress.rb +1 -1
  79. data/lib/solargraph/language_server/request.rb +27 -25
  80. data/lib/solargraph/language_server/transport/data_reader.rb +74 -74
  81. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  82. data/lib/solargraph/library.rb +683 -683
  83. data/lib/solargraph/location.rb +82 -81
  84. data/lib/solargraph/logging.rb +37 -37
  85. data/lib/solargraph/page.rb +92 -93
  86. data/lib/solargraph/parser/comment_ripper.rb +69 -69
  87. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -255
  88. data/lib/solargraph/parser/node_processor/base.rb +92 -92
  89. data/lib/solargraph/parser/node_processor.rb +62 -62
  90. data/lib/solargraph/parser/parser_gem/class_methods.rb +149 -159
  91. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  92. data/lib/solargraph/parser/parser_gem/node_chainer.rb +166 -166
  93. data/lib/solargraph/parser/parser_gem/node_methods.rb +486 -499
  94. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -21
  95. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +59 -59
  96. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +15 -15
  97. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
  98. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +53 -53
  99. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +37 -37
  100. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -23
  101. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +40 -40
  102. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +29 -29
  103. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +59 -59
  104. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -42
  105. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  106. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +38 -38
  107. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +52 -43
  108. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +291 -292
  109. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  110. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -29
  111. data/lib/solargraph/parser/parser_gem/node_processors.rb +70 -70
  112. data/lib/solargraph/parser/parser_gem.rb +12 -12
  113. data/lib/solargraph/parser/region.rb +69 -69
  114. data/lib/solargraph/parser/snippet.rb +17 -17
  115. data/lib/solargraph/parser.rb +23 -23
  116. data/lib/solargraph/pin/base.rb +729 -708
  117. data/lib/solargraph/pin/base_variable.rb +126 -124
  118. data/lib/solargraph/pin/block.rb +104 -103
  119. data/lib/solargraph/pin/breakable.rb +9 -9
  120. data/lib/solargraph/pin/callable.rb +231 -227
  121. data/lib/solargraph/pin/closure.rb +72 -76
  122. data/lib/solargraph/pin/common.rb +79 -79
  123. data/lib/solargraph/pin/constant.rb +45 -45
  124. data/lib/solargraph/pin/conversions.rb +123 -123
  125. data/lib/solargraph/pin/delegated_method.rb +120 -121
  126. data/lib/solargraph/pin/documenting.rb +114 -114
  127. data/lib/solargraph/pin/instance_variable.rb +34 -34
  128. data/lib/solargraph/pin/keyword.rb +20 -20
  129. data/lib/solargraph/pin/local_variable.rb +75 -79
  130. data/lib/solargraph/pin/method.rb +672 -656
  131. data/lib/solargraph/pin/method_alias.rb +34 -34
  132. data/lib/solargraph/pin/namespace.rb +115 -115
  133. data/lib/solargraph/pin/parameter.rb +275 -271
  134. data/lib/solargraph/pin/proxy_type.rb +39 -36
  135. data/lib/solargraph/pin/reference/override.rb +47 -47
  136. data/lib/solargraph/pin/reference/superclass.rb +15 -15
  137. data/lib/solargraph/pin/reference.rb +39 -48
  138. data/lib/solargraph/pin/search.rb +61 -58
  139. data/lib/solargraph/pin/signature.rb +61 -61
  140. data/lib/solargraph/pin/symbol.rb +53 -53
  141. data/lib/solargraph/pin/until.rb +18 -18
  142. data/lib/solargraph/pin/while.rb +18 -18
  143. data/lib/solargraph/pin.rb +44 -44
  144. data/lib/solargraph/pin_cache.rb +245 -245
  145. data/lib/solargraph/position.rb +132 -118
  146. data/lib/solargraph/range.rb +112 -108
  147. data/lib/solargraph/rbs_map/conversions.rb +823 -802
  148. data/lib/solargraph/rbs_map/core_fills.rb +84 -66
  149. data/lib/solargraph/rbs_map/core_map.rb +58 -54
  150. data/lib/solargraph/rbs_map/stdlib_map.rb +43 -43
  151. data/lib/solargraph/rbs_map.rb +163 -163
  152. data/lib/solargraph/server_methods.rb +16 -16
  153. data/lib/solargraph/shell.rb +363 -271
  154. data/lib/solargraph/source/chain/array.rb +37 -37
  155. data/lib/solargraph/source/chain/call.rb +337 -333
  156. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  157. data/lib/solargraph/source/chain/constant.rb +26 -89
  158. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  159. data/lib/solargraph/source/chain/hash.rb +34 -34
  160. data/lib/solargraph/source/chain/if.rb +28 -28
  161. data/lib/solargraph/source/chain/instance_variable.rb +13 -13
  162. data/lib/solargraph/source/chain/link.rb +109 -109
  163. data/lib/solargraph/source/chain/literal.rb +48 -48
  164. data/lib/solargraph/source/chain/or.rb +23 -23
  165. data/lib/solargraph/source/chain/q_call.rb +11 -11
  166. data/lib/solargraph/source/chain/variable.rb +13 -13
  167. data/lib/solargraph/source/chain/z_super.rb +30 -30
  168. data/lib/solargraph/source/chain.rb +291 -289
  169. data/lib/solargraph/source/change.rb +82 -82
  170. data/lib/solargraph/source/cursor.rb +166 -166
  171. data/lib/solargraph/source/encoding_fixes.rb +23 -23
  172. data/lib/solargraph/source/source_chainer.rb +194 -194
  173. data/lib/solargraph/source/updater.rb +55 -55
  174. data/lib/solargraph/source.rb +498 -498
  175. data/lib/solargraph/source_map/clip.rb +226 -234
  176. data/lib/solargraph/source_map/data.rb +34 -34
  177. data/lib/solargraph/source_map/mapper.rb +259 -261
  178. data/lib/solargraph/source_map.rb +212 -207
  179. data/lib/solargraph/type_checker/checks.rb +124 -124
  180. data/lib/solargraph/type_checker/param_def.rb +37 -37
  181. data/lib/solargraph/type_checker/problem.rb +32 -32
  182. data/lib/solargraph/type_checker/rules.rb +84 -70
  183. data/lib/solargraph/type_checker.rb +814 -752
  184. data/lib/solargraph/version.rb +5 -5
  185. data/lib/solargraph/workspace/config.rb +255 -237
  186. data/lib/solargraph/workspace/require_paths.rb +97 -98
  187. data/lib/solargraph/workspace.rb +220 -225
  188. data/lib/solargraph/yard_map/helpers.rb +44 -44
  189. data/lib/solargraph/yard_map/mapper/to_method.rb +130 -129
  190. data/lib/solargraph/yard_map/mapper/to_namespace.rb +31 -30
  191. data/lib/solargraph/yard_map/mapper.rb +79 -79
  192. data/lib/solargraph/yard_map/to_method.rb +89 -88
  193. data/lib/solargraph/yard_tags.rb +20 -20
  194. data/lib/solargraph/yardoc.rb +87 -64
  195. data/lib/solargraph.rb +105 -105
  196. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  197. data/rbs/fills/open3/0/open3.rbs +172 -0
  198. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  199. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  200. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  201. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  202. data/rbs/shims/ast/0/node.rbs +5 -0
  203. data/rbs/shims/ast/2.4/.rbs_meta.yaml +9 -0
  204. data/rbs/shims/ast/2.4/ast.rbs +73 -0
  205. data/rbs/shims/parser/3.2.0.1/manifest.yaml +7 -0
  206. data/rbs/shims/parser/3.2.0.1/parser.rbs +201 -0
  207. data/rbs/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  208. data/rbs_collection.yaml +4 -4
  209. data/solargraph.gemspec +15 -4
  210. metadata +71 -16
  211. data/lib/solargraph/parser/node_methods.rb +0 -97
  212. /data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +0 -0
  213. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  214. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  215. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  216. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,218 +1,279 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class ApiMap
5
- # Methods for handling constants.
6
- #
7
- class Constants
8
- # @param store [Store]
9
- def initialize store
10
- @store = store
11
- end
12
-
13
- # Resolve a name to a fully qualified namespace or constant.
14
- #
15
- # @param name [String]
16
- # @param gates [Array<Array<String>, String>]
17
- # @return [String, nil]
18
- def resolve(name, *gates)
19
- return store.get_path_pins(name[2..]).first&.path if name.start_with?('::')
20
-
21
- flat = gates.flatten
22
- flat.push '' if flat.empty?
23
- cached_resolve[[name, flat]] || resolve_and_cache(name, flat)
24
- end
25
-
26
- # Get a fully qualified namespace from a reference pin.
27
- #
28
- # @param pin [Pin::Reference]
29
- # @return [String, nil]
30
- def dereference pin
31
- resolve(pin.name, pin.reference_gates)
32
- end
33
-
34
- # Collect a list of all constants defined in the specified gates.
35
- #
36
- # @param gates [Array<Array<String>, String>]
37
- # @return [Array<Pin::Base>]
38
- def collect(*gates)
39
- flat = gates.flatten
40
- cached_collect[flat] || collect_and_cache(flat)
41
- end
42
-
43
- # Determine fully qualified tag for a given tag used inside the
44
- # definition of another tag ("context"). This method will start
45
- # the search in the specified context until it finds a match for
46
- # the tag.
47
- #
48
- # Does not recurse into qualifying the type parameters, but
49
- # returns any which were passed in unchanged.
50
- #
51
- # @param tag [String, nil] The namespace to
52
- # match, complete with generic parameters set to appropriate
53
- # values if available
54
- # @param context_tag [String] The fully qualified context in which
55
- # the tag was referenced; start from here to resolve the name.
56
- # Should not be prefixed with '::'.
57
- # @return [String, nil] fully qualified tag
58
- def qualify tag, context_tag = ''
59
- return tag if ['Boolean', 'self', nil].include?(tag)
60
-
61
- type = ComplexType.try_parse(tag)
62
- return unless type.defined?
63
- return tag if type.literal?
64
-
65
- context_type = ComplexType.try_parse(context_tag)
66
- return unless context_type.defined?
67
-
68
- fqns = qualify_namespace(type.rooted_namespace, context_type.rooted_namespace)
69
- return unless fqns
70
-
71
- fqns + type.substring
72
- end
73
-
74
- # @return [void]
75
- def clear
76
- [cached_collect, cached_resolve].each(&:clear)
77
- end
78
-
79
- private
80
-
81
- # @return [Store]
82
- attr_reader :store
83
-
84
- # @param name [String]
85
- # @param gates [Array<String>]
86
- # @return [String, nil]
87
- def resolve_and_cache name, gates
88
- cached_resolve[[name, gates]] = resolve_uncached(name, gates)
89
- end
90
-
91
- # @param name [String]
92
- # @param gates [Array<String>]
93
- # @return [String, nil]
94
- def resolve_uncached name, gates
95
- parts = name.split('::')
96
- here = parts.shift
97
- resolved = simple_resolve(here, gates)
98
- return resolved if parts.empty? || resolved.nil?
99
-
100
- final = "#{resolved}::#{parts.join('::')}".sub(/^::/, '')
101
- final if store.namespace_exists?(final)
102
- end
103
-
104
- # @param name [String]
105
- # @param gates [Array<String>]
106
- # @return [String, nil]
107
- def simple_resolve name, gates
108
- gates.each do |gate|
109
- here = "#{gate}::#{name}".sub(/^::/, '').sub(/::$/, '')
110
- return here if store.namespace_exists?(here)
111
- end
112
- nil
113
- end
114
-
115
- # @param gates [Array<String>]
116
- # @return [Array<Pin::Base>]
117
- def collect_and_cache gates
118
- skip = Set.new
119
- cached_collect[gates] = gates.flat_map do |gate|
120
- inner_get_constants(gate, %i[public private], skip)
121
- end
122
- end
123
-
124
- # @return [Hash{Array(Name, Array<String>) => String, nil}]
125
- def cached_resolve
126
- @cached_resolve ||= {}
127
- end
128
-
129
- # @return [Hash{Array<String> => Array<Pin::Base>}]
130
- def cached_collect
131
- @cached_collect ||= {}
132
- end
133
-
134
- # Determine fully qualified namespace for a given namespace used
135
- # inside the definition of another tag ("context"). This method
136
- # will start the search in the specified context until it finds a
137
- # match for the namespace.
138
- #
139
- # @param namespace [String, nil] The namespace to
140
- # match
141
- # @param context_namespace [String] The context namespace in which the
142
- # tag was referenced; start from here to resolve the name
143
- # @return [String, nil] fully qualified namespace
144
- def qualify_namespace namespace, context_namespace = ''
145
- if namespace.start_with?('::')
146
- inner_qualify(namespace[2..], '', Set.new)
147
- else
148
- inner_qualify(namespace, context_namespace, Set.new)
149
- end
150
- end
151
-
152
- # @param name [String] Namespace to fully qualify
153
- # @param root [String] The context to search
154
- # @param skip [Set<String>] Contexts already searched
155
- # @return [String, nil] Fully qualified ("rooted") namespace
156
- def inner_qualify name, root, skip
157
- return name if name == ComplexType::GENERIC_TAG_NAME
158
- return nil if name.nil?
159
- return nil if skip.include?(root)
160
- skip.add root
161
- possibles = []
162
- if name == ''
163
- return '' if root == ''
164
-
165
- inner_qualify(root, '', skip)
166
- else
167
- return name if root == '' && store.namespace_exists?(name)
168
- roots = root.to_s.split('::')
169
- while roots.length.positive?
170
- fqns = "#{roots.join('::')}::#{name}"
171
- return fqns if store.namespace_exists?(fqns)
172
- incs = store.get_includes(roots.join('::'))
173
- incs.each do |inc|
174
- foundinc = inner_qualify(name, inc.parametrized_tag.to_s, skip)
175
- possibles.push foundinc unless foundinc.nil?
176
- end
177
- roots.pop
178
- end
179
- if possibles.empty?
180
- incs = store.get_includes('')
181
- incs.each do |inc|
182
- foundinc = inner_qualify(name, inc.parametrized_tag.to_s, skip)
183
- possibles.push foundinc unless foundinc.nil?
184
- end
185
- end
186
- return name if store.namespace_exists?(name)
187
- possibles.last
188
- end
189
- end
190
-
191
- # @param fqns [String]
192
- # @param visibility [Array<Symbol>]
193
- # @param skip [Set<String>]
194
- # @return [Array<Pin::Base>]
195
- def inner_get_constants fqns, visibility, skip
196
- return [] if fqns.nil? || skip.include?(fqns)
197
- skip.add fqns
198
- result = []
199
-
200
- store.get_prepends(fqns).each do |pre|
201
- pre_fqns = resolve(pre.name, pre.closure.gates - skip.to_a)
202
- result.concat inner_get_constants(pre_fqns, [:public], skip)
203
- end
204
- result.concat(store.get_constants(fqns, visibility).sort { |a, b| a.name <=> b.name })
205
- store.get_includes(fqns).each do |pin|
206
- inc_fqns = resolve(pin.name, pin.closure.gates - skip.to_a)
207
- result.concat inner_get_constants(inc_fqns, [:public], skip)
208
- end
209
- sc_ref = store.get_superclass(fqns)
210
- if sc_ref
211
- fqsc = dereference(sc_ref)
212
- result.concat inner_get_constants(fqsc, [:public], skip) unless %w[Object BasicObject].include?(fqsc)
213
- end
214
- result
215
- end
216
- end
217
- end
218
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class ApiMap
5
+ # Methods for handling constants.
6
+ #
7
+ class Constants
8
+ # @param store [Store]
9
+ def initialize store
10
+ @store = store
11
+ end
12
+
13
+ # Resolve a name to a fully qualified namespace or constant.
14
+ #
15
+ # `Constants#resolve` finds fully qualified (absolute)
16
+ # namespaces based on relative names and the open gates
17
+ # (namespaces) provided. Names must be runtime-visible (erased)
18
+ # non-literal types, non-duck, non-signature types - e.g.,
19
+ # TrueClass, NilClass, Integer and Hash instead of true, nil,
20
+ # 96, or Hash{String => Symbol}
21
+ #
22
+ # Note: You may want to be using #qualify. Notably, #resolve:
23
+ # - does not handle anything with type parameters
24
+ # - will not gracefully handle nil, self and Boolean
25
+ # - will return a constant name instead of following its assignment
26
+ #
27
+ # @param name [String] Namespace which may relative and not be rooted.
28
+ # @param gates [Array<Array<String>, String>] Namespaces to search while resolving the name
29
+ #
30
+ # @return [String, nil] fully qualified namespace (i.e., is
31
+ # absolute, but will not start with ::)
32
+ def resolve(name, *gates)
33
+ return store.get_path_pins(name[2..]).first&.path if name.start_with?('::')
34
+
35
+ flat = gates.flatten
36
+ flat.push '' if flat.empty?
37
+ if cached_resolve.include? [name, flat]
38
+ cached_result = cached_resolve[[name, flat]]
39
+ # don't recurse
40
+ return nil if cached_result == :in_process
41
+ return cached_result
42
+ end
43
+ resolve_and_cache(name, flat)
44
+ end
45
+
46
+ # Get a fully qualified namespace from a reference pin.
47
+ #
48
+ # @param pin [Pin::Reference]
49
+ # @return [String, nil]
50
+ def dereference pin
51
+ qualify_type(pin.type, *pin.reference_gates)&.tag
52
+ end
53
+
54
+ # Collect a list of all constants defined in the specified gates.
55
+ #
56
+ # @param gates [Array<Array<String>, String>]
57
+ # @return [Array<Solargraph::Pin::Namespace, Solargraph::Pin::Constant>]
58
+ def collect(*gates)
59
+ flat = gates.flatten
60
+ cached_collect[flat] || collect_and_cache(flat)
61
+ end
62
+
63
+ # Determine a fully qualified namespace for a given tag
64
+ # referenced from the specified open gates. This method will
65
+ # search in each gate until it finds a match for the name.
66
+ #
67
+ # @param tag [String, nil] The type to match
68
+ # @param gates [Array<String>]
69
+ # @return [String, nil] fully qualified tag
70
+ def qualify tag, *gates
71
+ type = ComplexType.try_parse(tag)
72
+ qualify_type(type, *gates)&.tag
73
+ end
74
+
75
+ # @param type [ComplexType, nil] The type to match
76
+ # @param gates [Array<String>]
77
+ #
78
+ # @return [ComplexType, nil] A new rooted ComplexType
79
+ def qualify_type type, *gates
80
+ return nil if type.nil?
81
+ return type if type.selfy? || type.literal? || type.tag == 'nil' || type.interface? ||
82
+ type.tag == 'Boolean'
83
+
84
+ gates.push '' unless gates.include?('')
85
+ fqns = resolve(type.rooted_namespace, *gates)
86
+ return unless fqns
87
+ pin = store.get_path_pins(fqns).first
88
+ if pin.is_a?(Pin::Constant)
89
+ const = Solargraph::Parser::NodeMethods.unpack_name(pin.assignment)
90
+ return unless const
91
+ fqns = resolve(const, *pin.gates)
92
+ end
93
+ type.recreate(new_name: fqns, make_rooted: true)
94
+ end
95
+
96
+ # @return [void]
97
+ def clear
98
+ [cached_collect, cached_resolve].each(&:clear)
99
+ end
100
+
101
+ private
102
+
103
+ # @return [Store]
104
+ attr_reader :store
105
+
106
+ # @param name [String]
107
+ # @param gates [Array<String>]
108
+ # @return [String, nil]
109
+ def resolve_and_cache name, gates
110
+ cached_resolve[[name, gates]] = :in_process
111
+ cached_resolve[[name, gates]] = resolve_uncached(name, gates)
112
+ end
113
+
114
+ # @param name [String]
115
+ # @param gates [Array<String>]
116
+ # @return [String, nil]
117
+ def resolve_uncached name, gates
118
+ resolved = nil
119
+ base = gates
120
+ parts = name.split('::')
121
+ first = nil
122
+ parts.each.with_index do |nam, idx|
123
+ resolved, remainder = complex_resolve(nam, base, idx != parts.length - 1)
124
+ first ||= remainder
125
+ if resolved
126
+ base = [resolved]
127
+ else
128
+ return resolve(name, first) unless first.empty?
129
+ end
130
+ end
131
+ resolved
132
+ end
133
+
134
+ # @todo I'm not sure of a better way to express the return value in YARD.
135
+ # It's a tuple where the first element is a nullable string. Something
136
+ # like `Array(String|nil, Array<String>)` would be more accurate.
137
+ #
138
+ # @param name [String]
139
+ # @param gates [Array<String>]
140
+ # @param internal [Boolean] True if the name is not the last in the namespace
141
+ # @return [Array(Object, Array<String>)]
142
+ def complex_resolve name, gates, internal
143
+ resolved = nil
144
+ gates.each.with_index do |gate, idx|
145
+ resolved = simple_resolve(name, gate, internal)
146
+ return [resolved, gates[(idx + 1)..]] if resolved
147
+ store.get_ancestor_references(gate).each do |ref|
148
+ return ref.name.sub(/^::/, '') if ref.name.end_with?("::#{name}") && ref.name.start_with?('::')
149
+
150
+ mixin = resolve(ref.name, ref.reference_gates)
151
+ next unless mixin
152
+
153
+ resolved = simple_resolve(name, mixin, internal)
154
+ return [resolved, gates[(idx + 1)..]] if resolved
155
+ end
156
+ end
157
+ [nil, []]
158
+ end
159
+
160
+ # @param name [String]
161
+ # @param gate [String]
162
+ # @param internal [Boolean] True if the name is not the last in the namespace
163
+ # @return [String, nil]
164
+ def simple_resolve name, gate, internal
165
+ here = "#{gate}::#{name}".sub(/^::/, '').sub(/::$/, '')
166
+ pin = store.get_path_pins(here).first
167
+ if pin.is_a?(Pin::Constant) && internal
168
+ const = Solargraph::Parser::NodeMethods.unpack_name(pin.assignment)
169
+ return unless const
170
+ resolve(const, pin.gates)
171
+ else
172
+ pin&.path
173
+ end
174
+ end
175
+
176
+ # @param gates [Array<String>]
177
+ # @return [Array<Solargraph::Pin::Namespace, Solargraph::Pin::Constant>]
178
+ def collect_and_cache gates
179
+ skip = Set.new
180
+ cached_collect[gates] = gates.flat_map do |gate|
181
+ inner_get_constants(gate, %i[public private], skip)
182
+ end
183
+ end
184
+
185
+ # @return [Hash{Array(String, Array<String>) => String, :in_process, nil}]
186
+ def cached_resolve
187
+ @cached_resolve ||= {}
188
+ end
189
+
190
+ # @return [Hash{Array<String> => Array<Solargraph::Pin::Namespace, Solargraph::Pin::Constant>}]
191
+ def cached_collect
192
+ @cached_collect ||= {}
193
+ end
194
+
195
+ # Determine fully qualified namespace for a given namespace used
196
+ # inside the definition of another tag ("context"). This method
197
+ # will start the search in the specified context until it finds a
198
+ # match for the namespace.
199
+ #
200
+ # @param namespace [String, nil] The namespace to
201
+ # match
202
+ # @param context_namespace [String] The context namespace in which the
203
+ # tag was referenced; start from here to resolve the name
204
+ # @return [String, nil] fully qualified namespace
205
+ def qualify_namespace namespace, context_namespace = ''
206
+ if namespace.start_with?('::')
207
+ inner_qualify(namespace[2..], '', Set.new)
208
+ else
209
+ inner_qualify(namespace, context_namespace, Set.new)
210
+ end
211
+ end
212
+
213
+ # @param name [String] Namespace to fully qualify
214
+ # @param root [String] The context to search
215
+ # @param skip [Set<String>] Contexts already searched
216
+ # @return [String, nil] Fully qualified ("rooted") namespace
217
+ def inner_qualify name, root, skip
218
+ return name if name == ComplexType::GENERIC_TAG_NAME
219
+ return nil if name.nil?
220
+ return nil if skip.include?(root)
221
+ skip.add root
222
+ possibles = []
223
+ if name == ''
224
+ return '' if root == ''
225
+
226
+ inner_qualify(root, '', skip)
227
+ else
228
+ return name if root == '' && store.namespace_exists?(name)
229
+ roots = root.to_s.split('::')
230
+ while roots.length.positive?
231
+ fqns = "#{roots.join('::')}::#{name}"
232
+ return fqns if store.namespace_exists?(fqns)
233
+ incs = store.get_includes(roots.join('::'))
234
+ incs.each do |inc|
235
+ foundinc = inner_qualify(name, inc.type.to_s, skip)
236
+ possibles.push foundinc unless foundinc.nil?
237
+ end
238
+ roots.pop
239
+ end
240
+ if possibles.empty?
241
+ incs = store.get_includes('')
242
+ incs.each do |inc|
243
+ foundinc = inner_qualify(name, inc.type.to_s, skip)
244
+ possibles.push foundinc unless foundinc.nil?
245
+ end
246
+ end
247
+ return name if store.namespace_exists?(name)
248
+ possibles.last
249
+ end
250
+ end
251
+
252
+ # @param fqns [String]
253
+ # @param visibility [Array<Symbol>]
254
+ # @param skip [Set<String>]
255
+ # @return [Array<Solargraph::Pin::Namespace, Solargraph::Pin::Constant>]
256
+ def inner_get_constants fqns, visibility, skip
257
+ return [] if fqns.nil? || skip.include?(fqns)
258
+ skip.add fqns
259
+ result = []
260
+
261
+ store.get_prepends(fqns).each do |pre|
262
+ pre_fqns = resolve(pre.name, pre.closure.gates - skip.to_a)
263
+ result.concat inner_get_constants(pre_fqns, [:public], skip)
264
+ end
265
+ result.concat(store.get_constants(fqns, visibility).sort { |a, b| a.name <=> b.name })
266
+ store.get_includes(fqns).each do |pin|
267
+ inc_fqns = resolve(pin.name, pin.closure.gates - skip.to_a)
268
+ result.concat inner_get_constants(inc_fqns, [:public], skip)
269
+ end
270
+ sc_ref = store.get_superclass(fqns)
271
+ if sc_ref
272
+ fqsc = dereference(sc_ref)
273
+ result.concat inner_get_constants(fqsc, [:public], skip) unless %w[Object BasicObject].include?(fqsc)
274
+ end
275
+ result
276
+ end
277
+ end
278
+ end
279
+ end