solargraph 0.32.5 → 0.33.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 (125) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +2 -11
  4. data/lib/solargraph.rb +1 -2
  5. data/lib/solargraph/api_map.rb +93 -63
  6. data/lib/solargraph/api_map/cache.rb +16 -1
  7. data/lib/solargraph/api_map/source_to_yard.rb +16 -7
  8. data/lib/solargraph/api_map/store.rb +55 -12
  9. data/lib/solargraph/complex_type.rb +58 -14
  10. data/lib/solargraph/complex_type/type_methods.rb +2 -2
  11. data/lib/solargraph/complex_type/unique_type.rb +33 -4
  12. data/lib/solargraph/core_fills.rb +40 -12
  13. data/lib/solargraph/diagnostics.rb +4 -3
  14. data/lib/solargraph/diagnostics/base.rb +6 -0
  15. data/lib/solargraph/diagnostics/require_not_found.rb +17 -10
  16. data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
  17. data/lib/solargraph/diagnostics/type_check.rb +51 -0
  18. data/lib/solargraph/diagnostics/update_errors.rb +1 -0
  19. data/lib/solargraph/language_server/host.rb +55 -25
  20. data/lib/solargraph/language_server/host/diagnoser.rb +1 -2
  21. data/lib/solargraph/language_server/host/dispatch.rb +4 -8
  22. data/lib/solargraph/language_server/host/sources.rb +1 -1
  23. data/lib/solargraph/language_server/message.rb +1 -0
  24. data/lib/solargraph/language_server/message/completion_item/resolve.rb +4 -2
  25. data/lib/solargraph/language_server/message/initialize.rb +9 -0
  26. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  27. data/lib/solargraph/language_server/message/text_document.rb +1 -0
  28. data/lib/solargraph/language_server/message/text_document/code_action.rb +15 -0
  29. data/lib/solargraph/language_server/message/text_document/completion.rb +1 -1
  30. data/lib/solargraph/language_server/message/text_document/definition.rb +25 -5
  31. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  32. data/lib/solargraph/language_server/message/text_document/signature_help.rb +4 -0
  33. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +8 -4
  34. data/lib/solargraph/language_server/transport/adapter.rb +12 -15
  35. data/lib/solargraph/library.rb +23 -6
  36. data/lib/solargraph/location.rb +4 -0
  37. data/lib/solargraph/pin.rb +7 -3
  38. data/lib/solargraph/pin/attribute.rb +14 -13
  39. data/lib/solargraph/pin/base.rb +56 -43
  40. data/lib/solargraph/pin/base_method.rb +41 -18
  41. data/lib/solargraph/pin/base_variable.rb +17 -15
  42. data/lib/solargraph/pin/block.rb +22 -4
  43. data/lib/solargraph/pin/closure.rb +28 -0
  44. data/lib/solargraph/pin/common.rb +59 -0
  45. data/lib/solargraph/pin/constant.rb +4 -4
  46. data/lib/solargraph/pin/conversions.rb +8 -8
  47. data/lib/solargraph/pin/duck_method.rb +3 -3
  48. data/lib/solargraph/pin/instance_variable.rb +30 -0
  49. data/lib/solargraph/pin/keyword.rb +1 -1
  50. data/lib/solargraph/pin/local_variable.rb +3 -3
  51. data/lib/solargraph/pin/localized.rb +9 -5
  52. data/lib/solargraph/pin/method.rb +26 -40
  53. data/lib/solargraph/pin/method_alias.rb +9 -6
  54. data/lib/solargraph/pin/namespace.rb +33 -10
  55. data/lib/solargraph/pin/parameter.rb +150 -0
  56. data/lib/solargraph/pin/proxy_type.rb +8 -8
  57. data/lib/solargraph/pin/reference.rb +1 -12
  58. data/lib/solargraph/pin/reference/override.rb +18 -0
  59. data/lib/solargraph/pin/reference/require.rb +2 -1
  60. data/lib/solargraph/pin/singleton.rb +9 -0
  61. data/lib/solargraph/pin/symbol.rb +9 -4
  62. data/lib/solargraph/pin/yard_pin/constant.rb +12 -3
  63. data/lib/solargraph/pin/yard_pin/method.rb +18 -6
  64. data/lib/solargraph/pin/yard_pin/namespace.rb +13 -1
  65. data/lib/solargraph/position.rb +1 -1
  66. data/lib/solargraph/range.rb +4 -0
  67. data/lib/solargraph/shell.rb +83 -4
  68. data/lib/solargraph/source.rb +32 -12
  69. data/lib/solargraph/source/chain.rb +48 -28
  70. data/lib/solargraph/source/chain/call.rb +37 -38
  71. data/lib/solargraph/source/chain/constant.rb +1 -1
  72. data/lib/solargraph/source/chain/head.rb +2 -8
  73. data/lib/solargraph/source/chain/instance_variable.rb +1 -1
  74. data/lib/solargraph/source/chain/link.rb +2 -0
  75. data/lib/solargraph/source/cursor.rb +59 -24
  76. data/lib/solargraph/source/node_chainer.rb +0 -2
  77. data/lib/solargraph/source/node_methods.rb +12 -6
  78. data/lib/solargraph/source/source_chainer.rb +38 -44
  79. data/lib/solargraph/source_map.rb +11 -18
  80. data/lib/solargraph/source_map/clip.rb +13 -15
  81. data/lib/solargraph/source_map/mapper.rb +37 -26
  82. data/lib/solargraph/source_map/node_processor.rb +13 -8
  83. data/lib/solargraph/source_map/node_processor/alias_node.rb +8 -8
  84. data/lib/solargraph/source_map/node_processor/args_node.rb +10 -16
  85. data/lib/solargraph/source_map/node_processor/base.rb +47 -4
  86. data/lib/solargraph/source_map/node_processor/block_node.rb +9 -4
  87. data/lib/solargraph/source_map/node_processor/casgn_node.rb +7 -2
  88. data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +8 -3
  89. data/lib/solargraph/source_map/node_processor/def_node.rb +45 -38
  90. data/lib/solargraph/source_map/node_processor/defs_node.rb +16 -6
  91. data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +8 -1
  92. data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +20 -6
  93. data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +10 -4
  94. data/lib/solargraph/source_map/node_processor/namespace_node.rb +18 -12
  95. data/lib/solargraph/source_map/node_processor/orasgn_node.rb +1 -1
  96. data/lib/solargraph/source_map/node_processor/resbody_node.rb +30 -0
  97. data/lib/solargraph/source_map/node_processor/sclass_node.rb +7 -1
  98. data/lib/solargraph/source_map/node_processor/send_node.rb +102 -52
  99. data/lib/solargraph/source_map/node_processor/sym_node.rb +4 -1
  100. data/lib/solargraph/source_map/region.rb +9 -8
  101. data/lib/solargraph/type_checker.rb +282 -0
  102. data/lib/solargraph/type_checker/param_def.rb +47 -0
  103. data/lib/solargraph/type_checker/problem.rb +25 -0
  104. data/lib/solargraph/version.rb +1 -1
  105. data/lib/solargraph/views/environment.erb +1 -1
  106. data/lib/solargraph/workspace.rb +2 -2
  107. data/lib/solargraph/workspace/config.rb +0 -8
  108. data/lib/solargraph/yard_map.rb +25 -69
  109. data/lib/solargraph/yard_map/core_docs.rb +8 -3
  110. data/lib/solargraph/yard_map/core_gen.rb +1 -3
  111. data/lib/solargraph/yard_map/mapper.rb +85 -0
  112. data/lib/yard-solargraph.rb +2 -0
  113. metadata +14 -14
  114. data/lib/solargraph/diagnostics/type_not_defined.rb +0 -108
  115. data/lib/solargraph/live_map.rb +0 -126
  116. data/lib/solargraph/live_map/cache.rb +0 -38
  117. data/lib/solargraph/pin/block_parameter.rb +0 -103
  118. data/lib/solargraph/pin/method_parameter.rb +0 -40
  119. data/lib/solargraph/pin/plugin/method.rb +0 -25
  120. data/lib/solargraph/plugin.rb +0 -8
  121. data/lib/solargraph/plugin/base.rb +0 -41
  122. data/lib/solargraph/plugin/canceler.rb +0 -11
  123. data/lib/solargraph/plugin/process.rb +0 -172
  124. data/lib/solargraph/plugin/runtime.rb +0 -134
  125. data/lib/yard-coregen.rb +0 -16
@@ -8,47 +8,51 @@ module Solargraph
8
8
  # @return [Array<Chain>]
9
9
  attr_reader :arguments
10
10
 
11
+ # @param word [String]
12
+ # @param arguments [Array<Chain>]
11
13
  def initialize word, arguments = []
12
14
  @word = word
13
15
  @arguments = arguments
14
16
  end
15
17
 
18
+ # @param api_map [ApiMap]
19
+ # @param name_pin [Pin::Base]
20
+ # @param locals [Array<Pin::Base>]
16
21
  def resolve api_map, name_pin, locals
17
22
  found = locals.select{|p| p.name == word}
18
23
  return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
19
- pins = api_map.get_method_stack(name_pin.context.namespace, word, scope: name_pin.context.scope)
24
+ pins = api_map.get_method_stack(name_pin.binder.namespace, word, scope: name_pin.binder.scope)
20
25
  return [] if pins.empty?
21
- pins.unshift virtual_new_pin(pins.first, name_pin.context) if external_constructor?(pins.first, name_pin.context)
22
26
  inferred_pins(pins, api_map, name_pin.context, locals)
23
27
  end
24
28
 
25
29
  private
26
30
 
27
- # Create a `new` pin to facilitate type inference. This is necessary for
28
- # classes from YARD and classes in the namespace that do not have an
29
- # `initialize` method.
30
- #
31
- # @param new_pin [Solargraph::Pin::Base]
32
- # @param context [Solargraph::ComplexType]
33
- # @return [Pin::Method]
34
- def virtual_new_pin new_pin, context
35
- case new_pin.path
36
- when 'Class.new'
37
- Pin::ProxyType.anonymous(ComplexType.try_parse('Class<Object>'))
38
- when 'Class#new'
39
- Pin::ProxyType.anonymous(ComplexType.try_parse(context.namespace == 'Class' ? 'Object' : context.namespace))
40
- else
41
- Pin::ProxyType.anonymous(ComplexType.try_parse(context.namespace))
42
- end
43
- end
44
-
45
31
  def inferred_pins pins, api_map, context, locals
46
32
  result = pins.map do |p|
47
- if CoreFills::METHODS_RETURNING_SELF.include?(p.path)
48
- next Solargraph::Pin::Method.new(p.location, p.namespace, p.name, "@return [#{context.tag}]", p.scope, p.visibility, p.parameters, p.node)
49
- end
50
33
  if CoreFills::METHODS_RETURNING_SUBTYPES.include?(p.path) && !context.subtypes.empty?
51
- next Solargraph::Pin::Method.new(p.location, p.namespace, p.name, "@return [#{context.subtypes.first.tag}]", p.scope, p.visibility, p.parameters, p.node)
34
+ next Solargraph::Pin::Method.new(
35
+ location: p.location,
36
+ closure: p.closure,
37
+ name: p.name,
38
+ comments: "@return [#{context.subtypes.first.tag}]",
39
+ scope: p.scope,
40
+ visibility: p.visibility,
41
+ args: p.parameters,
42
+ node: p.node
43
+ )
44
+ end
45
+ if CoreFills::METHODS_RETURNING_VALUE_TYPES.include?(p.path) && !context.value_types.empty?
46
+ next Solargraph::Pin::Method.new(
47
+ location: p.location,
48
+ closure: p.closure,
49
+ name: p.name,
50
+ comments: "@return [#{context.value_types.first.tag}]",
51
+ scope: p.scope,
52
+ visibility: p.visibility,
53
+ args: p.parameters,
54
+ node: p.node
55
+ )
52
56
  end
53
57
  if p.kind == Pin::METHOD && !p.macros.empty?
54
58
  result = process_macro(p, api_map, context, locals)
@@ -57,18 +61,13 @@ module Solargraph
57
61
  result = process_directive(p, api_map, context, locals)
58
62
  next result unless result.return_type.undefined?
59
63
  end
60
- next p if p.kind == Pin::METHOD || p.kind == Pin::ATTRIBUTE || p.kind == Pin::NAMESPACE
61
- # type = p.infer(api_map)
62
- type = p.typify(api_map)
63
- type = p.probe(api_map) if type.undefined?
64
- next p if p.return_complex_type == type
65
- p.proxy type
64
+ p
65
+ end
66
+ result.map do |pin|
67
+ next pin if pin.return_type.undefined?
68
+ selfy = pin.return_type.self_to(context.namespace)
69
+ selfy == pin.return_type ? pin : pin.proxy(selfy)
66
70
  end
67
- result
68
- end
69
-
70
- def external_constructor? pin, context
71
- pin.path == 'Class#new' || (pin.name == 'new' && pin.scope == :class && pin.docstring.tag(:return).nil?)
72
71
  end
73
72
 
74
73
  # @param pin [Pin::Method]
@@ -80,7 +79,7 @@ module Solargraph
80
79
  result = inner_process_macro(pin, macro, api_map, context, locals)
81
80
  return result unless result.return_type.undefined?
82
81
  end
83
- Pin::ProxyType.new(nil, nil, nil, ComplexType::UNDEFINED)
82
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
84
83
  end
85
84
 
86
85
  def process_directive pin, api_map, context, locals
@@ -90,7 +89,7 @@ module Solargraph
90
89
  result = inner_process_macro(pin, macro, api_map, context, locals)
91
90
  return result unless result.return_type.undefined?
92
91
  end
93
- Pin::ProxyType.new(nil, nil, nil, ComplexType::UNDEFINED)
92
+ Pin::ProxyType.anonymous ComplexType::UNDEFINED
94
93
  end
95
94
 
96
95
  def inner_process_macro pin, macro, api_map, context, locals
@@ -106,7 +105,7 @@ module Solargraph
106
105
  unless tag.nil? || tag.types.nil?
107
106
  return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types))
108
107
  end
109
- Pin::ProxyType.new(nil, nil, nil, ComplexType::UNDEFINED)
108
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
110
109
  end
111
110
  end
112
111
  end
@@ -12,7 +12,7 @@ module Solargraph
12
12
  context = ''
13
13
  bottom = word[2..-1]
14
14
  else
15
- context = name_pin.context.namespace
15
+ context = name_pin.full_context.namespace
16
16
  bottom = word
17
17
  end
18
18
  if bottom.include?('::')
@@ -7,24 +7,18 @@ module Solargraph
7
7
  # @note Chain::Head is only intended to handle `self` and `super`.
8
8
  class Head < Link
9
9
  def resolve api_map, name_pin, locals
10
- return [self_pin(name_pin.context)] if word == 'self'
10
+ return [name_pin] if word == 'self'
11
11
  return super_pins(api_map, name_pin) if word == 'super'
12
12
  []
13
13
  end
14
14
 
15
15
  private
16
16
 
17
- # @param context [ComplexType]
18
- # @return [Pin::ProxyType]
19
- def self_pin(context)
20
- Pin::ProxyType.anonymous(context)
21
- end
22
-
23
17
  # @param api_map [ApiMap]
24
18
  # @param name_pin [Pin::Base]
25
19
  # @return [Array<Pin::Base>]
26
20
  def super_pins api_map, name_pin
27
- pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
21
+ pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
28
22
  pins.reject{|p| p.path == name_pin.path}
29
23
  end
30
24
  end
@@ -3,7 +3,7 @@ module Solargraph
3
3
  class Chain
4
4
  class InstanceVariable < Link
5
5
  def resolve api_map, name_pin, locals
6
- api_map.get_instance_variable_pins(name_pin.context.namespace, name_pin.context.scope).select{|p| p.name == word}
6
+ api_map.get_instance_variable_pins(name_pin.binder.namespace, name_pin.binder.scope).select{|p| p.name == word}
7
7
  end
8
8
  end
9
9
  end
@@ -4,6 +4,8 @@ module Solargraph
4
4
  class Link
5
5
  attr_reader :word
6
6
 
7
+ attr_accessor :last_context
8
+
7
9
  def initialize word = '<undefined>'
8
10
  @word = word
9
11
  end
@@ -55,6 +55,7 @@ module Solargraph
55
55
  end
56
56
  end
57
57
 
58
+ # @return [Boolean]
58
59
  def start_of_constant?
59
60
  source.code[offset-2, 2] == '::'
60
61
  end
@@ -75,9 +76,19 @@ module Solargraph
75
76
  @chain ||= SourceChainer.chain(source, position)
76
77
  end
77
78
 
79
+ # True if the statement at the cursor is an argument to a previous
80
+ # method.
81
+ #
82
+ # Given the code `process(foo)`, a cursor pointing at `foo` would
83
+ # identify it as an argument being passed to the `process` method.
84
+ #
85
+ # If #argument? is true, the #recipient method will return a cursor that
86
+ # points to the method receiving the argument.
87
+ #
78
88
  # @return [Boolean]
79
89
  def argument?
80
- @argument ||= !signature_position.nil?
90
+ # @argument ||= !signature_position.nil?
91
+ @argument ||= !recipient.nil?
81
92
  end
82
93
 
83
94
  # @return [Boolean]
@@ -90,12 +101,28 @@ module Solargraph
90
101
  @string ||= source.string_at?(position)
91
102
  end
92
103
 
104
+ # Get a cursor pointing to the method that receives the current statement
105
+ # as an argument.
106
+ #
93
107
  # @return [Cursor, nil]
94
108
  def recipient
95
- return nil unless argument?
96
- @recipient ||= Cursor.new(source, signature_position)
109
+ @recipient ||= begin
110
+ result = nil
111
+ node = recipient_node
112
+ unless node.nil?
113
+ result = if node.children[1].is_a?(AST::Node)
114
+ pos = Range.from_node(node.children[1]).start
115
+ Cursor.new(source, Position.new(pos.line, pos.column - 1))
116
+ else
117
+ Cursor.new(source, Range.from_node(node).ending)
118
+ end
119
+ end
120
+ result
121
+ end
97
122
  end
123
+ alias receiver recipient
98
124
 
125
+ # @return [Position]
99
126
  def node_position
100
127
  @node_position ||= begin
101
128
  if start_of_word.empty?
@@ -111,6 +138,22 @@ module Solargraph
111
138
  end
112
139
  end
113
140
 
141
+ # @return [Parser::AST::Node, nil]
142
+ def recipient_node
143
+ return nil if source.code[offset-1] == ')' || source.code[0..offset] =~ /[^,][ \t]*?\n[ \t]*?\Z/
144
+ return nil if first_char_offset < offset && source.code[first_char_offset..offset-1] =~ /\)[\s]*\Z/
145
+ pos = Position.from_offset(source.code, first_char_offset)
146
+ tree = source.tree_at(pos.line, pos.character)
147
+ if tree[0] && tree[0].type == :send
148
+ rng = Range.from_node(tree[0])
149
+ return tree[0] if (rng.contain?(position) || offset + 1 == Position.to_offset(source.code, rng.ending)) && source.code[offset] =~ /[ \t\)\,'")]/
150
+ return tree[0] if (source.code[0..offset-1] =~ /\([\s]*\Z/ || source.code[0..offset-1] =~ /[a-z0-9_][ \t]+\Z/i)
151
+ end
152
+ return tree[1] if tree[1] && tree[1].type == :send
153
+ return tree[3] if tree[1] && tree[3] && tree[1].type == :pair && tree[3].type == :send
154
+ nil
155
+ end
156
+
114
157
  private
115
158
 
116
159
  # @return [Integer]
@@ -118,6 +161,19 @@ module Solargraph
118
161
  @offset ||= Position.to_offset(source.code, position)
119
162
  end
120
163
 
164
+ # @return [Integer]
165
+ def first_char_offset
166
+ @first_char_position ||= begin
167
+ if source.code[offset - 1] == ')'
168
+ position
169
+ else
170
+ index = offset - 1
171
+ index -= 1 while index > 0 && source.code[index].strip.empty?
172
+ index
173
+ end
174
+ end
175
+ end
176
+
121
177
  # A regular expression to find the start of a word from an offset.
122
178
  #
123
179
  # @return [Regexp]
@@ -131,27 +187,6 @@ module Solargraph
131
187
  def end_word_pattern
132
188
  /^([a-z0-9_]|[^\u0000-\u007F])*[\?\!]?/i
133
189
  end
134
-
135
- def signature_position
136
- if @signature_position.nil?
137
- open_parens = 0
138
- cursor = offset - 1
139
- while cursor >= 0
140
- break if cursor < 0
141
- if source.code[cursor] == ')'
142
- open_parens -= 1
143
- elsif source.code[cursor] == '('
144
- open_parens += 1
145
- end
146
- break if open_parens == 1
147
- cursor -= 1
148
- end
149
- if cursor >= 0
150
- @signature_position = Position.from_offset(source.code, cursor)
151
- end
152
- end
153
- @signature_position
154
- end
155
190
  end
156
191
  end
157
192
  end
@@ -43,8 +43,6 @@ module Solargraph
43
43
  def generate_links n
44
44
  return [] unless n.is_a?(Parser::AST::Node)
45
45
  return generate_links(n.children[0]) if n.type == :begin
46
- # @todo This might not be right. It's weird either way.
47
- # return generate_links(n.children[2] || n.children[0]) if n.type == :block
48
46
  result = []
49
47
  if n.type == :block
50
48
  result.concat generate_links(n.children[0])
@@ -52,7 +52,7 @@ module Solargraph
52
52
  # @return [String]
53
53
  def infer_literal_node_type node
54
54
  return nil unless node.kind_of?(AST::Node)
55
- if node.type == :str or node.type == :dstr
55
+ if node.type == :str || node.type == :dstr
56
56
  return 'String'
57
57
  elsif node.type == :array
58
58
  return 'Array'
@@ -66,7 +66,7 @@ module Solargraph
66
66
  return 'Symbol'
67
67
  elsif node.type == :regexp
68
68
  return 'Regexp'
69
- # @todo Maybe ignore nils
69
+ # @todo Support `nil` keyword in types
70
70
  # elsif node.type == :nil
71
71
  # return 'NilClass'
72
72
  end
@@ -142,7 +142,7 @@ module Solargraph
142
142
  class << self
143
143
  CONDITIONAL = [:if, :unless]
144
144
  REDUCEABLE = [:begin, :kwbegin]
145
- SKIPPABLE = [:def, :defs, :class, :sclass, :module]
145
+ SKIPPABLE = [:def, :defs, :class, :sclass, :module, :block]
146
146
 
147
147
  # @param node [Parser::AST::Node]
148
148
  # @return [Array<Parser::AST::Node>]
@@ -157,6 +157,8 @@ module Solargraph
157
157
  result.concat reduce_to_value_nodes(node.children)
158
158
  elsif node.type == :return
159
159
  result.concat reduce_to_value_nodes([node.children[0]])
160
+ elsif node.type == :block
161
+ result.concat reduce_to_value_nodes(node.children[0..-2])
160
162
  else
161
163
  result.push node
162
164
  end
@@ -184,8 +186,9 @@ module Solargraph
184
186
  end
185
187
 
186
188
  def get_return_nodes_only parent
189
+ return [] unless parent.is_a?(Parser::AST::Node)
187
190
  result = []
188
- nodes = parent.children.select{|n| n.is_a?(AST::Node)}
191
+ nodes = parent.children.select{|n| n.is_a?(Parser::AST::Node)}
189
192
  nodes.each do |node|
190
193
  next if SKIPPABLE.include?(node.type)
191
194
  if node.type == :return
@@ -203,8 +206,9 @@ module Solargraph
203
206
  def reduce_to_value_nodes nodes
204
207
  result = []
205
208
  nodes.each do |node|
206
- next unless node.is_a?(Parser::AST::Node)
207
- if REDUCEABLE.include?(node.type)
209
+ if !node.is_a?(Parser::AST::Node)
210
+ result.push nil
211
+ elsif REDUCEABLE.include?(node.type)
208
212
  result.concat get_return_nodes_from_children(node)
209
213
  elsif CONDITIONAL.include?(node.type)
210
214
  result.concat reduce_to_value_nodes(node.children[1..-1])
@@ -212,6 +216,8 @@ module Solargraph
212
216
  result.concat get_return_nodes(node.children[0])
213
217
  elsif node.type == :and || node.type == :or
214
218
  result.concat reduce_to_value_nodes(node.children)
219
+ elsif node.type == :block
220
+ result.concat get_return_nodes_only(node.children[2])
215
221
  else
216
222
  result.push node
217
223
  end
@@ -67,7 +67,7 @@ module Solargraph
67
67
 
68
68
  # @return [String]
69
69
  def phrase
70
- @phrase ||= source.code[signature_data[0]..offset-1]
70
+ @phrase ||= source.code[signature_data..offset-1]
71
71
  end
72
72
 
73
73
  # @return [String]
@@ -120,63 +120,57 @@ module Solargraph
120
120
  brackets = 0
121
121
  squares = 0
122
122
  parens = 0
123
- signature = ''
124
123
  index -=1
125
124
  in_whitespace = false
126
125
  while index >= 0
127
126
  pos = Position.from_offset(@source.code, index)
128
127
  break if index > 0 and @source.comment_at?(pos)
129
- unless !in_whitespace and string?
130
- break if brackets > 0 or parens > 0 or squares > 0
131
- char = @source.code[index, 1]
132
- break if char.nil? # @todo Is this the right way to handle this?
133
- if brackets.zero? and parens.zero? and squares.zero? and [' ', "\r", "\n", "\t"].include?(char)
134
- in_whitespace = true
135
- else
136
- if brackets.zero? and parens.zero? and squares.zero? and in_whitespace
137
- unless char == '.' or @source.code[index+1..-1].strip.start_with?('.')
138
- old = @source.code[index+1..-1]
139
- nxt = @source.code[index+1..-1].lstrip
140
- index += (@source.code[index+1..-1].length - @source.code[index+1..-1].lstrip.length)
141
- break
142
- end
143
- end
144
- if char == ')'
145
- parens -=1
146
- elsif char == ']'
147
- squares -=1
148
- elsif char == '}'
149
- brackets -= 1
150
- elsif char == '('
151
- parens += 1
152
- elsif char == '{'
153
- brackets += 1
154
- elsif char == '['
155
- squares += 1
156
- signature = ".[]#{signature}" if parens.zero? and brackets.zero? and squares.zero? and @source.code[index-2] != '%'
128
+ break if brackets > 0 or parens > 0 or squares > 0
129
+ char = @source.code[index, 1]
130
+ break if char.nil? # @todo Is this the right way to handle this?
131
+ if brackets.zero? and parens.zero? and squares.zero? and [' ', "\r", "\n", "\t"].include?(char)
132
+ in_whitespace = true
133
+ else
134
+ if brackets.zero? and parens.zero? and squares.zero? and in_whitespace
135
+ unless char == '.' or @source.code[index+1..-1].strip.start_with?('.')
136
+ old = @source.code[index+1..-1]
137
+ nxt = @source.code[index+1..-1].lstrip
138
+ index += (@source.code[index+1..-1].length - @source.code[index+1..-1].lstrip.length)
139
+ break
157
140
  end
158
- if brackets.zero? and parens.zero? and squares.zero?
159
- break if ['"', "'", ',', ';', '%'].include?(char)
160
- break if !signature.empty? && ['!', '?'].include?(char)
161
- signature = char + signature if char.match(/[a-z0-9:\._@\$\?\!]/i) and @source.code[index - 1] != '%'
162
- break if char == '$'
163
- if char == '@'
141
+ end
142
+ if char == ')'
143
+ parens -=1
144
+ elsif char == ']'
145
+ squares -=1
146
+ elsif char == '}'
147
+ brackets -= 1
148
+ elsif char == '('
149
+ parens += 1
150
+ elsif char == '{'
151
+ brackets += 1
152
+ elsif char == '['
153
+ squares += 1
154
+ end
155
+ if brackets.zero? and parens.zero? and squares.zero?
156
+ break if ['"', "'", ',', ';', '%'].include?(char)
157
+ break if ['!', '?'].include?(char) && index < offset - 1
158
+ break if char == '$'
159
+ if char == '@'
160
+ index -= 1
161
+ if @source.code[index, 1] == '@'
164
162
  index -= 1
165
- if @source.code[index, 1] == '@'
166
- index -= 1
167
- signature = "@#{signature}"
168
- end
169
- break
170
163
  end
171
- elsif parens == 1 || brackets == 1 || squares == 1
172
164
  break
173
165
  end
174
- in_whitespace = false
166
+ elsif parens == 1 || brackets == 1 || squares == 1
167
+ break
175
168
  end
169
+ in_whitespace = false
176
170
  end
177
171
  index -= 1
178
172
  end
179
- [index + 1, signature]
173
+ index + 1
180
174
  end
181
175
  end
182
176
  end