solargraph 0.58.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.gitattributes +2 -0
  4. data/.github/workflows/linting.yml +6 -5
  5. data/.github/workflows/plugins.yml +48 -35
  6. data/.github/workflows/rspec.yml +15 -28
  7. data/.github/workflows/typecheck.yml +3 -2
  8. data/.gitignore +1 -0
  9. data/.rubocop.yml +38 -6
  10. data/.rubocop_todo.yml +53 -966
  11. data/CHANGELOG.md +24 -0
  12. data/Gemfile +3 -1
  13. data/README.md +3 -3
  14. data/Rakefile +26 -23
  15. data/bin/solargraph +9 -8
  16. data/lib/solargraph/api_map/cache.rb +110 -110
  17. data/lib/solargraph/api_map/constants.rb +288 -279
  18. data/lib/solargraph/api_map/index.rb +204 -193
  19. data/lib/solargraph/api_map/source_to_yard.rb +110 -97
  20. data/lib/solargraph/api_map/store.rb +395 -384
  21. data/lib/solargraph/api_map.rb +1029 -945
  22. data/lib/solargraph/bench.rb +44 -45
  23. data/lib/solargraph/complex_type/conformance.rb +176 -0
  24. data/lib/solargraph/complex_type/type_methods.rb +240 -228
  25. data/lib/solargraph/complex_type/unique_type.rb +641 -482
  26. data/lib/solargraph/complex_type.rb +557 -444
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  29. data/lib/solargraph/convention/data_definition.rb +108 -105
  30. data/lib/solargraph/convention/gemfile.rb +15 -15
  31. data/lib/solargraph/convention/gemspec.rb +23 -23
  32. data/lib/solargraph/convention/rakefile.rb +17 -17
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  35. data/lib/solargraph/convention/struct_definition.rb +168 -164
  36. data/lib/solargraph/convention.rb +78 -78
  37. data/lib/solargraph/converters/dd.rb +19 -17
  38. data/lib/solargraph/converters/dl.rb +17 -15
  39. data/lib/solargraph/converters/dt.rb +17 -15
  40. data/lib/solargraph/converters/misc.rb +3 -1
  41. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  42. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  44. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  45. data/lib/solargraph/diagnostics/update_errors.rb +37 -41
  46. data/lib/solargraph/doc_map.rb +438 -439
  47. data/lib/solargraph/equality.rb +34 -34
  48. data/lib/solargraph/gem_pins.rb +98 -98
  49. data/lib/solargraph/language_server/error_codes.rb +20 -20
  50. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  51. data/lib/solargraph/language_server/host/dispatch.rb +130 -130
  52. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  53. data/lib/solargraph/language_server/host/sources.rb +100 -99
  54. data/lib/solargraph/language_server/host.rb +886 -878
  55. data/lib/solargraph/language_server/message/base.rb +97 -97
  56. data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
  57. data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
  58. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +108 -114
  59. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  60. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  61. data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
  62. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  63. data/lib/solargraph/language_server/message/initialize.rb +197 -191
  64. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  65. data/lib/solargraph/language_server/message/text_document/definition.rb +49 -40
  66. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
  67. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +36 -26
  68. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  69. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  70. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
  71. data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
  72. data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
  73. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  74. data/lib/solargraph/language_server/message/text_document/type_definition.rb +33 -25
  75. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
  76. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
  77. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
  78. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +33 -23
  79. data/lib/solargraph/language_server/message.rb +94 -94
  80. data/lib/solargraph/language_server/request.rb +29 -27
  81. data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
  82. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  83. data/lib/solargraph/library.rb +702 -683
  84. data/lib/solargraph/location.rb +85 -82
  85. data/lib/solargraph/logging.rb +55 -37
  86. data/lib/solargraph/page.rb +92 -92
  87. data/lib/solargraph/parser/comment_ripper.rb +84 -69
  88. data/lib/solargraph/parser/flow_sensitive_typing.rb +471 -255
  89. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  90. data/lib/solargraph/parser/node_processor.rb +63 -62
  91. data/lib/solargraph/parser/parser_gem/class_methods.rb +165 -149
  92. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  93. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  94. data/lib/solargraph/parser/parser_gem/node_methods.rb +507 -486
  95. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  96. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  97. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  98. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +45 -46
  99. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  100. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
  101. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  102. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +42 -40
  103. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  104. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  105. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  106. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  108. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  109. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +51 -52
  110. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +302 -291
  111. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  112. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  113. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  114. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  115. data/lib/solargraph/parser/parser_gem.rb +14 -12
  116. data/lib/solargraph/parser/region.rb +75 -69
  117. data/lib/solargraph/parser/snippet.rb +19 -17
  118. data/lib/solargraph/parser.rb +25 -23
  119. data/lib/solargraph/pin/base.rb +773 -729
  120. data/lib/solargraph/pin/base_variable.rb +375 -126
  121. data/lib/solargraph/pin/block.rb +127 -104
  122. data/lib/solargraph/pin/breakable.rb +15 -9
  123. data/lib/solargraph/pin/callable.rb +275 -231
  124. data/lib/solargraph/pin/closure.rb +69 -72
  125. data/lib/solargraph/pin/common.rb +97 -79
  126. data/lib/solargraph/pin/compound_statement.rb +55 -0
  127. data/lib/solargraph/pin/constant.rb +43 -45
  128. data/lib/solargraph/pin/conversions.rb +129 -123
  129. data/lib/solargraph/pin/delegated_method.rb +131 -120
  130. data/lib/solargraph/pin/documenting.rb +116 -114
  131. data/lib/solargraph/pin/instance_variable.rb +38 -34
  132. data/lib/solargraph/pin/keyword.rb +16 -20
  133. data/lib/solargraph/pin/local_variable.rb +31 -75
  134. data/lib/solargraph/pin/method.rb +724 -672
  135. data/lib/solargraph/pin/method_alias.rb +42 -34
  136. data/lib/solargraph/pin/namespace.rb +122 -115
  137. data/lib/solargraph/pin/parameter.rb +339 -275
  138. data/lib/solargraph/pin/proxy_type.rb +42 -39
  139. data/lib/solargraph/pin/reference/override.rb +47 -47
  140. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  141. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  142. data/lib/solargraph/pin/reference.rb +59 -39
  143. data/lib/solargraph/pin/search.rb +62 -61
  144. data/lib/solargraph/pin/signature.rb +64 -61
  145. data/lib/solargraph/pin/symbol.rb +54 -53
  146. data/lib/solargraph/pin/until.rb +16 -18
  147. data/lib/solargraph/pin/while.rb +16 -18
  148. data/lib/solargraph/pin.rb +46 -44
  149. data/lib/solargraph/pin_cache.rb +248 -245
  150. data/lib/solargraph/position.rb +139 -119
  151. data/lib/solargraph/range.rb +113 -112
  152. data/lib/solargraph/rbs_map/conversions.rb +952 -823
  153. data/lib/solargraph/rbs_map/core_fills.rb +91 -84
  154. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  155. data/lib/solargraph/rbs_map/stdlib_map.rb +71 -43
  156. data/lib/solargraph/rbs_map.rb +207 -163
  157. data/lib/solargraph/server_methods.rb +16 -16
  158. data/lib/solargraph/shell.rb +555 -352
  159. data/lib/solargraph/source/chain/array.rb +39 -37
  160. data/lib/solargraph/source/chain/call.rb +377 -337
  161. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  162. data/lib/solargraph/source/chain/constant.rb +30 -26
  163. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  164. data/lib/solargraph/source/chain/hash.rb +37 -34
  165. data/lib/solargraph/source/chain/if.rb +30 -28
  166. data/lib/solargraph/source/chain/instance_variable.rb +36 -13
  167. data/lib/solargraph/source/chain/link.rb +99 -109
  168. data/lib/solargraph/source/chain/literal.rb +51 -48
  169. data/lib/solargraph/source/chain/or.rb +29 -23
  170. data/lib/solargraph/source/chain/q_call.rb +13 -11
  171. data/lib/solargraph/source/chain/variable.rb +15 -13
  172. data/lib/solargraph/source/chain/z_super.rb +28 -30
  173. data/lib/solargraph/source/chain.rb +304 -291
  174. data/lib/solargraph/source/change.rb +89 -82
  175. data/lib/solargraph/source/cursor.rb +172 -166
  176. data/lib/solargraph/source/encoding_fixes.rb +22 -23
  177. data/lib/solargraph/source/source_chainer.rb +218 -194
  178. data/lib/solargraph/source/updater.rb +59 -55
  179. data/lib/solargraph/source.rb +522 -498
  180. data/lib/solargraph/source_map/clip.rb +245 -226
  181. data/lib/solargraph/source_map/data.rb +37 -34
  182. data/lib/solargraph/source_map/mapper.rb +286 -259
  183. data/lib/solargraph/source_map.rb +224 -212
  184. data/lib/solargraph/type_checker/problem.rb +34 -32
  185. data/lib/solargraph/type_checker/rules.rb +157 -84
  186. data/lib/solargraph/type_checker.rb +888 -814
  187. data/lib/solargraph/version.rb +5 -5
  188. data/lib/solargraph/workspace/config.rb +258 -255
  189. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  190. data/lib/solargraph/workspace/require_paths.rb +98 -97
  191. data/lib/solargraph/workspace.rb +242 -220
  192. data/lib/solargraph/yard_map/helpers.rb +49 -44
  193. data/lib/solargraph/yard_map/mapper/to_method.rb +136 -130
  194. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  195. data/lib/solargraph/yard_map/mapper.rb +84 -79
  196. data/lib/solargraph/yard_map.rb +17 -18
  197. data/lib/solargraph/yard_tags.rb +20 -20
  198. data/lib/solargraph/yardoc.rb +90 -87
  199. data/lib/solargraph.rb +128 -105
  200. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  201. data/rbs/fills/tuple/tuple.rbs +28 -0
  202. data/rbs/shims/ast/0/node.rbs +5 -0
  203. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  204. data/rbs_collection.yaml +1 -1
  205. data/solargraph.gemspec +37 -35
  206. metadata +52 -51
  207. data/lib/solargraph/type_checker/checks.rb +0 -124
  208. data/lib/solargraph/type_checker/param_def.rb +0 -37
  209. data/lib/solargraph/yard_map/to_method.rb +0 -89
  210. data/sig/shims/ast/0/node.rbs +0 -5
  211. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  212. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  213. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  214. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  215. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  216. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  217. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  218. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  219. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,823 +1,952 @@
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
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
+ # @param loader [RBS::EnvironmentLoader]
41
+ #
42
+ # @return [void]
43
+ def load_environment_to_pins loader
44
+ environment = RBS::Environment.from_loader(loader).resolve_type_names
45
+ if environment.declarations.empty?
46
+ Solargraph.logger.info 'No RBS declarations found in environment for core_root ' \
47
+ "#{loader.core_root.inspect}, libraries #{loader.libs} and " \
48
+ "directories #{loader.dirs}"
49
+ return
50
+ end
51
+ environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
52
+ end
53
+
54
+ # @param decl [RBS::AST::Declarations::Base]
55
+ # @param closure [Pin::Closure]
56
+ # @return [void]
57
+ def convert_decl_to_pin decl, closure
58
+ case decl
59
+ when RBS::AST::Declarations::Class
60
+ # @sg-ignore flow sensitive typing should support case/when
61
+ unless closure.name == '' || decl.name.absolute?
62
+ Solargraph.assert_or_log(:rbs_closure, "Ignoring closure #{closure.inspect} on class #{decl.inspect}")
63
+ end
64
+ class_decl_to_pin decl
65
+ when RBS::AST::Declarations::Interface
66
+ # @sg-ignore flow sensitive typing should support case/when
67
+ unless closure.name == '' || decl.name.absolute?
68
+ Solargraph.assert_or_log(:rbs_closure, "Ignoring closure #{closure.inspect} on interface #{decl.inspect}")
69
+ end
70
+ # STDERR.puts "Skipping interface #{decl.name.relative!}"
71
+ interface_decl_to_pin decl
72
+ when RBS::AST::Declarations::TypeAlias
73
+ # @sg-ignore flow sensitive typing should support case/when
74
+ unless closure.name == '' || decl.name.absolute?
75
+ Solargraph.assert_or_log(:rbs_closure,
76
+ # @sg-ignore flow sensitive typing should support case/when
77
+ "Ignoring closure #{closure.inspect} on alias type name #{decl.name}")
78
+ end
79
+ pins.push(
80
+ # @sg-ignore Wrong argument type for Solargraph::Pin::Reference::TypeAlias.new: return_type expected Solargraph::ComplexType, received Solargraph::ComplexType::UniqueType, Solargraph::ComplexType
81
+ Solargraph::Pin::Reference::TypeAlias.new(
82
+ # @sg-ignore Unresolved calls to name, type, type_location; return_type type mismatch
83
+ name: ComplexType.try_parse(decl.name.to_s).to_s, return_type: other_type_to_type(decl.type).force_rooted, closure: closure, source: :rbs, type_location: location_decl_to_pin_location(decl.location)
84
+ )
85
+ )
86
+ when RBS::AST::Declarations::Module
87
+ # @sg-ignore flow sensitive typing should support case/when
88
+ unless closure.name == '' || decl.name.absolute?
89
+ Solargraph.assert_or_log(:rbs_closure,
90
+ # @sg-ignore flow sensitive typing should support case/when
91
+ "Ignoring closure #{closure.inspect} on alias type name #{decl.name}")
92
+ end
93
+ module_decl_to_pin decl
94
+ when RBS::AST::Declarations::Constant
95
+ # @sg-ignore flow sensitive typing should support case/when
96
+ unless closure.name == '' || decl.name.absolute?
97
+ Solargraph.assert_or_log(:rbs_closure, "Ignoring closure #{closure.inspect} on constant #{decl.inspect}")
98
+ end
99
+ constant_decl_to_pin decl
100
+ when RBS::AST::Declarations::ClassAlias
101
+ # @sg-ignore flow sensitive typing should support case/when
102
+ unless closure.name == '' || decl.new_name.absolute?
103
+ Solargraph.assert_or_log(:rbs_closure, "Ignoring closure #{closure.inspect} on class alias #{decl.inspect}")
104
+ end
105
+ class_alias_decl_to_pin decl
106
+ when RBS::AST::Declarations::ModuleAlias
107
+ unless closure.name == ''
108
+ Solargraph.assert_or_log(:rbs_closure,
109
+ "Ignoring closure #{closure.inspect} on module alias #{decl.inspect}")
110
+ end
111
+ module_alias_decl_to_pin decl
112
+ when RBS::AST::Declarations::Global
113
+ unless closure.name == ''
114
+ Solargraph.assert_or_log(:rbs_closure, "Ignoring closure #{closure.inspect} on global decl #{decl.inspect}")
115
+ end
116
+ global_decl_to_pin decl
117
+ else
118
+ Solargraph.logger.warn "Skipping declaration #{decl.class}"
119
+ end
120
+ end
121
+
122
+ # @param decl [RBS::AST::Declarations::Module]
123
+ # @param module_pin [Pin::Namespace]
124
+ # @return [void]
125
+ def convert_self_types_to_pins decl, module_pin
126
+ decl.self_types.each { |self_type| convert_self_type_to_pins(self_type, module_pin) }
127
+ end
128
+
129
+ # @type [Hash{String => String}]
130
+ RBS_TO_CLASS = {
131
+ 'bool' => 'Boolean',
132
+ 'string' => 'String',
133
+ 'int' => 'Integer'
134
+ }.freeze
135
+ private_constant :RBS_TO_CLASS
136
+
137
+ # rooted names (namespaces) use the prefix of :: when they are
138
+ # relative to the root namespace, or not if they are relative to
139
+ # the current namespace.
140
+ #
141
+ # @param type_name [RBS::TypeName]
142
+ #
143
+ # @return [String]
144
+ def rooted_name type_name
145
+ name = type_name.to_s
146
+ RBS_TO_CLASS.fetch(name, name)
147
+ end
148
+
149
+ # fqns names are implicitly fully qualified - they are relative
150
+ # to the root namespace and are not prefixed with ::
151
+ #
152
+ # @param type_name [RBS::TypeName]
153
+ #
154
+ # @return [String]
155
+ def fqns type_name
156
+ unless type_name.absolute?
157
+ Solargraph.assert_or_log(:rbs_fqns, "Received unexpected unqualified type name: #{type_name}")
158
+ end
159
+ ns = type_name.relative!.to_s
160
+ RBS_TO_CLASS.fetch(ns, ns)
161
+ end
162
+
163
+ # @param type_name [RBS::TypeName]
164
+ # @param type_args [Enumerable<RBS::Types::Bases::Base>]
165
+ # @return [ComplexType::UniqueType]
166
+ def build_type type_name, type_args = []
167
+ # we use .absolute? below to tell the type object what to
168
+ # expect
169
+ rbs_name = type_name.relative!.to_s
170
+ base = RBS_TO_CLASS.fetch(rbs_name, rbs_name)
171
+
172
+ params = type_args.map { |a| other_type_to_type(a) }
173
+ # tuples have their own class and are handled in other_type_to_type
174
+ if base == 'Hash' && params.length == 2
175
+ ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: type_name.absolute?,
176
+ parameters_type: :hash)
177
+ else
178
+ ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: type_name.absolute?,
179
+ parameters_type: :list)
180
+ end
181
+ end
182
+
183
+ # @param decl [RBS::AST::Declarations::Module::Self]
184
+ # @param closure [Pin::Namespace]
185
+ # @return [void]
186
+ def convert_self_type_to_pins decl, closure
187
+ type = build_type(decl.name, decl.args)
188
+ generic_values = type.all_params.map(&:rooted_tags)
189
+ include_pin = Solargraph::Pin::Reference::Include.new(
190
+ name: type.name,
191
+ type_location: location_decl_to_pin_location(decl.location),
192
+ generic_values: generic_values,
193
+ closure: closure,
194
+ source: :rbs
195
+ )
196
+ pins.push include_pin
197
+ end
198
+
199
+ # @param decl [RBS::AST::Declarations::Module,RBS::AST::Declarations::Class,RBS::AST::Declarations::Interface]
200
+ # @param closure [Pin::Namespace]
201
+ # @return [void]
202
+ def convert_members_to_pins decl, closure
203
+ context = Conversions::Context.new
204
+ decl.members.each { |m| context = convert_member_to_pin(m, closure, context) }
205
+ end
206
+
207
+ # @param member [RBS::AST::Members::Base,RBS::AST::Declarations::Base]
208
+ # @param closure [Pin::Namespace]
209
+ # @param context [Context]
210
+ # @return [Context]
211
+ def convert_member_to_pin member, closure, context
212
+ case member
213
+ when RBS::AST::Members::MethodDefinition
214
+ # @sg-ignore flow based typing needs to understand case when class pattern
215
+ method_def_to_pin(member, closure, context)
216
+ when RBS::AST::Members::AttrReader
217
+ # @sg-ignore flow based typing needs to understand case when class pattern
218
+ attr_reader_to_pin(member, closure, context)
219
+ when RBS::AST::Members::AttrWriter
220
+ # @sg-ignore flow based typing needs to understand case when class pattern
221
+ attr_writer_to_pin(member, closure, context)
222
+ when RBS::AST::Members::AttrAccessor
223
+ # @sg-ignore flow based typing needs to understand case when class pattern
224
+ attr_accessor_to_pin(member, closure, context)
225
+ when RBS::AST::Members::Include
226
+ # @sg-ignore flow based typing needs to understand case when class pattern
227
+ include_to_pin(member, closure)
228
+ when RBS::AST::Members::Prepend
229
+ # @sg-ignore flow based typing needs to understand case when class pattern
230
+ prepend_to_pin(member, closure)
231
+ when RBS::AST::Members::Extend
232
+ # @sg-ignore flow based typing needs to understand case when class pattern
233
+ extend_to_pin(member, closure)
234
+ when RBS::AST::Members::Alias
235
+ # @sg-ignore flow based typing needs to understand case when class pattern
236
+ alias_to_pin(member, closure)
237
+ when RBS::AST::Members::ClassInstanceVariable
238
+ # @sg-ignore flow based typing needs to understand case when class pattern
239
+ civar_to_pin(member, closure)
240
+ when RBS::AST::Members::ClassVariable
241
+ # @sg-ignore flow based typing needs to understand case when class pattern
242
+ cvar_to_pin(member, closure)
243
+ when RBS::AST::Members::InstanceVariable
244
+ # @sg-ignore flow based typing needs to understand case when class pattern
245
+ ivar_to_pin(member, closure)
246
+ when RBS::AST::Members::Public
247
+ return Context.new(:public)
248
+ when RBS::AST::Members::Private
249
+ return Context.new(:private)
250
+ when RBS::AST::Declarations::Base
251
+ # @sg-ignore flow based typing needs to understand case when class pattern
252
+ convert_decl_to_pin(member, closure)
253
+ else
254
+ Solargraph.logger.warn "Skipping member type #{member.class}"
255
+ end
256
+ context
257
+ end
258
+
259
+ # Pull the name of type variables for a generic - not the
260
+ # values, the names (e.g., T, U, V). As such, "rooting" isn't a
261
+ # thing, these are all in the global namespace.
262
+ #
263
+ # @param decl [RBS::AST::Declarations::Class, RBS::AST::Declarations::Interface,
264
+ # RBS::AST::Declarations::Module, RBS::MethodType]
265
+ #
266
+ # @return [Array<String>]
267
+ def type_parameter_names decl
268
+ decl.type_params.map(&:name).map(&:to_s)
269
+ end
270
+
271
+ # @param decl [RBS::AST::Declarations::Class]
272
+ # @return [void]
273
+ def class_decl_to_pin decl
274
+ # @type [Hash{String => ComplexType, ComplexType::UniqueType}]
275
+ generic_defaults = {}
276
+ decl.type_params.each do |param|
277
+ generic_defaults[param.name.to_s] = other_type_to_type param.default_type if param.default_type
278
+ end
279
+
280
+ class_name = fqns(decl.name)
281
+
282
+ generics = type_parameter_names(decl)
283
+
284
+ class_pin = Solargraph::Pin::Namespace.new(
285
+ type: :class,
286
+ name: class_name,
287
+ closure: Solargraph::Pin::ROOT_PIN,
288
+ comments: decl.comment&.string,
289
+ type_location: location_decl_to_pin_location(decl.location),
290
+ # @todo some type parameters in core/stdlib have default
291
+ # values; Solargraph doesn't support that yet as so these
292
+ # get treated as undefined if not specified
293
+ generics: generics,
294
+ generic_defaults: generic_defaults,
295
+ source: :rbs
296
+ )
297
+ pins.push class_pin
298
+ if decl.super_class
299
+ type = build_type(decl.super_class.name, decl.super_class.args)
300
+ generic_values = type.all_params.map(&:rooted_tags)
301
+ pins.push Solargraph::Pin::Reference::Superclass.new(
302
+ type_location: location_decl_to_pin_location(decl.super_class.location),
303
+ closure: class_pin,
304
+ generic_values: generic_values,
305
+ name: type.rooted_name, # reference pins use rooted names
306
+ source: :rbs
307
+ )
308
+ end
309
+ add_mixins decl, class_pin
310
+ convert_members_to_pins decl, class_pin
311
+ end
312
+
313
+ # @param decl [RBS::AST::Declarations::Interface]
314
+ # @return [void]
315
+ def interface_decl_to_pin decl
316
+ class_pin = Solargraph::Pin::Namespace.new(
317
+ type: :module,
318
+ type_location: location_decl_to_pin_location(decl.location),
319
+ name: fqns(decl.name),
320
+ closure: Solargraph::Pin::ROOT_PIN,
321
+ comments: decl.comment&.string,
322
+ generics: type_parameter_names(decl),
323
+ # HACK: Using :hidden to keep interfaces from appearing in
324
+ # autocompletion
325
+ visibility: :hidden,
326
+ source: :rbs
327
+ )
328
+ class_pin.docstring.add_tag(YARD::Tags::Tag.new(:abstract, '(RBS interface)'))
329
+ pins.push class_pin
330
+ convert_members_to_pins decl, class_pin
331
+ end
332
+
333
+ # @param decl [RBS::AST::Declarations::Module]
334
+ # @return [void]
335
+ def module_decl_to_pin decl
336
+ module_pin = Solargraph::Pin::Namespace.new(
337
+ type: :module,
338
+ name: fqns(decl.name),
339
+ type_location: location_decl_to_pin_location(decl.location),
340
+ closure: Solargraph::Pin::ROOT_PIN,
341
+ comments: decl.comment&.string,
342
+ generics: type_parameter_names(decl),
343
+ source: :rbs
344
+ )
345
+ pins.push module_pin
346
+ convert_self_types_to_pins decl, module_pin
347
+ convert_members_to_pins decl, module_pin
348
+
349
+ raise "Invalid type for module declaration: #{module_pin.class}" unless module_pin.is_a?(Pin::Namespace)
350
+
351
+ add_mixins decl, module_pin.closure
352
+ end
353
+
354
+ # @param fqns [String]
355
+ # @param type [ComplexType, ComplexType::UniqueType]
356
+ # @param comments [String, nil]
357
+ # @param decl [RBS::AST::Declarations::ClassAlias,
358
+ # RBS::AST::Declarations::Constant,
359
+ # RBS::AST::Declarations::ModuleAlias]
360
+ # @param base [String, nil] Optional conversion of tag to
361
+ # base<tag> - valid values are Class and Module
362
+ #
363
+ # @return [Solargraph::Pin::Constant]
364
+ def create_constant fqns, type, comments, decl, base = nil
365
+ parts = fqns.split('::')
366
+ if parts.length > 1
367
+ fqns = parts.last
368
+ # @sg-ignore Need to add nil check here
369
+ closure = pins.select { |pin| pin && pin.path == parts[0..-2].join('::') }.first
370
+ else
371
+ fqns = parts.first
372
+ closure = Solargraph::Pin::ROOT_PIN
373
+ end
374
+ constant_pin = Solargraph::Pin::Constant.new(
375
+ name: fqns,
376
+ closure: closure,
377
+ type_location: location_decl_to_pin_location(decl.location),
378
+ comments: comments,
379
+ source: :rbs
380
+ )
381
+ rooted_tag = type.rooted_tags
382
+ rooted_tag = "#{base}<#{rooted_tag}>" if base
383
+ constant_pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
384
+ constant_pin
385
+ end
386
+
387
+ # @param decl [RBS::AST::Declarations::ClassAlias]
388
+ # @return [void]
389
+ def class_alias_decl_to_pin decl
390
+ # See https://www.rubydoc.info/gems/rbs/3.4.3/RBS/AST/Declarations/ClassAlias
391
+ new_name = fqns(decl.new_name)
392
+ old_type = build_type(decl.old_name)
393
+ pins.push create_constant(new_name, old_type, decl.comment&.string, decl, '::Class')
394
+ end
395
+
396
+ # @param decl [RBS::AST::Declarations::ModuleAlias]
397
+ # @return [void]
398
+ def module_alias_decl_to_pin decl
399
+ # See https://www.rubydoc.info/gems/rbs/3.4.3/RBS/AST/Declarations/ModuleAlias
400
+ new_name = fqns(decl.new_name)
401
+ old_type = build_type(decl.old_name)
402
+
403
+ pins.push create_constant(new_name, old_type, decl.comment&.string, decl, '::Module')
404
+ end
405
+
406
+ # @param decl [RBS::AST::Declarations::Constant]
407
+ # @return [void]
408
+ def constant_decl_to_pin decl
409
+ target_type = other_type_to_type(decl.type)
410
+ constant_name = fqns(decl.name)
411
+ pins.push create_constant(constant_name, target_type, decl.comment&.string, decl)
412
+ end
413
+
414
+ # @param decl [RBS::AST::Declarations::Global]
415
+ # @return [void]
416
+ def global_decl_to_pin decl
417
+ closure = Solargraph::Pin::ROOT_PIN
418
+ name = decl.name.to_s
419
+ pin = Solargraph::Pin::GlobalVariable.new(
420
+ name: name,
421
+ closure: closure,
422
+ comments: decl.comment&.string,
423
+ type_location: location_decl_to_pin_location(decl.location),
424
+ source: :rbs
425
+ )
426
+ rooted_tag = other_type_to_type(decl.type).rooted_tags
427
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
428
+ pins.push pin
429
+ end
430
+
431
+ # Visibility overrides that will allow the Solargraph project
432
+ # and plugins to pass typechecking using SOLARGRAPH_ASSERTS=on,
433
+ # so that we can detect any regressions/issues elsewhere in the
434
+ # visibility logic.
435
+ #
436
+ # These should either reflect a bug upstream in the RBS
437
+ # definitions, or include a @todo indicating what needs to be
438
+ # fixed in Solargraph to properly understand it.
439
+ #
440
+ # @todo PR these fixes upstream and list open PRs here above
441
+ # related overrides
442
+ # @todo externalize remaining overrides into yaml file, then
443
+ # allow that to be extended via .solargraph.yml
444
+ # @type [Hash{Array(String, Symbol, String) => Symbol}
445
+ VISIBILITY_OVERRIDE = {
446
+ ['Rails::Engine', :instance, 'run_tasks_blocks'] => :protected,
447
+ # Should have been marked as both instance and class method in module -e.g., 'module_function'
448
+ ['Kernel', :instance, 'pretty_inspect'] => :private,
449
+ # marked incorrectly in RBS
450
+ ['WEBrick::HTTPUtils::FormData', :instance, 'next_data'] => :protected,
451
+ ['Rails::Command', :class, 'command_type'] => :private,
452
+ ['Rails::Command', :class, 'lookup_paths'] => :private,
453
+ ['Rails::Command', :class, 'file_lookup_paths'] => :private,
454
+ ['Rails::Railtie', :instance, 'run_console_blocks'] => :protected,
455
+ ['Rails::Railtie', :instance, 'run_generators_blocks'] => :protected,
456
+ ['Rails::Railtie', :instance, 'run_runner_blocks'] => :protected,
457
+ ['Rails::Railtie', :instance, 'run_tasks_blocks'] => :protected,
458
+ ['ActionController::Base', :instance, '_protected_ivars'] => :private,
459
+ ['ActionView::Template', :instance, 'method_name'] => :public,
460
+ ['Module', :instance, 'ruby2_keywords'] => :private,
461
+ ['Nokogiri::XML::Node', :instance, 'coerce'] => :protected,
462
+ ['Nokogiri::XML::Document', :class, 'empty_doc?'] => :private,
463
+ ['Nokogiri::Decorators::Slop', :instance, 'respond_to_missing?'] => :public,
464
+ ['RuboCop::Cop::RangeHelp', :instance, 'source_range'] => :private,
465
+ ['AST::Node', :instance, 'original_dup'] => :private,
466
+ ['Rainbow::Presenter', :instance, 'wrap_with_sgr'] => :private
467
+ }.freeze
468
+ private_constant :VISIBILITY_OVERRIDE
469
+
470
+ # @param decl [RBS::AST::Members::MethodDefinition, RBS::AST::Members::AttrReader,
471
+ # RBS::AST::Members::AttrWriter, RBS::AST::Members::AttrAccessor]
472
+ # @param closure [Pin::Closure]
473
+ # @param context [Context]
474
+ # @param scope [Symbol] :instance or :class
475
+ # @param name [String] The name of the method
476
+ # @return [Symbol]
477
+ # @sg-ignore Declared return type ::Symbol does not match inferred type
478
+ # ::Symbol, :public, :private, nil for Solargraph::RbsMap::Conversions#calculate_method_visibility
479
+ def calculate_method_visibility decl, context, closure, scope, name
480
+ override_key = [closure.path, scope, name]
481
+ visibility = VISIBILITY_OVERRIDE[override_key]
482
+ simple_override_key = [closure.path, scope]
483
+ visibility ||= VISIBILITY_OVERRIDE[simple_override_key]
484
+ if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(decl.name)
485
+ visibility ||= :private
486
+ end
487
+ if decl.kind == :singleton_instance
488
+ # this is a 'module function'
489
+ visibility ||= :private
490
+ end
491
+ visibility ||= decl.visibility
492
+ visibility ||= context.visibility
493
+ visibility ||= :public
494
+ visibility
495
+ end
496
+
497
+ # @param decl [RBS::AST::Members::MethodDefinition]
498
+ # @param closure [Pin::Closure]
499
+ # @param context [Context]
500
+ # @return [void]
501
+ def method_def_to_pin decl, closure, context
502
+ # there may be edge cases here around different signatures
503
+ # having different type params / orders - we may need to match
504
+ # this data model and have generics live in signatures to
505
+ # handle those correctly
506
+ generics = decl.overloads.map(&:method_type).map do |method_type|
507
+ type_parameter_names method_type
508
+ end
509
+
510
+ if decl.instance?
511
+ name = decl.name.to_s
512
+ final_scope = :instance
513
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
514
+ pin = Solargraph::Pin::Method.new(
515
+ name: name,
516
+ closure: closure,
517
+ type_location: location_decl_to_pin_location(decl.location),
518
+ comments: decl.comment&.string,
519
+ scope: final_scope,
520
+ signatures: [],
521
+ generics: generics,
522
+ visibility: visibility,
523
+ source: :rbs
524
+ )
525
+ pin.signatures.concat method_def_to_sigs(decl, pin)
526
+ pins.push pin
527
+ if pin.name == 'initialize'
528
+ pin.instance_variable_set(:@visibility, :private)
529
+ pin.instance_variable_set(:@return_type, ComplexType::VOID)
530
+ end
531
+ end
532
+ return unless decl.singleton?
533
+ final_scope = :class
534
+ name = decl.name.to_s
535
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
536
+ pin = Solargraph::Pin::Method.new(
537
+ name: name,
538
+ closure: closure,
539
+ comments: decl.comment&.string,
540
+ type_location: location_decl_to_pin_location(decl.location),
541
+ visibility: visibility,
542
+ scope: final_scope,
543
+ signatures: [],
544
+ generics: generics,
545
+ source: :rbs
546
+ )
547
+ pin.signatures.concat method_def_to_sigs(decl, pin)
548
+ pins.push pin
549
+ end
550
+
551
+ # @param decl [RBS::AST::Members::MethodDefinition]
552
+ # @param pin [Pin::Method]
553
+ # @return [void]
554
+ def method_def_to_sigs decl, pin
555
+ # @param overload [RBS::AST::Members::MethodDefinition::Overload]
556
+ decl.overloads.map do |overload|
557
+ # @sg-ignore Wrong argument type for Solargraph::RbsMap::Conversions#location_decl_to_pin_location:
558
+ # location expected RBS::Location, nil, received RBS::Location<:type, :type_params>, RBS::AST::Members::Attribute::loc, nil
559
+ type_location = location_decl_to_pin_location(overload.method_type.location)
560
+ generics = type_parameter_names(overload.method_type)
561
+ signature_parameters, signature_return_type = parts_of_function(overload.method_type, pin)
562
+ rbs_block = overload.method_type.block
563
+ block = if rbs_block
564
+ block_parameters, block_return_type = parts_of_function(rbs_block, pin)
565
+ Pin::Signature.new(generics: generics, parameters: block_parameters,
566
+ return_type: block_return_type, source: :rbs,
567
+ type_location: type_location, closure: pin)
568
+ end
569
+ Pin::Signature.new(generics: generics, parameters: signature_parameters,
570
+ return_type: signature_return_type, block: block, source: :rbs,
571
+ type_location: type_location, closure: pin)
572
+ end
573
+ end
574
+
575
+ # @param location [RBS::Location, nil]
576
+ # @return [Solargraph::Location, nil]
577
+ def location_decl_to_pin_location location
578
+ return nil if location&.name.nil?
579
+
580
+ # @sg-ignore flow sensitive typing should handle return nil if location&.name.nil?
581
+ start_pos = Position.new(location.start_line - 1, location.start_column)
582
+ # @sg-ignore flow sensitive typing should handle return nil if location&.name.nil?
583
+ end_pos = Position.new(location.end_line - 1, location.end_column)
584
+ range = Range.new(start_pos, end_pos)
585
+ # @sg-ignore flow sensitve typing should handle return nil if location&.name.nil?
586
+ Location.new(location.name.to_s, range)
587
+ end
588
+
589
+ # @param type [RBS::MethodType, RBS::Types::Block]
590
+ # @param pin [Pin::Method]
591
+ # @return [Array(Array<Pin::Parameter>, ComplexType)]
592
+ def parts_of_function type, pin
593
+ type_location = pin.type_location
594
+ if defined?(RBS::Types::UntypedFunction) && type.type.is_a?(RBS::Types::UntypedFunction)
595
+ return [
596
+ [Solargraph::Pin::Parameter.new(decl: :restarg, name: 'arg', closure: pin, source: :rbs,
597
+ type_location: type_location)],
598
+ method_type_to_type(type)
599
+ ]
600
+ end
601
+
602
+ parameters = []
603
+ arg_num = -1
604
+ type.type.required_positionals.each do |param|
605
+ # @sg-ignore Unresolved call to name
606
+ name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
607
+ parameters.push Solargraph::Pin::Parameter.new(decl: :arg, name: name, closure: pin,
608
+ # @sg-ignore RBS generic type understanding issue
609
+ return_type: other_type_to_type(param.type),
610
+ source: :rbs, type_location: type_location)
611
+ end
612
+ type.type.optional_positionals.each do |param|
613
+ # @sg-ignore Unresolved call to name
614
+ name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
615
+ parameters.push Solargraph::Pin::Parameter.new(decl: :optarg, name: name, closure: pin,
616
+ # @sg-ignore RBS generic type understanding issue
617
+ return_type: other_type_to_type(param.type),
618
+ type_location: type_location,
619
+ source: :rbs)
620
+ end
621
+ if type.type.rest_positionals
622
+ name = type.type.rest_positionals.name ? type.type.rest_positionals.name.to_s : "arg_#{arg_num += 1}"
623
+ inner_rest_positional_type = other_type_to_type(type.type.rest_positionals.type)
624
+ rest_positional_type = ComplexType::UniqueType.new('Array',
625
+ [],
626
+ [inner_rest_positional_type],
627
+ rooted: true, parameters_type: :list)
628
+ parameters.push Solargraph::Pin::Parameter.new(decl: :restarg, name: name, closure: pin,
629
+ source: :rbs, type_location: type_location,
630
+ return_type: rest_positional_type)
631
+ end
632
+ type.type.trailing_positionals.each do |param|
633
+ # @sg-ignore Unresolved call to name
634
+ name = param.name ? param.name.to_s : "arg_#{arg_num += 1}"
635
+ parameters.push Solargraph::Pin::Parameter.new(decl: :arg, name: name, closure: pin, source: :rbs,
636
+ type_location: type_location)
637
+ end
638
+ type.type.required_keywords.each do |orig, param|
639
+ # @sg-ignore Unresolved call to to_s
640
+ name = orig ? orig.to_s : "arg_#{arg_num += 1}"
641
+ parameters.push Solargraph::Pin::Parameter.new(decl: :kwarg, name: name, closure: pin,
642
+ # @sg-ignore RBS generic type understanding issue
643
+ return_type: other_type_to_type(param.type),
644
+ source: :rbs, type_location: type_location)
645
+ end
646
+ type.type.optional_keywords.each do |orig, param|
647
+ # @sg-ignore Unresolved call to to_s
648
+ name = orig ? orig.to_s : "arg_#{arg_num += 1}"
649
+ parameters.push Solargraph::Pin::Parameter.new(decl: :kwoptarg, name: name, closure: pin,
650
+ # @sg-ignore RBS generic type understanding issue
651
+ return_type: other_type_to_type(param.type),
652
+ type_location: type_location,
653
+ source: :rbs)
654
+ end
655
+ if type.type.rest_keywords
656
+ name = type.type.rest_keywords.name ? type.type.rest_keywords.name.to_s : "arg_#{arg_num += 1}"
657
+ parameters.push Solargraph::Pin::Parameter.new(decl: :kwrestarg,
658
+ name: type.type.rest_keywords.name.to_s, closure: pin,
659
+ source: :rbs, type_location: type_location)
660
+ end
661
+
662
+ return_type = method_type_to_type(type)
663
+ [parameters, return_type]
664
+ end
665
+
666
+ # @param decl [RBS::AST::Members::AttrReader,RBS::AST::Members::AttrAccessor]
667
+ # @param closure [Pin::Namespace]
668
+ # @param context [Context]
669
+ # @return [void]
670
+ def attr_reader_to_pin decl, closure, context
671
+ name = decl.name.to_s
672
+ final_scope = decl.kind == :instance ? :instance : :class
673
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
674
+ pin = Solargraph::Pin::Method.new(
675
+ name: name,
676
+ type_location: location_decl_to_pin_location(decl.location),
677
+ closure: closure,
678
+ comments: decl.comment&.string,
679
+ scope: final_scope,
680
+ attribute: true,
681
+ visibility: visibility,
682
+ source: :rbs
683
+ )
684
+ rooted_tag = other_type_to_type(decl.type).rooted_tags
685
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
686
+ logger.debug do
687
+ "Conversions#attr_reader_to_pin(name=#{name.inspect}, visibility=#{visibility.inspect}) => #{pin.inspect}"
688
+ end
689
+ pins.push pin
690
+ end
691
+
692
+ # @param decl [RBS::AST::Members::AttrWriter, RBS::AST::Members::AttrAccessor]
693
+ # @param closure [Pin::Namespace]
694
+ # @param context [Context]
695
+ # @return [void]
696
+ def attr_writer_to_pin decl, closure, context
697
+ final_scope = decl.kind == :instance ? :instance : :class
698
+ name = "#{decl.name}="
699
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
700
+ type_location = location_decl_to_pin_location(decl.location)
701
+ pin = Solargraph::Pin::Method.new(
702
+ name: name,
703
+ type_location: type_location,
704
+ closure: closure,
705
+ parameters: [],
706
+ comments: decl.comment&.string,
707
+ scope: final_scope,
708
+ attribute: true,
709
+ visibility: visibility,
710
+ source: :rbs
711
+ )
712
+ pin.parameters <<
713
+ Solargraph::Pin::Parameter.new(
714
+ name: 'value',
715
+ return_type: other_type_to_type(decl.type),
716
+ source: :rbs,
717
+ closure: pin,
718
+ type_location: type_location
719
+ )
720
+ rooted_tags = other_type_to_type(decl.type).rooted_tags
721
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tags))
722
+ pins.push pin
723
+ end
724
+
725
+ # @param decl [RBS::AST::Members::AttrAccessor]
726
+ # @param closure [Pin::Namespace]
727
+ # @param context [Context]
728
+ # @return [void]
729
+ def attr_accessor_to_pin decl, closure, context
730
+ attr_reader_to_pin(decl, closure, context)
731
+ attr_writer_to_pin(decl, closure, context)
732
+ end
733
+
734
+ # @param decl [RBS::AST::Members::InstanceVariable]
735
+ # @param closure [Pin::Namespace]
736
+ # @return [void]
737
+ def ivar_to_pin decl, closure
738
+ pin = Solargraph::Pin::InstanceVariable.new(
739
+ name: decl.name.to_s,
740
+ closure: closure,
741
+ type_location: location_decl_to_pin_location(decl.location),
742
+ comments: decl.comment&.string,
743
+ source: :rbs
744
+ )
745
+ rooted_tag = other_type_to_type(decl.type).rooted_tags
746
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
747
+ pins.push pin
748
+ end
749
+
750
+ # @param decl [RBS::AST::Members::ClassVariable]
751
+ # @param closure [Pin::Namespace]
752
+ # @return [void]
753
+ def cvar_to_pin decl, closure
754
+ name = decl.name.to_s
755
+ pin = Solargraph::Pin::ClassVariable.new(
756
+ name: name,
757
+ closure: closure,
758
+ comments: decl.comment&.string,
759
+ type_location: location_decl_to_pin_location(decl.location),
760
+ source: :rbs
761
+ )
762
+ rooted_tag = other_type_to_type(decl.type).rooted_tags
763
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
764
+ pins.push pin
765
+ end
766
+
767
+ # @param decl [RBS::AST::Members::ClassInstanceVariable]
768
+ # @param closure [Pin::Namespace]
769
+ # @return [void]
770
+ def civar_to_pin decl, closure
771
+ name = decl.name.to_s
772
+ pin = Solargraph::Pin::InstanceVariable.new(
773
+ name: name,
774
+ closure: closure,
775
+ comments: decl.comment&.string,
776
+ type_location: location_decl_to_pin_location(decl.location),
777
+ source: :rbs
778
+ )
779
+ rooted_tag = other_type_to_type(decl.type).rooted_tags
780
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
781
+ pins.push pin
782
+ end
783
+
784
+ # @param decl [RBS::AST::Members::Include]
785
+ # @param closure [Pin::Namespace]
786
+ # @return [void]
787
+ def include_to_pin decl, closure
788
+ type = build_type(decl.name, decl.args)
789
+ generic_values = type.all_params.map(&:rooted_tags)
790
+ pins.push Solargraph::Pin::Reference::Include.new(
791
+ name: type.rooted_name, # reference pins use rooted names
792
+ type_location: location_decl_to_pin_location(decl.location),
793
+ generic_values: generic_values,
794
+ closure: closure,
795
+ source: :rbs
796
+ )
797
+ end
798
+
799
+ # @param decl [RBS::AST::Members::Prepend]
800
+ # @param closure [Pin::Namespace]
801
+ # @return [void]
802
+ def prepend_to_pin decl, closure
803
+ type = build_type(decl.name, decl.args)
804
+ generic_values = type.all_params.map(&:rooted_tags)
805
+ pins.push Solargraph::Pin::Reference::Prepend.new(
806
+ name: type.rooted_name, # reference pins use rooted names
807
+ type_location: location_decl_to_pin_location(decl.location),
808
+ generic_values: generic_values,
809
+ closure: closure,
810
+ source: :rbs
811
+ )
812
+ end
813
+
814
+ # @param decl [RBS::AST::Members::Extend]
815
+ # @param closure [Pin::Namespace]
816
+ # @return [void]
817
+ def extend_to_pin decl, closure
818
+ type = build_type(decl.name, decl.args)
819
+ generic_values = type.all_params.map(&:rooted_tags)
820
+ pins.push Solargraph::Pin::Reference::Extend.new(
821
+ name: type.rooted_name, # reference pins use rooted names
822
+ type_location: location_decl_to_pin_location(decl.location),
823
+ generic_values: generic_values,
824
+ closure: closure,
825
+ source: :rbs
826
+ )
827
+ end
828
+
829
+ # @param decl [RBS::AST::Members::Alias]
830
+ # @param closure [Pin::Namespace]
831
+ # @return [void]
832
+ def alias_to_pin decl, closure
833
+ final_scope = decl.singleton? ? :class : :instance
834
+ pins.push Solargraph::Pin::MethodAlias.new(
835
+ name: decl.new_name.to_s,
836
+ type_location: location_decl_to_pin_location(decl.location),
837
+ original: decl.old_name.to_s,
838
+ closure: closure,
839
+ scope: final_scope,
840
+ source: :rbs
841
+ )
842
+ end
843
+
844
+ # @param type [RBS::MethodType, RBS::Types::Block]
845
+ # @return [ComplexType, ComplexType::UniqueType]
846
+ def method_type_to_type type
847
+ other_type_to_type type.type.return_type
848
+ end
849
+
850
+ # @param type [RBS::Types::Bases::Base,Object] RBS type object.
851
+ # Note: Generally these extend from RBS::Types::Bases::Base,
852
+ # but not all.
853
+ #
854
+ # @return [ComplexType, ComplexType::UniqueType]
855
+ def other_type_to_type type
856
+ case type
857
+ when RBS::Types::Optional
858
+ # @sg-ignore flow based typing needs to understand case when class pattern
859
+ ComplexType.new([other_type_to_type(type.type),
860
+ ComplexType::UniqueType::NIL])
861
+ when RBS::Types::Bases::Any
862
+ ComplexType::UNDEFINED
863
+ when RBS::Types::Bases::Bool
864
+ ComplexType::BOOLEAN
865
+ when RBS::Types::Tuple
866
+ # @sg-ignore flow based typing needs to understand case when class pattern
867
+ tuple_types = type.types.map { |t| other_type_to_type(t) }
868
+ ComplexType::UniqueType.new('Array', [], tuple_types, rooted: true, parameters_type: :fixed)
869
+ when RBS::Types::Literal
870
+ # @sg-ignore flow based typing needs to understand case when class pattern
871
+ ComplexType.try_parse(type.literal.inspect).force_rooted
872
+ when RBS::Types::Union
873
+ # @sg-ignore flow based typing needs to understand case when class pattern
874
+ ComplexType.new(type.types.map { |t| other_type_to_type(t) })
875
+ when RBS::Types::Record
876
+ # @todo Better record support
877
+ ComplexType::UniqueType.new('Hash', rooted: true)
878
+ when RBS::Types::Bases::Nil
879
+ ComplexType::NIL
880
+ when RBS::Types::Bases::Self
881
+ ComplexType::SELF
882
+ when RBS::Types::Bases::Void
883
+ ComplexType::VOID
884
+ when RBS::Types::Variable
885
+ # @sg-ignore flow based typing needs to understand case when class pattern
886
+ ComplexType.parse("generic<#{type.name}>").force_rooted
887
+ when RBS::Types::ClassInstance # && !type.args.empty?
888
+ # @sg-ignore flow based typing needs to understand case when class pattern
889
+ build_type(type.name, type.args)
890
+ when RBS::Types::Bases::Instance
891
+ ComplexType::SELF
892
+ when RBS::Types::Bases::Top
893
+ # top is the most super superclass
894
+ ComplexType::UniqueType.new('BasicObject', rooted: true)
895
+ when RBS::Types::Bases::Bottom
896
+ # bottom is used in contexts where nothing will ever return
897
+ # - e.g., it could be the return type of 'exit()' or 'raise'
898
+ #
899
+ # @todo define a specific bottom type and use it to
900
+ # determine dead code
901
+ ComplexType::UNDEFINED
902
+ when RBS::Types::Intersection
903
+ # @sg-ignore flow based typing needs to understand case when class pattern
904
+ ComplexType.new(type.types.map { |member| other_type_to_type(member) })
905
+ when RBS::Types::Proc
906
+ ComplexType::UniqueType.new('Proc', rooted: true)
907
+ when RBS::Types::Alias
908
+ # type-level alias use - e.g., 'bool' in "type bool = true | false"
909
+ # @todo ensure these get resolved after processing all aliases
910
+ # @todo handle recursive aliases
911
+ # @sg-ignore flow based typing needs to understand case when class pattern
912
+ build_type(type.name, type.args)
913
+ when RBS::Types::Interface
914
+ # represents a mix-in module which can be considered a
915
+ # subtype of a consumer of it
916
+ # @sg-ignore flow based typing needs to understand case when class pattern
917
+ build_type(type.name, type.args)
918
+ when RBS::Types::ClassSingleton
919
+ # e.g., singleton(String)
920
+ # @sg-ignore flow based typing needs to understand case when class pattern
921
+ build_type(type.name)
922
+ else
923
+ # RBS doesn't provide a common base class for its type AST nodes
924
+ #
925
+ # @sg-ignore all types should include location
926
+ Solargraph.logger.warn "Unrecognized RBS type: #{type.class} at #{type.location}"
927
+ ComplexType::UNDEFINED
928
+ end
929
+ end
930
+
931
+ # @param decl [RBS::AST::Declarations::Class, RBS::AST::Declarations::Module]
932
+ # @param namespace [Pin::Namespace, nil]
933
+ # @return [void]
934
+ def add_mixins decl, namespace
935
+ # @param mixin [RBS::AST::Members::Include, RBS::AST::Members::Extend, RBS::AST::Members::Prepend]
936
+ decl.each_mixin do |mixin|
937
+ # @todo are we handling prepend correctly?
938
+ klass = mixin.is_a?(RBS::AST::Members::Include) ? Pin::Reference::Include : Pin::Reference::Extend
939
+ type = build_type(mixin.name, mixin.args)
940
+ generic_values = type.all_params.map(&:rooted_tags)
941
+ pins.push klass.new(
942
+ name: type.rooted_name, # reference pins use rooted names
943
+ type_location: location_decl_to_pin_location(mixin.location),
944
+ generic_values: generic_values,
945
+ closure: namespace,
946
+ source: :rbs
947
+ )
948
+ end
949
+ end
950
+ end
951
+ end
952
+ end