solargraph 0.58.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.gitattributes +2 -0
  4. data/.github/workflows/linting.yml +6 -5
  5. data/.github/workflows/plugins.yml +48 -35
  6. data/.github/workflows/rspec.yml +15 -28
  7. data/.github/workflows/typecheck.yml +3 -2
  8. data/.gitignore +1 -0
  9. data/.rubocop.yml +38 -6
  10. data/.rubocop_todo.yml +53 -966
  11. data/CHANGELOG.md +24 -0
  12. data/Gemfile +3 -1
  13. data/README.md +3 -3
  14. data/Rakefile +26 -23
  15. data/bin/solargraph +9 -8
  16. data/lib/solargraph/api_map/cache.rb +110 -110
  17. data/lib/solargraph/api_map/constants.rb +288 -279
  18. data/lib/solargraph/api_map/index.rb +204 -193
  19. data/lib/solargraph/api_map/source_to_yard.rb +110 -97
  20. data/lib/solargraph/api_map/store.rb +395 -384
  21. data/lib/solargraph/api_map.rb +1029 -945
  22. data/lib/solargraph/bench.rb +44 -45
  23. data/lib/solargraph/complex_type/conformance.rb +176 -0
  24. data/lib/solargraph/complex_type/type_methods.rb +240 -228
  25. data/lib/solargraph/complex_type/unique_type.rb +641 -482
  26. data/lib/solargraph/complex_type.rb +557 -444
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  29. data/lib/solargraph/convention/data_definition.rb +108 -105
  30. data/lib/solargraph/convention/gemfile.rb +15 -15
  31. data/lib/solargraph/convention/gemspec.rb +23 -23
  32. data/lib/solargraph/convention/rakefile.rb +17 -17
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  35. data/lib/solargraph/convention/struct_definition.rb +168 -164
  36. data/lib/solargraph/convention.rb +78 -78
  37. data/lib/solargraph/converters/dd.rb +19 -17
  38. data/lib/solargraph/converters/dl.rb +17 -15
  39. data/lib/solargraph/converters/dt.rb +17 -15
  40. data/lib/solargraph/converters/misc.rb +3 -1
  41. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  42. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  44. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  45. data/lib/solargraph/diagnostics/update_errors.rb +37 -41
  46. data/lib/solargraph/doc_map.rb +438 -439
  47. data/lib/solargraph/equality.rb +34 -34
  48. data/lib/solargraph/gem_pins.rb +98 -98
  49. data/lib/solargraph/language_server/error_codes.rb +20 -20
  50. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  51. data/lib/solargraph/language_server/host/dispatch.rb +130 -130
  52. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  53. data/lib/solargraph/language_server/host/sources.rb +100 -99
  54. data/lib/solargraph/language_server/host.rb +886 -878
  55. data/lib/solargraph/language_server/message/base.rb +97 -97
  56. data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
  57. data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
  58. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +108 -114
  59. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  60. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  61. data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
  62. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  63. data/lib/solargraph/language_server/message/initialize.rb +197 -191
  64. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  65. data/lib/solargraph/language_server/message/text_document/definition.rb +49 -40
  66. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
  67. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +36 -26
  68. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  69. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  70. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
  71. data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
  72. data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
  73. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  74. data/lib/solargraph/language_server/message/text_document/type_definition.rb +33 -25
  75. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
  76. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
  77. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
  78. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +33 -23
  79. data/lib/solargraph/language_server/message.rb +94 -94
  80. data/lib/solargraph/language_server/request.rb +29 -27
  81. data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
  82. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  83. data/lib/solargraph/library.rb +702 -683
  84. data/lib/solargraph/location.rb +85 -82
  85. data/lib/solargraph/logging.rb +55 -37
  86. data/lib/solargraph/page.rb +92 -92
  87. data/lib/solargraph/parser/comment_ripper.rb +84 -69
  88. data/lib/solargraph/parser/flow_sensitive_typing.rb +471 -255
  89. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  90. data/lib/solargraph/parser/node_processor.rb +63 -62
  91. data/lib/solargraph/parser/parser_gem/class_methods.rb +165 -149
  92. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  93. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  94. data/lib/solargraph/parser/parser_gem/node_methods.rb +507 -486
  95. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  96. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  97. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  98. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +45 -46
  99. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  100. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
  101. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  102. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +42 -40
  103. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  104. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  105. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  106. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  108. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  109. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +51 -52
  110. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +302 -291
  111. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  112. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  113. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  114. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  115. data/lib/solargraph/parser/parser_gem.rb +14 -12
  116. data/lib/solargraph/parser/region.rb +75 -69
  117. data/lib/solargraph/parser/snippet.rb +19 -17
  118. data/lib/solargraph/parser.rb +25 -23
  119. data/lib/solargraph/pin/base.rb +773 -729
  120. data/lib/solargraph/pin/base_variable.rb +375 -126
  121. data/lib/solargraph/pin/block.rb +127 -104
  122. data/lib/solargraph/pin/breakable.rb +15 -9
  123. data/lib/solargraph/pin/callable.rb +275 -231
  124. data/lib/solargraph/pin/closure.rb +69 -72
  125. data/lib/solargraph/pin/common.rb +97 -79
  126. data/lib/solargraph/pin/compound_statement.rb +55 -0
  127. data/lib/solargraph/pin/constant.rb +43 -45
  128. data/lib/solargraph/pin/conversions.rb +129 -123
  129. data/lib/solargraph/pin/delegated_method.rb +131 -120
  130. data/lib/solargraph/pin/documenting.rb +116 -114
  131. data/lib/solargraph/pin/instance_variable.rb +38 -34
  132. data/lib/solargraph/pin/keyword.rb +16 -20
  133. data/lib/solargraph/pin/local_variable.rb +31 -75
  134. data/lib/solargraph/pin/method.rb +724 -672
  135. data/lib/solargraph/pin/method_alias.rb +42 -34
  136. data/lib/solargraph/pin/namespace.rb +122 -115
  137. data/lib/solargraph/pin/parameter.rb +339 -275
  138. data/lib/solargraph/pin/proxy_type.rb +42 -39
  139. data/lib/solargraph/pin/reference/override.rb +47 -47
  140. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  141. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  142. data/lib/solargraph/pin/reference.rb +59 -39
  143. data/lib/solargraph/pin/search.rb +62 -61
  144. data/lib/solargraph/pin/signature.rb +64 -61
  145. data/lib/solargraph/pin/symbol.rb +54 -53
  146. data/lib/solargraph/pin/until.rb +16 -18
  147. data/lib/solargraph/pin/while.rb +16 -18
  148. data/lib/solargraph/pin.rb +46 -44
  149. data/lib/solargraph/pin_cache.rb +248 -245
  150. data/lib/solargraph/position.rb +139 -119
  151. data/lib/solargraph/range.rb +113 -112
  152. data/lib/solargraph/rbs_map/conversions.rb +952 -823
  153. data/lib/solargraph/rbs_map/core_fills.rb +91 -84
  154. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  155. data/lib/solargraph/rbs_map/stdlib_map.rb +71 -43
  156. data/lib/solargraph/rbs_map.rb +207 -163
  157. data/lib/solargraph/server_methods.rb +16 -16
  158. data/lib/solargraph/shell.rb +555 -352
  159. data/lib/solargraph/source/chain/array.rb +39 -37
  160. data/lib/solargraph/source/chain/call.rb +377 -337
  161. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  162. data/lib/solargraph/source/chain/constant.rb +30 -26
  163. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  164. data/lib/solargraph/source/chain/hash.rb +37 -34
  165. data/lib/solargraph/source/chain/if.rb +30 -28
  166. data/lib/solargraph/source/chain/instance_variable.rb +36 -13
  167. data/lib/solargraph/source/chain/link.rb +99 -109
  168. data/lib/solargraph/source/chain/literal.rb +51 -48
  169. data/lib/solargraph/source/chain/or.rb +29 -23
  170. data/lib/solargraph/source/chain/q_call.rb +13 -11
  171. data/lib/solargraph/source/chain/variable.rb +15 -13
  172. data/lib/solargraph/source/chain/z_super.rb +28 -30
  173. data/lib/solargraph/source/chain.rb +304 -291
  174. data/lib/solargraph/source/change.rb +89 -82
  175. data/lib/solargraph/source/cursor.rb +172 -166
  176. data/lib/solargraph/source/encoding_fixes.rb +22 -23
  177. data/lib/solargraph/source/source_chainer.rb +218 -194
  178. data/lib/solargraph/source/updater.rb +59 -55
  179. data/lib/solargraph/source.rb +522 -498
  180. data/lib/solargraph/source_map/clip.rb +245 -226
  181. data/lib/solargraph/source_map/data.rb +37 -34
  182. data/lib/solargraph/source_map/mapper.rb +286 -259
  183. data/lib/solargraph/source_map.rb +224 -212
  184. data/lib/solargraph/type_checker/problem.rb +34 -32
  185. data/lib/solargraph/type_checker/rules.rb +157 -84
  186. data/lib/solargraph/type_checker.rb +888 -814
  187. data/lib/solargraph/version.rb +5 -5
  188. data/lib/solargraph/workspace/config.rb +258 -255
  189. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  190. data/lib/solargraph/workspace/require_paths.rb +98 -97
  191. data/lib/solargraph/workspace.rb +242 -220
  192. data/lib/solargraph/yard_map/helpers.rb +49 -44
  193. data/lib/solargraph/yard_map/mapper/to_method.rb +136 -130
  194. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  195. data/lib/solargraph/yard_map/mapper.rb +84 -79
  196. data/lib/solargraph/yard_map.rb +17 -18
  197. data/lib/solargraph/yard_tags.rb +20 -20
  198. data/lib/solargraph/yardoc.rb +90 -87
  199. data/lib/solargraph.rb +128 -105
  200. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  201. data/rbs/fills/tuple/tuple.rbs +28 -0
  202. data/rbs/shims/ast/0/node.rbs +5 -0
  203. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  204. data/rbs_collection.yaml +1 -1
  205. data/solargraph.gemspec +37 -35
  206. metadata +52 -51
  207. data/lib/solargraph/type_checker/checks.rb +0 -124
  208. data/lib/solargraph/type_checker/param_def.rb +0 -37
  209. data/lib/solargraph/yard_map/to_method.rb +0 -89
  210. data/sig/shims/ast/0/node.rbs +0 -5
  211. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  212. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  213. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  214. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  215. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  216. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  217. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  218. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  219. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,194 +1,218 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class Source
5
- # Information about a location in a source, including the location's word
6
- # and signature, literal values at the base of signatures, and whether the
7
- # location is inside a string or comment. ApiMaps use Fragments to provide
8
- # results for completion and definition queries.
9
- #
10
- class SourceChainer
11
- # include Source::NodeMethods
12
-
13
- private_class_method :new
14
-
15
- class << self
16
- # @param source [Source]
17
- # @param position [Position, Array(Integer, Integer)]
18
- # @return [Source::Chain]
19
- def chain source, position
20
- new(source, Solargraph::Position.normalize(position)).chain
21
- end
22
- end
23
-
24
- # @param source [Source]
25
- # @param position [Position]
26
- def initialize source, position
27
- @source = source
28
- @position = position
29
- @calculated_literal = false
30
- end
31
-
32
- # @return [Source::Chain]
33
- def chain
34
- # Special handling for files that end with an integer and a period
35
- return Chain.new([Chain::Literal.new('Integer', Integer(phrase[0..-2])), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
36
- return Chain.new([Chain::Literal.new('Symbol', phrase[1..].to_sym)]) if phrase.start_with?(':') && !phrase.start_with?('::')
37
- return SourceChainer.chain(source, Position.new(position.line, position.character + 1)) if end_of_phrase.strip == '::' && source.code[Position.to_offset(source.code, position)].to_s.match?(/[a-z]/i)
38
- begin
39
- return Chain.new([]) if phrase.end_with?('..')
40
- node = nil
41
- parent = nil
42
- if !source.repaired? && source.parsed? && source.synchronized?
43
- tree = source.tree_at(position.line, position.column)
44
- node, parent = tree[0..2]
45
- elsif source.parsed? && source.repaired? && end_of_phrase == '.'
46
- node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2]
47
- node = Parser.parse(fixed_phrase) if node.nil?
48
- elsif source.repaired?
49
- node = Parser.parse(fixed_phrase)
50
- else
51
- node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2] unless source.error_ranges.any?{|r| r.nil? || r.include?(fixed_position)}
52
- # Exception for positions that chain literal nodes in unsynchronized sources
53
- node = nil unless source.synchronized? || !Parser.infer_literal_node_type(node).nil?
54
- node = Parser.parse(fixed_phrase) if node.nil?
55
- end
56
- rescue Parser::SyntaxError
57
- return Chain.new([Chain::UNDEFINED_CALL])
58
- end
59
- return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
60
- # chain = NodeChainer.chain(node, source.filename, parent && parent.type == :block)
61
- chain = Parser.chain(node, source.filename, parent)
62
- if source.repaired? || !source.parsed? || !source.synchronized?
63
- if end_of_phrase.strip == '.'
64
- chain.links.push Chain::UNDEFINED_CALL
65
- elsif end_of_phrase.strip == '::'
66
- chain.links.push Chain::UNDEFINED_CONSTANT
67
- end
68
- elsif chain.links.last.is_a?(Source::Chain::Constant) && end_of_phrase.strip == '::'
69
- chain.links.push Source::Chain::UNDEFINED_CONSTANT
70
- end
71
- chain
72
- end
73
-
74
- private
75
-
76
- # @return [Position]
77
- attr_reader :position
78
-
79
- # @return [Solargraph::Source]
80
- attr_reader :source
81
-
82
- # @return [String]
83
- def phrase
84
- @phrase ||= source.code[signature_data..offset-1]
85
- end
86
-
87
- # @return [String]
88
- def fixed_phrase
89
- @fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
90
- end
91
-
92
- # @return [Position]
93
- def fixed_position
94
- @fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
95
- end
96
-
97
- # @return [String]
98
- def end_of_phrase
99
- @end_of_phrase ||= begin
100
- match = phrase.match(/\s*(\.{1}|::)\s*$/)
101
- if match
102
- match[0]
103
- else
104
- ''
105
- end
106
- end
107
- end
108
-
109
- # True if the current offset is inside a string.
110
- #
111
- # @return [Boolean]
112
- def string?
113
- # @string ||= (node.type == :str or node.type == :dstr)
114
- @string ||= @source.string_at?(position)
115
- end
116
-
117
- # @return [Integer]
118
- def offset
119
- @offset ||= get_offset(position.line, position.column)
120
- end
121
-
122
- # @param line [Integer]
123
- # @param column [Integer]
124
- # @return [Integer]
125
- def get_offset line, column
126
- Position.line_char_to_offset(@source.code, line, column)
127
- end
128
-
129
- # @return [Integer]
130
- def signature_data
131
- @signature_data ||= get_signature_data_at(offset)
132
- end
133
-
134
- # @param index [Integer]
135
- # @return [Integer]
136
- def get_signature_data_at index
137
- brackets = 0
138
- squares = 0
139
- parens = 0
140
- index -=1
141
- in_whitespace = false
142
- while index >= 0
143
- pos = Position.from_offset(@source.code, index)
144
- break if index > 0 and @source.comment_at?(pos)
145
- break if brackets > 0 or parens > 0 or squares > 0
146
- char = @source.code[index, 1]
147
- break if char.nil? # @todo Is this the right way to handle this?
148
- if brackets.zero? and parens.zero? and squares.zero? and [' ', "\r", "\n", "\t"].include?(char)
149
- in_whitespace = true
150
- else
151
- if brackets.zero? and parens.zero? and squares.zero? and in_whitespace
152
- unless char == '.' or @source.code[index+1..-1].strip.start_with?('.')
153
- old = @source.code[index+1..-1]
154
- nxt = @source.code[index+1..-1].lstrip
155
- index += (@source.code[index+1..-1].length - @source.code[index+1..-1].lstrip.length)
156
- break
157
- end
158
- end
159
- if char == ')'
160
- parens -=1
161
- elsif char == ']'
162
- squares -=1
163
- elsif char == '}'
164
- brackets -= 1
165
- elsif char == '('
166
- parens += 1
167
- elsif char == '{'
168
- brackets += 1
169
- elsif char == '['
170
- squares += 1
171
- end
172
- if brackets.zero? and parens.zero? and squares.zero?
173
- break if ['"', "'", ',', ';', '%'].include?(char)
174
- break if ['!', '?'].include?(char) && index < offset - 1
175
- break if char == '$'
176
- if char == '@'
177
- index -= 1
178
- if @source.code[index, 1] == '@'
179
- index -= 1
180
- end
181
- break
182
- end
183
- elsif parens == 1 || brackets == 1 || squares == 1
184
- break
185
- end
186
- in_whitespace = false
187
- end
188
- index -= 1
189
- end
190
- index + 1
191
- end
192
- end
193
- end
194
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ # Information about a location in a source, including the location's word
6
+ # and signature, literal values at the base of signatures, and whether the
7
+ # location is inside a string or comment. ApiMaps use Fragments to provide
8
+ # results for completion and definition queries.
9
+ #
10
+ class SourceChainer
11
+ # include Source::NodeMethods
12
+
13
+ private_class_method :new
14
+
15
+ class << self
16
+ # @param source [Source]
17
+ # @param position [Position, Array(Integer, Integer)]
18
+ # @return [Source::Chain]
19
+ def chain source, position
20
+ new(source, Solargraph::Position.normalize(position)).chain
21
+ end
22
+ end
23
+
24
+ # @param source [Source]
25
+ # @param position [Position]
26
+ def initialize source, position
27
+ @source = source
28
+ @position = position
29
+ @calculated_literal = false
30
+ end
31
+
32
+ # @return [Source::Chain]
33
+ def chain
34
+ # Special handling for files that end with an integer and a period
35
+ if phrase =~ /^[0-9]+\.$/
36
+ return Chain.new([Chain::Literal.new('Integer', Integer(phrase[0..-2])),
37
+ Chain::UNDEFINED_CALL])
38
+ end
39
+ if phrase.start_with?(':') && !phrase.start_with?('::')
40
+ return Chain.new([Chain::Literal.new('Symbol',
41
+ # @sg-ignore Need to add nil check here
42
+ phrase[1..].to_sym)])
43
+ end
44
+ if end_of_phrase.strip == '::' && source.code[Position.to_offset(
45
+ source.code, position
46
+ )].to_s.match?(/[a-z]/i)
47
+ return SourceChainer.chain(source,
48
+ Position.new(position.line,
49
+ position.character + 1))
50
+ end
51
+ begin
52
+ return Chain.new([]) if phrase.end_with?('..')
53
+ # @type [::Parser::AST::Node, nil]
54
+ node = nil
55
+ # @type [::Parser::AST::Node, nil]
56
+ parent = nil
57
+ if !source.repaired? && source.parsed? && source.synchronized?
58
+ tree = source.tree_at(position.line, position.column)
59
+ node, parent = tree[0..2]
60
+ elsif source.parsed? && source.repaired? && end_of_phrase == '.'
61
+ node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2]
62
+ # provide filename and line so that we can look up local variables there later
63
+ node = Parser.parse(fixed_phrase, source.filename, fixed_position.line) if node.nil?
64
+ elsif source.repaired?
65
+ node = Parser.parse(fixed_phrase, source.filename, fixed_position.line)
66
+ else
67
+ unless source.error_ranges.any? do |r|
68
+ r.nil? || r.include?(fixed_position)
69
+ end
70
+ node, parent = source.tree_at(fixed_position.line,
71
+ fixed_position.column)[0..2]
72
+ end
73
+ # Exception for positions that chain literal nodes in unsynchronized sources
74
+ node = nil unless source.synchronized? || !Parser.infer_literal_node_type(node).nil?
75
+ node = Parser.parse(fixed_phrase, source.filename, fixed_position.line) if node.nil?
76
+ end
77
+ rescue Parser::SyntaxError
78
+ return Chain.new([Chain::UNDEFINED_CALL])
79
+ end
80
+ return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
81
+ # chain = NodeChainer.chain(node, source.filename, parent && parent.type == :block)
82
+ chain = Parser.chain(node, source.filename, parent)
83
+ if source.repaired? || !source.parsed? || !source.synchronized?
84
+ if end_of_phrase.strip == '.'
85
+ chain.links.push Chain::UNDEFINED_CALL
86
+ elsif end_of_phrase.strip == '::'
87
+ chain.links.push Chain::UNDEFINED_CONSTANT
88
+ end
89
+ elsif chain.links.last.is_a?(Source::Chain::Constant) && end_of_phrase.strip == '::'
90
+ chain.links.push Source::Chain::UNDEFINED_CONSTANT
91
+ end
92
+ chain
93
+ end
94
+
95
+ private
96
+
97
+ # @return [Position]
98
+ attr_reader :position
99
+
100
+ # @return [Solargraph::Source]
101
+ attr_reader :source
102
+
103
+ # @sg-ignore Need to add nil check here
104
+ # @return [String]
105
+ def phrase
106
+ @phrase ||= source.code[signature_data..(offset - 1)]
107
+ end
108
+
109
+ # @sg-ignore Need to add nil check here
110
+ # @return [String]
111
+ def fixed_phrase
112
+ @fixed_phrase ||= phrase[0..-(end_of_phrase.length + 1)]
113
+ end
114
+
115
+ # @return [Position]
116
+ def fixed_position
117
+ @fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
118
+ end
119
+
120
+ # @return [String]
121
+ # @sg-ignore Need to add nil check here
122
+ def end_of_phrase
123
+ @end_of_phrase ||= begin
124
+ match = phrase.match(/\s*(\.{1}|::)\s*$/)
125
+ if match
126
+ match[0]
127
+ else
128
+ ''
129
+ end
130
+ end
131
+ end
132
+
133
+ # True if the current offset is inside a string.
134
+ #
135
+ # @return [Boolean]
136
+ def string?
137
+ # @string ||= (node.type == :str or node.type == :dstr)
138
+ @string ||= @source.string_at?(position)
139
+ end
140
+
141
+ # @return [Integer]
142
+ def offset
143
+ @offset ||= get_offset(position.line, position.column)
144
+ end
145
+
146
+ # @param line [Integer]
147
+ # @param column [Integer]
148
+ # @return [Integer]
149
+ def get_offset line, column
150
+ Position.line_char_to_offset(@source.code, line, column)
151
+ end
152
+
153
+ # @return [Integer]
154
+ def signature_data
155
+ @signature_data ||= get_signature_data_at(offset)
156
+ end
157
+
158
+ # @param index [Integer]
159
+ # @return [Integer]
160
+ def get_signature_data_at index
161
+ brackets = 0
162
+ squares = 0
163
+ parens = 0
164
+ index -= 1
165
+ in_whitespace = false
166
+ while index >= 0
167
+ pos = Position.from_offset(@source.code, index)
168
+ break if index.positive? && @source.comment_at?(pos)
169
+ break if brackets.positive? || parens.positive? || squares.positive?
170
+ char = @source.code[index, 1]
171
+ break if char.nil? # @todo Is this the right way to handle this?
172
+ if brackets.zero? && parens.zero? && squares.zero? && [' ', "\r", "\n", "\t"].include?(char)
173
+ in_whitespace = true
174
+ else
175
+ # @sg-ignore Need to add nil check here
176
+ if brackets.zero? && parens.zero? && squares.zero? && in_whitespace && !((char == '.') || @source.code[(index + 1)..].strip.start_with?('.'))
177
+ @source.code[(index + 1)..]
178
+ # @sg-ignore Need to add nil check here
179
+ @source.code[(index + 1)..].lstrip
180
+ # @sg-ignore Need to add nil check here
181
+ index += (@source.code[(index + 1)..].length - @source.code[(index + 1)..].lstrip.length)
182
+ break
183
+ end
184
+ case char
185
+ when ')'
186
+ parens -= 1
187
+ when ']'
188
+ squares -= 1
189
+ when '}'
190
+ brackets -= 1
191
+ when '('
192
+ parens += 1
193
+ when '{'
194
+ brackets += 1
195
+ when '['
196
+ squares += 1
197
+ end
198
+ if brackets.zero? && parens.zero? && squares.zero?
199
+ break if ['"', "'", ',', ';', '%'].include?(char)
200
+ break if ['!', '?'].include?(char) && index < offset - 1
201
+ break if char == '$'
202
+ if char == '@'
203
+ index -= 1
204
+ index -= 1 if @source.code[index, 1] == '@'
205
+ break
206
+ end
207
+ elsif parens == 1 || brackets == 1 || squares == 1
208
+ break
209
+ end
210
+ in_whitespace = false
211
+ end
212
+ index -= 1
213
+ end
214
+ index + 1
215
+ end
216
+ end
217
+ end
218
+ end
@@ -1,55 +1,59 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class Source
5
- # Updaters contain changes to be applied to a source. The source applies
6
- # the update via the Source#synchronize method.
7
- #
8
- class Updater
9
- # @return [String]
10
- attr_reader :filename
11
-
12
- # @return [Integer]
13
- attr_reader :version
14
-
15
- # @return [Array<Change>]
16
- attr_reader :changes
17
-
18
- # @param filename [String] The file to update.
19
- # @param version [Integer] A version number associated with this update.
20
- # @param changes [Array<Solargraph::Source::Change>] The changes.
21
- def initialize filename, version, changes
22
- @filename = filename
23
- @version = version
24
- @changes = changes
25
- @input = nil
26
- @did_nullify = nil
27
- @output = nil
28
- end
29
-
30
- # @param text [String]
31
- # @param nullable [Boolean]
32
- # @return [String]
33
- def write text, nullable = false
34
- can_nullify = (nullable and changes.length == 1)
35
- return @output if @input == text and can_nullify == @did_nullify
36
- @input = text
37
- @output = text
38
- @did_nullify = can_nullify
39
- changes.each do |ch|
40
- @output = ch.write(@output, can_nullify)
41
- end
42
- @output
43
- end
44
-
45
- # @param text [String]
46
- # @return [String]
47
- def repair text
48
- changes.each do |ch|
49
- text = ch.repair(text)
50
- end
51
- text
52
- end
53
- end
54
- end
55
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ # Updaters contain changes to be applied to a source. The source applies
6
+ # the update via the Source#synchronize method.
7
+ #
8
+ class Updater
9
+ # @return [String]
10
+ attr_reader :filename
11
+
12
+ # @return [Integer]
13
+ attr_reader :version
14
+
15
+ # @return [Array<Change>]
16
+ attr_reader :changes
17
+
18
+ # @param filename [String] The file to update.
19
+ # @param version [Integer] A version number associated with this update.
20
+ # @param changes [Array<Solargraph::Source::Change>] The changes.
21
+ def initialize filename, version, changes
22
+ @filename = filename
23
+ @version = version
24
+ @changes = changes
25
+ @input = nil
26
+ @did_nullify = nil
27
+ @output = nil
28
+ end
29
+
30
+ # @param text [String]
31
+ # @param nullable [Boolean]
32
+ # @sg-ignore changes doesn't mutate @output, so this can never be nil
33
+ # @return [String]
34
+ def write text, nullable = false
35
+ can_nullify = (nullable and changes.length == 1)
36
+ return @output if (@input == text) && (can_nullify == @did_nullify)
37
+ @input = text
38
+ @output = text
39
+ @did_nullify = can_nullify
40
+ changes.each do |ch|
41
+ # @sg-ignore Wrong argument type for
42
+ # Solargraph::Source::Change#write: text expected String,
43
+ # received String, nil
44
+ @output = ch.write(@output, can_nullify)
45
+ end
46
+ @output
47
+ end
48
+
49
+ # @param text [String]
50
+ # @return [String]
51
+ def repair text
52
+ changes.each do |ch|
53
+ text = ch.repair(text)
54
+ end
55
+ text
56
+ end
57
+ end
58
+ end
59
+ end