solargraph 0.32.1 → 0.32.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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