solargraph 0.58.3 → 0.59.2

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +12 -5
  4. data/.github/workflows/plugins.yml +54 -34
  5. data/.github/workflows/rspec.yml +15 -28
  6. data/.github/workflows/typecheck.yml +6 -3
  7. data/.rubocop.yml +38 -6
  8. data/.rubocop_todo.yml +53 -966
  9. data/CHANGELOG.md +24 -0
  10. data/Gemfile +3 -1
  11. data/README.md +3 -3
  12. data/Rakefile +26 -23
  13. data/bin/solargraph +2 -1
  14. data/lib/solargraph/api_map/cache.rb +3 -3
  15. data/lib/solargraph/api_map/constants.rb +12 -3
  16. data/lib/solargraph/api_map/index.rb +29 -18
  17. data/lib/solargraph/api_map/source_to_yard.rb +22 -9
  18. data/lib/solargraph/api_map/store.rb +40 -30
  19. data/lib/solargraph/api_map.rb +160 -78
  20. data/lib/solargraph/bench.rb +2 -3
  21. data/lib/solargraph/complex_type/conformance.rb +176 -0
  22. data/lib/solargraph/complex_type/type_methods.rb +31 -18
  23. data/lib/solargraph/complex_type/unique_type.rb +221 -63
  24. data/lib/solargraph/complex_type.rb +173 -59
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -111
  26. data/lib/solargraph/convention/base.rb +50 -50
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -1
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +7 -5
  29. data/lib/solargraph/convention/data_definition.rb +5 -2
  30. data/lib/solargraph/convention/gemfile.rb +1 -1
  31. data/lib/solargraph/convention/gemspec.rb +1 -1
  32. data/lib/solargraph/convention/rakefile.rb +1 -1
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -3
  35. data/lib/solargraph/convention/struct_definition.rb +8 -4
  36. data/lib/solargraph/convention.rb +2 -2
  37. data/lib/solargraph/converters/dd.rb +2 -0
  38. data/lib/solargraph/converters/dl.rb +2 -0
  39. data/lib/solargraph/converters/dt.rb +2 -0
  40. data/lib/solargraph/converters/misc.rb +2 -0
  41. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  42. data/lib/solargraph/diagnostics/rubocop.rb +11 -10
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  44. data/lib/solargraph/diagnostics/type_check.rb +11 -10
  45. data/lib/solargraph/diagnostics/update_errors.rb +4 -8
  46. data/lib/solargraph/diagnostics.rb +55 -55
  47. data/lib/solargraph/doc_map.rb +38 -39
  48. data/lib/solargraph/environ.rb +52 -52
  49. data/lib/solargraph/equality.rb +4 -4
  50. data/lib/solargraph/gem_pins.rb +4 -15
  51. data/lib/solargraph/language_server/error_codes.rb +10 -10
  52. data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
  53. data/lib/solargraph/language_server/host/dispatch.rb +3 -3
  54. data/lib/solargraph/language_server/host/message_worker.rb +4 -3
  55. data/lib/solargraph/language_server/host/sources.rb +2 -1
  56. data/lib/solargraph/language_server/host.rb +35 -28
  57. data/lib/solargraph/language_server/message/base.rb +1 -1
  58. data/lib/solargraph/language_server/message/client/register_capability.rb +1 -3
  59. data/lib/solargraph/language_server/message/completion_item/resolve.rb +6 -8
  60. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +12 -18
  61. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  62. data/lib/solargraph/language_server/message/extended/document_gems.rb +7 -7
  63. data/lib/solargraph/language_server/message/extended/download_core.rb +2 -1
  64. data/lib/solargraph/language_server/message/extended/environment.rb +25 -25
  65. data/lib/solargraph/language_server/message/extended/search.rb +1 -1
  66. data/lib/solargraph/language_server/message/initialize.rb +20 -14
  67. data/lib/solargraph/language_server/message/initialized.rb +28 -28
  68. data/lib/solargraph/language_server/message/text_document/completion.rb +10 -8
  69. data/lib/solargraph/language_server/message/text_document/definition.rb +41 -32
  70. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +17 -10
  71. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +29 -19
  72. data/lib/solargraph/language_server/message/text_document/formatting.rb +8 -6
  73. data/lib/solargraph/language_server/message/text_document/hover.rb +5 -5
  74. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +13 -6
  75. data/lib/solargraph/language_server/message/text_document/references.rb +17 -10
  76. data/lib/solargraph/language_server/message/text_document/rename.rb +20 -13
  77. data/lib/solargraph/language_server/message/text_document/signature_help.rb +3 -2
  78. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -17
  79. data/lib/solargraph/language_server/message/text_document.rb +28 -28
  80. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +34 -28
  81. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +38 -30
  82. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +23 -17
  83. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +27 -17
  84. data/lib/solargraph/language_server/message.rb +1 -1
  85. data/lib/solargraph/language_server/progress.rb +143 -143
  86. data/lib/solargraph/language_server/request.rb +4 -2
  87. data/lib/solargraph/language_server/transport/adapter.rb +68 -68
  88. data/lib/solargraph/language_server/transport/data_reader.rb +11 -13
  89. data/lib/solargraph/language_server/uri_helpers.rb +2 -2
  90. data/lib/solargraph/language_server.rb +20 -20
  91. data/lib/solargraph/library.rb +57 -38
  92. data/lib/solargraph/location.rb +17 -14
  93. data/lib/solargraph/logging.rb +22 -4
  94. data/lib/solargraph/page.rb +1 -1
  95. data/lib/solargraph/parser/comment_ripper.rb +19 -4
  96. data/lib/solargraph/parser/flow_sensitive_typing.rb +324 -108
  97. data/lib/solargraph/parser/node_processor/base.rb +34 -4
  98. data/lib/solargraph/parser/node_processor.rb +8 -7
  99. data/lib/solargraph/parser/parser_gem/class_methods.rb +30 -14
  100. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -1
  101. data/lib/solargraph/parser/parser_gem/node_chainer.rb +51 -25
  102. data/lib/solargraph/parser/parser_gem/node_methods.rb +181 -73
  103. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +24 -24
  104. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  105. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +13 -11
  106. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -12
  108. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +36 -36
  109. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +24 -24
  110. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +10 -3
  111. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +9 -8
  112. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +24 -24
  113. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  114. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +5 -3
  115. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  116. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  117. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +40 -40
  118. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +3 -3
  119. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  120. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  121. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  122. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -5
  123. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +124 -113
  124. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +20 -20
  125. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +1 -1
  126. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  127. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +6 -2
  128. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  129. data/lib/solargraph/parser/parser_gem.rb +2 -0
  130. data/lib/solargraph/parser/region.rb +9 -3
  131. data/lib/solargraph/parser/snippet.rb +3 -1
  132. data/lib/solargraph/parser.rb +2 -0
  133. data/lib/solargraph/pin/base.rb +126 -82
  134. data/lib/solargraph/pin/base_variable.rb +273 -24
  135. data/lib/solargraph/pin/block.rb +29 -6
  136. data/lib/solargraph/pin/breakable.rb +7 -1
  137. data/lib/solargraph/pin/callable.rb +65 -21
  138. data/lib/solargraph/pin/closure.rb +7 -10
  139. data/lib/solargraph/pin/common.rb +24 -6
  140. data/lib/solargraph/pin/compound_statement.rb +55 -0
  141. data/lib/solargraph/pin/constant.rb +3 -5
  142. data/lib/solargraph/pin/conversions.rb +10 -4
  143. data/lib/solargraph/pin/delegated_method.rb +19 -8
  144. data/lib/solargraph/pin/documenting.rb +4 -2
  145. data/lib/solargraph/pin/instance_variable.rb +5 -1
  146. data/lib/solargraph/pin/keyword.rb +0 -4
  147. data/lib/solargraph/pin/local_variable.rb +15 -59
  148. data/lib/solargraph/pin/method.rb +158 -104
  149. data/lib/solargraph/pin/method_alias.rb +8 -0
  150. data/lib/solargraph/pin/namespace.rb +19 -12
  151. data/lib/solargraph/pin/parameter.rb +102 -36
  152. data/lib/solargraph/pin/proxy_type.rb +4 -1
  153. data/lib/solargraph/pin/reference/override.rb +1 -1
  154. data/lib/solargraph/pin/reference/require.rb +14 -14
  155. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  156. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  157. data/lib/solargraph/pin/reference.rb +20 -0
  158. data/lib/solargraph/pin/search.rb +8 -7
  159. data/lib/solargraph/pin/signature.rb +15 -12
  160. data/lib/solargraph/pin/singleton.rb +11 -11
  161. data/lib/solargraph/pin/symbol.rb +2 -1
  162. data/lib/solargraph/pin/until.rb +2 -4
  163. data/lib/solargraph/pin/while.rb +2 -4
  164. data/lib/solargraph/pin.rb +2 -0
  165. data/lib/solargraph/pin_cache.rb +22 -19
  166. data/lib/solargraph/position.rb +17 -10
  167. data/lib/solargraph/range.rb +16 -15
  168. data/lib/solargraph/rbs_map/conversions.rb +367 -231
  169. data/lib/solargraph/rbs_map/core_fills.rb +18 -11
  170. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  171. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -5
  172. data/lib/solargraph/rbs_map.rb +76 -32
  173. data/lib/solargraph/server_methods.rb +1 -1
  174. data/lib/solargraph/shell.rb +258 -66
  175. data/lib/solargraph/source/chain/array.rb +3 -12
  176. data/lib/solargraph/source/chain/block_symbol.rb +13 -13
  177. data/lib/solargraph/source/chain/block_variable.rb +13 -13
  178. data/lib/solargraph/source/chain/call.rb +96 -56
  179. data/lib/solargraph/source/chain/class_variable.rb +1 -1
  180. data/lib/solargraph/source/chain/constant.rb +5 -1
  181. data/lib/solargraph/source/chain/global_variable.rb +1 -1
  182. data/lib/solargraph/source/chain/hash.rb +8 -5
  183. data/lib/solargraph/source/chain/head.rb +19 -19
  184. data/lib/solargraph/source/chain/if.rb +12 -10
  185. data/lib/solargraph/source/chain/instance_variable.rb +24 -1
  186. data/lib/solargraph/source/chain/link.rb +12 -22
  187. data/lib/solargraph/source/chain/literal.rb +22 -15
  188. data/lib/solargraph/source/chain/or.rb +10 -4
  189. data/lib/solargraph/source/chain/q_call.rb +2 -0
  190. data/lib/solargraph/source/chain/variable.rb +3 -1
  191. data/lib/solargraph/source/chain/z_super.rb +1 -3
  192. data/lib/solargraph/source/chain.rb +51 -38
  193. data/lib/solargraph/source/change.rb +12 -5
  194. data/lib/solargraph/source/cursor.rb +33 -18
  195. data/lib/solargraph/source/encoding_fixes.rb +6 -7
  196. data/lib/solargraph/source/source_chainer.rb +56 -32
  197. data/lib/solargraph/source/updater.rb +5 -1
  198. data/lib/solargraph/source.rb +59 -35
  199. data/lib/solargraph/source_map/clip.rb +54 -30
  200. data/lib/solargraph/source_map/data.rb +4 -1
  201. data/lib/solargraph/source_map/mapper.rb +69 -42
  202. data/lib/solargraph/source_map.rb +21 -9
  203. data/lib/solargraph/type_checker/problem.rb +3 -1
  204. data/lib/solargraph/type_checker/rules.rb +81 -8
  205. data/lib/solargraph/type_checker.rb +196 -122
  206. data/lib/solargraph/version.rb +1 -1
  207. data/lib/solargraph/workspace/config.rb +14 -11
  208. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  209. data/lib/solargraph/workspace/require_paths.rb +1 -0
  210. data/lib/solargraph/workspace.rb +50 -28
  211. data/lib/solargraph/yard_map/cache.rb +25 -25
  212. data/lib/solargraph/yard_map/helpers.rb +8 -3
  213. data/lib/solargraph/yard_map/mapper/to_constant.rb +28 -28
  214. data/lib/solargraph/yard_map/mapper/to_method.rb +13 -7
  215. data/lib/solargraph/yard_map/mapper/to_namespace.rb +2 -1
  216. data/lib/solargraph/yard_map/mapper.rb +13 -8
  217. data/lib/solargraph/yard_map.rb +17 -18
  218. data/lib/solargraph/yard_tags.rb +2 -2
  219. data/lib/solargraph/yardoc.rb +7 -4
  220. data/lib/solargraph.rb +33 -10
  221. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  222. data/rbs/shims/ast/0/node.rbs +1 -1
  223. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  224. data/solargraph.gemspec +37 -35
  225. metadata +41 -42
  226. data/lib/solargraph/type_checker/checks.rb +0 -124
  227. data/lib/solargraph/type_checker/param_def.rb +0 -37
  228. data/lib/solargraph/yard_map/to_method.rb +0 -89
  229. data/rbs/fills/tuple/tuple.rbs +0 -149
@@ -4,6 +4,7 @@ require 'parser'
4
4
  require 'ast'
5
5
 
6
6
  # https://github.com/whitequark/parser
7
+ # rubocop:disable Metrics/ModuleLength
7
8
  module Solargraph
8
9
  module Parser
9
10
  module ParserGem
@@ -12,17 +13,17 @@ module Solargraph
12
13
 
13
14
  # @param node [Parser::AST::Node]
14
15
  # @return [String]
15
- def unpack_name(node)
16
- pack_name(node).join("::")
16
+ def unpack_name node
17
+ pack_name(node).join('::')
17
18
  end
18
19
 
19
20
  # @param node [Parser::AST::Node]
20
21
  # @return [Array<String>]
21
- def pack_name(node)
22
+ def pack_name node
22
23
  # @type [Array<String>]
23
24
  parts = []
24
25
  if node.is_a?(AST::Node)
25
- node.children.each { |n|
26
+ node.children.each do |n|
26
27
  if n.is_a?(AST::Node)
27
28
  if n.type == :cbase
28
29
  parts = [''] + pack_name(n)
@@ -32,16 +33,16 @@ module Solargraph
32
33
  else
33
34
  parts.push n unless n.nil?
34
35
  end
35
- }
36
+ end
36
37
  end
37
38
  parts
38
39
  end
39
40
 
40
- # @param node [Parser::AST::Node]
41
+ # @param node [Parser::AST::Node, nil]
41
42
  # @return [String, nil]
42
43
  def infer_literal_node_type node
43
44
  return nil unless node.is_a?(AST::Node)
44
- if node.type == :str || node.type == :dstr
45
+ if %i[str dstr].include?(node.type)
45
46
  return '::String'
46
47
  elsif node.type == :array
47
48
  return '::Array'
@@ -53,30 +54,30 @@ module Solargraph
53
54
  return '::Integer'
54
55
  elsif node.type == :float
55
56
  return '::Float'
56
- elsif node.type == :sym || node.type == :dsym
57
+ elsif %i[sym dsym].include?(node.type)
57
58
  return '::Symbol'
58
59
  elsif node.type == :regexp
59
60
  return '::Regexp'
60
61
  elsif node.type == :irange
61
62
  return '::Range'
62
- elsif node.type == :true || node.type == :false
63
+ elsif %i[true false].include?(node.type)
63
64
  return '::Boolean'
64
65
  # @todo Support `nil` keyword in types
65
- # elsif node.type == :nil
66
- # return 'NilClass'
66
+ # elsif node.type == :nil
67
+ # return 'NilClass'
67
68
  end
68
69
  nil
69
70
  end
70
71
 
71
72
  # @param node [Parser::AST::Node]
72
73
  # @return [Position]
73
- def get_node_start_position(node)
74
+ def get_node_start_position node
74
75
  Position.new(node.loc.line, node.loc.column)
75
76
  end
76
77
 
77
78
  # @param node [Parser::AST::Node]
78
79
  # @return [Position]
79
- def get_node_end_position(node)
80
+ def get_node_end_position node
80
81
  Position.new(node.loc.last_line, node.loc.last_column)
81
82
  end
82
83
 
@@ -86,40 +87,42 @@ module Solargraph
86
87
  # @return [String]
87
88
  def drill_signature node, signature
88
89
  return signature unless node.is_a?(AST::Node)
89
- if node.type == :const or node.type == :cbase
90
- unless node.children[0].nil?
91
- signature += drill_signature(node.children[0], signature)
92
- end
90
+ if %i[const cbase].include?(node.type)
91
+ signature += drill_signature(node.children[0], signature) unless node.children[0].nil?
93
92
  signature += '::' unless signature.empty?
94
93
  signature += node.children[1].to_s
95
- elsif node.type == :lvar or node.type == :ivar or node.type == :cvar
94
+ elsif %i[lvar ivar cvar].include?(node.type)
96
95
  signature += '.' unless signature.empty?
97
96
  signature += node.children[0].to_s
98
97
  elsif node.type == :send
99
- unless node.children[0].nil?
100
- signature += drill_signature(node.children[0], signature)
101
- end
98
+ signature += drill_signature(node.children[0], signature) unless node.children[0].nil?
102
99
  signature += '.' unless signature.empty?
103
100
  signature += node.children[1].to_s
104
101
  end
105
102
  signature
106
103
  end
107
104
 
108
- # @param node [Parser::AST::Node]
105
+ # @param node [Parser::AST::Node, nil]
109
106
  # @return [Hash{Symbol => Chain}]
110
107
  def convert_hash node
111
108
  return {} unless Parser.is_ast_node?(node)
109
+ # @sg-ignore Translate to something flow sensitive typing understands
112
110
  return convert_hash(node.children[0]) if node.type == :kwsplat
113
- return convert_hash(node.children[0]) if Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat
111
+ # @sg-ignore Translate to something flow sensitive typing understands
112
+ if Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat
113
+ # @sg-ignore Translate to something flow sensitive typing understands
114
+ return convert_hash(node.children[0])
115
+ end
116
+ # @sg-ignore Translate to something flow sensitive typing understands
114
117
  return {} unless node.type == :hash
115
118
  result = {}
119
+ # @sg-ignore Translate to something flow sensitive typing understands
116
120
  node.children.each do |pair|
117
121
  result[pair.children[0].children[0]] = Solargraph::Parser.chain(pair.children[1])
118
122
  end
119
123
  result
120
124
  end
121
125
 
122
- # @sg-ignore Wrong argument type for AST::Node.new: type expected AST::_ToSym, received :nil
123
126
  NIL_NODE = ::Parser::AST::Node.new(:nil)
124
127
 
125
128
  # @param node [Parser::AST::Node]
@@ -148,7 +151,7 @@ module Solargraph
148
151
  end
149
152
 
150
153
  # @param nodes [Enumerable<Parser::AST::Node>]
151
- def any_splatted_call?(nodes)
154
+ def any_splatted_call? nodes
152
155
  nodes.any? { |n| splatted_call?(n) }
153
156
  end
154
157
 
@@ -161,14 +164,17 @@ module Solargraph
161
164
  if node.type == :block
162
165
  result.push node
163
166
  if Parser.is_ast_node?(node.children[0]) && node.children[0].children.length > 2
164
- node.children[0].children[2..-1].each { |child| result.concat call_nodes_from(child) }
167
+ # @sg-ignore Need to add nil check here
168
+ node.children[0].children[2..].each { |child| result.concat call_nodes_from(child) }
165
169
  end
166
- node.children[1..-1].each { |child| result.concat call_nodes_from(child) }
170
+ # @sg-ignore Need to add nil check here
171
+ node.children[1..].each { |child| result.concat call_nodes_from(child) }
167
172
  elsif node.type == :send
168
173
  result.push node
169
174
  result.concat call_nodes_from(node.children.first)
170
- node.children[2..-1].each { |child| result.concat call_nodes_from(child) }
171
- elsif [:super, :zsuper].include?(node.type)
175
+ # @sg-ignore Need to add nil check here
176
+ node.children[2..].each { |child| result.concat call_nodes_from(child) }
177
+ elsif %i[super zsuper].include?(node.type)
172
178
  result.push node
173
179
  node.children.each { |child| result.concat call_nodes_from(child) }
174
180
  else
@@ -199,53 +205,142 @@ module Solargraph
199
205
  # @return [Array<AST::Node>] low-level value nodes in
200
206
  # value position. Does not include explicit return
201
207
  # statements
202
- def value_position_nodes_only(node)
208
+ def value_position_nodes_only node
203
209
  DeepInference.value_position_nodes_only(node).map { |n| n || NIL_NODE }
204
210
  end
205
211
 
206
212
  # @param cursor [Solargraph::Source::Cursor]
207
213
  # @return [Parser::AST::Node, nil]
208
214
  def find_recipient_node cursor
209
- return repaired_find_recipient_node(cursor) if cursor.source.repaired? && cursor.source.code[cursor.offset - 1] == '('
215
+ if cursor.source.repaired? && cursor.source.code[cursor.offset - 1] == '('
216
+ return repaired_find_recipient_node(cursor)
217
+ end
210
218
  source = cursor.source
211
219
  position = cursor.position
212
220
  offset = cursor.offset
213
221
  tree = if source.synchronized?
214
- match = source.code[0..offset-1].match(/,\s*\z/)
215
- if match
216
- source.tree_at(position.line, position.column - match[0].length)
217
- else
218
- source.tree_at(position.line, position.column)
219
- end
220
- else
221
- source.tree_at(position.line, position.column - 1)
222
- end
222
+ # @sg-ignore Need to add nil check here
223
+ match = source.code[0..(offset - 1)].match(/,\s*\z/)
224
+ if match
225
+ # @sg-ignore Need to add nil check here
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
223
233
  # @type [AST::Node, nil]
224
234
  prev = nil
225
235
  tree.each do |node|
226
236
  if node.type == :send
227
- args = node.children[2..-1]
237
+ args = node.children[2..]
238
+ # @sg-ignore Need to add nil check here
228
239
  if !args.empty?
240
+ # @sg-ignore Need to add nil check here
229
241
  return node if prev && args.include?(prev)
230
- else
231
- if source.synchronized?
232
- return node if source.code[0..offset-1] =~ /\(\s*\z/ && source.code[offset..-1] =~ /^\s*\)/
233
- else
234
- return node if source.code[0..offset-1] =~ /\([^(]*\z/
235
- end
242
+ elsif source.synchronized?
243
+ return node if source.code[0..(offset - 1)] =~ /\(\s*\z/ && source.code[offset..] =~ /^\s*\)/
244
+ elsif source.code[0..(offset - 1)] =~ /\([^(]*\z/
245
+ return node
236
246
  end
237
247
  end
238
248
  prev = node
239
249
  end
240
- nil
250
+ find_recipient_node_by_text(source, offset)
251
+ end
252
+
253
+ # Text-based fallback for finding a method call recipient when the AST
254
+ # is unavailable (e.g., unparseable source with syntax errors).
255
+ #
256
+ # Scans backward from cursor offset to find '(' and the method name
257
+ # before it, then creates a minimal :send node.
258
+ #
259
+ # @param source [Solargraph::Source]
260
+ # @param offset [Integer]
261
+ # @return [Parser::AST::Node, nil]
262
+ def find_recipient_node_by_text source, offset
263
+ code = source.code
264
+ return nil if offset.nil? || offset <= 0 || offset > code.length
265
+
266
+ # The '(' could be at offset-1 (cursor after '(') or at offset (cursor on '(')
267
+ start_pos = offset - 1
268
+ if start_pos.positive? && code[start_pos] != '(' && code[offset] == '('
269
+ start_pos = offset
270
+ end
271
+
272
+ # Scan backward to find the matching '(' (handle nested parens)
273
+ depth = 0
274
+ paren_pos = nil
275
+ pos = start_pos
276
+ while pos >= 0
277
+ case code[pos]
278
+ when ')'
279
+ depth += 1
280
+ when '('
281
+ if depth.zero?
282
+ paren_pos = pos
283
+ break
284
+ end
285
+ depth -= 1
286
+ end
287
+ pos -= 1
288
+ end
289
+ return nil if paren_pos.nil?
290
+
291
+ # Skip whitespace before '(' to find method name
292
+ idx = paren_pos - 1
293
+ idx -= 1 while idx >= 0 && code[idx] =~ /\s/
294
+ return nil if idx.negative?
295
+
296
+ # Read method name (including ? and !)
297
+ name_end = idx + 1
298
+ idx -= 1 while idx >= 0 && code[idx] =~ /[a-zA-Z0-9_?!]/
299
+ name_start = idx + 1
300
+ return nil if name_start >= name_end
301
+ method_name = code[name_start...name_end]
302
+ return nil if method_name.empty?
303
+
304
+ # Check for receiver pattern: receiver.method( or receiver::method(
305
+ idx = name_start - 1
306
+ idx -= 1 while idx >= 0 && code[idx] =~ /\s/
307
+ if idx >= 0 && code[idx] == '.'
308
+ idx -= 1
309
+ idx -= 1 while idx >= 0 && code[idx] =~ /\s/
310
+ recv_end = idx + 1
311
+ idx -= 1 while idx >= 0 && code[idx] =~ /[a-zA-Z0-9_@$]/
312
+ recv_start = idx + 1
313
+ if recv_start < recv_end
314
+ recv_name = code[recv_start...recv_end]
315
+ unless recv_name.empty?
316
+ receiver_node = ::Parser::AST::Node.new(:send, [nil, recv_name.to_sym])
317
+ return ::Parser::AST::Node.new(:send, [receiver_node, method_name.to_sym])
318
+ end
319
+ end
320
+ elsif idx >= 0 && idx.positive? && code[idx - 1] == ':' && code[idx] == ':'
321
+ const_end = idx - 1
322
+ const_start = const_end
323
+ const_start -= 1 while const_start.positive? && code[const_start - 1] =~ /[a-zA-Z0-9_]/
324
+ const_name = code[const_start...const_end]
325
+ unless const_name.empty? || method_name.empty?
326
+ const_node = ::Parser::AST::Node.new(:const, [nil, const_name.to_sym])
327
+ return ::Parser::AST::Node.new(:send, [const_node, method_name.to_sym])
328
+ end
329
+ end
330
+
331
+ # Simple method call without receiver
332
+ ::Parser::AST::Node.new(:send, [nil, method_name.to_sym])
241
333
  end
242
334
 
243
335
  # @param cursor [Solargraph::Source::Cursor]
244
336
  # @return [Parser::AST::Node, nil]
245
337
  def repaired_find_recipient_node cursor
246
- cursor = cursor.source.cursor_at([cursor.position.line, cursor.position.column - 1])
247
- node = cursor.source.tree_at(cursor.position.line, cursor.position.column).first
248
- return node if node && node.type == :send
338
+ c = cursor.source.cursor_at([cursor.position.line, cursor.position.column - 1])
339
+ tree = c.source.tree_at(c.position.line, c.position.column)
340
+ tree.each do |node|
341
+ return node if node.type == :send
342
+ end
343
+ find_recipient_node_by_text(cursor.source, cursor.offset)
249
344
  end
250
345
 
251
346
  #
@@ -302,19 +397,15 @@ module Solargraph
302
397
  # statements in value positions.
303
398
  module DeepInference
304
399
  class << self
305
- CONDITIONAL_ALL_BUT_FIRST = [:if, :unless]
306
- CONDITIONAL_ALL = [:or]
307
- ONLY_ONE_CHILD = [:return]
308
- FIRST_TWO_CHILDREN = [:rescue]
309
- COMPOUND_STATEMENTS = [:begin, :kwbegin]
310
- SKIPPABLE = [:def, :defs, :class, :sclass, :module]
311
- FUNCTION_VALUE = [:block]
312
- CASE_STATEMENT = [:case]
400
+ CONDITIONAL_ALL_BUT_FIRST = %i[if unless].freeze
401
+ ONLY_ONE_CHILD = [:return].freeze
402
+ FIRST_TWO_CHILDREN = [:rescue].freeze
403
+ COMPOUND_STATEMENTS = %i[begin kwbegin].freeze
404
+ SKIPPABLE = %i[def defs class sclass module].freeze
405
+ FUNCTION_VALUE = [:block].freeze
406
+ CASE_STATEMENT = [:case].freeze
313
407
 
314
408
  # @param node [AST::Node] a method body compound statement
315
- # @param include_explicit_returns [Boolean] If true,
316
- # include the value nodes of the parameter of the
317
- # 'return' statements in the type returned.
318
409
  # @return [Array<AST::Node>] low-level value nodes from
319
410
  # both nodes in value position as well as explicit
320
411
  # return statements in the method's closure.
@@ -327,14 +418,14 @@ module Solargraph
327
418
  # @return [Array<AST::Node>] low-level value nodes in
328
419
  # value position. Does not include explicit return
329
420
  # statements
330
- def value_position_nodes_only(node)
421
+ def value_position_nodes_only node
331
422
  from_value_position_statement(node, include_explicit_returns: false)
332
423
  end
333
424
 
334
425
  # Look at known control statements and use them to find
335
426
  # more specific return nodes.
336
427
  #
337
- # @param node [Parser::AST::Node] Statement which is in
428
+ # @param node [AST::Node] Statement which is in
338
429
  # value position for a method body
339
430
  # @param include_explicit_returns [Boolean] If true,
340
431
  # include the value nodes of the parameter of the
@@ -348,10 +439,9 @@ module Solargraph
348
439
  if COMPOUND_STATEMENTS.include?(node.type)
349
440
  result.concat from_value_position_compound_statement node
350
441
  elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
351
- result.concat reduce_to_value_nodes(node.children[1..-1])
442
+ # @sg-ignore Need to add nil check here
443
+ result.concat reduce_to_value_nodes(node.children[1..])
352
444
  # result.push NIL_NODE unless node.children[2]
353
- elsif CONDITIONAL_ALL.include?(node.type)
354
- result.concat reduce_to_value_nodes(node.children)
355
445
  elsif ONLY_ONE_CHILD.include?(node.type)
356
446
  result.concat reduce_to_value_nodes([node.children[0]])
357
447
  elsif FIRST_TWO_CHILDREN.include?(node.type)
@@ -362,9 +452,12 @@ module Solargraph
362
452
  # @todo any explicit returns actually return from
363
453
  # scope in which the proc is run. This asssumes
364
454
  # that the function is executed here.
365
- result.concat explicit_return_values_from_compound_statement(node.children[2]) if include_explicit_returns
455
+ if include_explicit_returns
456
+ result.concat explicit_return_values_from_compound_statement(node.children[2])
457
+ end
366
458
  elsif CASE_STATEMENT.include?(node.type)
367
- node.children[1..-1].each do |cc|
459
+ # @sg-ignore Need to add nil check here
460
+ node.children[1..].each do |cc|
368
461
  if cc.nil?
369
462
  result.push NIL_NODE
370
463
  elsif cc.type == :when
@@ -397,7 +490,7 @@ module Solargraph
397
490
  # @return [Array<Parser::AST::Node>]
398
491
  def from_value_position_compound_statement parent
399
492
  result = []
400
- nodes = parent.children.select{|n| n.is_a?(AST::Node)}
493
+ nodes = parent.children.select { |n| n.is_a?(AST::Node) }
401
494
  nodes.each_with_index do |node, idx|
402
495
  if node.type == :block
403
496
  result.concat explicit_return_values_from_compound_statement(node.children[2])
@@ -422,7 +515,10 @@ module Solargraph
422
515
  # value position. we already have the explicit values
423
516
  # from above; now we need to also gather the value
424
517
  # position nodes
425
- result.concat from_value_position_statement(nodes.last, include_explicit_returns: false) if idx == nodes.length - 1
518
+ if idx == nodes.length - 1
519
+ result.concat from_value_position_statement(nodes.last,
520
+ include_explicit_returns: false)
521
+ end
426
522
  end
427
523
  result
428
524
  end
@@ -438,7 +534,7 @@ module Solargraph
438
534
  def explicit_return_values_from_compound_statement parent
439
535
  return [] unless parent.is_a?(::Parser::AST::Node)
440
536
  result = []
441
- nodes = parent.children.select{|n| n.is_a?(::Parser::AST::Node)}
537
+ nodes = parent.children.select { |n| n.is_a?(::Parser::AST::Node) }
442
538
  nodes.each do |node|
443
539
  next if SKIPPABLE.include?(node.type)
444
540
  if node.type == :return
@@ -460,17 +556,28 @@ module Solargraph
460
556
  nodes.each do |node|
461
557
  if !node.is_a?(::Parser::AST::Node)
462
558
  result.push nil
559
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
463
560
  elsif COMPOUND_STATEMENTS.include?(node.type)
464
561
  result.concat from_value_position_compound_statement(node)
562
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
465
563
  elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
466
- result.concat reduce_to_value_nodes(node.children[1..-1])
564
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
565
+ result.concat reduce_to_value_nodes(node.children[1..])
566
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
467
567
  elsif node.type == :return
568
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
468
569
  result.concat reduce_to_value_nodes([node.children[0]])
570
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
469
571
  elsif node.type == :or
572
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
470
573
  result.concat reduce_to_value_nodes(node.children)
574
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
471
575
  elsif node.type == :block
576
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
472
577
  result.concat explicit_return_values_from_compound_statement(node.children[2])
578
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
473
579
  elsif node.type == :resbody
580
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
474
581
  result.concat reduce_to_value_nodes([node.children[2]])
475
582
  else
476
583
  result.push node
@@ -484,3 +591,4 @@ module Solargraph
484
591
  end
485
592
  end
486
593
  end
594
+ # rubocop:enable Metrics/ModuleLength
@@ -1,24 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Parser
5
- module ParserGem
6
- module NodeProcessors
7
- class AliasNode < Parser::NodeProcessor::Base
8
- def process
9
- loc = get_node_location(node)
10
- pins.push Solargraph::Pin::MethodAlias.new(
11
- location: loc,
12
- closure: region.closure,
13
- name: node.children[0].children[0].to_s,
14
- original: node.children[1].children[0].to_s,
15
- scope: region.scope || :instance,
16
- source: :parser
17
- )
18
- process_children
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class AliasNode < Parser::NodeProcessor::Base
8
+ def process
9
+ loc = get_node_location(node)
10
+ pins.push Solargraph::Pin::MethodAlias.new(
11
+ location: loc,
12
+ closure: region.closure,
13
+ name: node.children[0].children[0].to_s,
14
+ original: node.children[1].children[0].to_s,
15
+ scope: region.scope || :instance,
16
+ source: :parser
17
+ )
18
+ process_children
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -10,10 +10,10 @@ module Solargraph
10
10
  def process
11
11
  process_children
12
12
 
13
- position = get_node_start_position(node)
14
- # @sg-ignore https://github.com/castwide/solargraph/pull/1114
15
- enclosing_breakable_pin = pins.select{|pin| pin.is_a?(Pin::Breakable) && pin.location.range.contain?(position)}.last
16
- FlowSensitiveTyping.new(locals, enclosing_breakable_pin).process_and(node)
13
+ FlowSensitiveTyping.new(locals,
14
+ ivars,
15
+ enclosing_breakable_pin,
16
+ enclosing_compound_statement_pin).process_and(node)
17
17
  end
18
18
  end
19
19
  end
@@ -14,16 +14,17 @@ module Solargraph
14
14
  node.children.each do |u|
15
15
  loc = get_node_location(u)
16
16
  locals.push Solargraph::Pin::Parameter.new(
17
- location: loc,
18
- closure: callable,
19
- comments: comments_for(node),
20
- name: u.children[0].to_s,
21
- assignment: u.children[1],
22
- asgn_code: u.children[1] ? region.code_for(u.children[1]) : nil,
23
- presence: callable.location.range,
24
- decl: get_decl(u),
25
- source: :parser
26
- )
17
+ location: loc,
18
+ closure: callable,
19
+ comments: comments_for(node),
20
+ name: u.children[0].to_s,
21
+ assignment: u.children[1],
22
+ asgn_code: u.children[1] ? region.code_for(u.children[1]) : nil,
23
+ # @sg-ignore Need to add nil check here
24
+ presence: callable.location.range,
25
+ decl: get_decl(u),
26
+ source: :parser
27
+ )
27
28
  callable.parameters.push locals.last
28
29
  end
29
30
  end
@@ -35,11 +36,12 @@ module Solargraph
35
36
 
36
37
  # @param callable [Pin::Callable]
37
38
  # @return [void]
38
- def forward(callable)
39
+ def forward callable
39
40
  loc = get_node_location(node)
40
41
  locals.push Solargraph::Pin::Parameter.new(
41
42
  location: loc,
42
43
  closure: callable,
44
+ # @sg-ignore Need to add nil check here
43
45
  presence: region.closure.location.range,
44
46
  decl: get_decl(node),
45
47
  source: :parser
@@ -6,6 +6,15 @@ module Solargraph
6
6
  module NodeProcessors
7
7
  class BeginNode < Parser::NodeProcessor::Base
8
8
  def process
9
+ # We intentionally don't create a CompoundStatement pin
10
+ # here, as this is not necessarily a control flow block -
11
+ # e.g., a begin...end without rescue or ensure should be
12
+ # treated by flow sensitive typing as if the begin and end
13
+ # didn't exist at all. As such, we create the
14
+ # CompoundStatement pins around the things which actually
15
+ # result in control flow changes - like
16
+ # if/while/rescue/etc
17
+
9
18
  process_children
10
19
  end
11
20
  end
@@ -9,23 +9,22 @@ module Solargraph
9
9
 
10
10
  def process
11
11
  location = get_node_location(node)
12
- parent = if other_class_eval?
13
- Solargraph::Pin::Namespace.new(
14
- location: location,
15
- type: :class,
16
- name: unpack_name(node.children[0].children[0]),
17
- source: :parser,
18
- )
19
- else
20
- region.closure
12
+ scope = region.scope || region.closure.context.scope
13
+ if other_class_eval?
14
+ clazz_name = unpack_name(node.children[0].children[0])
15
+ # instance variables should come from the Class<T> type
16
+ # - i.e., treated as class instance variables
17
+ context = ComplexType.try_parse("Class<#{clazz_name}>")
18
+ scope = :class
21
19
  end
22
20
  block_pin = Solargraph::Pin::Block.new(
23
21
  location: location,
24
- closure: parent,
22
+ closure: region.closure,
25
23
  node: node,
24
+ context: context,
26
25
  receiver: node.children[0],
27
26
  comments: comments_for(node),
28
- scope: region.scope || region.closure.context.scope,
27
+ scope: scope,
29
28
  source: :parser
30
29
  )
31
30
  pins.push block_pin
@@ -37,7 +36,7 @@ module Solargraph
37
36
  def other_class_eval?
38
37
  node.children[0].type == :send &&
39
38
  node.children[0].children[1] == :class_eval &&
40
- [:cbase, :const].include?(node.children[0].children[0]&.type)
39
+ %i[cbase const].include?(node.children[0].children[0]&.type)
41
40
  end
42
41
  end
43
42
  end