solargraph 0.32.1 → 0.32.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +6 -0
  5. data/.travis.yml +25 -0
  6. data/EXAMPLES.md +76 -0
  7. data/Gemfile +3 -0
  8. data/LANGUAGE_SERVER.md +51 -0
  9. data/LICENSE +21 -0
  10. data/OVERVIEW.md +37 -0
  11. data/README.md +106 -0
  12. data/Rakefile +14 -0
  13. data/SERVER.md +95 -0
  14. data/bin/solargraph +0 -0
  15. data/bin/solargraph-runtime +5 -5
  16. data/lib/solargraph.rb +54 -54
  17. data/lib/solargraph/api_map.rb +659 -659
  18. data/lib/solargraph/api_map/cache.rb +49 -49
  19. data/lib/solargraph/api_map/source_to_yard.rb +67 -67
  20. data/lib/solargraph/api_map/store.rb +201 -201
  21. data/lib/solargraph/bundle.rb +24 -24
  22. data/lib/solargraph/complex_type.rb +150 -150
  23. data/lib/solargraph/complex_type/type_methods.rb +124 -124
  24. data/lib/solargraph/complex_type/unique_type.rb +44 -44
  25. data/lib/solargraph/core_fills.rb +37 -37
  26. data/lib/solargraph/diagnostics.rb +52 -52
  27. data/lib/solargraph/diagnostics/base.rb +20 -20
  28. data/lib/solargraph/diagnostics/require_not_found.rb +28 -28
  29. data/lib/solargraph/diagnostics/rubocop.rb +98 -98
  30. data/lib/solargraph/diagnostics/rubocop_helpers.rb +46 -46
  31. data/lib/solargraph/diagnostics/type_not_defined.rb +108 -108
  32. data/lib/solargraph/diagnostics/update_errors.rb +38 -38
  33. data/lib/solargraph/language_server/completion_item_kinds.rb +33 -33
  34. data/lib/solargraph/language_server/error_codes.rb +18 -18
  35. data/lib/solargraph/language_server/host.rb +684 -681
  36. data/lib/solargraph/language_server/host/cataloger.rb +54 -79
  37. data/lib/solargraph/language_server/host/diagnoser.rb +80 -80
  38. data/lib/solargraph/language_server/host/dispatch.rb +112 -113
  39. data/lib/solargraph/language_server/host/sources.rb +138 -138
  40. data/lib/solargraph/language_server/message.rb +90 -90
  41. data/lib/solargraph/language_server/message/base.rb +83 -83
  42. data/lib/solargraph/language_server/message/completion_item/resolve.rb +40 -40
  43. data/lib/solargraph/language_server/message/exit_notification.rb +11 -11
  44. data/lib/solargraph/language_server/message/extended.rb +19 -19
  45. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +86 -86
  46. data/lib/solargraph/language_server/message/extended/document.rb +18 -18
  47. data/lib/solargraph/language_server/message/extended/document_gems.rb +30 -30
  48. data/lib/solargraph/language_server/message/extended/environment.rb +20 -20
  49. data/lib/solargraph/language_server/message/extended/search.rb +18 -18
  50. data/lib/solargraph/language_server/message/initialize.rb +141 -141
  51. data/lib/solargraph/language_server/message/initialized.rb +23 -23
  52. data/lib/solargraph/language_server/message/shutdown.rb +11 -11
  53. data/lib/solargraph/language_server/message/text_document.rb +25 -25
  54. data/lib/solargraph/language_server/message/text_document/completion.rb +51 -51
  55. data/lib/solargraph/language_server/message/text_document/definition.rb +18 -18
  56. data/lib/solargraph/language_server/message/text_document/did_change.rb +13 -13
  57. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +21 -21
  58. data/lib/solargraph/language_server/message/text_document/folding_range.rb +24 -24
  59. data/lib/solargraph/language_server/message/text_document/formatting.rb +50 -50
  60. data/lib/solargraph/language_server/message/text_document/hover.rb +31 -31
  61. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +32 -32
  62. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +9 -9
  63. data/lib/solargraph/language_server/message/text_document/references.rb +14 -14
  64. data/lib/solargraph/language_server/message/text_document/rename.rb +17 -17
  65. data/lib/solargraph/language_server/message/text_document/signature_help.rb +19 -19
  66. data/lib/solargraph/language_server/message/workspace.rb +12 -12
  67. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -29
  68. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +29 -27
  69. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -24
  70. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +21 -21
  71. data/lib/solargraph/language_server/request.rb +22 -22
  72. data/lib/solargraph/language_server/symbol_kinds.rb +34 -34
  73. data/lib/solargraph/language_server/transport.rb +11 -11
  74. data/lib/solargraph/language_server/transport/adapter.rb +60 -60
  75. data/lib/solargraph/language_server/transport/data_reader.rb +66 -66
  76. data/lib/solargraph/language_server/uri_helpers.rb +25 -25
  77. data/lib/solargraph/library.rb +421 -419
  78. data/lib/solargraph/live_map.rb +126 -126
  79. data/lib/solargraph/live_map/cache.rb +38 -38
  80. data/lib/solargraph/location.rb +31 -31
  81. data/lib/solargraph/logging.rb +25 -25
  82. data/lib/solargraph/page.rb +68 -68
  83. data/lib/solargraph/pin.rb +50 -50
  84. data/lib/solargraph/pin/attribute.rb +41 -41
  85. data/lib/solargraph/pin/base.rb +280 -280
  86. data/lib/solargraph/pin/base_method.rb +76 -76
  87. data/lib/solargraph/pin/base_variable.rb +72 -72
  88. data/lib/solargraph/pin/block.rb +32 -32
  89. data/lib/solargraph/pin/block_parameter.rb +103 -103
  90. data/lib/solargraph/pin/class_variable.rb +9 -9
  91. data/lib/solargraph/pin/constant.rb +30 -30
  92. data/lib/solargraph/pin/conversions.rb +79 -79
  93. data/lib/solargraph/pin/documenting.rb +41 -41
  94. data/lib/solargraph/pin/duck_method.rb +14 -14
  95. data/lib/solargraph/pin/global_variable.rb +9 -9
  96. data/lib/solargraph/pin/instance_variable.rb +9 -9
  97. data/lib/solargraph/pin/keyword.rb +17 -17
  98. data/lib/solargraph/pin/local_variable.rb +23 -23
  99. data/lib/solargraph/pin/localized.rb +22 -22
  100. data/lib/solargraph/pin/method.rb +126 -126
  101. data/lib/solargraph/pin/method_alias.rb +30 -30
  102. data/lib/solargraph/pin/method_parameter.rb +40 -40
  103. data/lib/solargraph/pin/namespace.rb +54 -54
  104. data/lib/solargraph/pin/plugin/method.rb +25 -25
  105. data/lib/solargraph/pin/proxy_type.rb +35 -35
  106. data/lib/solargraph/pin/reference.rb +22 -22
  107. data/lib/solargraph/pin/reference/extend.rb +11 -11
  108. data/lib/solargraph/pin/reference/include.rb +11 -11
  109. data/lib/solargraph/pin/reference/require.rb +15 -15
  110. data/lib/solargraph/pin/reference/superclass.rb +11 -11
  111. data/lib/solargraph/pin/symbol.rb +44 -44
  112. data/lib/solargraph/pin/yard_pin.rb +10 -10
  113. data/lib/solargraph/pin/yard_pin/constant.rb +14 -14
  114. data/lib/solargraph/pin/yard_pin/method.rb +35 -35
  115. data/lib/solargraph/pin/yard_pin/namespace.rb +19 -19
  116. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +14 -14
  117. data/lib/solargraph/plugin.rb +8 -8
  118. data/lib/solargraph/plugin/base.rb +41 -41
  119. data/lib/solargraph/plugin/canceler.rb +11 -11
  120. data/lib/solargraph/plugin/process.rb +172 -172
  121. data/lib/solargraph/plugin/runtime.rb +134 -134
  122. data/lib/solargraph/position.rb +110 -110
  123. data/lib/solargraph/range.rb +83 -83
  124. data/lib/solargraph/server_methods.rb +14 -14
  125. data/lib/solargraph/shell.rb +102 -102
  126. data/lib/solargraph/source.rb +521 -521
  127. data/lib/solargraph/source/chain.rb +120 -120
  128. data/lib/solargraph/source/chain/call.rb +107 -107
  129. data/lib/solargraph/source/chain/class_variable.rb +11 -11
  130. data/lib/solargraph/source/chain/constant.rb +30 -30
  131. data/lib/solargraph/source/chain/global_variable.rb +11 -11
  132. data/lib/solargraph/source/chain/head.rb +33 -33
  133. data/lib/solargraph/source/chain/instance_variable.rb +11 -11
  134. data/lib/solargraph/source/chain/link.rb +33 -33
  135. data/lib/solargraph/source/chain/literal.rb +21 -21
  136. data/lib/solargraph/source/chain/variable.rb +11 -11
  137. data/lib/solargraph/source/change.rb +77 -77
  138. data/lib/solargraph/source/cursor.rb +157 -157
  139. data/lib/solargraph/source/node_chainer.rb +96 -96
  140. data/lib/solargraph/source/node_methods.rb +225 -225
  141. data/lib/solargraph/source/source_chainer.rb +183 -183
  142. data/lib/solargraph/source_map.rb +169 -169
  143. data/lib/solargraph/source_map/clip.rb +145 -145
  144. data/lib/solargraph/source_map/completion.rb +21 -21
  145. data/lib/solargraph/source_map/mapper.rb +149 -149
  146. data/lib/solargraph/source_map/node_processor.rb +78 -78
  147. data/lib/solargraph/source_map/node_processor/alias_node.rb +19 -19
  148. data/lib/solargraph/source_map/node_processor/args_node.rb +28 -28
  149. data/lib/solargraph/source_map/node_processor/base.rb +68 -68
  150. data/lib/solargraph/source_map/node_processor/begin_node.rb +11 -11
  151. data/lib/solargraph/source_map/node_processor/block_node.rb +14 -14
  152. data/lib/solargraph/source_map/node_processor/casgn_node.rb +14 -14
  153. data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +14 -14
  154. data/lib/solargraph/source_map/node_processor/def_node.rb +54 -54
  155. data/lib/solargraph/source_map/node_processor/defs_node.rb +21 -21
  156. data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +12 -12
  157. data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +18 -18
  158. data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +16 -16
  159. data/lib/solargraph/source_map/node_processor/namespace_node.rb +26 -26
  160. data/lib/solargraph/source_map/node_processor/orasgn_node.rb +12 -12
  161. data/lib/solargraph/source_map/node_processor/sclass_node.rb +11 -11
  162. data/lib/solargraph/source_map/node_processor/send_node.rb +162 -162
  163. data/lib/solargraph/source_map/node_processor/sym_node.rb +11 -11
  164. data/lib/solargraph/source_map/region.rb +58 -58
  165. data/lib/solargraph/version.rb +3 -3
  166. data/lib/solargraph/views/environment.erb +53 -53
  167. data/lib/solargraph/workspace.rb +183 -183
  168. data/lib/solargraph/workspace/config.rb +170 -170
  169. data/lib/solargraph/yard_map.rb +298 -298
  170. data/lib/solargraph/yard_map/cache.rb +17 -17
  171. data/lib/solargraph/yard_map/core_docs.rb +163 -163
  172. data/lib/solargraph/yard_map/core_gen.rb +76 -76
  173. data/lib/yard-coregen.rb +16 -16
  174. data/lib/yard-solargraph.rb +18 -18
  175. data/solargraph.gemspec +37 -0
  176. data/travis-bundler.rb +10 -0
  177. metadata +19 -6
@@ -1,225 +1,225 @@
1
- module Solargraph
2
- class Source
3
- module NodeMethods
4
- module_function
5
-
6
- # @param node [Parser::AST::Node]
7
- # @return [String]
8
- def unpack_name(node)
9
- pack_name(node).join("::")
10
- end
11
-
12
- # @param node [Parser::AST::Node]
13
- # @return [Array<String>]
14
- def pack_name(node)
15
- parts = []
16
- if node.kind_of?(AST::Node)
17
- node.children.each { |n|
18
- if n.kind_of?(AST::Node)
19
- if n.type == :cbase
20
- parts = [''] + pack_name(n)
21
- else
22
- parts += pack_name(n)
23
- end
24
- else
25
- parts.push n unless n.nil?
26
- end
27
- }
28
- end
29
- parts
30
- end
31
-
32
- # @param node [Parser::AST::Node]
33
- # @return [String]
34
- def const_from node
35
- if node.kind_of?(AST::Node) and node.type == :const
36
- result = ''
37
- unless node.children[0].nil?
38
- result = const_from(node.children[0])
39
- end
40
- if result == ''
41
- result = node.children[1].to_s
42
- else
43
- result = result + '::' + node.children[1].to_s
44
- end
45
- result
46
- else
47
- nil
48
- end
49
- end
50
-
51
- # @param node [Parser::AST::Node]
52
- # @return [String]
53
- def infer_literal_node_type node
54
- return nil unless node.kind_of?(AST::Node)
55
- if node.type == :str or node.type == :dstr
56
- return 'String'
57
- elsif node.type == :array
58
- return 'Array'
59
- elsif node.type == :hash
60
- return 'Hash'
61
- elsif node.type == :int
62
- return 'Integer'
63
- elsif node.type == :float
64
- return 'Float'
65
- elsif node.type == :sym
66
- return 'Symbol'
67
- elsif node.type == :regexp
68
- return 'Regexp'
69
- # @todo Maybe ignore nils
70
- # elsif node.type == :nil
71
- # return 'NilClass'
72
- end
73
- nil
74
- end
75
-
76
- # Get a call signature from a node.
77
- # The result should be a string in the form of a method path, e.g.,
78
- # String.new or variable.method.
79
- #
80
- # @param node [Parser::AST::Node]
81
- # @return [String]
82
- def resolve_node_signature node
83
- result = drill_signature node, ''
84
- return nil if result.empty?
85
- result
86
- end
87
-
88
- # @param node [Parser::AST::Node]
89
- # @return [Position]
90
- def get_node_start_position(node)
91
- Position.new(node.loc.line, node.loc.column)
92
- end
93
-
94
- # @param node [Parser::AST::Node]
95
- # @return [Position]
96
- def get_node_end_position(node)
97
- Position.new(node.loc.last_line, node.loc.last_column)
98
- end
99
-
100
- def drill_signature node, signature
101
- return signature unless node.kind_of?(AST::Node)
102
- if node.type == :const or node.type == :cbase
103
- unless node.children[0].nil?
104
- signature += drill_signature(node.children[0], signature)
105
- end
106
- signature += '::' unless signature.empty?
107
- signature += node.children[1].to_s
108
- elsif node.type == :lvar or node.type == :ivar or node.type == :cvar
109
- signature += '.' unless signature.empty?
110
- signature += node.children[0].to_s
111
- elsif node.type == :send
112
- unless node.children[0].nil?
113
- signature += drill_signature(node.children[0], signature)
114
- end
115
- signature += '.' unless signature.empty?
116
- signature += node.children[1].to_s
117
- end
118
- signature
119
- end
120
-
121
- # Find all the nodes within the provided node that potentially return a
122
- # value.
123
- #
124
- # The node parameter typically represents a method's logic, e.g., the
125
- # second child (after the :args node) of a :def node. A simple one-line
126
- # method would typically return itself, while a node with conditions
127
- # would return the resulting node from each conditional branch. Nodes
128
- # that follow a :return node are assumed to be unreachable. Implicit nil
129
- # values are ignored.
130
- #
131
- # @todo Maybe this method should include implicit nil values in results.
132
- # For example, a bare `return` would return a :nil node instead of an
133
- # empty array.
134
- #
135
- # @param node [AST::Node]
136
- # @return [Array<AST::Node>]
137
- def returns_from node
138
- DeepInference.get_return_nodes(node)
139
- end
140
-
141
- module DeepInference
142
- class << self
143
- CONDITIONAL = [:if, :unless]
144
- REDUCEABLE = [:begin, :kwbegin]
145
- SKIPPABLE = [:def, :defs, :class, :sclass, :module]
146
-
147
- # @param node [Parser::AST::Node]
148
- # @return [Array<Parser::AST::Node>]
149
- def get_return_nodes node
150
- return [] unless node.is_a?(Parser::AST::Node)
151
- result = []
152
- if REDUCEABLE.include?(node.type)
153
- result.concat get_return_nodes_from_children(node)
154
- elsif CONDITIONAL.include?(node.type)
155
- result.concat reduce_to_value_nodes(node.children[1..-1])
156
- elsif node.type == :and || node.type == :or
157
- result.concat reduce_to_value_nodes(node.children)
158
- elsif node.type == :return
159
- result.concat reduce_to_value_nodes([node.children[0]])
160
- else
161
- result.push node
162
- end
163
- result
164
- end
165
-
166
- private
167
-
168
- def get_return_nodes_from_children parent
169
- result = []
170
- nodes = parent.children.select{|n| n.is_a?(AST::Node)}
171
- nodes[0..-2].each do |node|
172
- next if SKIPPABLE.include?(node.type)
173
- if node.type == :return
174
- result.concat reduce_to_value_nodes([node.children[0]])
175
- # Return the result here because the rest of the code is
176
- # unreachable
177
- return result
178
- else
179
- result.concat get_return_nodes_only(node)
180
- end
181
- end
182
- result.concat reduce_to_value_nodes([nodes.last]) unless nodes.last.nil?
183
- result
184
- end
185
-
186
- def get_return_nodes_only parent
187
- result = []
188
- nodes = parent.children.select{|n| n.is_a?(AST::Node)}
189
- nodes.each do |node|
190
- next if SKIPPABLE.include?(node.type)
191
- if node.type == :return
192
- result.concat reduce_to_value_nodes([node.children[0]])
193
- # Return the result here because the rest of the code is
194
- # unreachable
195
- return result
196
- else
197
- result.concat get_return_nodes_only(node)
198
- end
199
- end
200
- result
201
- end
202
-
203
- def reduce_to_value_nodes nodes
204
- result = []
205
- nodes.each do |node|
206
- next unless node.is_a?(Parser::AST::Node)
207
- if REDUCEABLE.include?(node.type)
208
- result.concat get_return_nodes_from_children(node)
209
- elsif CONDITIONAL.include?(node.type)
210
- result.concat reduce_to_value_nodes(node.children[1..-1])
211
- elsif node.type == :return
212
- result.concat get_return_nodes(node.children[0])
213
- elsif node.type == :and || node.type == :or
214
- result.concat reduce_to_value_nodes(node.children)
215
- else
216
- result.push node
217
- end
218
- end
219
- result
220
- end
221
- end
222
- end
223
- end
224
- end
225
- end
1
+ module Solargraph
2
+ class Source
3
+ module NodeMethods
4
+ module_function
5
+
6
+ # @param node [Parser::AST::Node]
7
+ # @return [String]
8
+ def unpack_name(node)
9
+ pack_name(node).join("::")
10
+ end
11
+
12
+ # @param node [Parser::AST::Node]
13
+ # @return [Array<String>]
14
+ def pack_name(node)
15
+ parts = []
16
+ if node.kind_of?(AST::Node)
17
+ node.children.each { |n|
18
+ if n.kind_of?(AST::Node)
19
+ if n.type == :cbase
20
+ parts = [''] + pack_name(n)
21
+ else
22
+ parts += pack_name(n)
23
+ end
24
+ else
25
+ parts.push n unless n.nil?
26
+ end
27
+ }
28
+ end
29
+ parts
30
+ end
31
+
32
+ # @param node [Parser::AST::Node]
33
+ # @return [String]
34
+ def const_from node
35
+ if node.kind_of?(AST::Node) and node.type == :const
36
+ result = ''
37
+ unless node.children[0].nil?
38
+ result = const_from(node.children[0])
39
+ end
40
+ if result == ''
41
+ result = node.children[1].to_s
42
+ else
43
+ result = result + '::' + node.children[1].to_s
44
+ end
45
+ result
46
+ else
47
+ nil
48
+ end
49
+ end
50
+
51
+ # @param node [Parser::AST::Node]
52
+ # @return [String]
53
+ def infer_literal_node_type node
54
+ return nil unless node.kind_of?(AST::Node)
55
+ if node.type == :str or node.type == :dstr
56
+ return 'String'
57
+ elsif node.type == :array
58
+ return 'Array'
59
+ elsif node.type == :hash
60
+ return 'Hash'
61
+ elsif node.type == :int
62
+ return 'Integer'
63
+ elsif node.type == :float
64
+ return 'Float'
65
+ elsif node.type == :sym
66
+ return 'Symbol'
67
+ elsif node.type == :regexp
68
+ return 'Regexp'
69
+ # @todo Maybe ignore nils
70
+ # elsif node.type == :nil
71
+ # return 'NilClass'
72
+ end
73
+ nil
74
+ end
75
+
76
+ # Get a call signature from a node.
77
+ # The result should be a string in the form of a method path, e.g.,
78
+ # String.new or variable.method.
79
+ #
80
+ # @param node [Parser::AST::Node]
81
+ # @return [String]
82
+ def resolve_node_signature node
83
+ result = drill_signature node, ''
84
+ return nil if result.empty?
85
+ result
86
+ end
87
+
88
+ # @param node [Parser::AST::Node]
89
+ # @return [Position]
90
+ def get_node_start_position(node)
91
+ Position.new(node.loc.line, node.loc.column)
92
+ end
93
+
94
+ # @param node [Parser::AST::Node]
95
+ # @return [Position]
96
+ def get_node_end_position(node)
97
+ Position.new(node.loc.last_line, node.loc.last_column)
98
+ end
99
+
100
+ def drill_signature node, signature
101
+ return signature unless node.kind_of?(AST::Node)
102
+ if node.type == :const or node.type == :cbase
103
+ unless node.children[0].nil?
104
+ signature += drill_signature(node.children[0], signature)
105
+ end
106
+ signature += '::' unless signature.empty?
107
+ signature += node.children[1].to_s
108
+ elsif node.type == :lvar or node.type == :ivar or node.type == :cvar
109
+ signature += '.' unless signature.empty?
110
+ signature += node.children[0].to_s
111
+ elsif node.type == :send
112
+ unless node.children[0].nil?
113
+ signature += drill_signature(node.children[0], signature)
114
+ end
115
+ signature += '.' unless signature.empty?
116
+ signature += node.children[1].to_s
117
+ end
118
+ signature
119
+ end
120
+
121
+ # Find all the nodes within the provided node that potentially return a
122
+ # value.
123
+ #
124
+ # The node parameter typically represents a method's logic, e.g., the
125
+ # second child (after the :args node) of a :def node. A simple one-line
126
+ # method would typically return itself, while a node with conditions
127
+ # would return the resulting node from each conditional branch. Nodes
128
+ # that follow a :return node are assumed to be unreachable. Implicit nil
129
+ # values are ignored.
130
+ #
131
+ # @todo Maybe this method should include implicit nil values in results.
132
+ # For example, a bare `return` would return a :nil node instead of an
133
+ # empty array.
134
+ #
135
+ # @param node [AST::Node]
136
+ # @return [Array<AST::Node>]
137
+ def returns_from node
138
+ DeepInference.get_return_nodes(node)
139
+ end
140
+
141
+ module DeepInference
142
+ class << self
143
+ CONDITIONAL = [:if, :unless]
144
+ REDUCEABLE = [:begin, :kwbegin]
145
+ SKIPPABLE = [:def, :defs, :class, :sclass, :module]
146
+
147
+ # @param node [Parser::AST::Node]
148
+ # @return [Array<Parser::AST::Node>]
149
+ def get_return_nodes node
150
+ return [] unless node.is_a?(Parser::AST::Node)
151
+ result = []
152
+ if REDUCEABLE.include?(node.type)
153
+ result.concat get_return_nodes_from_children(node)
154
+ elsif CONDITIONAL.include?(node.type)
155
+ result.concat reduce_to_value_nodes(node.children[1..-1])
156
+ elsif node.type == :and || node.type == :or
157
+ result.concat reduce_to_value_nodes(node.children)
158
+ elsif node.type == :return
159
+ result.concat reduce_to_value_nodes([node.children[0]])
160
+ else
161
+ result.push node
162
+ end
163
+ result
164
+ end
165
+
166
+ private
167
+
168
+ def get_return_nodes_from_children parent
169
+ result = []
170
+ nodes = parent.children.select{|n| n.is_a?(AST::Node)}
171
+ nodes[0..-2].each do |node|
172
+ next if SKIPPABLE.include?(node.type)
173
+ if node.type == :return
174
+ result.concat reduce_to_value_nodes([node.children[0]])
175
+ # Return the result here because the rest of the code is
176
+ # unreachable
177
+ return result
178
+ else
179
+ result.concat get_return_nodes_only(node)
180
+ end
181
+ end
182
+ result.concat reduce_to_value_nodes([nodes.last]) unless nodes.last.nil?
183
+ result
184
+ end
185
+
186
+ def get_return_nodes_only parent
187
+ result = []
188
+ nodes = parent.children.select{|n| n.is_a?(AST::Node)}
189
+ nodes.each do |node|
190
+ next if SKIPPABLE.include?(node.type)
191
+ if node.type == :return
192
+ result.concat reduce_to_value_nodes([node.children[0]])
193
+ # Return the result here because the rest of the code is
194
+ # unreachable
195
+ return result
196
+ else
197
+ result.concat get_return_nodes_only(node)
198
+ end
199
+ end
200
+ result
201
+ end
202
+
203
+ def reduce_to_value_nodes nodes
204
+ result = []
205
+ nodes.each do |node|
206
+ next unless node.is_a?(Parser::AST::Node)
207
+ if REDUCEABLE.include?(node.type)
208
+ result.concat get_return_nodes_from_children(node)
209
+ elsif CONDITIONAL.include?(node.type)
210
+ result.concat reduce_to_value_nodes(node.children[1..-1])
211
+ elsif node.type == :return
212
+ result.concat get_return_nodes(node.children[0])
213
+ elsif node.type == :and || node.type == :or
214
+ result.concat reduce_to_value_nodes(node.children)
215
+ else
216
+ result.push node
217
+ end
218
+ end
219
+ result
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
@@ -1,183 +1,183 @@
1
- module Solargraph
2
- class Source
3
- # Information about a location in a source, including the location's word
4
- # and signature, literal values at the base of signatures, and whether the
5
- # location is inside a string or comment. ApiMaps use Fragments to provide
6
- # results for completion and definition queries.
7
- #
8
- class SourceChainer
9
- include Source::NodeMethods
10
-
11
- private_class_method :new
12
-
13
- class << self
14
- # @param source [Source]
15
- # @param position [Position]
16
- # @return [Source::Chain]
17
- def chain source, position
18
- # raise "Not a source" unless source.is_a?(Source)
19
- new(source, position).chain
20
- end
21
- end
22
-
23
- # @param source [Source]
24
- # @param position [Position]
25
- def initialize source, position
26
- @source = source
27
- @position = position
28
- @calculated_literal = false
29
- end
30
-
31
- # @return [Source::Chain]
32
- def chain
33
- return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
34
- begin
35
- return Chain.new([]) if phrase.end_with?('..')
36
- if !source.repaired? && source.parsed? && source.synchronized?
37
- node = source.node_at(position.line, position.column)
38
- else
39
- node = nil
40
- node = source.node_at(fixed_position.line, fixed_position.column) unless source.error_ranges.any?{|r| r.nil? || r.include?(fixed_position)}
41
- # Exception for positions that chain literal nodes in unsynchronized sources
42
- node = nil unless source.synchronized? || !infer_literal_node_type(node).nil?
43
- node = Source.parse(fixed_phrase) if node.nil?
44
- end
45
- rescue Parser::SyntaxError
46
- return Chain.new([Chain::UNDEFINED_CALL])
47
- end
48
- return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
49
- chain = NodeChainer.chain(node, source.filename)
50
- if source.repaired? || !source.parsed? || !source.synchronized?
51
- if end_of_phrase.strip == '.'
52
- chain.links.push Chain::UNDEFINED_CALL
53
- elsif end_of_phrase.strip == '::'
54
- chain.links.push Chain::UNDEFINED_CONSTANT
55
- end
56
- end
57
- chain
58
- end
59
-
60
- private
61
-
62
- # @return [Position]
63
- attr_reader :position
64
-
65
- # @return [Solargraph::Source]
66
- attr_reader :source
67
-
68
- # @return [String]
69
- def phrase
70
- @phrase ||= source.code[signature_data[0]..offset-1]
71
- end
72
-
73
- # @return [String]
74
- def fixed_phrase
75
- @fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
76
- end
77
-
78
- # @return [Position]
79
- def fixed_position
80
- @fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
81
- end
82
-
83
- # @return [String]
84
- def end_of_phrase
85
- @end_of_phrase ||= begin
86
- match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
87
- if match
88
- match[0]
89
- else
90
- ''
91
- end
92
- end
93
- end
94
-
95
- # True if the current offset is inside a string.
96
- #
97
- # @return [Boolean]
98
- def string?
99
- # @string ||= (node.type == :str or node.type == :dstr)
100
- @string ||= @source.string_at?(position)
101
- end
102
-
103
- # @return [Integer]
104
- def offset
105
- @offset ||= get_offset(position.line, position.column)
106
- end
107
-
108
- # @param line [Integer]
109
- # @param column [Integer]
110
- # @return [Integer]
111
- def get_offset line, column
112
- Position.line_char_to_offset(@source.code, line, column)
113
- end
114
-
115
- def signature_data
116
- @signature_data ||= get_signature_data_at(offset)
117
- end
118
-
119
- def get_signature_data_at index
120
- brackets = 0
121
- squares = 0
122
- parens = 0
123
- signature = ''
124
- index -=1
125
- in_whitespace = false
126
- while index >= 0
127
- pos = Position.from_offset(@source.code, index)
128
- 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] != '%'
157
- 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 == '@'
164
- index -= 1
165
- if @source.code[index, 1] == '@'
166
- index -= 1
167
- signature = "@#{signature}"
168
- end
169
- break
170
- end
171
- elsif parens == 1 || brackets == 1 || squares == 1
172
- break
173
- end
174
- in_whitespace = false
175
- end
176
- end
177
- index -= 1
178
- end
179
- [index + 1, signature]
180
- end
181
- end
182
- end
183
- end
1
+ module Solargraph
2
+ class Source
3
+ # Information about a location in a source, including the location's word
4
+ # and signature, literal values at the base of signatures, and whether the
5
+ # location is inside a string or comment. ApiMaps use Fragments to provide
6
+ # results for completion and definition queries.
7
+ #
8
+ class SourceChainer
9
+ include Source::NodeMethods
10
+
11
+ private_class_method :new
12
+
13
+ class << self
14
+ # @param source [Source]
15
+ # @param position [Position]
16
+ # @return [Source::Chain]
17
+ def chain source, position
18
+ # raise "Not a source" unless source.is_a?(Source)
19
+ new(source, position).chain
20
+ end
21
+ end
22
+
23
+ # @param source [Source]
24
+ # @param position [Position]
25
+ def initialize source, position
26
+ @source = source
27
+ @position = position
28
+ @calculated_literal = false
29
+ end
30
+
31
+ # @return [Source::Chain]
32
+ def chain
33
+ return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
34
+ begin
35
+ return Chain.new([]) if phrase.end_with?('..')
36
+ if !source.repaired? && source.parsed? && source.synchronized?
37
+ node = source.node_at(position.line, position.column)
38
+ else
39
+ node = nil
40
+ node = source.node_at(fixed_position.line, fixed_position.column) unless source.error_ranges.any?{|r| r.nil? || r.include?(fixed_position)}
41
+ # Exception for positions that chain literal nodes in unsynchronized sources
42
+ node = nil unless source.synchronized? || !infer_literal_node_type(node).nil?
43
+ node = Source.parse(fixed_phrase) if node.nil?
44
+ end
45
+ rescue Parser::SyntaxError
46
+ return Chain.new([Chain::UNDEFINED_CALL])
47
+ end
48
+ return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
49
+ chain = NodeChainer.chain(node, source.filename)
50
+ if source.repaired? || !source.parsed? || !source.synchronized?
51
+ if end_of_phrase.strip == '.'
52
+ chain.links.push Chain::UNDEFINED_CALL
53
+ elsif end_of_phrase.strip == '::'
54
+ chain.links.push Chain::UNDEFINED_CONSTANT
55
+ end
56
+ end
57
+ chain
58
+ end
59
+
60
+ private
61
+
62
+ # @return [Position]
63
+ attr_reader :position
64
+
65
+ # @return [Solargraph::Source]
66
+ attr_reader :source
67
+
68
+ # @return [String]
69
+ def phrase
70
+ @phrase ||= source.code[signature_data[0]..offset-1]
71
+ end
72
+
73
+ # @return [String]
74
+ def fixed_phrase
75
+ @fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
76
+ end
77
+
78
+ # @return [Position]
79
+ def fixed_position
80
+ @fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
81
+ end
82
+
83
+ # @return [String]
84
+ def end_of_phrase
85
+ @end_of_phrase ||= begin
86
+ match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
87
+ if match
88
+ match[0]
89
+ else
90
+ ''
91
+ end
92
+ end
93
+ end
94
+
95
+ # True if the current offset is inside a string.
96
+ #
97
+ # @return [Boolean]
98
+ def string?
99
+ # @string ||= (node.type == :str or node.type == :dstr)
100
+ @string ||= @source.string_at?(position)
101
+ end
102
+
103
+ # @return [Integer]
104
+ def offset
105
+ @offset ||= get_offset(position.line, position.column)
106
+ end
107
+
108
+ # @param line [Integer]
109
+ # @param column [Integer]
110
+ # @return [Integer]
111
+ def get_offset line, column
112
+ Position.line_char_to_offset(@source.code, line, column)
113
+ end
114
+
115
+ def signature_data
116
+ @signature_data ||= get_signature_data_at(offset)
117
+ end
118
+
119
+ def get_signature_data_at index
120
+ brackets = 0
121
+ squares = 0
122
+ parens = 0
123
+ signature = ''
124
+ index -=1
125
+ in_whitespace = false
126
+ while index >= 0
127
+ pos = Position.from_offset(@source.code, index)
128
+ 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] != '%'
157
+ 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 == '@'
164
+ index -= 1
165
+ if @source.code[index, 1] == '@'
166
+ index -= 1
167
+ signature = "@#{signature}"
168
+ end
169
+ break
170
+ end
171
+ elsif parens == 1 || brackets == 1 || squares == 1
172
+ break
173
+ end
174
+ in_whitespace = false
175
+ end
176
+ end
177
+ index -= 1
178
+ end
179
+ [index + 1, signature]
180
+ end
181
+ end
182
+ end
183
+ end