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,802 +1,823 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rbs'
4
-
5
- module Solargraph
6
- class RbsMap
7
- # Functions for converting RBS declarations to Solargraph pins
8
- #
9
- class Conversions
10
- include Logging
11
-
12
- # A container for tracking the current context of the RBS conversion
13
- # process, e.g., what visibility is declared for methods in the current
14
- # scope
15
- #
16
- class Context
17
- attr_reader :visibility
18
-
19
- # @param visibility [Symbol]
20
- def initialize visibility = :public
21
- @visibility = visibility
22
- end
23
- end
24
-
25
- # @param loader [RBS::EnvironmentLoader]
26
- def initialize(loader:)
27
- @loader = loader
28
- @pins = []
29
- load_environment_to_pins(loader)
30
- end
31
-
32
- # @return [RBS::EnvironmentLoader]
33
- attr_reader :loader
34
-
35
- # @return [Array<Pin::Base>]
36
- attr_reader :pins
37
-
38
- private
39
-
40
- # @return [Hash{String => RBS::AST::Declarations::TypeAlias}]
41
- def type_aliases
42
- @type_aliases ||= {}
43
- end
44
-
45
- # @param loader [RBS::EnvironmentLoader]
46
- # @return [void]
47
- def load_environment_to_pins(loader)
48
- environment = RBS::Environment.from_loader(loader).resolve_type_names
49
- cursor = pins.length
50
- if environment.declarations.empty?
51
- Solargraph.logger.info "No RBS declarations found in environment for core_root #{loader.core_root.inspect}, libraries #{loader.libs} and directories #{loader.dirs}"
52
- return
53
- end
54
- environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
55
- end
56
-
57
- # @param decl [RBS::AST::Declarations::Base]
58
- # @param closure [Pin::Closure]
59
- # @return [void]
60
- def convert_decl_to_pin decl, closure
61
- case decl
62
- when RBS::AST::Declarations::Class
63
- class_decl_to_pin decl
64
- when RBS::AST::Declarations::Interface
65
- # STDERR.puts "Skipping interface #{decl.name.relative!}"
66
- interface_decl_to_pin decl, closure
67
- when RBS::AST::Declarations::TypeAlias
68
- type_aliases[decl.name.to_s] = decl
69
- when RBS::AST::Declarations::Module
70
- module_decl_to_pin decl
71
- when RBS::AST::Declarations::Constant
72
- constant_decl_to_pin decl
73
- when RBS::AST::Declarations::ClassAlias
74
- class_alias_decl_to_pin decl
75
- when RBS::AST::Declarations::ModuleAlias
76
- module_alias_decl_to_pin decl
77
- when RBS::AST::Declarations::Global
78
- global_decl_to_pin decl
79
- else
80
- Solargraph.logger.warn "Skipping declaration #{decl.class}"
81
- end
82
- end
83
-
84
- # @param decl [RBS::AST::Declarations::Module]
85
- # @param module_pin [Pin::Namespace]
86
- # @return [void]
87
- def convert_self_types_to_pins decl, module_pin
88
- decl.self_types.each { |self_type| context = convert_self_type_to_pins(self_type, module_pin) }
89
- end
90
-
91
- # @param decl [RBS::AST::Declarations::Module::Self]
92
- # @param closure [Pin::Namespace]
93
- # @return [void]
94
- def convert_self_type_to_pins decl, closure
95
- type = build_type(decl.name, decl.args)
96
- generic_values = type.all_params.map(&:to_s)
97
- include_pin = Solargraph::Pin::Reference::Include.new(
98
- name: decl.name.relative!.to_s,
99
- type_location: location_decl_to_pin_location(decl.location),
100
- generic_values: generic_values,
101
- closure: closure,
102
- source: :rbs
103
- )
104
- pins.push include_pin
105
- end
106
-
107
- # @param decl [RBS::AST::Declarations::Module,RBS::AST::Declarations::Class,RBS::AST::Declarations::Interface]
108
- # @param closure [Pin::Namespace]
109
- # @return [void]
110
- def convert_members_to_pins decl, closure
111
- context = Conversions::Context.new
112
- decl.members.each { |m| context = convert_member_to_pin(m, closure, context) }
113
- end
114
-
115
- # @param member [RBS::AST::Members::Base,RBS::AST::Declarations::Base]
116
- # @param closure [Pin::Namespace]
117
- # @param context [Context]
118
- # @return [Context]
119
- def convert_member_to_pin member, closure, context
120
- case member
121
- when RBS::AST::Members::MethodDefinition
122
- method_def_to_pin(member, closure, context)
123
- when RBS::AST::Members::AttrReader
124
- attr_reader_to_pin(member, closure, context)
125
- when RBS::AST::Members::AttrWriter
126
- attr_writer_to_pin(member, closure, context)
127
- when RBS::AST::Members::AttrAccessor
128
- attr_accessor_to_pin(member, closure, context)
129
- when RBS::AST::Members::Include
130
- include_to_pin(member, closure)
131
- when RBS::AST::Members::Prepend
132
- prepend_to_pin(member, closure)
133
- when RBS::AST::Members::Extend
134
- extend_to_pin(member, closure)
135
- when RBS::AST::Members::Alias
136
- alias_to_pin(member, closure)
137
- when RBS::AST::Members::ClassInstanceVariable
138
- civar_to_pin(member, closure)
139
- when RBS::AST::Members::ClassVariable
140
- cvar_to_pin(member, closure)
141
- when RBS::AST::Members::InstanceVariable
142
- ivar_to_pin(member, closure)
143
- when RBS::AST::Members::Public
144
- return Context.new(:public)
145
- when RBS::AST::Members::Private
146
- return Context.new(:private)
147
- when RBS::AST::Declarations::Base
148
- convert_decl_to_pin(member, closure)
149
- else
150
- Solargraph.logger.warn "Skipping member type #{member.class}"
151
- end
152
- context
153
- end
154
-
155
- # @param decl [RBS::AST::Declarations::Class]
156
- # @return [void]
157
- def class_decl_to_pin decl
158
- generics = decl.type_params.map(&:name).map(&:to_s)
159
- generic_defaults = {}
160
- decl.type_params.each do |param|
161
- if param.default_type
162
- tag = other_type_to_tag param.default_type
163
- generic_defaults[param.name.to_s] = ComplexType.parse(tag).force_rooted
164
- end
165
- end
166
- class_name = decl.name.relative!.to_s
167
- class_pin = Solargraph::Pin::Namespace.new(
168
- type: :class,
169
- name: class_name,
170
- closure: Solargraph::Pin::ROOT_PIN,
171
- comments: decl.comment&.string,
172
- type_location: location_decl_to_pin_location(decl.location),
173
- # @todo some type parameters in core/stdlib have default
174
- # values; Solargraph doesn't support that yet as so these
175
- # get treated as undefined if not specified
176
- generics: generics,
177
- generic_defaults: generic_defaults,
178
- source: :rbs
179
- )
180
- pins.push class_pin
181
- if decl.super_class
182
- type = build_type(decl.super_class.name, decl.super_class.args)
183
- generic_values = type.all_params.map(&:to_s)
184
- superclass_name = decl.super_class.name.to_s
185
- pins.push Solargraph::Pin::Reference::Superclass.new(
186
- type_location: location_decl_to_pin_location(decl.super_class.location),
187
- closure: class_pin,
188
- generic_values: generic_values,
189
- name: superclass_name,
190
- source: :rbs
191
- )
192
- end
193
- add_mixins decl, class_pin
194
- convert_members_to_pins decl, class_pin
195
- end
196
-
197
- # @param decl [RBS::AST::Declarations::Interface]
198
- # @param closure [Pin::Closure]
199
- # @return [void]
200
- def interface_decl_to_pin decl, closure
201
- class_pin = Solargraph::Pin::Namespace.new(
202
- type: :module,
203
- type_location: location_decl_to_pin_location(decl.location),
204
- name: decl.name.relative!.to_s,
205
- closure: Solargraph::Pin::ROOT_PIN,
206
- comments: decl.comment&.string,
207
- generics: decl.type_params.map(&:name).map(&:to_s),
208
- # HACK: Using :hidden to keep interfaces from appearing in
209
- # autocompletion
210
- visibility: :hidden,
211
- source: :rbs
212
- )
213
- class_pin.docstring.add_tag(YARD::Tags::Tag.new(:abstract, '(RBS interface)'))
214
- pins.push class_pin
215
- convert_members_to_pins decl, class_pin
216
- end
217
-
218
- # @param decl [RBS::AST::Declarations::Module]
219
- # @return [void]
220
- def module_decl_to_pin decl
221
- module_pin = Solargraph::Pin::Namespace.new(
222
- type: :module,
223
- name: decl.name.relative!.to_s,
224
- type_location: location_decl_to_pin_location(decl.location),
225
- closure: Solargraph::Pin::ROOT_PIN,
226
- comments: decl.comment&.string,
227
- generics: decl.type_params.map(&:name).map(&:to_s),
228
- source: :rbs
229
- )
230
- pins.push module_pin
231
- convert_self_types_to_pins decl, module_pin
232
- convert_members_to_pins decl, module_pin
233
-
234
- add_mixins decl, module_pin.closure
235
- end
236
-
237
- # @param name [String]
238
- # @param tag [String]
239
- # @param comments [String]
240
- # @param decl [RBS::AST::Declarations::ClassAlias, RBS::AST::Declarations::Constant, RBS::AST::Declarations::ModuleAlias]
241
- # @param base [String, nil] Optional conversion of tag to base<tag>
242
- #
243
- # @return [Solargraph::Pin::Constant]
244
- def create_constant(name, tag, comments, decl, base = nil)
245
- parts = name.split('::')
246
- if parts.length > 1
247
- name = parts.last
248
- closure = pins.select { |pin| pin && pin.path == parts[0..-2].join('::') }.first
249
- else
250
- name = parts.first
251
- closure = Solargraph::Pin::ROOT_PIN
252
- end
253
- constant_pin = Solargraph::Pin::Constant.new(
254
- name: name,
255
- closure: closure,
256
- type_location: location_decl_to_pin_location(decl.location),
257
- comments: comments,
258
- source: :rbs
259
- )
260
- tag = "#{base}<#{tag}>" if base
261
- rooted_tag = ComplexType.parse(tag).force_rooted.rooted_tags
262
- constant_pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
263
- constant_pin
264
- end
265
-
266
- # @param decl [RBS::AST::Declarations::ClassAlias]
267
- # @return [void]
268
- def class_alias_decl_to_pin decl
269
- # See https://www.rubydoc.info/gems/rbs/3.4.3/RBS/AST/Declarations/ClassAlias
270
- new_name = decl.new_name.relative!.to_s
271
- old_name = decl.old_name.relative!.to_s
272
-
273
- pins.push create_constant(new_name, old_name, decl.comment&.string, decl, 'Class')
274
- end
275
-
276
- # @param decl [RBS::AST::Declarations::ModuleAlias]
277
- # @return [void]
278
- def module_alias_decl_to_pin decl
279
- # See https://www.rubydoc.info/gems/rbs/3.4.3/RBS/AST/Declarations/ModuleAlias
280
- new_name = decl.new_name.relative!.to_s
281
- old_name = decl.old_name.relative!.to_s
282
-
283
- pins.push create_constant(new_name, old_name, decl.comment&.string, decl, 'Module')
284
- end
285
-
286
- # @param decl [RBS::AST::Declarations::Constant]
287
- # @return [void]
288
- def constant_decl_to_pin decl
289
- tag = other_type_to_tag(decl.type)
290
- pins.push create_constant(decl.name.relative!.to_s, tag, decl.comment&.string, decl)
291
- end
292
-
293
- # @param decl [RBS::AST::Declarations::Global]
294
- # @return [void]
295
- def global_decl_to_pin decl
296
- closure = Solargraph::Pin::ROOT_PIN
297
- name = decl.name.to_s
298
- pin = Solargraph::Pin::GlobalVariable.new(
299
- name: name,
300
- closure: closure,
301
- comments: decl.comment&.string,
302
- type_location: location_decl_to_pin_location(decl.location),
303
- source: :rbs
304
- )
305
- rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
306
- pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
307
- pins.push pin
308
- end
309
-
310
-
311
- # Visibility overrides that will allow the Solargraph project
312
- # and plugins to pass typechecking using SOLARGRAPH_ASSERTS=on,
313
- # so that we can detect any regressions/issues elsewhere in the
314
- # visibility logic.
315
- #
316
- # These should either reflect a bug upstream in the RBS
317
- # definitions, or include a @todo indicating what needs to be
318
- # fixed in Solargraph to properly understand it.
319
- #
320
- # @todo PR these fixes upstream and list open PRs here above
321
- # related overrides
322
- # @todo externalize remaining overrides into yaml file, then
323
- # allow that to be extended via .solargraph.yml
324
- # @type [Hash{Array(String, Symbol, String) => Symbol}
325
- VISIBILITY_OVERRIDE = {
326
- ["Rails::Engine", :instance, "run_tasks_blocks"] => :protected,
327
- # Should have been marked as both instance and class method in module -e.g., 'module_function'
328
- ["Kernel", :instance, "pretty_inspect"] => :private,
329
- # marked incorrectly in RBS
330
- ["WEBrick::HTTPUtils::FormData", :instance, "next_data"] => :protected,
331
- ["Rails::Command", :class, "command_type"] => :private,
332
- ["Rails::Command", :class, "lookup_paths"] => :private,
333
- ["Rails::Command", :class, "file_lookup_paths"] => :private,
334
- ["Rails::Railtie", :instance, "run_console_blocks"] => :protected,
335
- ["Rails::Railtie", :instance, "run_generators_blocks"] => :protected,
336
- ["Rails::Railtie", :instance, "run_runner_blocks"] => :protected,
337
- ["Rails::Railtie", :instance, "run_tasks_blocks"] => :protected,
338
- ["ActionController::Base", :instance, "_protected_ivars"] => :private,
339
- ["ActionView::Template", :instance, "method_name"] => :public,
340
- ["Module", :instance, "ruby2_keywords"] => :private,
341
- ["Nokogiri::XML::Node", :instance, "coerce"] => :protected,
342
- ["Nokogiri::XML::Document", :class, "empty_doc?"] => :private,
343
- ["Nokogiri::Decorators::Slop", :instance, "respond_to_missing?"] => :public,
344
- ["RuboCop::Cop::RangeHelp", :instance, "source_range"] => :private,
345
- ["AST::Node", :instance, "original_dup"] => :private,
346
- ["Rainbow::Presenter", :instance, "wrap_with_sgr"] => :private,
347
- }
348
-
349
- # @param decl [RBS::AST::Members::MethodDefinition, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrAccessor]
350
- # @param closure [Pin::Closure]
351
- # @param context [Context]
352
- # @param scope [Symbol] :instance or :class
353
- # @param name [String] The name of the method
354
- # @sg-ignore
355
- # @return [Symbol]
356
- def calculate_method_visibility(decl, context, closure, scope, name)
357
- override_key = [closure.path, scope, name]
358
- visibility = VISIBILITY_OVERRIDE[override_key]
359
- simple_override_key = [closure.path, scope]
360
- visibility ||= VISIBILITY_OVERRIDE[simple_override_key]
361
- visibility ||= :private if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(decl.name)
362
- if decl.kind == :singleton_instance
363
- # this is a 'module function'
364
- visibility ||= :private
365
- end
366
- visibility ||= decl.visibility
367
- visibility ||= context.visibility
368
- visibility ||= :public
369
- visibility
370
- end
371
-
372
- # @param decl [RBS::AST::Members::MethodDefinition]
373
- # @param closure [Pin::Closure]
374
- # @param context [Context]
375
- # @return [void]
376
- def method_def_to_pin decl, closure, context
377
- # there may be edge cases here around different signatures
378
- # having different type params / orders - we may need to match
379
- # this data model and have generics live in signatures to
380
- # handle those correctly
381
- generics = decl.overloads.map(&:method_type).flat_map(&:type_params).map(&:name).map(&:to_s).uniq
382
-
383
- if decl.instance?
384
- name = decl.name.to_s
385
- final_scope = :instance
386
- visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
387
- pin = Solargraph::Pin::Method.new(
388
- name: name,
389
- closure: closure,
390
- type_location: location_decl_to_pin_location(decl.location),
391
- comments: decl.comment&.string,
392
- scope: final_scope,
393
- signatures: [],
394
- generics: generics,
395
- visibility: visibility,
396
- source: :rbs
397
- )
398
- pin.signatures.concat method_def_to_sigs(decl, pin)
399
- pins.push pin
400
- if pin.name == 'initialize'
401
- pin.instance_variable_set(:@visibility, :private)
402
- pin.instance_variable_set(:@return_type, ComplexType::VOID)
403
- end
404
- end
405
- if decl.singleton?
406
- final_scope = :class
407
- name = decl.name.to_s
408
- visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
409
- pin = Solargraph::Pin::Method.new(
410
- name: name,
411
- closure: closure,
412
- comments: decl.comment&.string,
413
- type_location: location_decl_to_pin_location(decl.location),
414
- visibility: visibility,
415
- scope: final_scope,
416
- signatures: [],
417
- generics: generics,
418
- source: :rbs
419
- )
420
- pin.signatures.concat method_def_to_sigs(decl, pin)
421
- pins.push pin
422
- end
423
- end
424
-
425
- # @param decl [RBS::AST::Members::MethodDefinition]
426
- # @param pin [Pin::Method]
427
- # @return [void]
428
- def method_def_to_sigs decl, pin
429
- decl.overloads.map do |overload|
430
- type_location = location_decl_to_pin_location(overload.method_type.location)
431
- generics = overload.method_type.type_params.map(&:name).map(&:to_s)
432
- signature_parameters, signature_return_type = parts_of_function(overload.method_type, pin)
433
- block = if overload.method_type.block
434
- block_parameters, block_return_type = parts_of_function(overload.method_type.block, pin)
435
- Pin::Signature.new(generics: generics, parameters: block_parameters, return_type: block_return_type, source: :rbs,
436
- type_location: type_location, closure: pin)
437
- end
438
- Pin::Signature.new(generics: generics, parameters: signature_parameters, return_type: signature_return_type, block: block, source: :rbs,
439
- type_location: type_location, closure: pin)
440
- end
441
- end
442
-
443
- # @param location [RBS::Location, nil]
444
- # @return [Solargraph::Location, nil]
445
- def location_decl_to_pin_location(location)
446
- return nil if location&.name.nil?
447
-
448
- start_pos = Position.new(location.start_line - 1, location.start_column)
449
- end_pos = Position.new(location.end_line - 1, location.end_column)
450
- range = Range.new(start_pos, end_pos)
451
- Location.new(location.name.to_s, range)
452
- end
453
-
454
- # @param type [RBS::MethodType,RBS::Types::Block]
455
- # @param pin [Pin::Method]
456
- # @return [Array(Array<Pin::Parameter>, ComplexType)]
457
- def parts_of_function type, pin
458
- type_location = pin.type_location
459
- if defined?(RBS::Types::UntypedFunction) && type.type.is_a?(RBS::Types::UntypedFunction)
460
- return [
461
- [Solargraph::Pin::Parameter.new(decl: :restarg, name: 'arg', closure: pin, source: :rbs, type_location: type_location)],
462
- ComplexType.try_parse(method_type_to_tag(type)).force_rooted
463
- ]
464
- end
465
-
466
- parameters = []
467
- arg_num = -1
468
- type.type.required_positionals.each do |param|
469
- name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
470
- parameters.push Solargraph::Pin::Parameter.new(decl: :arg, name: name, closure: pin, return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted, source: :rbs, type_location: type_location)
471
- end
472
- type.type.optional_positionals.each do |param|
473
- name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
474
- parameters.push Solargraph::Pin::Parameter.new(decl: :optarg, name: name, closure: pin,
475
- return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted,
476
- type_location: type_location,
477
- source: :rbs)
478
- end
479
- if type.type.rest_positionals
480
- name = type.type.rest_positionals.name ? type.type.rest_positionals.name.to_s : "arg_#{arg_num += 1}"
481
- parameters.push Solargraph::Pin::Parameter.new(decl: :restarg, name: name, closure: pin, source: :rbs, type_location: type_location)
482
- end
483
- type.type.trailing_positionals.each do |param|
484
- name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
485
- parameters.push Solargraph::Pin::Parameter.new(decl: :arg, name: name, closure: pin, source: :rbs, type_location: type_location)
486
- end
487
- type.type.required_keywords.each do |orig, param|
488
- name = orig ? orig.to_s : "arg_#{arg_num += 1}"
489
- parameters.push Solargraph::Pin::Parameter.new(decl: :kwarg, name: name, closure: pin,
490
- return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted,
491
- source: :rbs, type_location: type_location)
492
- end
493
- type.type.optional_keywords.each do |orig, param|
494
- name = orig ? orig.to_s : "arg_#{arg_num += 1}"
495
- parameters.push Solargraph::Pin::Parameter.new(decl: :kwoptarg, name: name, closure: pin,
496
- return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted,
497
- type_location: type_location,
498
- source: :rbs)
499
- end
500
- if type.type.rest_keywords
501
- name = type.type.rest_keywords.name ? type.type.rest_keywords.name.to_s : "arg_#{arg_num += 1}"
502
- parameters.push Solargraph::Pin::Parameter.new(decl: :kwrestarg, name: type.type.rest_keywords.name.to_s, closure: pin,
503
- source: :rbs, type_location: type_location)
504
- end
505
-
506
- rooted_tag = method_type_to_tag(type)
507
- return_type = ComplexType.try_parse(rooted_tag).force_rooted
508
- [parameters, return_type]
509
- end
510
-
511
- # @param decl [RBS::AST::Members::AttrReader,RBS::AST::Members::AttrAccessor]
512
- # @param closure [Pin::Namespace]
513
- # @param context [Context]
514
- # @return [void]
515
- def attr_reader_to_pin(decl, closure, context)
516
- name = decl.name.to_s
517
- final_scope = decl.kind == :instance ? :instance : :class
518
- visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
519
- pin = Solargraph::Pin::Method.new(
520
- name: name,
521
- type_location: location_decl_to_pin_location(decl.location),
522
- closure: closure,
523
- comments: decl.comment&.string,
524
- scope: final_scope,
525
- attribute: true,
526
- visibility: visibility,
527
- source: :rbs
528
- )
529
- rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
530
- pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
531
- logger.debug { "Conversions#attr_reader_to_pin(name=#{name.inspect}, visibility=#{visibility.inspect}) => #{pin.inspect}" }
532
- pins.push pin
533
- end
534
-
535
- # @param decl [RBS::AST::Members::AttrWriter, RBS::AST::Members::AttrAccessor]
536
- # @param closure [Pin::Namespace]
537
- # @param context [Context]
538
- # @return [void]
539
- def attr_writer_to_pin(decl, closure, context)
540
- final_scope = decl.kind == :instance ? :instance : :class
541
- name = "#{decl.name.to_s}="
542
- visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
543
- type_location = location_decl_to_pin_location(decl.location)
544
- pin = Solargraph::Pin::Method.new(
545
- name: name,
546
- type_location: type_location,
547
- closure: closure,
548
- parameters: [],
549
- comments: decl.comment&.string,
550
- scope: final_scope,
551
- attribute: true,
552
- visibility: visibility,
553
- source: :rbs
554
- )
555
- pin.parameters <<
556
- Solargraph::Pin::Parameter.new(
557
- name: 'value',
558
- return_type: ComplexType.try_parse(other_type_to_tag(decl.type)).force_rooted,
559
- source: :rbs,
560
- closure: pin,
561
- type_location: type_location
562
- )
563
- rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
564
- pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
565
- pins.push pin
566
- end
567
-
568
- # @param decl [RBS::AST::Members::AttrAccessor]
569
- # @param closure [Pin::Namespace]
570
- # @param context [Context]
571
- # @return [void]
572
- def attr_accessor_to_pin(decl, closure, context)
573
- attr_reader_to_pin(decl, closure, context)
574
- attr_writer_to_pin(decl, closure, context)
575
- end
576
-
577
- # @param decl [RBS::AST::Members::InstanceVariable]
578
- # @param closure [Pin::Namespace]
579
- # @return [void]
580
- def ivar_to_pin(decl, closure)
581
- pin = Solargraph::Pin::InstanceVariable.new(
582
- name: decl.name.to_s,
583
- closure: closure,
584
- type_location: location_decl_to_pin_location(decl.location),
585
- comments: decl.comment&.string,
586
- source: :rbs
587
- )
588
- rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
589
- pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
590
- pins.push pin
591
- end
592
-
593
- # @param decl [RBS::AST::Members::ClassVariable]
594
- # @param closure [Pin::Namespace]
595
- # @return [void]
596
- def cvar_to_pin(decl, closure)
597
- name = decl.name.to_s
598
- pin = Solargraph::Pin::ClassVariable.new(
599
- name: name,
600
- closure: closure,
601
- comments: decl.comment&.string,
602
- type_location: location_decl_to_pin_location(decl.location),
603
- source: :rbs
604
- )
605
- rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
606
- pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
607
- pins.push pin
608
- end
609
-
610
- # @param decl [RBS::AST::Members::ClassInstanceVariable]
611
- # @param closure [Pin::Namespace]
612
- # @return [void]
613
- def civar_to_pin(decl, closure)
614
- name = decl.name.to_s
615
- pin = Solargraph::Pin::InstanceVariable.new(
616
- name: name,
617
- closure: closure,
618
- comments: decl.comment&.string,
619
- type_location: location_decl_to_pin_location(decl.location),
620
- source: :rbs
621
- )
622
- rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
623
- pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
624
- pins.push pin
625
- end
626
-
627
- # @param decl [RBS::AST::Members::Include]
628
- # @param closure [Pin::Namespace]
629
- # @return [void]
630
- def include_to_pin decl, closure
631
- type = build_type(decl.name, decl.args)
632
- generic_values = type.all_params.map(&:to_s)
633
- pins.push Solargraph::Pin::Reference::Include.new(
634
- name: decl.name.relative!.to_s,
635
- type_location: location_decl_to_pin_location(decl.location),
636
- generic_values: generic_values,
637
- closure: closure,
638
- source: :rbs
639
- )
640
- end
641
-
642
- # @param decl [RBS::AST::Members::Prepend]
643
- # @param closure [Pin::Namespace]
644
- # @return [void]
645
- def prepend_to_pin decl, closure
646
- pins.push Solargraph::Pin::Reference::Prepend.new(
647
- name: decl.name.relative!.to_s,
648
- type_location: location_decl_to_pin_location(decl.location),
649
- closure: closure,
650
- source: :rbs
651
- )
652
- end
653
-
654
- # @param decl [RBS::AST::Members::Extend]
655
- # @param closure [Pin::Namespace]
656
- # @return [void]
657
- def extend_to_pin decl, closure
658
- pins.push Solargraph::Pin::Reference::Extend.new(
659
- name: decl.name.relative!.to_s,
660
- type_location: location_decl_to_pin_location(decl.location),
661
- closure: closure,
662
- source: :rbs
663
- )
664
- end
665
-
666
- # @param decl [RBS::AST::Members::Alias]
667
- # @param closure [Pin::Namespace]
668
- # @return [void]
669
- def alias_to_pin decl, closure
670
- final_scope = decl.singleton? ? :class : :instance
671
- pins.push Solargraph::Pin::MethodAlias.new(
672
- name: decl.new_name.to_s,
673
- type_location: location_decl_to_pin_location(decl.location),
674
- original: decl.old_name.to_s,
675
- closure: closure,
676
- scope: final_scope,
677
- source: :rbs,
678
- )
679
- end
680
-
681
- RBS_TO_YARD_TYPE = {
682
- 'bool' => 'Boolean',
683
- 'string' => 'String',
684
- 'int' => 'Integer',
685
- 'untyped' => '',
686
- 'NilClass' => 'nil'
687
- }
688
-
689
- # @param type [RBS::MethodType]
690
- # @return [String]
691
- def method_type_to_tag type
692
- if type_aliases.key?(type.type.return_type.to_s)
693
- other_type_to_tag(type_aliases[type.type.return_type.to_s].type)
694
- else
695
- other_type_to_tag type.type.return_type
696
- end
697
- end
698
-
699
- # @param type_name [RBS::TypeName]
700
- # @param type_args [Enumerable<RBS::Types::Bases::Base>]
701
- # @return [ComplexType::UniqueType]
702
- def build_type(type_name, type_args = [])
703
- base = RBS_TO_YARD_TYPE[type_name.relative!.to_s] || type_name.relative!.to_s
704
- params = type_args.map { |a| other_type_to_tag(a) }.map do |t|
705
- ComplexType.try_parse(t).force_rooted
706
- end
707
- if base == 'Hash' && params.length == 2
708
- ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: true, parameters_type: :hash)
709
- else
710
- ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: true, parameters_type: :list)
711
- end
712
- end
713
-
714
- # @param type_name [RBS::TypeName]
715
- # @param type_args [Enumerable<RBS::Types::Bases::Base>]
716
- # @return [String]
717
- def type_tag(type_name, type_args = [])
718
- build_type(type_name, type_args).tags
719
- end
720
-
721
- # @param type [RBS::Types::Bases::Base]
722
- # @return [String]
723
- def other_type_to_tag type
724
- if type.is_a?(RBS::Types::Optional)
725
- "#{other_type_to_tag(type.type)}, nil"
726
- elsif type.is_a?(RBS::Types::Bases::Any)
727
- 'undefined'
728
- elsif type.is_a?(RBS::Types::Bases::Bool)
729
- 'Boolean'
730
- elsif type.is_a?(RBS::Types::Tuple)
731
- "Array(#{type.types.map { |t| other_type_to_tag(t) }.join(', ')})"
732
- elsif type.is_a?(RBS::Types::Literal)
733
- type.literal.inspect
734
- elsif type.is_a?(RBS::Types::Union)
735
- type.types.map { |t| other_type_to_tag(t) }.join(', ')
736
- elsif type.is_a?(RBS::Types::Record)
737
- # @todo Better record support
738
- 'Hash'
739
- elsif type.is_a?(RBS::Types::Bases::Nil)
740
- 'nil'
741
- elsif type.is_a?(RBS::Types::Bases::Self)
742
- 'self'
743
- elsif type.is_a?(RBS::Types::Bases::Void)
744
- 'void'
745
- elsif type.is_a?(RBS::Types::Variable)
746
- "#{Solargraph::ComplexType::GENERIC_TAG_NAME}<#{type.name}>"
747
- elsif type.is_a?(RBS::Types::ClassInstance) #&& !type.args.empty?
748
- type_tag(type.name, type.args)
749
- elsif type.is_a?(RBS::Types::Bases::Instance)
750
- 'self'
751
- elsif type.is_a?(RBS::Types::Bases::Top)
752
- # top is the most super superclass
753
- 'BasicObject'
754
- elsif type.is_a?(RBS::Types::Bases::Bottom)
755
- # bottom is used in contexts where nothing will ever return
756
- # - e.g., it could be the return type of 'exit()' or 'raise'
757
- #
758
- # @todo define a specific bottom type and use it to
759
- # determine dead code
760
- 'undefined'
761
- elsif type.is_a?(RBS::Types::Intersection)
762
- type.types.map { |member| other_type_to_tag(member) }.join(', ')
763
- elsif type.is_a?(RBS::Types::Proc)
764
- 'Proc'
765
- elsif type.is_a?(RBS::Types::Alias)
766
- # type-level alias use - e.g., 'bool' in "type bool = true | false"
767
- # @todo ensure these get resolved after processing all aliases
768
- # @todo handle recursive aliases
769
- type_tag(type.name, type.args)
770
- elsif type.is_a?(RBS::Types::Interface)
771
- # represents a mix-in module which can be considered a
772
- # subtype of a consumer of it
773
- type_tag(type.name, type.args)
774
- elsif type.is_a?(RBS::Types::ClassSingleton)
775
- # e.g., singleton(String)
776
- type_tag(type.name)
777
- else
778
- Solargraph.logger.warn "Unrecognized RBS type: #{type.class} at #{type.location}"
779
- 'undefined'
780
- end
781
- end
782
-
783
- # @param decl [RBS::AST::Declarations::Class, RBS::AST::Declarations::Module]
784
- # @param namespace [Pin::Namespace]
785
- # @return [void]
786
- def add_mixins decl, namespace
787
- decl.each_mixin do |mixin|
788
- klass = mixin.is_a?(RBS::AST::Members::Include) ? Pin::Reference::Include : Pin::Reference::Extend
789
- type = build_type(mixin.name, mixin.args)
790
- generic_values = type.all_params.map(&:to_s)
791
- pins.push klass.new(
792
- name: mixin.name.relative!.to_s,
793
- type_location: location_decl_to_pin_location(mixin.location),
794
- generic_values: generic_values,
795
- closure: namespace,
796
- source: :rbs
797
- )
798
- end
799
- end
800
- end
801
- end
802
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+
5
+ module Solargraph
6
+ class RbsMap
7
+ # Functions for converting RBS declarations to Solargraph pins
8
+ #
9
+ class Conversions
10
+ include Logging
11
+
12
+ # A container for tracking the current context of the RBS conversion
13
+ # process, e.g., what visibility is declared for methods in the current
14
+ # scope
15
+ #
16
+ class Context
17
+ attr_reader :visibility
18
+
19
+ # @param visibility [Symbol]
20
+ def initialize visibility = :public
21
+ @visibility = visibility
22
+ end
23
+ end
24
+
25
+ # @param loader [RBS::EnvironmentLoader]
26
+ def initialize(loader:)
27
+ @loader = loader
28
+ @pins = []
29
+ load_environment_to_pins(loader)
30
+ end
31
+
32
+ # @return [RBS::EnvironmentLoader]
33
+ attr_reader :loader
34
+
35
+ # @return [Array<Pin::Base>]
36
+ attr_reader :pins
37
+
38
+ private
39
+
40
+ # @return [Hash{String => RBS::AST::Declarations::TypeAlias}]
41
+ def type_aliases
42
+ @type_aliases ||= {}
43
+ end
44
+
45
+ # @param loader [RBS::EnvironmentLoader]
46
+ # @return [void]
47
+ def load_environment_to_pins(loader)
48
+ environment = RBS::Environment.from_loader(loader).resolve_type_names
49
+ cursor = pins.length
50
+ if environment.declarations.empty?
51
+ Solargraph.logger.info "No RBS declarations found in environment for core_root #{loader.core_root.inspect}, libraries #{loader.libs} and directories #{loader.dirs}"
52
+ return
53
+ end
54
+ environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
55
+ end
56
+
57
+ # @param decl [RBS::AST::Declarations::Base]
58
+ # @param closure [Pin::Closure]
59
+ # @return [void]
60
+ def convert_decl_to_pin decl, closure
61
+ case decl
62
+ when RBS::AST::Declarations::Class
63
+ class_decl_to_pin decl
64
+ when RBS::AST::Declarations::Interface
65
+ # STDERR.puts "Skipping interface #{decl.name.relative!}"
66
+ interface_decl_to_pin decl, closure
67
+ when RBS::AST::Declarations::TypeAlias
68
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
69
+ type_aliases[decl.name.to_s] = decl
70
+ when RBS::AST::Declarations::Module
71
+ module_decl_to_pin decl
72
+ when RBS::AST::Declarations::Constant
73
+ constant_decl_to_pin decl
74
+ when RBS::AST::Declarations::ClassAlias
75
+ class_alias_decl_to_pin decl
76
+ when RBS::AST::Declarations::ModuleAlias
77
+ module_alias_decl_to_pin decl
78
+ when RBS::AST::Declarations::Global
79
+ global_decl_to_pin decl
80
+ else
81
+ Solargraph.logger.warn "Skipping declaration #{decl.class}"
82
+ end
83
+ end
84
+
85
+ # @param decl [RBS::AST::Declarations::Module]
86
+ # @param module_pin [Pin::Namespace]
87
+ # @return [void]
88
+ def convert_self_types_to_pins decl, module_pin
89
+ decl.self_types.each { |self_type| context = convert_self_type_to_pins(self_type, module_pin) }
90
+ end
91
+
92
+ # @param decl [RBS::AST::Declarations::Module::Self]
93
+ # @param closure [Pin::Namespace]
94
+ # @return [void]
95
+ def convert_self_type_to_pins decl, closure
96
+ type = build_type(decl.name, decl.args)
97
+ generic_values = type.all_params.map(&:to_s)
98
+ include_pin = Solargraph::Pin::Reference::Include.new(
99
+ name: decl.name.relative!.to_s,
100
+ type_location: location_decl_to_pin_location(decl.location),
101
+ generic_values: generic_values,
102
+ closure: closure,
103
+ source: :rbs
104
+ )
105
+ pins.push include_pin
106
+ end
107
+
108
+ # @param decl [RBS::AST::Declarations::Module,RBS::AST::Declarations::Class,RBS::AST::Declarations::Interface]
109
+ # @param closure [Pin::Namespace]
110
+ # @return [void]
111
+ def convert_members_to_pins decl, closure
112
+ context = Conversions::Context.new
113
+ decl.members.each { |m| context = convert_member_to_pin(m, closure, context) }
114
+ end
115
+
116
+ # @param member [RBS::AST::Members::Base,RBS::AST::Declarations::Base]
117
+ # @param closure [Pin::Namespace]
118
+ # @param context [Context]
119
+ # @return [Context]
120
+ def convert_member_to_pin member, closure, context
121
+ case member
122
+ when RBS::AST::Members::MethodDefinition
123
+ method_def_to_pin(member, closure, context)
124
+ when RBS::AST::Members::AttrReader
125
+ attr_reader_to_pin(member, closure, context)
126
+ when RBS::AST::Members::AttrWriter
127
+ attr_writer_to_pin(member, closure, context)
128
+ when RBS::AST::Members::AttrAccessor
129
+ attr_accessor_to_pin(member, closure, context)
130
+ when RBS::AST::Members::Include
131
+ include_to_pin(member, closure)
132
+ when RBS::AST::Members::Prepend
133
+ prepend_to_pin(member, closure)
134
+ when RBS::AST::Members::Extend
135
+ extend_to_pin(member, closure)
136
+ when RBS::AST::Members::Alias
137
+ alias_to_pin(member, closure)
138
+ when RBS::AST::Members::ClassInstanceVariable
139
+ civar_to_pin(member, closure)
140
+ when RBS::AST::Members::ClassVariable
141
+ cvar_to_pin(member, closure)
142
+ when RBS::AST::Members::InstanceVariable
143
+ ivar_to_pin(member, closure)
144
+ when RBS::AST::Members::Public
145
+ return Context.new(:public)
146
+ when RBS::AST::Members::Private
147
+ return Context.new(:private)
148
+ when RBS::AST::Declarations::Base
149
+ convert_decl_to_pin(member, closure)
150
+ else
151
+ Solargraph.logger.warn "Skipping member type #{member.class}"
152
+ end
153
+ context
154
+ end
155
+
156
+ # @param decl [RBS::AST::Declarations::Class]
157
+ # @return [void]
158
+ def class_decl_to_pin decl
159
+ generics = decl.type_params.map(&:name).map(&:to_s)
160
+ generic_defaults = {}
161
+ decl.type_params.each do |param|
162
+ if param.default_type
163
+ tag = other_type_to_tag param.default_type
164
+ generic_defaults[param.name.to_s] = ComplexType.parse(tag).force_rooted
165
+ end
166
+ end
167
+ class_name = decl.name.relative!.to_s
168
+ class_pin = Solargraph::Pin::Namespace.new(
169
+ type: :class,
170
+ name: class_name,
171
+ closure: Solargraph::Pin::ROOT_PIN,
172
+ comments: decl.comment&.string,
173
+ type_location: location_decl_to_pin_location(decl.location),
174
+ # @todo some type parameters in core/stdlib have default
175
+ # values; Solargraph doesn't support that yet as so these
176
+ # get treated as undefined if not specified
177
+ generics: generics,
178
+ generic_defaults: generic_defaults,
179
+ source: :rbs
180
+ )
181
+ pins.push class_pin
182
+ if decl.super_class
183
+ type = build_type(decl.super_class.name, decl.super_class.args)
184
+ generic_values = type.all_params.map(&:to_s)
185
+ superclass_name = decl.super_class.name.to_s
186
+ pins.push Solargraph::Pin::Reference::Superclass.new(
187
+ type_location: location_decl_to_pin_location(decl.super_class.location),
188
+ closure: class_pin,
189
+ generic_values: generic_values,
190
+ name: superclass_name,
191
+ source: :rbs
192
+ )
193
+ end
194
+ add_mixins decl, class_pin
195
+ convert_members_to_pins decl, class_pin
196
+ end
197
+
198
+ # @param decl [RBS::AST::Declarations::Interface]
199
+ # @param closure [Pin::Closure]
200
+ # @return [void]
201
+ def interface_decl_to_pin decl, closure
202
+ class_pin = Solargraph::Pin::Namespace.new(
203
+ type: :module,
204
+ type_location: location_decl_to_pin_location(decl.location),
205
+ name: decl.name.relative!.to_s,
206
+ closure: Solargraph::Pin::ROOT_PIN,
207
+ comments: decl.comment&.string,
208
+ generics: decl.type_params.map(&:name).map(&:to_s),
209
+ # HACK: Using :hidden to keep interfaces from appearing in
210
+ # autocompletion
211
+ visibility: :hidden,
212
+ source: :rbs
213
+ )
214
+ class_pin.docstring.add_tag(YARD::Tags::Tag.new(:abstract, '(RBS interface)'))
215
+ pins.push class_pin
216
+ convert_members_to_pins decl, class_pin
217
+ end
218
+
219
+ # @param decl [RBS::AST::Declarations::Module]
220
+ # @return [void]
221
+ def module_decl_to_pin decl
222
+ module_pin = Solargraph::Pin::Namespace.new(
223
+ type: :module,
224
+ name: decl.name.relative!.to_s,
225
+ type_location: location_decl_to_pin_location(decl.location),
226
+ closure: Solargraph::Pin::ROOT_PIN,
227
+ comments: decl.comment&.string,
228
+ generics: decl.type_params.map(&:name).map(&:to_s),
229
+ source: :rbs
230
+ )
231
+ pins.push module_pin
232
+ convert_self_types_to_pins decl, module_pin
233
+ convert_members_to_pins decl, module_pin
234
+
235
+ add_mixins decl, module_pin.closure
236
+ end
237
+
238
+ # @param name [String]
239
+ # @param tag [String]
240
+ # @param comments [String]
241
+ # @param decl [RBS::AST::Declarations::ClassAlias, RBS::AST::Declarations::Constant, RBS::AST::Declarations::ModuleAlias]
242
+ # @param base [String, nil] Optional conversion of tag to base<tag>
243
+ #
244
+ # @return [Solargraph::Pin::Constant]
245
+ def create_constant(name, tag, comments, decl, base = nil)
246
+ parts = name.split('::')
247
+ if parts.length > 1
248
+ name = parts.last
249
+ closure = pins.select { |pin| pin && pin.path == parts[0..-2].join('::') }.first
250
+ else
251
+ name = parts.first
252
+ closure = Solargraph::Pin::ROOT_PIN
253
+ end
254
+ constant_pin = Solargraph::Pin::Constant.new(
255
+ name: name,
256
+ closure: closure,
257
+ type_location: location_decl_to_pin_location(decl.location),
258
+ comments: comments,
259
+ source: :rbs
260
+ )
261
+ tag = "#{base}<#{tag}>" if base
262
+ rooted_tag = ComplexType.parse(tag).force_rooted.rooted_tags
263
+ constant_pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
264
+ constant_pin
265
+ end
266
+
267
+ # @param decl [RBS::AST::Declarations::ClassAlias]
268
+ # @return [void]
269
+ def class_alias_decl_to_pin decl
270
+ # See https://www.rubydoc.info/gems/rbs/3.4.3/RBS/AST/Declarations/ClassAlias
271
+ new_name = decl.new_name.relative!.to_s
272
+ old_name = decl.old_name.relative!.to_s
273
+
274
+ pins.push create_constant(new_name, old_name, decl.comment&.string, decl, 'Class')
275
+ end
276
+
277
+ # @param decl [RBS::AST::Declarations::ModuleAlias]
278
+ # @return [void]
279
+ def module_alias_decl_to_pin decl
280
+ # See https://www.rubydoc.info/gems/rbs/3.4.3/RBS/AST/Declarations/ModuleAlias
281
+ new_name = decl.new_name.relative!.to_s
282
+ old_name = decl.old_name.relative!.to_s
283
+
284
+ pins.push create_constant(new_name, old_name, decl.comment&.string, decl, 'Module')
285
+ end
286
+
287
+ # @param decl [RBS::AST::Declarations::Constant]
288
+ # @return [void]
289
+ def constant_decl_to_pin decl
290
+ tag = other_type_to_tag(decl.type)
291
+ pins.push create_constant(decl.name.relative!.to_s, tag, decl.comment&.string, decl)
292
+ end
293
+
294
+ # @param decl [RBS::AST::Declarations::Global]
295
+ # @return [void]
296
+ def global_decl_to_pin decl
297
+ closure = Solargraph::Pin::ROOT_PIN
298
+ name = decl.name.to_s
299
+ pin = Solargraph::Pin::GlobalVariable.new(
300
+ name: name,
301
+ closure: closure,
302
+ comments: decl.comment&.string,
303
+ type_location: location_decl_to_pin_location(decl.location),
304
+ source: :rbs
305
+ )
306
+ rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
307
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
308
+ pins.push pin
309
+ end
310
+
311
+
312
+ # Visibility overrides that will allow the Solargraph project
313
+ # and plugins to pass typechecking using SOLARGRAPH_ASSERTS=on,
314
+ # so that we can detect any regressions/issues elsewhere in the
315
+ # visibility logic.
316
+ #
317
+ # These should either reflect a bug upstream in the RBS
318
+ # definitions, or include a @todo indicating what needs to be
319
+ # fixed in Solargraph to properly understand it.
320
+ #
321
+ # @todo PR these fixes upstream and list open PRs here above
322
+ # related overrides
323
+ # @todo externalize remaining overrides into yaml file, then
324
+ # allow that to be extended via .solargraph.yml
325
+ # @type [Hash{Array(String, Symbol, String) => Symbol}
326
+ VISIBILITY_OVERRIDE = {
327
+ ["Rails::Engine", :instance, "run_tasks_blocks"] => :protected,
328
+ # Should have been marked as both instance and class method in module -e.g., 'module_function'
329
+ ["Kernel", :instance, "pretty_inspect"] => :private,
330
+ # marked incorrectly in RBS
331
+ ["WEBrick::HTTPUtils::FormData", :instance, "next_data"] => :protected,
332
+ ["Rails::Command", :class, "command_type"] => :private,
333
+ ["Rails::Command", :class, "lookup_paths"] => :private,
334
+ ["Rails::Command", :class, "file_lookup_paths"] => :private,
335
+ ["Rails::Railtie", :instance, "run_console_blocks"] => :protected,
336
+ ["Rails::Railtie", :instance, "run_generators_blocks"] => :protected,
337
+ ["Rails::Railtie", :instance, "run_runner_blocks"] => :protected,
338
+ ["Rails::Railtie", :instance, "run_tasks_blocks"] => :protected,
339
+ ["ActionController::Base", :instance, "_protected_ivars"] => :private,
340
+ ["ActionView::Template", :instance, "method_name"] => :public,
341
+ ["Module", :instance, "ruby2_keywords"] => :private,
342
+ ["Nokogiri::XML::Node", :instance, "coerce"] => :protected,
343
+ ["Nokogiri::XML::Document", :class, "empty_doc?"] => :private,
344
+ ["Nokogiri::Decorators::Slop", :instance, "respond_to_missing?"] => :public,
345
+ ["RuboCop::Cop::RangeHelp", :instance, "source_range"] => :private,
346
+ ["AST::Node", :instance, "original_dup"] => :private,
347
+ ["Rainbow::Presenter", :instance, "wrap_with_sgr"] => :private,
348
+ }
349
+
350
+ # @param decl [RBS::AST::Members::MethodDefinition, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrAccessor]
351
+ # @param closure [Pin::Closure]
352
+ # @param context [Context]
353
+ # @param scope [Symbol] :instance or :class
354
+ # @param name [String] The name of the method
355
+ # @sg-ignore
356
+ # @return [Symbol]
357
+ def calculate_method_visibility(decl, context, closure, scope, name)
358
+ override_key = [closure.path, scope, name]
359
+ visibility = VISIBILITY_OVERRIDE[override_key]
360
+ simple_override_key = [closure.path, scope]
361
+ visibility ||= VISIBILITY_OVERRIDE[simple_override_key]
362
+ visibility ||= :private if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(decl.name)
363
+ if decl.kind == :singleton_instance
364
+ # this is a 'module function'
365
+ visibility ||= :private
366
+ end
367
+ visibility ||= decl.visibility
368
+ visibility ||= context.visibility
369
+ visibility ||= :public
370
+ visibility
371
+ end
372
+
373
+ # @param decl [RBS::AST::Members::MethodDefinition]
374
+ # @param closure [Pin::Closure]
375
+ # @param context [Context]
376
+ # @return [void]
377
+ def method_def_to_pin decl, closure, context
378
+ # there may be edge cases here around different signatures
379
+ # having different type params / orders - we may need to match
380
+ # this data model and have generics live in signatures to
381
+ # handle those correctly
382
+ generics = decl.overloads.map(&:method_type).flat_map(&:type_params).map(&:name).map(&:to_s).uniq
383
+
384
+ if decl.instance?
385
+ name = decl.name.to_s
386
+ final_scope = :instance
387
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
388
+ pin = Solargraph::Pin::Method.new(
389
+ name: name,
390
+ closure: closure,
391
+ type_location: location_decl_to_pin_location(decl.location),
392
+ comments: decl.comment&.string,
393
+ scope: final_scope,
394
+ signatures: [],
395
+ generics: generics,
396
+ visibility: visibility,
397
+ source: :rbs
398
+ )
399
+ pin.signatures.concat method_def_to_sigs(decl, pin)
400
+ pins.push pin
401
+ if pin.name == 'initialize'
402
+ pin.instance_variable_set(:@visibility, :private)
403
+ pin.instance_variable_set(:@return_type, ComplexType::VOID)
404
+ end
405
+ end
406
+ if decl.singleton?
407
+ final_scope = :class
408
+ name = decl.name.to_s
409
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
410
+ pin = Solargraph::Pin::Method.new(
411
+ name: name,
412
+ closure: closure,
413
+ comments: decl.comment&.string,
414
+ type_location: location_decl_to_pin_location(decl.location),
415
+ visibility: visibility,
416
+ scope: final_scope,
417
+ signatures: [],
418
+ generics: generics,
419
+ source: :rbs
420
+ )
421
+ pin.signatures.concat method_def_to_sigs(decl, pin)
422
+ pins.push pin
423
+ end
424
+ end
425
+
426
+ # @param decl [RBS::AST::Members::MethodDefinition]
427
+ # @param pin [Pin::Method]
428
+ # @return [void]
429
+ def method_def_to_sigs decl, pin
430
+ # @param overload [RBS::AST::Members::MethodDefinition::Overload]
431
+ decl.overloads.map do |overload|
432
+ type_location = location_decl_to_pin_location(overload.method_type.location)
433
+ generics = overload.method_type.type_params.map(&:name).map(&:to_s)
434
+ signature_parameters, signature_return_type = parts_of_function(overload.method_type, pin)
435
+ block = if overload.method_type.block
436
+ block_parameters, block_return_type = parts_of_function(overload.method_type.block, pin)
437
+ Pin::Signature.new(generics: generics, parameters: block_parameters, return_type: block_return_type, source: :rbs,
438
+ type_location: type_location, closure: pin)
439
+ end
440
+ Pin::Signature.new(generics: generics, parameters: signature_parameters, return_type: signature_return_type, block: block, source: :rbs,
441
+ type_location: type_location, closure: pin)
442
+ end
443
+ end
444
+
445
+ # @param location [RBS::Location, nil]
446
+ # @return [Solargraph::Location, nil]
447
+ def location_decl_to_pin_location(location)
448
+ return nil if location&.name.nil?
449
+
450
+ start_pos = Position.new(location.start_line - 1, location.start_column)
451
+ end_pos = Position.new(location.end_line - 1, location.end_column)
452
+ range = Range.new(start_pos, end_pos)
453
+ Location.new(location.name.to_s, range)
454
+ end
455
+
456
+ # @param type [RBS::MethodType,RBS::Types::Block]
457
+ # @param pin [Pin::Method]
458
+ # @return [Array(Array<Pin::Parameter>, ComplexType)]
459
+ def parts_of_function type, pin
460
+ type_location = pin.type_location
461
+ if defined?(RBS::Types::UntypedFunction) && type.type.is_a?(RBS::Types::UntypedFunction)
462
+ return [
463
+ [Solargraph::Pin::Parameter.new(decl: :restarg, name: 'arg', closure: pin, source: :rbs, type_location: type_location)],
464
+ ComplexType.try_parse(method_type_to_tag(type)).force_rooted
465
+ ]
466
+ end
467
+
468
+ parameters = []
469
+ arg_num = -1
470
+ type.type.required_positionals.each do |param|
471
+ # @sg-ignore RBS generic type understanding issue
472
+ name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
473
+ # @sg-ignore RBS generic type understanding issue
474
+ parameters.push Solargraph::Pin::Parameter.new(decl: :arg, name: name, closure: pin, return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted, source: :rbs, type_location: type_location)
475
+ end
476
+ type.type.optional_positionals.each do |param|
477
+ # @sg-ignore RBS generic type understanding issue
478
+ name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
479
+ parameters.push Solargraph::Pin::Parameter.new(decl: :optarg, name: name, closure: pin,
480
+ # @sg-ignore RBS generic type understanding issue
481
+ return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted,
482
+ type_location: type_location,
483
+ source: :rbs)
484
+ end
485
+ if type.type.rest_positionals
486
+ name = type.type.rest_positionals.name ? type.type.rest_positionals.name.to_s : "arg_#{arg_num += 1}"
487
+ inner_rest_positional_type =
488
+ ComplexType.try_parse(other_type_to_tag(type.type.rest_positionals.type))
489
+ rest_positional_type = ComplexType::UniqueType.new('Array',
490
+ [],
491
+ [inner_rest_positional_type],
492
+ rooted: true, parameters_type: :list)
493
+ parameters.push Solargraph::Pin::Parameter.new(decl: :restarg, name: name, closure: pin,
494
+ source: :rbs, type_location: type_location,
495
+ return_type: rest_positional_type,)
496
+ end
497
+ type.type.trailing_positionals.each do |param|
498
+ # @sg-ignore RBS generic type understanding issue
499
+ name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
500
+ parameters.push Solargraph::Pin::Parameter.new(decl: :arg, name: name, closure: pin, source: :rbs, type_location: type_location)
501
+ end
502
+ type.type.required_keywords.each do |orig, param|
503
+ # @sg-ignore RBS generic type understanding issue
504
+ name = orig ? orig.to_s : "arg_#{arg_num += 1}"
505
+ parameters.push Solargraph::Pin::Parameter.new(decl: :kwarg, name: name, closure: pin,
506
+ # @sg-ignore RBS generic type understanding issue
507
+ return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted,
508
+ source: :rbs, type_location: type_location)
509
+ end
510
+ type.type.optional_keywords.each do |orig, param|
511
+ # @sg-ignore RBS generic type understanding issue
512
+ name = orig ? orig.to_s : "arg_#{arg_num += 1}"
513
+ parameters.push Solargraph::Pin::Parameter.new(decl: :kwoptarg, name: name, closure: pin,
514
+ # @sg-ignore RBS generic type understanding issue
515
+ return_type: ComplexType.try_parse(other_type_to_tag(param.type)).force_rooted,
516
+ type_location: type_location,
517
+ source: :rbs)
518
+ end
519
+ if type.type.rest_keywords
520
+ name = type.type.rest_keywords.name ? type.type.rest_keywords.name.to_s : "arg_#{arg_num += 1}"
521
+ parameters.push Solargraph::Pin::Parameter.new(decl: :kwrestarg, name: type.type.rest_keywords.name.to_s, closure: pin,
522
+ source: :rbs, type_location: type_location)
523
+ end
524
+
525
+ rooted_tag = method_type_to_tag(type)
526
+ return_type = ComplexType.try_parse(rooted_tag).force_rooted
527
+ [parameters, return_type]
528
+ end
529
+
530
+ # @param decl [RBS::AST::Members::AttrReader,RBS::AST::Members::AttrAccessor]
531
+ # @param closure [Pin::Namespace]
532
+ # @param context [Context]
533
+ # @return [void]
534
+ def attr_reader_to_pin(decl, closure, context)
535
+ name = decl.name.to_s
536
+ final_scope = decl.kind == :instance ? :instance : :class
537
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
538
+ pin = Solargraph::Pin::Method.new(
539
+ name: name,
540
+ type_location: location_decl_to_pin_location(decl.location),
541
+ closure: closure,
542
+ comments: decl.comment&.string,
543
+ scope: final_scope,
544
+ attribute: true,
545
+ visibility: visibility,
546
+ source: :rbs
547
+ )
548
+ rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
549
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
550
+ logger.debug { "Conversions#attr_reader_to_pin(name=#{name.inspect}, visibility=#{visibility.inspect}) => #{pin.inspect}" }
551
+ pins.push pin
552
+ end
553
+
554
+ # @param decl [RBS::AST::Members::AttrWriter, RBS::AST::Members::AttrAccessor]
555
+ # @param closure [Pin::Namespace]
556
+ # @param context [Context]
557
+ # @return [void]
558
+ def attr_writer_to_pin(decl, closure, context)
559
+ final_scope = decl.kind == :instance ? :instance : :class
560
+ name = "#{decl.name.to_s}="
561
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
562
+ type_location = location_decl_to_pin_location(decl.location)
563
+ pin = Solargraph::Pin::Method.new(
564
+ name: name,
565
+ type_location: type_location,
566
+ closure: closure,
567
+ parameters: [],
568
+ comments: decl.comment&.string,
569
+ scope: final_scope,
570
+ attribute: true,
571
+ visibility: visibility,
572
+ source: :rbs
573
+ )
574
+ pin.parameters <<
575
+ Solargraph::Pin::Parameter.new(
576
+ name: 'value',
577
+ return_type: ComplexType.try_parse(other_type_to_tag(decl.type)).force_rooted,
578
+ source: :rbs,
579
+ closure: pin,
580
+ type_location: type_location
581
+ )
582
+ rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
583
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
584
+ pins.push pin
585
+ end
586
+
587
+ # @param decl [RBS::AST::Members::AttrAccessor]
588
+ # @param closure [Pin::Namespace]
589
+ # @param context [Context]
590
+ # @return [void]
591
+ def attr_accessor_to_pin(decl, closure, context)
592
+ attr_reader_to_pin(decl, closure, context)
593
+ attr_writer_to_pin(decl, closure, context)
594
+ end
595
+
596
+ # @param decl [RBS::AST::Members::InstanceVariable]
597
+ # @param closure [Pin::Namespace]
598
+ # @return [void]
599
+ def ivar_to_pin(decl, closure)
600
+ pin = Solargraph::Pin::InstanceVariable.new(
601
+ name: decl.name.to_s,
602
+ closure: closure,
603
+ type_location: location_decl_to_pin_location(decl.location),
604
+ comments: decl.comment&.string,
605
+ source: :rbs
606
+ )
607
+ rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
608
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
609
+ pins.push pin
610
+ end
611
+
612
+ # @param decl [RBS::AST::Members::ClassVariable]
613
+ # @param closure [Pin::Namespace]
614
+ # @return [void]
615
+ def cvar_to_pin(decl, closure)
616
+ name = decl.name.to_s
617
+ pin = Solargraph::Pin::ClassVariable.new(
618
+ name: name,
619
+ closure: closure,
620
+ comments: decl.comment&.string,
621
+ type_location: location_decl_to_pin_location(decl.location),
622
+ source: :rbs
623
+ )
624
+ rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
625
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
626
+ pins.push pin
627
+ end
628
+
629
+ # @param decl [RBS::AST::Members::ClassInstanceVariable]
630
+ # @param closure [Pin::Namespace]
631
+ # @return [void]
632
+ def civar_to_pin(decl, closure)
633
+ name = decl.name.to_s
634
+ pin = Solargraph::Pin::InstanceVariable.new(
635
+ name: name,
636
+ closure: closure,
637
+ comments: decl.comment&.string,
638
+ type_location: location_decl_to_pin_location(decl.location),
639
+ source: :rbs
640
+ )
641
+ rooted_tag = ComplexType.parse(other_type_to_tag(decl.type)).force_rooted.rooted_tags
642
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
643
+ pins.push pin
644
+ end
645
+
646
+ # @param decl [RBS::AST::Members::Include]
647
+ # @param closure [Pin::Namespace]
648
+ # @return [void]
649
+ def include_to_pin decl, closure
650
+ type = build_type(decl.name, decl.args)
651
+ generic_values = type.all_params.map(&:to_s)
652
+ pins.push Solargraph::Pin::Reference::Include.new(
653
+ name: decl.name.relative!.to_s,
654
+ type_location: location_decl_to_pin_location(decl.location),
655
+ generic_values: generic_values,
656
+ closure: closure,
657
+ source: :rbs
658
+ )
659
+ end
660
+
661
+ # @param decl [RBS::AST::Members::Prepend]
662
+ # @param closure [Pin::Namespace]
663
+ # @return [void]
664
+ def prepend_to_pin decl, closure
665
+ pins.push Solargraph::Pin::Reference::Prepend.new(
666
+ name: decl.name.relative!.to_s,
667
+ type_location: location_decl_to_pin_location(decl.location),
668
+ closure: closure,
669
+ source: :rbs
670
+ )
671
+ end
672
+
673
+ # @param decl [RBS::AST::Members::Extend]
674
+ # @param closure [Pin::Namespace]
675
+ # @return [void]
676
+ def extend_to_pin decl, closure
677
+ pins.push Solargraph::Pin::Reference::Extend.new(
678
+ name: decl.name.relative!.to_s,
679
+ type_location: location_decl_to_pin_location(decl.location),
680
+ closure: closure,
681
+ source: :rbs
682
+ )
683
+ end
684
+
685
+ # @param decl [RBS::AST::Members::Alias]
686
+ # @param closure [Pin::Namespace]
687
+ # @return [void]
688
+ def alias_to_pin decl, closure
689
+ final_scope = decl.singleton? ? :class : :instance
690
+ pins.push Solargraph::Pin::MethodAlias.new(
691
+ name: decl.new_name.to_s,
692
+ type_location: location_decl_to_pin_location(decl.location),
693
+ original: decl.old_name.to_s,
694
+ closure: closure,
695
+ scope: final_scope,
696
+ source: :rbs,
697
+ )
698
+ end
699
+
700
+ RBS_TO_YARD_TYPE = {
701
+ 'bool' => 'Boolean',
702
+ 'string' => 'String',
703
+ 'int' => 'Integer',
704
+ 'untyped' => '',
705
+ 'NilClass' => 'nil'
706
+ }
707
+
708
+ # @param type [RBS::MethodType]
709
+ # @return [String]
710
+ def method_type_to_tag type
711
+ if type_aliases.key?(type.type.return_type.to_s)
712
+ other_type_to_tag(type_aliases[type.type.return_type.to_s].type)
713
+ else
714
+ other_type_to_tag type.type.return_type
715
+ end
716
+ end
717
+
718
+ # @param type_name [RBS::TypeName]
719
+ # @param type_args [Enumerable<RBS::Types::Bases::Base>]
720
+ # @return [ComplexType::UniqueType]
721
+ def build_type(type_name, type_args = [])
722
+ base = RBS_TO_YARD_TYPE[type_name.relative!.to_s] || type_name.relative!.to_s
723
+ params = type_args.map { |a| other_type_to_tag(a) }.map do |t|
724
+ ComplexType.try_parse(t).force_rooted
725
+ end
726
+ if base == 'Hash' && params.length == 2
727
+ ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: true, parameters_type: :hash)
728
+ else
729
+ ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: true, parameters_type: :list)
730
+ end
731
+ end
732
+
733
+ # @param type_name [RBS::TypeName]
734
+ # @param type_args [Enumerable<RBS::Types::Bases::Base>]
735
+ # @return [String]
736
+ def type_tag(type_name, type_args = [])
737
+ build_type(type_name, type_args).tags
738
+ end
739
+
740
+ # @param type [RBS::Types::Bases::Base]
741
+ # @return [String]
742
+ def other_type_to_tag type
743
+ if type.is_a?(RBS::Types::Optional)
744
+ "#{other_type_to_tag(type.type)}, nil"
745
+ elsif type.is_a?(RBS::Types::Bases::Any)
746
+ 'undefined'
747
+ elsif type.is_a?(RBS::Types::Bases::Bool)
748
+ 'Boolean'
749
+ elsif type.is_a?(RBS::Types::Tuple)
750
+ "Array(#{type.types.map { |t| other_type_to_tag(t) }.join(', ')})"
751
+ elsif type.is_a?(RBS::Types::Literal)
752
+ type.literal.inspect
753
+ elsif type.is_a?(RBS::Types::Union)
754
+ type.types.map { |t| other_type_to_tag(t) }.join(', ')
755
+ elsif type.is_a?(RBS::Types::Record)
756
+ # @todo Better record support
757
+ 'Hash'
758
+ elsif type.is_a?(RBS::Types::Bases::Nil)
759
+ 'nil'
760
+ elsif type.is_a?(RBS::Types::Bases::Self)
761
+ 'self'
762
+ elsif type.is_a?(RBS::Types::Bases::Void)
763
+ 'void'
764
+ elsif type.is_a?(RBS::Types::Variable)
765
+ "#{Solargraph::ComplexType::GENERIC_TAG_NAME}<#{type.name}>"
766
+ elsif type.is_a?(RBS::Types::ClassInstance) #&& !type.args.empty?
767
+ type_tag(type.name, type.args)
768
+ elsif type.is_a?(RBS::Types::Bases::Instance)
769
+ 'self'
770
+ elsif type.is_a?(RBS::Types::Bases::Top)
771
+ # top is the most super superclass
772
+ 'BasicObject'
773
+ elsif type.is_a?(RBS::Types::Bases::Bottom)
774
+ # bottom is used in contexts where nothing will ever return
775
+ # - e.g., it could be the return type of 'exit()' or 'raise'
776
+ #
777
+ # @todo define a specific bottom type and use it to
778
+ # determine dead code
779
+ 'undefined'
780
+ elsif type.is_a?(RBS::Types::Intersection)
781
+ type.types.map { |member| other_type_to_tag(member) }.join(', ')
782
+ elsif type.is_a?(RBS::Types::Proc)
783
+ 'Proc'
784
+ elsif type.is_a?(RBS::Types::Alias)
785
+ # type-level alias use - e.g., 'bool' in "type bool = true | false"
786
+ # @todo ensure these get resolved after processing all aliases
787
+ # @todo handle recursive aliases
788
+ type_tag(type.name, type.args)
789
+ elsif type.is_a?(RBS::Types::Interface)
790
+ # represents a mix-in module which can be considered a
791
+ # subtype of a consumer of it
792
+ type_tag(type.name, type.args)
793
+ elsif type.is_a?(RBS::Types::ClassSingleton)
794
+ # e.g., singleton(String)
795
+ type_tag(type.name)
796
+ else
797
+ Solargraph.logger.warn "Unrecognized RBS type: #{type.class} at #{type.location}"
798
+ 'undefined'
799
+ end
800
+ end
801
+
802
+ # @param decl [RBS::AST::Declarations::Class, RBS::AST::Declarations::Module]
803
+ # @param namespace [Pin::Namespace]
804
+ # @return [void]
805
+ def add_mixins decl, namespace
806
+ # @param mixin [RBS::AST::Members::Include, RBS::AST::Members::Members::Extend, RBS::AST::Members::Members::Prepend]
807
+ decl.each_mixin do |mixin|
808
+ # @todo are we handling prepend correctly?
809
+ klass = mixin.is_a?(RBS::AST::Members::Include) ? Pin::Reference::Include : Pin::Reference::Extend
810
+ type = build_type(mixin.name, mixin.args)
811
+ generic_values = type.all_params.map(&:to_s)
812
+ pins.push klass.new(
813
+ name: mixin.name.relative!.to_s,
814
+ type_location: location_decl_to_pin_location(mixin.location),
815
+ generic_values: generic_values,
816
+ closure: namespace,
817
+ source: :rbs
818
+ )
819
+ end
820
+ end
821
+ end
822
+ end
823
+ end