solargraph 0.32.5 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
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