solargraph 0.58.2 → 0.59.0.dev.1

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 (154) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +4 -5
  4. data/.github/workflows/plugins.yml +40 -36
  5. data/.github/workflows/rspec.yml +45 -13
  6. data/.github/workflows/typecheck.yml +2 -2
  7. data/.gitignore +0 -1
  8. data/.rubocop_todo.yml +27 -49
  9. data/CHANGELOG.md +1 -7
  10. data/README.md +3 -3
  11. data/Rakefile +1 -0
  12. data/lib/solargraph/api_map/cache.rb +3 -3
  13. data/lib/solargraph/api_map/constants.rb +13 -3
  14. data/lib/solargraph/api_map/index.rb +22 -11
  15. data/lib/solargraph/api_map/source_to_yard.rb +13 -1
  16. data/lib/solargraph/api_map/store.rb +11 -8
  17. data/lib/solargraph/api_map.rb +105 -50
  18. data/lib/solargraph/complex_type/conformance.rb +176 -0
  19. data/lib/solargraph/complex_type/type_methods.rb +16 -2
  20. data/lib/solargraph/complex_type/unique_type.rb +170 -20
  21. data/lib/solargraph/complex_type.rb +119 -14
  22. data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
  23. data/lib/solargraph/convention/data_definition.rb +4 -1
  24. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
  25. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +1 -0
  26. data/lib/solargraph/convention/struct_definition.rb +5 -1
  27. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  28. data/lib/solargraph/diagnostics/rubocop.rb +1 -0
  29. data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
  30. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  31. data/lib/solargraph/doc_map.rb +134 -373
  32. data/lib/solargraph/equality.rb +1 -1
  33. data/lib/solargraph/gem_pins.rb +14 -15
  34. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  35. data/lib/solargraph/language_server/host/dispatch.rb +1 -0
  36. data/lib/solargraph/language_server/host/message_worker.rb +2 -1
  37. data/lib/solargraph/language_server/host/sources.rb +1 -0
  38. data/lib/solargraph/language_server/host.rb +6 -1
  39. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -7
  40. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  41. data/lib/solargraph/language_server/message/text_document/completion.rb +2 -0
  42. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  43. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -0
  44. data/lib/solargraph/language_server/message/text_document/formatting.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  46. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -0
  47. data/lib/solargraph/language_server/message/text_document/type_definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -0
  49. data/lib/solargraph/library.rb +59 -13
  50. data/lib/solargraph/location.rb +9 -4
  51. data/lib/solargraph/logging.rb +21 -1
  52. data/lib/solargraph/parser/comment_ripper.rb +7 -0
  53. data/lib/solargraph/parser/flow_sensitive_typing.rb +330 -102
  54. data/lib/solargraph/parser/node_processor/base.rb +32 -2
  55. data/lib/solargraph/parser/node_processor.rb +7 -6
  56. data/lib/solargraph/parser/parser_gem/class_methods.rb +28 -10
  57. data/lib/solargraph/parser/parser_gem/node_chainer.rb +31 -6
  58. data/lib/solargraph/parser/parser_gem/node_methods.rb +27 -7
  59. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  60. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +2 -0
  61. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  62. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -11
  63. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +7 -0
  64. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  65. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +3 -2
  66. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  68. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +2 -2
  69. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  70. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +1 -0
  73. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +12 -7
  74. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  75. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +5 -1
  76. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  77. data/lib/solargraph/parser/region.rb +9 -3
  78. data/lib/solargraph/parser/snippet.rb +1 -1
  79. data/lib/solargraph/pin/base.rb +53 -21
  80. data/lib/solargraph/pin/base_variable.rb +312 -20
  81. data/lib/solargraph/pin/block.rb +26 -4
  82. data/lib/solargraph/pin/breakable.rb +5 -1
  83. data/lib/solargraph/pin/callable.rb +50 -3
  84. data/lib/solargraph/pin/closure.rb +2 -6
  85. data/lib/solargraph/pin/common.rb +20 -5
  86. data/lib/solargraph/pin/compound_statement.rb +55 -0
  87. data/lib/solargraph/pin/conversions.rb +2 -1
  88. data/lib/solargraph/pin/delegated_method.rb +15 -4
  89. data/lib/solargraph/pin/documenting.rb +1 -0
  90. data/lib/solargraph/pin/instance_variable.rb +5 -1
  91. data/lib/solargraph/pin/keyword.rb +0 -4
  92. data/lib/solargraph/pin/local_variable.rb +13 -57
  93. data/lib/solargraph/pin/method.rb +90 -42
  94. data/lib/solargraph/pin/method_alias.rb +8 -0
  95. data/lib/solargraph/pin/namespace.rb +7 -1
  96. data/lib/solargraph/pin/parameter.rb +76 -13
  97. data/lib/solargraph/pin/proxy_type.rb +2 -1
  98. data/lib/solargraph/pin/reference/override.rb +1 -1
  99. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  100. data/lib/solargraph/pin/reference.rb +2 -0
  101. data/lib/solargraph/pin/search.rb +1 -0
  102. data/lib/solargraph/pin/signature.rb +8 -0
  103. data/lib/solargraph/pin/symbol.rb +1 -1
  104. data/lib/solargraph/pin/until.rb +1 -1
  105. data/lib/solargraph/pin/while.rb +1 -1
  106. data/lib/solargraph/pin.rb +2 -0
  107. data/lib/solargraph/pin_cache.rb +477 -57
  108. data/lib/solargraph/position.rb +12 -26
  109. data/lib/solargraph/range.rb +6 -6
  110. data/lib/solargraph/rbs_map/conversions.rb +33 -10
  111. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  112. data/lib/solargraph/rbs_map/stdlib_map.rb +34 -5
  113. data/lib/solargraph/rbs_map.rb +74 -20
  114. data/lib/solargraph/shell.rb +73 -28
  115. data/lib/solargraph/source/chain/call.rb +52 -17
  116. data/lib/solargraph/source/chain/constant.rb +2 -0
  117. data/lib/solargraph/source/chain/hash.rb +1 -0
  118. data/lib/solargraph/source/chain/if.rb +1 -0
  119. data/lib/solargraph/source/chain/instance_variable.rb +22 -1
  120. data/lib/solargraph/source/chain/literal.rb +5 -0
  121. data/lib/solargraph/source/chain/or.rb +9 -1
  122. data/lib/solargraph/source/chain.rb +25 -22
  123. data/lib/solargraph/source/change.rb +9 -2
  124. data/lib/solargraph/source/cursor.rb +7 -1
  125. data/lib/solargraph/source/source_chainer.rb +13 -3
  126. data/lib/solargraph/source/updater.rb +4 -0
  127. data/lib/solargraph/source.rb +33 -7
  128. data/lib/solargraph/source_map/clip.rb +13 -2
  129. data/lib/solargraph/source_map/data.rb +4 -1
  130. data/lib/solargraph/source_map/mapper.rb +24 -1
  131. data/lib/solargraph/source_map.rb +14 -6
  132. data/lib/solargraph/type_checker/problem.rb +3 -1
  133. data/lib/solargraph/type_checker/rules.rb +75 -2
  134. data/lib/solargraph/type_checker.rb +111 -30
  135. data/lib/solargraph/version.rb +1 -1
  136. data/lib/solargraph/workspace/config.rb +3 -1
  137. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  138. data/lib/solargraph/workspace/require_paths.rb +1 -0
  139. data/lib/solargraph/workspace.rb +158 -16
  140. data/lib/solargraph/yard_map/helpers.rb +2 -1
  141. data/lib/solargraph/yard_map/mapper/to_method.rb +5 -1
  142. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  143. data/lib/solargraph/yard_map/mapper.rb +5 -0
  144. data/lib/solargraph/yardoc.rb +33 -23
  145. data/lib/solargraph.rb +24 -3
  146. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  147. data/rbs/fills/tuple/tuple.rbs +28 -0
  148. data/rbs/shims/ast/0/node.rbs +1 -1
  149. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  150. data/solargraph.gemspec +2 -1
  151. metadata +12 -7
  152. data/lib/solargraph/type_checker/checks.rb +0 -124
  153. data/lib/solargraph/type_checker/param_def.rb +0 -37
  154. data/lib/solargraph/yard_map/to_method.rb +0 -89
@@ -35,9 +35,10 @@ module Solargraph
35
35
  # @param node [Parser::AST::Node]
36
36
  # @param region [Region]
37
37
  # @param pins [Array<Pin::Base>]
38
- # @param locals [Array<Pin::BaseVariable>]
39
- # @return [Array(Array<Pin::Base>, Array<Pin::Base>)]
40
- def self.process node, region = Region.new, pins = [], locals = []
38
+ # @param locals [Array<Pin::LocalVariable>]
39
+ # @param ivars [Array<Pin::InstanceVariable>]
40
+ # @return [Array(Array<Pin::Base>, Array<Pin::LocalVariable>, Array<Pin::InstanceVariable>)]
41
+ def self.process node, region = Region.new, pins = [], locals = [], ivars = []
41
42
  if pins.empty?
42
43
  pins.push Pin::Namespace.new(
43
44
  location: region.source.location,
@@ -45,17 +46,17 @@ module Solargraph
45
46
  source: :parser,
46
47
  )
47
48
  end
48
- return [pins, locals] unless Parser.is_ast_node?(node)
49
+ return [pins, locals, ivars] unless Parser.is_ast_node?(node)
49
50
  node_processor_classes = @@processors[node.type] || [NodeProcessor::Base]
50
51
 
51
52
  node_processor_classes.each do |klass|
52
- processor = klass.new(node, region, pins, locals)
53
+ processor = klass.new(node, region, pins, locals, ivars)
53
54
  process_next = processor.process
54
55
 
55
56
  break unless process_next
56
57
  end
57
58
 
58
- [pins, locals]
59
+ [pins, locals, ivars]
59
60
  end
60
61
  end
61
62
  end
@@ -8,19 +8,23 @@ module Solargraph
8
8
  module ClassMethods
9
9
  # @param code [String]
10
10
  # @param filename [String, nil]
11
+ # @param starting_line [Integer] must be provided so that we
12
+ # can find relevant local variables later even if this is just
13
+ # a subset of the file in question
11
14
  # @return [Array(Parser::AST::Node, Hash{Integer => Solargraph::Parser::Snippet})]
12
- def parse_with_comments code, filename = nil
13
- node = parse(code, filename)
15
+ def parse_with_comments code, filename = nil, starting_line = 0
16
+ node = parse(code, filename, starting_line)
14
17
  comments = CommentRipper.new(code, filename, 0).parse
15
18
  [node, comments]
16
19
  end
17
20
 
18
21
  # @param code [String]
19
22
  # @param filename [String, nil]
20
- # @param line [Integer]
23
+ # @param starting_line [Integer]
24
+ # @sg-ignore need to understand that raise does not return
21
25
  # @return [Parser::AST::Node]
22
- def parse code, filename = nil, line = 0
23
- buffer = ::Parser::Source::Buffer.new(filename, line)
26
+ def parse code, filename = nil, starting_line = 0
27
+ buffer = ::Parser::Source::Buffer.new(filename, starting_line)
24
28
  buffer.source = code
25
29
  parser.parse(buffer)
26
30
  rescue ::Parser::SyntaxError, ::Parser::UnknownEncodingInMagicComment => e
@@ -30,15 +34,20 @@ module Solargraph
30
34
  # @return [::Parser::Base]
31
35
  def parser
32
36
  @parser ||= Prism::Translation::Parser.new(FlawedBuilder.new).tap do |parser|
37
+ # @sg-ignore Unresolved call to diagnostics on Prism::Translation::Parser
33
38
  parser.diagnostics.all_errors_are_fatal = true
39
+ # @sg-ignore Unresolved call to diagnostics on Prism::Translation::Parser
34
40
  parser.diagnostics.ignore_warnings = true
35
41
  end
36
42
  end
37
43
 
38
44
  # @param source [Source]
39
- # @return [Array(Array<Pin::Base>, Array<Pin::Base>)]
45
+ # @return [Array(Array<Pin::Base>, Array<Pin::LocalVariable>)]
40
46
  def map source
41
- NodeProcessor.process(source.node, Region.new(source: source))
47
+ # @sg-ignore Need to add nil check here
48
+ pins, locals, ivars = NodeProcessor.process(source.node, Region.new(source: source))
49
+ pins.concat(ivars)
50
+ [pins, locals]
42
51
  end
43
52
 
44
53
  # @param source [Source]
@@ -50,15 +59,18 @@ module Solargraph
50
59
  # @param code [String]
51
60
  # @param offset [Integer]
52
61
  # @return [Array(Integer, Integer), Array(nil, nil)]
62
+ # @sg-ignore Need to add nil check here
53
63
  extract_offset = ->(code, offset) { reg.match(code, offset).offset(0) }
54
64
  else
55
65
  # @param code [String]
56
66
  # @param offset [Integer]
57
67
  # @return [Array(Integer, Integer), Array(nil, nil)]
68
+ # @sg-ignore Need to add nil check here
58
69
  extract_offset = ->(code, offset) { [soff = code.index(name, offset), soff + name.length] }
59
70
  end
60
71
  inner_node_references(name, source.node).map do |n|
61
72
  rng = Range.from_node(n)
73
+ # @sg-ignore Need to add nil check here
62
74
  offset = Position.to_offset(source.code, rng.start)
63
75
  soff, eoff = extract_offset[source.code, offset]
64
76
  Location.new(
@@ -99,7 +111,7 @@ module Solargraph
99
111
  Solargraph::Parser::NodeProcessor.process *args
100
112
  end
101
113
 
102
- # @param node [Parser::AST::Node]
114
+ # @param node [Parser::AST::Node, nil]
103
115
  # @return [String, nil]
104
116
  def infer_literal_node_type node
105
117
  NodeMethods.infer_literal_node_type node
@@ -110,7 +122,7 @@ module Solargraph
110
122
  parser.version
111
123
  end
112
124
 
113
- # @param node [BasicObject]
125
+ # @param node [BasicObject, nil]
114
126
  # @return [Boolean]
115
127
  def is_ast_node? node
116
128
  node.is_a?(::Parser::AST::Node)
@@ -124,19 +136,25 @@ module Solargraph
124
136
  Range.new(st, en)
125
137
  end
126
138
 
127
- # @param node [Parser::AST::Node]
139
+ # @param node [Parser::AST::Node, nil]
128
140
  # @return [Array<Range>]
129
141
  def string_ranges node
130
142
  return [] unless is_ast_node?(node)
131
143
  result = []
144
+ # @sg-ignore Translate to something flow sensitive typing understands
132
145
  result.push Range.from_node(node) if node.type == :str
146
+ # @sg-ignore Translate to something flow sensitive typing understands
133
147
  node.children.each do |child|
134
148
  result.concat string_ranges(child)
135
149
  end
150
+ # @sg-ignore Translate to something flow sensitive typing understands
136
151
  if node.type == :dstr && node.children.last.nil?
152
+ # @sg-ignore Translate to something flow sensitive typing understands
137
153
  last = node.children[-2]
154
+ # @sg-ignore Need to add nil check here
138
155
  unless last.nil?
139
156
  rng = Range.from_node(last)
157
+ # @sg-ignore Need to add nil check here
140
158
  pos = Position.new(rng.ending.line, rng.ending.column - 1)
141
159
  result.push Range.new(pos, pos)
142
160
  end
@@ -35,9 +35,12 @@ module Solargraph
35
35
  end
36
36
 
37
37
  # @param code [String]
38
+ # @param filename [String]
39
+ # @param starting_line [Integer]
40
+ #
38
41
  # @return [Source::Chain]
39
- def load_string(code)
40
- node = Parser.parse(code.sub(/\.$/, ''))
42
+ def load_string(code, filename, starting_line)
43
+ node = Parser.parse(code.sub(/\.$/, ''), filename, starting_line)
41
44
  chain = NodeChainer.new(node).chain
42
45
  chain.links.push(Chain::Link.new) if code.end_with?('.')
43
46
  chain
@@ -61,6 +64,7 @@ module Solargraph
61
64
  result.push Chain::Call.new(n.children[1].to_s, Location.from_node(n), node_args(n), passed_block(n))
62
65
  elsif n.children[0].nil?
63
66
  args = []
67
+ # @sg-ignore Need to add nil check here
64
68
  n.children[2..-1].each do |c|
65
69
  args.push NodeChainer.chain(c, @filename, n)
66
70
  end
@@ -93,14 +97,22 @@ module Solargraph
93
97
  elsif [:lvar, :lvasgn].include?(n.type)
94
98
  result.push Chain::Call.new(n.children[0].to_s, Location.from_node(n))
95
99
  elsif [:ivar, :ivasgn].include?(n.type)
96
- result.push Chain::InstanceVariable.new(n.children[0].to_s)
100
+ result.push Chain::InstanceVariable.new(n.children[0].to_s, n, Location.from_node(n))
97
101
  elsif [:cvar, :cvasgn].include?(n.type)
98
102
  result.push Chain::ClassVariable.new(n.children[0].to_s)
99
103
  elsif [:gvar, :gvasgn].include?(n.type)
100
104
  result.push Chain::GlobalVariable.new(n.children[0].to_s)
101
105
  elsif n.type == :or_asgn
102
- new_node = n.updated(n.children[0].type, n.children[0].children + [n.children[1]])
103
- result.concat generate_links new_node
106
+ # @bar ||= 123 translates to:
107
+ #
108
+ # s(:or_asgn,
109
+ # s(:ivasgn, :@bar),
110
+ # s(:int, 123))
111
+ lhs_chain = NodeChainer.chain n.children[0] # s(:ivasgn, :@bar)
112
+ rhs_chain = NodeChainer.chain n.children[1] # s(:int, 123)
113
+ or_link = Chain::Or.new([lhs_chain, rhs_chain])
114
+ # this is just for a call chain, so we don't need to record the assignment
115
+ result.push(or_link)
104
116
  elsif [:class, :module, :def, :defs].include?(n.type)
105
117
  # @todo Undefined or what?
106
118
  result.push Chain::UNDEFINED_CALL
@@ -109,7 +121,17 @@ module Solargraph
109
121
  elsif n.type == :or
110
122
  result.push Chain::Or.new([NodeChainer.chain(n.children[0], @filename), NodeChainer.chain(n.children[1], @filename, n)])
111
123
  elsif n.type == :if
112
- result.push Chain::If.new([NodeChainer.chain(n.children[1], @filename), NodeChainer.chain(n.children[2], @filename, n)])
124
+ then_clause = if n.children[1]
125
+ NodeChainer.chain(n.children[1], @filename, n)
126
+ else
127
+ Source::Chain.new([Source::Chain::Literal.new('nil', nil)], n)
128
+ end
129
+ else_clause = if n.children[2]
130
+ NodeChainer.chain(n.children[2], @filename, n)
131
+ else
132
+ Source::Chain.new([Source::Chain::Literal.new('nil', nil)], n)
133
+ end
134
+ result.push Chain::If.new([then_clause, else_clause])
113
135
  elsif [:begin, :kwbegin].include?(n.type)
114
136
  result.concat generate_links(n.children.last)
115
137
  elsif n.type == :block_pass
@@ -150,12 +172,15 @@ module Solargraph
150
172
  def passed_block node
151
173
  return unless node == @node && @parent&.type == :block
152
174
 
175
+ # @sg-ignore Need to add nil check here
153
176
  NodeChainer.chain(@parent.children[2], @filename)
154
177
  end
155
178
 
156
179
  # @param node [Parser::AST::Node]
180
+ # @sg-ignore Need to add nil check here
157
181
  # @return [Array<Source::Chain>]
158
182
  def node_args node
183
+ # @sg-ignore Need to add nil check here
159
184
  node.children[2..-1].map do |child|
160
185
  NodeChainer.chain(child, @filename, node)
161
186
  end
@@ -37,7 +37,7 @@ module Solargraph
37
37
  parts
38
38
  end
39
39
 
40
- # @param node [Parser::AST::Node]
40
+ # @param node [Parser::AST::Node, nil]
41
41
  # @return [String, nil]
42
42
  def infer_literal_node_type node
43
43
  return nil unless node.is_a?(AST::Node)
@@ -105,21 +105,24 @@ module Solargraph
105
105
  signature
106
106
  end
107
107
 
108
- # @param node [Parser::AST::Node]
108
+ # @param node [Parser::AST::Node, nil]
109
109
  # @return [Hash{Symbol => Chain}]
110
110
  def convert_hash node
111
111
  return {} unless Parser.is_ast_node?(node)
112
+ # @sg-ignore Translate to something flow sensitive typing understands
112
113
  return convert_hash(node.children[0]) if node.type == :kwsplat
114
+ # @sg-ignore Translate to something flow sensitive typing understands
113
115
  return convert_hash(node.children[0]) if Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat
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]
@@ -161,12 +164,15 @@ 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
167
+ # @sg-ignore Need to add nil check here
164
168
  node.children[0].children[2..-1].each { |child| result.concat call_nodes_from(child) }
165
169
  end
170
+ # @sg-ignore Need to add nil check here
166
171
  node.children[1..-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)
175
+ # @sg-ignore Need to add nil check here
170
176
  node.children[2..-1].each { |child| result.concat call_nodes_from(child) }
171
177
  elsif [:super, :zsuper].include?(node.type)
172
178
  result.push node
@@ -211,8 +217,10 @@ module Solargraph
211
217
  position = cursor.position
212
218
  offset = cursor.offset
213
219
  tree = if source.synchronized?
220
+ # @sg-ignore Need to add nil check here
214
221
  match = source.code[0..offset-1].match(/,\s*\z/)
215
222
  if match
223
+ # @sg-ignore Need to add nil check here
216
224
  source.tree_at(position.line, position.column - match[0].length)
217
225
  else
218
226
  source.tree_at(position.line, position.column)
@@ -225,7 +233,9 @@ module Solargraph
225
233
  tree.each do |node|
226
234
  if node.type == :send
227
235
  args = node.children[2..-1]
236
+ # @sg-ignore Need to add nil check here
228
237
  if !args.empty?
238
+ # @sg-ignore Need to add nil check here
229
239
  return node if prev && args.include?(prev)
230
240
  else
231
241
  if source.synchronized?
@@ -303,7 +313,6 @@ module Solargraph
303
313
  module DeepInference
304
314
  class << self
305
315
  CONDITIONAL_ALL_BUT_FIRST = [:if, :unless]
306
- CONDITIONAL_ALL = [:or]
307
316
  ONLY_ONE_CHILD = [:return]
308
317
  FIRST_TWO_CHILDREN = [:rescue]
309
318
  COMPOUND_STATEMENTS = [:begin, :kwbegin]
@@ -334,7 +343,7 @@ module Solargraph
334
343
  # Look at known control statements and use them to find
335
344
  # more specific return nodes.
336
345
  #
337
- # @param node [Parser::AST::Node] Statement which is in
346
+ # @param node [AST::Node] Statement which is in
338
347
  # value position for a method body
339
348
  # @param include_explicit_returns [Boolean] If true,
340
349
  # include the value nodes of the parameter of the
@@ -348,10 +357,9 @@ module Solargraph
348
357
  if COMPOUND_STATEMENTS.include?(node.type)
349
358
  result.concat from_value_position_compound_statement node
350
359
  elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
360
+ # @sg-ignore Need to add nil check here
351
361
  result.concat reduce_to_value_nodes(node.children[1..-1])
352
362
  # 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
363
  elsif ONLY_ONE_CHILD.include?(node.type)
356
364
  result.concat reduce_to_value_nodes([node.children[0]])
357
365
  elsif FIRST_TWO_CHILDREN.include?(node.type)
@@ -364,6 +372,7 @@ module Solargraph
364
372
  # that the function is executed here.
365
373
  result.concat explicit_return_values_from_compound_statement(node.children[2]) if include_explicit_returns
366
374
  elsif CASE_STATEMENT.include?(node.type)
375
+ # @sg-ignore Need to add nil check here
367
376
  node.children[1..-1].each do |cc|
368
377
  if cc.nil?
369
378
  result.push NIL_NODE
@@ -460,17 +469,28 @@ module Solargraph
460
469
  nodes.each do |node|
461
470
  if !node.is_a?(::Parser::AST::Node)
462
471
  result.push nil
472
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
463
473
  elsif COMPOUND_STATEMENTS.include?(node.type)
464
474
  result.concat from_value_position_compound_statement(node)
475
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
465
476
  elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
477
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
466
478
  result.concat reduce_to_value_nodes(node.children[1..-1])
479
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
467
480
  elsif node.type == :return
481
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
468
482
  result.concat reduce_to_value_nodes([node.children[0]])
483
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
469
484
  elsif node.type == :or
485
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
470
486
  result.concat reduce_to_value_nodes(node.children)
487
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
471
488
  elsif node.type == :block
489
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
472
490
  result.concat explicit_return_values_from_compound_statement(node.children[2])
491
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
473
492
  elsif node.type == :resbody
493
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
474
494
  result.concat reduce_to_value_nodes([node.children[2]])
475
495
  else
476
496
  result.push node
@@ -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
@@ -20,6 +20,7 @@ module Solargraph
20
20
  name: u.children[0].to_s,
21
21
  assignment: u.children[1],
22
22
  asgn_code: u.children[1] ? region.code_for(u.children[1]) : nil,
23
+ # @sg-ignore Need to add nil check here
23
24
  presence: callable.location.range,
24
25
  decl: get_decl(u),
25
26
  source: :parser
@@ -40,6 +41,7 @@ module Solargraph
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,6 +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 &&
39
+ # @sg-ignore Need to add nil check here
40
40
  [:cbase, :const].include?(node.children[0].children[0]&.type)
41
41
  end
42
42
  end
@@ -8,10 +8,15 @@ module Solargraph
8
8
  def process
9
9
  name = node.children[0].to_s
10
10
  scope = region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance)
11
+ # specify context explicitly instead of relying on
12
+ # closure, as they may differ (e.g., defs inside
13
+ # class_eval)
14
+ method_context = scope == :instance ? region.closure.binder.namespace_type : region.closure.binder
11
15
  methpin = Solargraph::Pin::Method.new(
12
16
  location: get_node_location(node),
13
17
  closure: region.closure,
14
18
  name: name,
19
+ context: method_context,
15
20
  comments: comments_for(node),
16
21
  scope: scope,
17
22
  visibility: scope == :instance && name == 'initialize' ? :private : region.visibility,
@@ -23,6 +28,7 @@ module Solargraph
23
28
  location: methpin.location,
24
29
  closure: methpin.closure,
25
30
  name: methpin.name,
31
+ context: method_context,
26
32
  comments: methpin.comments,
27
33
  scope: :class,
28
34
  visibility: :public,
@@ -34,6 +40,7 @@ module Solargraph
34
40
  location: methpin.location,
35
41
  closure: methpin.closure,
36
42
  name: methpin.name,
43
+ context: method_context,
37
44
  comments: methpin.comments,
38
45
  scope: :instance,
39
46
  visibility: :private,
@@ -8,13 +8,43 @@ module Solargraph
8
8
  include ParserGem::NodeMethods
9
9
 
10
10
  def process
11
- process_children
11
+ FlowSensitiveTyping.new(locals,
12
+ ivars,
13
+ enclosing_breakable_pin,
14
+ enclosing_compound_statement_pin).process_if(node)
15
+ condition_node = node.children[0]
16
+ if condition_node
17
+ pins.push Solargraph::Pin::CompoundStatement.new(
18
+ location: get_node_location(condition_node),
19
+ closure: region.closure,
20
+ node: condition_node,
21
+ source: :parser,
22
+ )
23
+ NodeProcessor.process(condition_node, region, pins, locals, ivars)
24
+ end
25
+ then_node = node.children[1]
26
+ if then_node
27
+ pins.push Solargraph::Pin::CompoundStatement.new(
28
+ location: get_node_location(then_node),
29
+ closure: region.closure,
30
+ node: then_node,
31
+ source: :parser,
32
+ )
33
+ NodeProcessor.process(then_node, region, pins, locals, ivars)
34
+ end
12
35
 
13
- position = get_node_start_position(node)
14
- # @sg-ignore
15
- # @type [Solargraph::Pin::Breakable, nil]
16
- enclosing_breakable_pin = pins.select{|pin| pin.is_a?(Pin::Breakable) && pin.location.range.contain?(position)}.last
17
- FlowSensitiveTyping.new(locals, enclosing_breakable_pin).process_if(node)
36
+ else_node = node.children[2]
37
+ if else_node
38
+ pins.push Solargraph::Pin::CompoundStatement.new(
39
+ location: get_node_location(else_node),
40
+ closure: region.closure,
41
+ node: else_node,
42
+ source: :parser,
43
+ )
44
+ NodeProcessor.process(else_node, region, pins, locals, ivars)
45
+ end
46
+
47
+ true
18
48
  end
19
49
  end
20
50
  end
@@ -9,7 +9,7 @@ module Solargraph
9
9
 
10
10
  def process
11
11
  loc = get_node_location(node)
12
- pins.push Solargraph::Pin::InstanceVariable.new(
12
+ ivars.push Solargraph::Pin::InstanceVariable.new(
13
13
  location: loc,
14
14
  closure: region.closure,
15
15
  name: node.children[0].to_s,
@@ -19,9 +19,10 @@ module Solargraph
19
19
  )
20
20
  if region.visibility == :module_function
21
21
  here = get_node_start_position(node)
22
+ # @type [Pin::Closure, nil]
22
23
  named_path = named_path_pin(here)
23
24
  if named_path.is_a?(Pin::Method)
24
- pins.push Solargraph::Pin::InstanceVariable.new(
25
+ ivars.push Solargraph::Pin::InstanceVariable.new(
25
26
  location: loc,
26
27
  closure: Pin::Namespace.new(type: :module, closure: region.closure.closure, name: region.closure.name),
27
28
  name: node.children[0].to_s,
@@ -9,6 +9,7 @@ module Solargraph
9
9
 
10
10
  def process
11
11
  here = get_node_start_position(node)
12
+ # @sg-ignore Need to add nil check here
12
13
  presence = Range.new(here, region.closure.location.range.ending)
13
14
  loc = get_node_location(node)
14
15
  locals.push Solargraph::Pin::LocalVariable.new(
@@ -37,8 +37,10 @@ module Solargraph
37
37
  pin = if lhs.type == :lvasgn
38
38
  # lvasgn is a local variable
39
39
  locals.find { |l| l.location == location }
40
+ elsif lhs.type == :ivasgn
41
+ # ivasgn is an instance variable assignment
42
+ ivars.find { |iv| iv.location == location }
40
43
  else
41
- # e.g., ivasgn is an instance variable, etc
42
44
  pins.find { |iv| iv.location == location && iv.is_a?(Pin::BaseVariable) }
43
45
  end
44
46
  # @todo in line below, nothing in typechecking alerts
@@ -57,7 +57,7 @@ module Solargraph
57
57
  [callee,
58
58
  asgn_method,
59
59
  node.updated(:send, [call, operator, argument])])
60
- NodeProcessor.process(new_send, region, pins, locals)
60
+ NodeProcessor.process(new_send, region, pins, locals, ivars)
61
61
  end
62
62
 
63
63
  # @param asgn [Parser::AST::Node] the target of the assignment
@@ -89,7 +89,7 @@ module Solargraph
89
89
  ]
90
90
  send_node = node.updated(:send, send_children)
91
91
  new_asgn = node.updated(asgn.type, [variable_name, send_node])
92
- NodeProcessor.process(new_asgn, region, pins, locals)
92
+ NodeProcessor.process(new_asgn, region, pins, locals, ivars)
93
93
  end
94
94
  end
95
95
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class OrNode < Parser::NodeProcessor::Base
8
+ include ParserGem::NodeMethods
9
+
10
+ def process
11
+ process_children
12
+
13
+ FlowSensitiveTyping.new(locals,
14
+ ivars,
15
+ enclosing_breakable_pin,
16
+ enclosing_compound_statement_pin).process_or(node)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -8,7 +8,7 @@ module Solargraph
8
8
  # @return [void]
9
9
  def process
10
10
  new_node = node.updated(node.children[0].type, node.children[0].children + [node.children[1]])
11
- NodeProcessor.process(new_node, region, pins, locals)
11
+ NodeProcessor.process(new_node, region, pins, locals, ivars)
12
12
  end
13
13
  end
14
14
  end
@@ -11,6 +11,7 @@ module Solargraph
11
11
  def process
12
12
  if node.children[1] # Exception local variable name
13
13
  here = get_node_start_position(node.children[1])
14
+ # @sg-ignore Need to add nil check here
14
15
  presence = Range.new(here, region.closure.location.range.ending)
15
16
  loc = get_node_location(node.children[1])
16
17
  types = if node.children[0].nil?
@@ -29,7 +30,7 @@ module Solargraph
29
30
  source: :parser
30
31
  )
31
32
  end
32
- NodeProcessor.process(node.children[2], region, pins, locals)
33
+ NodeProcessor.process(node.children[2], region, pins, locals, ivars)
33
34
  end
34
35
  end
35
36
  end