solargraph 0.47.2 → 0.54.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 (191) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/plugins.yml +40 -0
  4. data/.github/workflows/rspec.yml +4 -8
  5. data/.github/workflows/typecheck.yml +34 -0
  6. data/.yardopts +2 -2
  7. data/CHANGELOG.md +166 -3
  8. data/LICENSE +1 -1
  9. data/README.md +19 -16
  10. data/SPONSORS.md +2 -9
  11. data/lib/solargraph/api_map/cache.rb +50 -20
  12. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  13. data/lib/solargraph/api_map/store.rb +68 -15
  14. data/lib/solargraph/api_map.rb +238 -112
  15. data/lib/solargraph/bench.rb +3 -2
  16. data/lib/solargraph/cache.rb +77 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +116 -35
  18. data/lib/solargraph/complex_type/unique_type.rb +261 -33
  19. data/lib/solargraph/complex_type.rb +149 -30
  20. data/lib/solargraph/convention/rakefile.rb +17 -0
  21. data/lib/solargraph/convention.rb +2 -3
  22. data/lib/solargraph/converters/dd.rb +5 -0
  23. data/lib/solargraph/converters/dl.rb +3 -0
  24. data/lib/solargraph/converters/dt.rb +3 -0
  25. data/lib/solargraph/diagnostics/rubocop.rb +23 -8
  26. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  27. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  28. data/lib/solargraph/diagnostics.rb +2 -2
  29. data/lib/solargraph/doc_map.rb +187 -0
  30. data/lib/solargraph/gem_pins.rb +72 -0
  31. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  32. data/lib/solargraph/language_server/host/dispatch.rb +22 -5
  33. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  34. data/lib/solargraph/language_server/host/sources.rb +8 -65
  35. data/lib/solargraph/language_server/host.rb +88 -93
  36. data/lib/solargraph/language_server/message/base.rb +1 -1
  37. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  38. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  39. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  40. data/lib/solargraph/language_server/message/initialize.rb +27 -0
  41. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  42. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  43. data/lib/solargraph/language_server/message/text_document/formatting.rb +5 -4
  44. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  46. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  47. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  48. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  49. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  50. data/lib/solargraph/language_server/message.rb +1 -0
  51. data/lib/solargraph/language_server/progress.rb +118 -0
  52. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  53. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  54. data/lib/solargraph/language_server.rb +1 -0
  55. data/lib/solargraph/library.rb +231 -104
  56. data/lib/solargraph/location.rb +1 -0
  57. data/lib/solargraph/page.rb +6 -0
  58. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  59. data/lib/solargraph/parser/node_methods.rb +47 -7
  60. data/lib/solargraph/parser/node_processor/base.rb +11 -1
  61. data/lib/solargraph/parser/node_processor.rb +1 -0
  62. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
  63. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
  66. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  68. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +14 -4
  71. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  72. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/def_node.rb +7 -20
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  77. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
  78. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  79. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  80. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  81. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +42 -0
  82. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +7 -5
  83. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
  84. data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
  85. data/lib/solargraph/parser/parser_gem.rb +12 -0
  86. data/lib/solargraph/parser/region.rb +1 -1
  87. data/lib/solargraph/parser/snippet.rb +2 -0
  88. data/lib/solargraph/parser.rb +9 -10
  89. data/lib/solargraph/pin/base.rb +69 -11
  90. data/lib/solargraph/pin/base_variable.rb +40 -7
  91. data/lib/solargraph/pin/block.rb +81 -33
  92. data/lib/solargraph/pin/closure.rb +17 -2
  93. data/lib/solargraph/pin/common.rb +7 -3
  94. data/lib/solargraph/pin/conversions.rb +34 -8
  95. data/lib/solargraph/pin/delegated_method.rb +101 -0
  96. data/lib/solargraph/pin/documenting.rb +25 -32
  97. data/lib/solargraph/pin/instance_variable.rb +4 -0
  98. data/lib/solargraph/pin/local_variable.rb +13 -1
  99. data/lib/solargraph/pin/method.rb +273 -17
  100. data/lib/solargraph/pin/namespace.rb +17 -1
  101. data/lib/solargraph/pin/parameter.rb +40 -28
  102. data/lib/solargraph/pin/reference/override.rb +2 -2
  103. data/lib/solargraph/pin/reference.rb +8 -0
  104. data/lib/solargraph/pin/search.rb +4 -4
  105. data/lib/solargraph/pin/signature.rb +143 -0
  106. data/lib/solargraph/pin.rb +2 -1
  107. data/lib/solargraph/range.rb +4 -6
  108. data/lib/solargraph/rbs_map/conversions.rb +607 -0
  109. data/lib/solargraph/rbs_map/core_fills.rb +50 -0
  110. data/lib/solargraph/rbs_map/core_map.rb +28 -0
  111. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -0
  112. data/lib/solargraph/rbs_map.rb +92 -0
  113. data/lib/solargraph/shell.rb +85 -59
  114. data/lib/solargraph/source/chain/array.rb +32 -0
  115. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  116. data/lib/solargraph/source/chain/call.rb +125 -61
  117. data/lib/solargraph/source/chain/constant.rb +15 -1
  118. data/lib/solargraph/source/chain/if.rb +23 -0
  119. data/lib/solargraph/source/chain/link.rb +8 -2
  120. data/lib/solargraph/source/chain/or.rb +1 -1
  121. data/lib/solargraph/source/chain/z_super.rb +3 -3
  122. data/lib/solargraph/source/chain.rb +64 -14
  123. data/lib/solargraph/source/change.rb +3 -0
  124. data/lib/solargraph/source/cursor.rb +2 -0
  125. data/lib/solargraph/source/source_chainer.rb +8 -5
  126. data/lib/solargraph/source/updater.rb +1 -0
  127. data/lib/solargraph/source.rb +18 -63
  128. data/lib/solargraph/source_map/clip.rb +31 -23
  129. data/lib/solargraph/source_map/mapper.rb +23 -7
  130. data/lib/solargraph/source_map.rb +36 -11
  131. data/lib/solargraph/type_checker/checks.rb +10 -2
  132. data/lib/solargraph/type_checker.rb +229 -100
  133. data/lib/solargraph/version.rb +1 -1
  134. data/lib/solargraph/views/environment.erb +2 -2
  135. data/lib/solargraph/workspace/config.rb +15 -11
  136. data/lib/solargraph/workspace.rb +41 -17
  137. data/lib/solargraph/yard_map/cache.rb +6 -0
  138. data/lib/solargraph/yard_map/helpers.rb +1 -1
  139. data/lib/solargraph/yard_map/mapper/to_method.rb +23 -7
  140. data/lib/solargraph/yard_map/mapper.rb +1 -1
  141. data/lib/solargraph/yard_map/to_method.rb +11 -4
  142. data/lib/solargraph/yard_map.rb +1 -443
  143. data/lib/solargraph/yard_tags.rb +20 -0
  144. data/lib/solargraph/yardoc.rb +52 -0
  145. data/lib/solargraph.rb +8 -6
  146. data/solargraph.gemspec +19 -8
  147. metadata +164 -99
  148. data/.travis.yml +0 -19
  149. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  150. data/lib/solargraph/compat.rb +0 -37
  151. data/lib/solargraph/convention/rspec.rb +0 -30
  152. data/lib/solargraph/documentor.rb +0 -76
  153. data/lib/solargraph/language_server/host/cataloger.rb +0 -56
  154. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  155. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  156. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  157. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  158. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
  159. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +0 -63
  160. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +0 -21
  161. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  162. data/lib/solargraph/parser/legacy.rb +0 -12
  163. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -144
  164. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  165. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  166. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  167. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  168. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -22
  169. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -57
  170. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  171. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  172. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  173. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  174. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  175. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  176. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  177. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  178. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  179. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -21
  180. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  181. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -277
  182. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +0 -18
  183. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  184. data/lib/solargraph/parser/rubyvm.rb +0 -40
  185. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  186. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  187. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  188. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  189. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  190. data/lib/yard-solargraph.rb +0 -33
  191. data/yardoc/2.2.2.tar.gz +0 -0
@@ -0,0 +1,495 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parser'
4
+ require 'ast'
5
+
6
+ # Teach AST::Node#children about its generic type
7
+ #
8
+ # @todo contribute back to https://github.com/ruby/gem_rbs_collection/blob/main/gems/ast/2.4/ast.rbs
9
+ #
10
+ # @!parse
11
+ # module ::AST
12
+ # class Node
13
+ # # New children
14
+ #
15
+ # # @return [Array<AST::Node>]
16
+ # attr_reader :children
17
+ # end
18
+ # end
19
+
20
+ # https://github.com/whitequark/parser
21
+ module Solargraph
22
+ module Parser
23
+ module ParserGem
24
+ module NodeMethods
25
+ module_function
26
+
27
+ # @param node [Parser::AST::Node]
28
+ # @return [String]
29
+ def unpack_name(node)
30
+ pack_name(node).join("::")
31
+ end
32
+
33
+ # @param node [Parser::AST::Node]
34
+ # @return [Array<String>]
35
+ def pack_name(node)
36
+ # @type [Array<String>]
37
+ parts = []
38
+ if node.is_a?(AST::Node)
39
+ node.children.each { |n|
40
+ if n.is_a?(AST::Node)
41
+ if n.type == :cbase
42
+ parts = [''] + pack_name(n)
43
+ else
44
+ parts += pack_name(n)
45
+ end
46
+ else
47
+ parts.push n unless n.nil?
48
+ end
49
+ }
50
+ end
51
+ parts
52
+ end
53
+
54
+ # @param node [Parser::AST::Node]
55
+ # @return [String, nil]
56
+ def infer_literal_node_type node
57
+ return nil unless node.is_a?(AST::Node)
58
+ if node.type == :str || node.type == :dstr
59
+ return '::String'
60
+ elsif node.type == :array
61
+ return '::Array'
62
+ elsif node.type == :hash
63
+ return '::Hash'
64
+ elsif node.type == :int
65
+ return '::Integer'
66
+ elsif node.type == :float
67
+ return '::Float'
68
+ elsif node.type == :sym || node.type == :dsym
69
+ return '::Symbol'
70
+ elsif node.type == :regexp
71
+ return '::Regexp'
72
+ elsif node.type == :irange
73
+ return '::Range'
74
+ elsif node.type == :true || node.type == :false
75
+ return '::Boolean'
76
+ # @todo Support `nil` keyword in types
77
+ # elsif node.type == :nil
78
+ # return 'NilClass'
79
+ end
80
+ nil
81
+ end
82
+
83
+ # @param node [Parser::AST::Node]
84
+ # @return [Position]
85
+ def get_node_start_position(node)
86
+ Position.new(node.loc.line, node.loc.column)
87
+ end
88
+
89
+ # @param node [Parser::AST::Node]
90
+ # @return [Position]
91
+ def get_node_end_position(node)
92
+ Position.new(node.loc.last_line, node.loc.last_column)
93
+ end
94
+
95
+ # @param node [Parser::AST::Node]
96
+ # @param signature [String]
97
+ #
98
+ # @return [String]
99
+ def drill_signature node, signature
100
+ return signature unless node.is_a?(AST::Node)
101
+ if node.type == :const or node.type == :cbase
102
+ unless node.children[0].nil?
103
+ signature += drill_signature(node.children[0], signature)
104
+ end
105
+ signature += '::' unless signature.empty?
106
+ signature += node.children[1].to_s
107
+ elsif node.type == :lvar or node.type == :ivar or node.type == :cvar
108
+ signature += '.' unless signature.empty?
109
+ signature += node.children[0].to_s
110
+ elsif node.type == :send
111
+ unless node.children[0].nil?
112
+ signature += drill_signature(node.children[0], signature)
113
+ end
114
+ signature += '.' unless signature.empty?
115
+ signature += node.children[1].to_s
116
+ end
117
+ signature
118
+ end
119
+
120
+ # @param node [Parser::AST::Node]
121
+ # @return [Hash{Parser::AST::Node => Chain}]
122
+ def convert_hash node
123
+ return {} unless Parser.is_ast_node?(node)
124
+ return convert_hash(node.children[0]) if node.type == :kwsplat
125
+ return convert_hash(node.children[0]) if Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat
126
+ return {} unless node.type == :hash
127
+ result = {}
128
+ node.children.each do |pair|
129
+ result[pair.children[0].children[0]] = Solargraph::Parser.chain(pair.children[1])
130
+ end
131
+ result
132
+ end
133
+
134
+ NIL_NODE = ::Parser::AST::Node.new(:nil)
135
+
136
+ # @param node [Parser::AST::Node]
137
+ #
138
+ # @return [Array<Parser::AST::Node>]
139
+ def const_nodes_from node
140
+ return [] unless Parser.is_ast_node?(node)
141
+ result = []
142
+ if node.type == :const
143
+ result.push node
144
+ else
145
+ node.children.each { |child| result.concat const_nodes_from(child) }
146
+ end
147
+ result
148
+ end
149
+
150
+ # @param node [Parser::AST::Node]
151
+ def splatted_hash? node
152
+ Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat
153
+ end
154
+
155
+ # @param node [Parser::AST::Node]
156
+ def splatted_call? node
157
+ return false unless Parser.is_ast_node?(node)
158
+ Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat && node.children[0].children[0].type != :hash
159
+ end
160
+
161
+ # @param nodes [Enumerable<Parser::AST::Node>]
162
+ def any_splatted_call?(nodes)
163
+ nodes.any? { |n| splatted_call?(n) }
164
+ end
165
+
166
+ # @todo Temporarily here for testing. Move to Solargraph::Parser.
167
+ # @param node [Parser::AST::Node]
168
+ # @return [Array<Parser::AST::Node>]
169
+ def call_nodes_from node
170
+ return [] unless node.is_a?(::Parser::AST::Node)
171
+ result = []
172
+ if node.type == :block
173
+ result.push node
174
+ if Parser.is_ast_node?(node.children[0]) && node.children[0].children.length > 2
175
+ node.children[0].children[2..-1].each { |child| result.concat call_nodes_from(child) }
176
+ end
177
+ node.children[1..-1].each { |child| result.concat call_nodes_from(child) }
178
+ elsif node.type == :send
179
+ result.push node
180
+ node.children[2..-1].each { |child| result.concat call_nodes_from(child) }
181
+ elsif [:super, :zsuper].include?(node.type)
182
+ result.push node
183
+ node.children.each { |child| result.concat call_nodes_from(child) }
184
+ else
185
+ node.children.each { |child| result.concat call_nodes_from(child) }
186
+ end
187
+ result
188
+ end
189
+
190
+ # Find all the nodes within the provided node that potentially return a
191
+ # value.
192
+ #
193
+ # The node parameter typically represents a method's logic, e.g., the
194
+ # second child (after the :args node) of a :def node. A simple one-line
195
+ # method would typically return itself, while a node with conditions
196
+ # would return the resulting node from each conditional branch. Nodes
197
+ # that follow a :return node are assumed to be unreachable. Nil values
198
+ # are converted to nil node types.
199
+ #
200
+ # @param node [Parser::AST::Node]
201
+ # @return [Array<Parser::AST::Node>]
202
+ def returns_from_method_body node
203
+ # @todo is the || NIL_NODE necessary?
204
+ # STDERR.puts("Evaluating expression: #{node.inspect}")
205
+ DeepInference.from_method_body(node).map { |n| n || NIL_NODE }
206
+ end
207
+
208
+ # @param node [Parser::AST::Node]
209
+ # @return [Array<AST::Node>] low-level value nodes in
210
+ # value position. Does not include explicit return
211
+ # statements
212
+ def value_position_nodes_only(node)
213
+ DeepInference.value_position_nodes_only(node).map { |n| n || NIL_NODE }
214
+ end
215
+
216
+ # @param cursor [Solargraph::Source::Cursor]
217
+ # @return [Parser::AST::Node, nil]
218
+ def find_recipient_node cursor
219
+ return repaired_find_recipient_node(cursor) if cursor.source.repaired? && cursor.source.code[cursor.offset - 1] == '('
220
+ source = cursor.source
221
+ position = cursor.position
222
+ offset = cursor.offset
223
+ tree = if source.synchronized?
224
+ match = source.code[0..offset-1].match(/,\s*\z/)
225
+ if match
226
+ source.tree_at(position.line, position.column - match[0].length)
227
+ else
228
+ source.tree_at(position.line, position.column)
229
+ end
230
+ else
231
+ source.tree_at(position.line, position.column - 1)
232
+ end
233
+ prev = nil
234
+ tree.each do |node|
235
+ if node.type == :send
236
+ args = node.children[2..-1]
237
+ if !args.empty?
238
+ return node if prev && args.include?(prev)
239
+ else
240
+ if source.synchronized?
241
+ return node if source.code[0..offset-1] =~ /\(\s*\z/ && source.code[offset..-1] =~ /^\s*\)/
242
+ else
243
+ return node if source.code[0..offset-1] =~ /\([^\(]*\z/
244
+ end
245
+ end
246
+ end
247
+ prev = node
248
+ end
249
+ nil
250
+ end
251
+
252
+ # @param cursor [Solargraph::Source::Cursor]
253
+ # @return [Parser::AST::Node, nil]
254
+ def repaired_find_recipient_node cursor
255
+ cursor = cursor.source.cursor_at([cursor.position.line, cursor.position.column - 1])
256
+ node = cursor.source.tree_at(cursor.position.line, cursor.position.column).first
257
+ return node if node && node.type == :send
258
+ end
259
+
260
+ #
261
+ # Concepts:
262
+ #
263
+ # - statement - one single node in the AST. Generally used
264
+ # synonymously with how the Parser gem uses the term
265
+ # 'expression'. This may have side effects (e.g.,
266
+ # registering a method in the namespace, modifying
267
+ # variables or doing I/O). It may encapsulate multiple
268
+ # other statements (see compound statement).
269
+ #
270
+ # - value - something that can be assigned to a variable by
271
+ # evaluating a statement
272
+ #
273
+ # - value node - the 'lowest level' AST node whose return
274
+ # type is a subset of the value type of the overall
275
+ # statement. Might be a literal, a method call, etc - the
276
+ # goal is to find the lowest level node, which we can use
277
+ # Chains and Pins later on to determine the type of.
278
+ #
279
+ # e.g., if the node 'b ? 123 : 456' were a return value, we
280
+ # know the actual return values possible are 123 and 456,
281
+ # and can disregard the rest.
282
+ #
283
+ # - value type - the type representing the multiple possible
284
+ # values that can result from evaluation of the statement.
285
+ #
286
+ # - return type - the type describing the values a statement
287
+ # might evaluate to. When used with a method, the term
288
+ # describes the values that may result from the method
289
+ # being called, and includes explicit return statements
290
+ # within the method body's closure.
291
+ #
292
+ # - method body - a compound statement with parameters whose
293
+ # return value type must account both for the explicit
294
+ # 'return' statemnts as well as the final statements
295
+ # executed in any given control flow through the method.
296
+ #
297
+ # - explicit return statement - a statement which, when part of a
298
+ # method body, is a possible value of a call to that method -
299
+ # e.g., "return 123"
300
+ #
301
+ # - compound statement - a statement which can be expanded to
302
+ # be multiple statements in a row, executed in the context
303
+ # of a method which can be explicitly returned from.
304
+ #
305
+ # - value position - the positions in the AST where the
306
+ # return type of the statement would be one of the return
307
+ # types of any compound statements it is a part of. For a
308
+ # compound statement, the last of the child statements
309
+ # would be in return position. This concept can be applied
310
+ # recursively through e.g. conditionals to find a list of
311
+ # statements in value positions.
312
+ module DeepInference
313
+ class << self
314
+ CONDITIONAL_ALL_BUT_FIRST = [:if, :unless, :or_asgn]
315
+ CONDITIONAL_ALL = [:or]
316
+ ONLY_ONE_CHILD = [:return]
317
+ FIRST_TWO_CHILDREN = [:rescue]
318
+ COMPOUND_STATEMENTS = [:begin, :kwbegin]
319
+ SKIPPABLE = [:def, :defs, :class, :sclass, :module]
320
+ FUNCTION_VALUE = [:block]
321
+ CASE_STATEMENT = [:case]
322
+
323
+ # @param node [AST::Node] a method body compound statement
324
+ # @param include_explicit_returns [Boolean] If true,
325
+ # include the value nodes of the parameter of the
326
+ # 'return' statements in the type returned.
327
+ # @return [Array<AST::Node>] low-level value nodes from
328
+ # both nodes in value position as well as explicit
329
+ # return statements in the method's closure.
330
+ def from_method_body node
331
+ from_value_position_statement(node, include_explicit_returns: true)
332
+ end
333
+
334
+ # @param node [AST::Node] an individual statement, to be
335
+ # evaluated outside the context of a containing method
336
+ # @return [Array<AST::Node>] low-level value nodes in
337
+ # value position. Does not include explicit return
338
+ # statements
339
+ def value_position_nodes_only(node)
340
+ from_value_position_statement(node, include_explicit_returns: false)
341
+ end
342
+
343
+ # Look at known control statements and use them to find
344
+ # more specific return nodes.
345
+ #
346
+ # @param node [Parser::AST::Node] Statement which is in
347
+ # value position for a method body
348
+ # @param include_explicit_returns [Boolean] If true,
349
+ # include the value nodes of the parameter of the
350
+ # 'return' statements in the type returned.
351
+ # @return [Array<Parser::AST::Node>]
352
+ def from_value_position_statement node, include_explicit_returns: true
353
+ # STDERR.puts("from_expression called on #{node.inspect}")
354
+ return [] unless node.is_a?(::Parser::AST::Node)
355
+ # @type [Array<Parser::AST::Node>]
356
+ result = []
357
+ if COMPOUND_STATEMENTS.include?(node.type)
358
+ result.concat from_value_position_compound_statement node
359
+ elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
360
+ result.concat reduce_to_value_nodes(node.children[1..-1])
361
+ # result.push NIL_NODE unless node.children[2]
362
+ elsif CONDITIONAL_ALL.include?(node.type)
363
+ result.concat reduce_to_value_nodes(node.children)
364
+ elsif ONLY_ONE_CHILD.include?(node.type)
365
+ result.concat reduce_to_value_nodes([node.children[0]])
366
+ elsif FIRST_TWO_CHILDREN.include?(node.type)
367
+ result.concat reduce_to_value_nodes([node.children[0], node.children[1]])
368
+ elsif FUNCTION_VALUE.include?(node.type)
369
+ # the block itself is a first class value that could be returned
370
+ result.push node
371
+ # @todo any explicit returns actually return from
372
+ # scope in which the proc is run. This asssumes
373
+ # that the function is executed here.
374
+ result.concat explicit_return_values_from_compound_statement(node.children[2]) if include_explicit_returns
375
+ elsif CASE_STATEMENT.include?(node.type)
376
+ node.children[1..-1].each do |cc|
377
+ if cc.nil?
378
+ result.push NIL_NODE
379
+ elsif cc.type == :when
380
+ result.concat reduce_to_value_nodes([cc.children.last])
381
+ else
382
+ # else clause in case
383
+ result.concat reduce_to_value_nodes([cc])
384
+ end
385
+ end
386
+ elsif node.type == :resbody
387
+ result.concat reduce_to_value_nodes([node.children[2]])
388
+ else
389
+ result.push node
390
+ end
391
+ result
392
+ end
393
+
394
+ # Treat parent as as a begin block and use the last node's
395
+ # return node plus any explicit return nodes' return nodes. e.g.,
396
+ #
397
+ # 123
398
+ # 456
399
+ # return 'a' if foo == bar
400
+ # 789
401
+ #
402
+ # would return 'a' and 789.
403
+ #
404
+ # @param parent [Parser::AST::Node]
405
+ #
406
+ # @return [Array<Parser::AST::Node>]
407
+ def from_value_position_compound_statement parent
408
+ result = []
409
+ nodes = parent.children.select{|n| n.is_a?(AST::Node)}
410
+ nodes.each_with_index do |node, idx|
411
+ if node.type == :block
412
+ result.concat explicit_return_values_from_compound_statement(node.children[2])
413
+ elsif node.type == :rescue
414
+ # body statements
415
+ result.concat from_value_position_statement(node.children[0])
416
+ # rescue statements
417
+ result.concat from_value_position_statement(node.children[1])
418
+ elsif SKIPPABLE.include?(node.type)
419
+ next
420
+ elsif node.type == :resbody
421
+ result.concat reduce_to_value_nodes([node.children[2]])
422
+ elsif node.type == :return
423
+ result.concat reduce_to_value_nodes([node.children[0]])
424
+ # Return here because the rest of the code is
425
+ # unreachable and shouldn't be looked at
426
+ return result
427
+ else
428
+ result.concat explicit_return_values_from_compound_statement(node)
429
+ end
430
+ # handle last line of compound statements, which is in
431
+ # value position. we already have the explicit values
432
+ # from above; now we need to also gather the value
433
+ # position nodes
434
+ result.concat from_value_position_statement(nodes.last, include_explicit_returns: false) if idx == nodes.length - 1
435
+ end
436
+ result
437
+ end
438
+
439
+ private
440
+
441
+ # Useful when this statement isn't in value position, but
442
+ # we care explicit return statements nonetheless.
443
+ #
444
+ # @param parent [Parser::AST::Node]
445
+ #
446
+ # @return [Array<Parser::AST::Node>]
447
+ def explicit_return_values_from_compound_statement parent
448
+ return [] unless parent.is_a?(::Parser::AST::Node)
449
+ result = []
450
+ nodes = parent.children.select{|n| n.is_a?(::Parser::AST::Node)}
451
+ nodes.each do |node|
452
+ next if SKIPPABLE.include?(node.type)
453
+ if node.type == :return
454
+ result.concat reduce_to_value_nodes([node.children[0]])
455
+ # Return the result here because the rest of the code is
456
+ # unreachable
457
+ return result
458
+ else
459
+ result.concat explicit_return_values_from_compound_statement(node)
460
+ end
461
+ end
462
+ result
463
+ end
464
+
465
+ # @param nodes [Enumerable<Parser::AST::Node, BaseObject>]
466
+ # @return [Array<Parser::AST::Node, nil>]
467
+ def reduce_to_value_nodes nodes
468
+ result = []
469
+ nodes.each do |node|
470
+ if !node.is_a?(::Parser::AST::Node)
471
+ result.push nil
472
+ elsif COMPOUND_STATEMENTS.include?(node.type)
473
+ result.concat from_value_position_compound_statement(node)
474
+ elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
475
+ result.concat reduce_to_value_nodes(node.children[1..-1])
476
+ elsif node.type == :return
477
+ result.concat reduce_to_value_nodes([node.children[0]])
478
+ elsif node.type == :or
479
+ result.concat reduce_to_value_nodes(node.children)
480
+ elsif node.type == :block
481
+ result.concat explicit_return_values_from_compound_statement(node.children[2])
482
+ elsif node.type == :resbody
483
+ result.concat reduce_to_value_nodes([node.children[2]])
484
+ else
485
+ result.push node
486
+ end
487
+ end
488
+ result
489
+ end
490
+ end
491
+ end
492
+ end
493
+ end
494
+ end
495
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Rubyvm
5
+ module ParserGem
6
6
  module NodeProcessors
7
7
  class AliasNode < Parser::NodeProcessor::Base
8
8
  def process
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class ArgsNode < Parser::NodeProcessor::Base
8
+ def process
9
+ if node.type == :forward_args
10
+ forward
11
+ else
12
+ node.children.each do |u|
13
+ loc = get_node_location(u)
14
+ locals.push Solargraph::Pin::Parameter.new(
15
+ location: loc,
16
+ closure: region.closure,
17
+ comments: comments_for(node),
18
+ name: u.children[0].to_s,
19
+ assignment: u.children[1],
20
+ asgn_code: u.children[1] ? region.code_for(u.children[1]) : nil,
21
+ presence: region.closure.location.range,
22
+ decl: get_decl(u)
23
+ )
24
+ region.closure.parameters.push locals.last
25
+ end
26
+ end
27
+ process_children
28
+ end
29
+
30
+ private
31
+
32
+ # @return [void]
33
+ def forward
34
+ loc = get_node_location(node)
35
+ locals.push Solargraph::Pin::Parameter.new(
36
+ location: loc,
37
+ closure: region.closure,
38
+ presence: region.closure.location.range,
39
+ decl: get_decl(node)
40
+ )
41
+ region.closure.parameters.push locals.last
42
+ end
43
+
44
+ # @param node [AST::Node]
45
+ # @return [Symbol]
46
+ def get_decl node
47
+ node.type
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Rubyvm
5
+ module ParserGem
6
6
  module NodeProcessors
7
7
  class BeginNode < Parser::NodeProcessor::Base
8
8
  def process
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Legacy
5
+ module ParserGem
6
6
  module NodeProcessors
7
7
  class BlockNode < Parser::NodeProcessor::Base
8
- include Legacy::NodeMethods
8
+ include ParserGem::NodeMethods
9
9
 
10
10
  def process
11
11
  location = get_node_location(node)
@@ -21,6 +21,7 @@ module Solargraph
21
21
  pins.push Solargraph::Pin::Block.new(
22
22
  location: location,
23
23
  closure: parent,
24
+ node: node,
24
25
  receiver: node.children[0],
25
26
  comments: comments_for(node),
26
27
  scope: region.scope || region.closure.context.scope
@@ -2,22 +2,32 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Legacy
5
+ module ParserGem
6
6
  module NodeProcessors
7
7
  class CasgnNode < Parser::NodeProcessor::Base
8
- include Legacy::NodeMethods
8
+ include ParserGem::NodeMethods
9
9
 
10
10
  def process
11
- here = get_node_start_position(node)
12
11
  pins.push Solargraph::Pin::Constant.new(
13
12
  location: get_node_location(node),
14
13
  closure: region.closure,
15
- name: node.children[1].to_s,
14
+ name: const_name,
16
15
  comments: comments_for(node),
17
16
  assignment: node.children[2]
18
17
  )
19
18
  process_children
20
19
  end
20
+
21
+ private
22
+
23
+ # @return [String]
24
+ def const_name
25
+ if node.children[0]
26
+ Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
27
+ else
28
+ node.children[1].to_s
29
+ end
30
+ end
21
31
  end
22
32
  end
23
33
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Rubyvm
5
+ module ParserGem
6
6
  module NodeProcessors
7
7
  class CvasgnNode < Parser::NodeProcessor::Base
8
8
  def process
@@ -2,35 +2,22 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Rubyvm
5
+ module ParserGem
6
6
  module NodeProcessors
7
7
  class DefNode < Parser::NodeProcessor::Base
8
8
  def process
9
+ name = node.children[0].to_s
10
+ scope = region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance)
9
11
  methpin = Solargraph::Pin::Method.new(
10
12
  location: get_node_location(node),
11
13
  closure: region.closure,
12
- name: node.children[0].to_s,
14
+ name: name,
13
15
  comments: comments_for(node),
14
- scope: region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance),
15
- visibility: region.visibility,
16
+ scope: scope,
17
+ visibility: scope == :instance && name == 'initialize' ? :private : region.visibility,
16
18
  node: node
17
19
  )
18
- if methpin.name == 'initialize' and methpin.scope == :instance
19
- pins.push Solargraph::Pin::Method.new(
20
- location: methpin.location,
21
- closure: methpin.closure,
22
- name: 'new',
23
- comments: methpin.comments,
24
- scope: :class,
25
- parameters: methpin.parameters
26
- )
27
- # @todo Smelly instance variable access.
28
- pins.last.instance_variable_set(:@return_type, ComplexType::SELF)
29
- pins.push methpin
30
- # @todo Smelly instance variable access.
31
- methpin.instance_variable_set(:@visibility, :private)
32
- methpin.instance_variable_set(:@return_type, ComplexType::VOID)
33
- elsif region.visibility == :module_function
20
+ if region.visibility == :module_function
34
21
  pins.push Solargraph::Pin::Method.new(
35
22
  location: methpin.location,
36
23
  closure: methpin.closure,
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Legacy
5
+ module ParserGem
6
6
  module NodeProcessors
7
7
  class DefsNode < DefNode
8
- include Legacy::NodeMethods
8
+ include ParserGem::NodeMethods
9
9
 
10
10
  def process
11
11
  s_visi = region.visibility