solargraph 0.58.0 → 0.59.0.dev.1

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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.gitattributes +2 -0
  4. data/.github/workflows/linting.yml +4 -5
  5. data/.github/workflows/plugins.yml +40 -36
  6. data/.github/workflows/rspec.yml +45 -13
  7. data/.github/workflows/typecheck.yml +2 -2
  8. data/.rubocop_todo.yml +27 -49
  9. data/CHANGELOG.md +3 -0
  10. data/README.md +3 -3
  11. data/Rakefile +1 -0
  12. data/bin/solargraph +8 -8
  13. data/lib/solargraph/api_map/cache.rb +110 -110
  14. data/lib/solargraph/api_map/constants.rb +289 -279
  15. data/lib/solargraph/api_map/index.rb +204 -193
  16. data/lib/solargraph/api_map/source_to_yard.rb +109 -97
  17. data/lib/solargraph/api_map/store.rb +387 -384
  18. data/lib/solargraph/api_map.rb +1000 -945
  19. data/lib/solargraph/complex_type/conformance.rb +176 -0
  20. data/lib/solargraph/complex_type/type_methods.rb +242 -228
  21. data/lib/solargraph/complex_type/unique_type.rb +632 -482
  22. data/lib/solargraph/complex_type.rb +549 -444
  23. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  24. data/lib/solargraph/convention/data_definition.rb +108 -105
  25. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  26. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  27. data/lib/solargraph/convention/struct_definition.rb +168 -164
  28. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  29. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  30. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  31. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  32. data/lib/solargraph/doc_map.rb +200 -439
  33. data/lib/solargraph/equality.rb +34 -34
  34. data/lib/solargraph/gem_pins.rb +97 -98
  35. data/lib/solargraph/language_server/host/dispatch.rb +131 -130
  36. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  37. data/lib/solargraph/language_server/host/sources.rb +100 -99
  38. data/lib/solargraph/language_server/host.rb +883 -878
  39. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +109 -114
  40. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  41. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  42. data/lib/solargraph/language_server/message/text_document/definition.rb +42 -40
  43. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +28 -26
  44. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  45. data/lib/solargraph/language_server/message/text_document/hover.rb +60 -58
  46. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  47. data/lib/solargraph/language_server/message/text_document/type_definition.rb +27 -25
  48. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +25 -23
  49. data/lib/solargraph/library.rb +729 -683
  50. data/lib/solargraph/location.rb +87 -82
  51. data/lib/solargraph/logging.rb +57 -37
  52. data/lib/solargraph/parser/comment_ripper.rb +76 -69
  53. data/lib/solargraph/parser/flow_sensitive_typing.rb +483 -255
  54. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  55. data/lib/solargraph/parser/node_processor.rb +63 -62
  56. data/lib/solargraph/parser/parser_gem/class_methods.rb +167 -149
  57. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  58. data/lib/solargraph/parser/parser_gem/node_methods.rb +506 -486
  59. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  60. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  61. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  62. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
  63. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  64. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  65. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +41 -40
  66. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  67. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  68. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  69. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  70. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  71. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  72. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +53 -52
  73. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +296 -291
  74. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  75. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  76. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  77. data/lib/solargraph/parser/region.rb +75 -69
  78. data/lib/solargraph/parser/snippet.rb +17 -17
  79. data/lib/solargraph/pin/base.rb +761 -729
  80. data/lib/solargraph/pin/base_variable.rb +418 -126
  81. data/lib/solargraph/pin/block.rb +126 -104
  82. data/lib/solargraph/pin/breakable.rb +13 -9
  83. data/lib/solargraph/pin/callable.rb +278 -231
  84. data/lib/solargraph/pin/closure.rb +68 -72
  85. data/lib/solargraph/pin/common.rb +94 -79
  86. data/lib/solargraph/pin/compound_statement.rb +55 -0
  87. data/lib/solargraph/pin/conversions.rb +124 -123
  88. data/lib/solargraph/pin/delegated_method.rb +131 -120
  89. data/lib/solargraph/pin/documenting.rb +115 -114
  90. data/lib/solargraph/pin/instance_variable.rb +38 -34
  91. data/lib/solargraph/pin/keyword.rb +16 -20
  92. data/lib/solargraph/pin/local_variable.rb +31 -75
  93. data/lib/solargraph/pin/method.rb +720 -672
  94. data/lib/solargraph/pin/method_alias.rb +42 -34
  95. data/lib/solargraph/pin/namespace.rb +121 -115
  96. data/lib/solargraph/pin/parameter.rb +338 -275
  97. data/lib/solargraph/pin/proxy_type.rb +40 -39
  98. data/lib/solargraph/pin/reference/override.rb +47 -47
  99. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  100. data/lib/solargraph/pin/reference.rb +41 -39
  101. data/lib/solargraph/pin/search.rb +62 -61
  102. data/lib/solargraph/pin/signature.rb +69 -61
  103. data/lib/solargraph/pin/symbol.rb +53 -53
  104. data/lib/solargraph/pin/until.rb +18 -18
  105. data/lib/solargraph/pin/while.rb +18 -18
  106. data/lib/solargraph/pin.rb +46 -44
  107. data/lib/solargraph/pin_cache.rb +665 -245
  108. data/lib/solargraph/position.rb +118 -119
  109. data/lib/solargraph/range.rb +112 -112
  110. data/lib/solargraph/rbs_map/conversions.rb +846 -823
  111. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  112. data/lib/solargraph/rbs_map/stdlib_map.rb +72 -43
  113. data/lib/solargraph/rbs_map.rb +217 -163
  114. data/lib/solargraph/shell.rb +397 -352
  115. data/lib/solargraph/source/chain/call.rb +372 -337
  116. data/lib/solargraph/source/chain/constant.rb +28 -26
  117. data/lib/solargraph/source/chain/hash.rb +35 -34
  118. data/lib/solargraph/source/chain/if.rb +29 -28
  119. data/lib/solargraph/source/chain/instance_variable.rb +34 -13
  120. data/lib/solargraph/source/chain/literal.rb +53 -48
  121. data/lib/solargraph/source/chain/or.rb +31 -23
  122. data/lib/solargraph/source/chain.rb +294 -291
  123. data/lib/solargraph/source/change.rb +89 -82
  124. data/lib/solargraph/source/cursor.rb +172 -166
  125. data/lib/solargraph/source/encoding_fixes.rb +23 -23
  126. data/lib/solargraph/source/source_chainer.rb +204 -194
  127. data/lib/solargraph/source/updater.rb +59 -55
  128. data/lib/solargraph/source.rb +524 -498
  129. data/lib/solargraph/source_map/clip.rb +237 -226
  130. data/lib/solargraph/source_map/data.rb +37 -34
  131. data/lib/solargraph/source_map/mapper.rb +282 -259
  132. data/lib/solargraph/source_map.rb +220 -212
  133. data/lib/solargraph/type_checker/problem.rb +34 -32
  134. data/lib/solargraph/type_checker/rules.rb +157 -84
  135. data/lib/solargraph/type_checker.rb +895 -814
  136. data/lib/solargraph/version.rb +5 -5
  137. data/lib/solargraph/workspace/config.rb +257 -255
  138. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  139. data/lib/solargraph/workspace/require_paths.rb +98 -97
  140. data/lib/solargraph/workspace.rb +362 -220
  141. data/lib/solargraph/yard_map/helpers.rb +45 -44
  142. data/lib/solargraph/yard_map/mapper/to_method.rb +134 -130
  143. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  144. data/lib/solargraph/yard_map/mapper.rb +84 -79
  145. data/lib/solargraph/yardoc.rb +97 -87
  146. data/lib/solargraph.rb +126 -105
  147. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  148. data/rbs/fills/tuple/tuple.rbs +28 -0
  149. data/rbs/shims/ast/0/node.rbs +5 -0
  150. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  151. data/rbs_collection.yaml +1 -1
  152. data/solargraph.gemspec +2 -1
  153. metadata +23 -17
  154. data/lib/solargraph/type_checker/checks.rb +0 -124
  155. data/lib/solargraph/type_checker/param_def.rb +0 -37
  156. data/lib/solargraph/yard_map/to_method.rb +0 -89
  157. data/sig/shims/ast/0/node.rbs +0 -5
  158. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  159. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  160. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  161. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  162. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  163. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  164. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  165. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  166. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,226 +1,237 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class SourceMap
5
- # A static analysis tool for obtaining definitions, Completions,
6
- # signatures, and type inferences from a Cursor.
7
- #
8
- class Clip
9
- # @param api_map [ApiMap]
10
- # @param cursor [Source::Cursor]
11
- def initialize api_map, cursor
12
- @api_map = api_map
13
- @cursor = cursor
14
- closure_pin = closure
15
- closure_pin.rebind(api_map) if closure_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(closure_pin.receiver).contain?(cursor.range.start)
16
- end
17
-
18
- # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
19
- def define
20
- return [] if cursor.comment? || cursor.chain.literal?
21
- result = cursor.chain.define(api_map, closure, locals)
22
- result.concat file_global_methods
23
- result.concat((source_map.pins + source_map.locals).select{ |p| p.name == cursor.word && p.location.range.contain?(cursor.position) }) if result.empty?
24
- result
25
- end
26
-
27
- # @return [Array<Pin::Base>]
28
- def types
29
- infer.namespaces.map { |namespace| api_map.get_path_pins(namespace) }.flatten
30
- end
31
-
32
- # @return [Completion]
33
- def complete
34
- return package_completions([]) if !source_map.source.parsed? || cursor.string?
35
- return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
36
- return Completion.new([], cursor.range) if cursor.chain.literal?
37
- if cursor.comment?
38
- tag_complete
39
- else
40
- code_complete
41
- end
42
- end
43
-
44
- # @return [Array<Pin::Method>]
45
- def signify
46
- return [] unless cursor.argument?
47
- chain = Parser.chain(cursor.recipient_node, cursor.filename)
48
- chain.define(api_map, context_pin, locals).select { |pin| pin.is_a?(Pin::Method) }
49
- end
50
-
51
- # @return [ComplexType]
52
- def infer
53
- result = cursor.chain.infer(api_map, closure, locals)
54
- if result.tag == 'Class'
55
- # HACK: Exception to return BasicObject from Class#new
56
- dfn = cursor.chain.define(api_map, closure, locals).first
57
- return ComplexType.try_parse('::BasicObject') if dfn && dfn.path == 'Class#new'
58
- end
59
- # should receive result with selfs resolved from infer()
60
- Solargraph.assert_or_log(:clip_infer_self, 'Received selfy inference') if result.selfy?
61
- result
62
- end
63
-
64
- # Get an array of all the locals that are visible from the cursors's
65
- # position. Locals can be local variables, method parameters, or block
66
- # parameters. The array starts with the nearest local pin.
67
- #
68
- # @return [::Array<Solargraph::Pin::LocalVariable>]
69
- def locals
70
- @locals ||= source_map.locals_at(location)
71
- end
72
-
73
- # @return [::Array<String>]
74
- def gates
75
- closure.gates
76
- end
77
-
78
- # @param phrase [String]
79
- # @return [Array<Solargraph::Pin::Base>]
80
- def translate phrase
81
- chain = Parser.chain(Parser.parse(phrase))
82
- chain.define(api_map, closure, locals)
83
- end
84
-
85
- private
86
-
87
- # @return [ApiMap]
88
- attr_reader :api_map
89
-
90
- # @return [Source::Cursor]
91
- attr_reader :cursor
92
-
93
- # @return [SourceMap]
94
- def source_map
95
- @source_map ||= api_map.source_map(cursor.filename)
96
- end
97
-
98
- # @return [Location]
99
- def location
100
- Location.new(source_map.filename, Solargraph::Range.new(cursor.position, cursor.position))
101
- end
102
-
103
- # @return [Solargraph::Pin::Closure]
104
- def closure
105
- @closure ||= source_map.locate_closure_pin(cursor.node_position.line, cursor.node_position.character)
106
- end
107
-
108
- # The context at the current position.
109
- #
110
- # @return [Pin::Base]
111
- def context_pin
112
- @context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
113
- end
114
-
115
- # @return [Array<Pin::KeywordParam>]
116
- def complete_keyword_parameters
117
- return [] unless cursor.argument? && cursor.chain.links.one? && cursor.word =~ /^[a-z0-9_]*:?$/
118
- pins = signify
119
- result = []
120
- done = []
121
- pins.each do |pin|
122
- pin.parameters.each do |param|
123
- next if done.include?(param.name)
124
- done.push param.name
125
- next unless param.keyword?
126
- result.push Pin::KeywordParam.new(pin.location, "#{param.name}:")
127
- end
128
- if !pin.parameters.empty? && pin.parameters.last.kwrestarg?
129
- pin.docstring.tags(:param).each do |tag|
130
- next if done.include?(tag.name)
131
- done.push tag.name
132
- result.push Pin::KeywordParam.new(pin.location, "#{tag.name}:")
133
- end
134
- end
135
- end
136
- result
137
- end
138
-
139
- # @param result [Enumerable<Pin::Base>]
140
- # @return [Completion]
141
- def package_completions result
142
- frag_start = cursor.start_of_word.to_s.downcase
143
- filtered = result.uniq(&:name).select { |s|
144
- s.name.downcase.start_with?(frag_start) &&
145
- (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
146
- }
147
- Completion.new(filtered, cursor.range)
148
- end
149
-
150
- # @return [Completion]
151
- def tag_complete
152
- result = []
153
- match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i)
154
- if match
155
- full = match[1]
156
- if full.include?('::')
157
- if full.end_with?('::')
158
- result.concat api_map.get_constants(full[0..-3], *gates)
159
- else
160
- result.concat api_map.get_constants(full.split('::')[0..-2].join('::'), *gates)
161
- end
162
- else
163
- result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
164
- end
165
- end
166
- package_completions(result)
167
- end
168
-
169
- # @return [Completion]
170
- def code_complete
171
- result = []
172
- result.concat complete_keyword_parameters
173
- if cursor.chain.constant? || cursor.start_of_constant?
174
- full = cursor.chain.links.first.word
175
- type = if cursor.chain.undefined?
176
- cursor.chain.base.infer(api_map, context_pin, locals)
177
- else
178
- if full.include?('::') && cursor.chain.links.length == 1
179
- ComplexType.try_parse(full.split('::')[0..-2].join('::'))
180
- elsif cursor.chain.links.length > 1
181
- ComplexType.try_parse(full)
182
- else
183
- ComplexType::UNDEFINED
184
- end
185
- end
186
- if type.undefined?
187
- if full.include?('::')
188
- result.concat api_map.get_constants(full, *gates)
189
- else
190
- result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
191
- end
192
- else
193
- result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
194
- end
195
- else
196
- type = cursor.chain.base.infer(api_map, closure, locals)
197
- result.concat api_map.get_complex_type_methods(type, closure.binder.namespace, cursor.chain.links.length == 1)
198
- if cursor.chain.links.length == 1
199
- if cursor.word.start_with?('@@')
200
- return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
201
- elsif cursor.word.start_with?('@')
202
- return package_completions(api_map.get_instance_variable_pins(closure.binder.namespace, closure.binder.scope))
203
- elsif cursor.word.start_with?('$')
204
- return package_completions(api_map.get_global_variable_pins)
205
- end
206
- result.concat locals
207
- result.concat file_global_methods unless closure.binder.namespace.empty?
208
- result.concat api_map.get_constants(context_pin.context.namespace, *gates)
209
- result.concat api_map.get_methods(closure.binder.namespace, scope: closure.binder.scope, visibility: [:public, :private, :protected])
210
- result.concat api_map.get_methods('Kernel')
211
- result.concat api_map.keyword_pins.to_a
212
- end
213
- end
214
- package_completions(result)
215
- end
216
-
217
- # @return [Array<Pin::Base>]
218
- def file_global_methods
219
- return [] if cursor.word.empty?
220
- source_map.pins.select do |pin|
221
- pin.is_a?(Pin::Method) && pin.namespace == '' && pin.name.start_with?(cursor.word)
222
- end
223
- end
224
- end
225
- end
226
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class SourceMap
5
+ # A static analysis tool for obtaining definitions, Completions,
6
+ # signatures, and type inferences from a Cursor.
7
+ #
8
+ class Clip
9
+ # @param api_map [ApiMap]
10
+ # @param cursor [Source::Cursor]
11
+ def initialize api_map, cursor
12
+ @api_map = api_map
13
+ @cursor = cursor
14
+ closure_pin = closure
15
+ # @sg-ignore Need to add nil check here
16
+ closure_pin.rebind(api_map) if closure_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(closure_pin.receiver).contain?(cursor.range.start)
17
+ end
18
+
19
+ # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
20
+ def define
21
+ return [] if cursor.comment? || cursor.chain.literal?
22
+ result = cursor.chain.define(api_map, closure, locals)
23
+ result.concat file_global_methods
24
+ # @sg-ignore Need to add nil check here
25
+ result.concat((source_map.pins + source_map.locals).select{ |p| p.name == cursor.word && p.location.range.contain?(cursor.position) }) if result.empty?
26
+ result
27
+ end
28
+
29
+ # @return [Array<Pin::Base>]
30
+ def types
31
+ infer.namespaces.map { |namespace| api_map.get_path_pins(namespace) }.flatten
32
+ end
33
+
34
+ # @return [Completion]
35
+ def complete
36
+ return package_completions([]) if !source_map.source.parsed? || cursor.string?
37
+ return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
38
+ return Completion.new([], cursor.range) if cursor.chain.literal?
39
+ if cursor.comment?
40
+ tag_complete
41
+ else
42
+ code_complete
43
+ end
44
+ end
45
+
46
+ # @return [Array<Pin::Method>]
47
+ def signify
48
+ return [] unless cursor.argument?
49
+ chain = Parser.chain(cursor.recipient_node, cursor.filename)
50
+ chain.define(api_map, context_pin, locals).select { |pin| pin.is_a?(Pin::Method) }
51
+ end
52
+
53
+ # @return [ComplexType]
54
+ def infer
55
+ result = cursor.chain.infer(api_map, closure, locals)
56
+ if result.tag == 'Class'
57
+ # HACK: Exception to return BasicObject from Class#new
58
+ dfn = cursor.chain.define(api_map, closure, locals).first
59
+ return ComplexType.try_parse('::BasicObject') if dfn && dfn.path == 'Class#new'
60
+ end
61
+ # should receive result with selfs resolved from infer()
62
+ Solargraph.assert_or_log(:clip_infer_self, 'Received selfy inference') if result.selfy?
63
+ result
64
+ end
65
+
66
+ # Get an array of all the locals that are visible from the cursors's
67
+ # position. Locals can be local variables, method parameters, or block
68
+ # parameters. The array starts with the nearest local pin.
69
+ #
70
+ # @return [::Array<Solargraph::Pin::LocalVariable>]
71
+ def locals
72
+ @locals ||= source_map.locals_at(location)
73
+ end
74
+
75
+ # @return [::Array<String>]
76
+ def gates
77
+ closure.gates
78
+ end
79
+
80
+ # @param phrase [String]
81
+ # @return [Array<Solargraph::Pin::Base>]
82
+ def translate phrase
83
+ chain = Parser.chain(Parser.parse(phrase, cursor.filename, cursor.position.line))
84
+ chain.define(api_map, closure, locals)
85
+ end
86
+
87
+ private
88
+
89
+ # @return [ApiMap]
90
+ attr_reader :api_map
91
+
92
+ # @return [Source::Cursor]
93
+ attr_reader :cursor
94
+
95
+ # @return [SourceMap]
96
+ def source_map
97
+ # @sg-ignore Need to add nil check here
98
+ @source_map ||= api_map.source_map(cursor.filename)
99
+ end
100
+
101
+ # @return [Location]
102
+ def location
103
+ Location.new(source_map.filename, Solargraph::Range.new(cursor.position, cursor.position))
104
+ end
105
+
106
+ # @return [Solargraph::Pin::Closure]
107
+ def closure
108
+ @closure ||= source_map.locate_closure_pin(cursor.node_position.line, cursor.node_position.character)
109
+ end
110
+
111
+ # The context at the current position.
112
+ #
113
+ # @return [Pin::Base]
114
+ def context_pin
115
+ @context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
116
+ end
117
+
118
+ # @return [Array<Pin::KeywordParam>]
119
+ def complete_keyword_parameters
120
+ return [] unless cursor.argument? && cursor.chain.links.one? && cursor.word =~ /^[a-z0-9_]*:?$/
121
+ pins = signify
122
+ result = []
123
+ done = []
124
+ pins.each do |pin|
125
+ pin.parameters.each do |param|
126
+ next if done.include?(param.name)
127
+ done.push param.name
128
+ next unless param.keyword?
129
+ result.push Pin::KeywordParam.new(pin.location, "#{param.name}:")
130
+ end
131
+ if !pin.parameters.empty? && pin.parameters.last.kwrestarg?
132
+ pin.docstring.tags(:param).each do |tag|
133
+ next if done.include?(tag.name)
134
+ done.push tag.name
135
+ result.push Pin::KeywordParam.new(pin.location, "#{tag.name}:")
136
+ end
137
+ end
138
+ end
139
+ result
140
+ end
141
+
142
+ # @param result [Enumerable<Pin::Base>]
143
+ # @return [Completion]
144
+ def package_completions result
145
+ frag_start = cursor.start_of_word.to_s.downcase
146
+ filtered = result.uniq(&:name).select { |s|
147
+ s.name.downcase.start_with?(frag_start) &&
148
+ (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
149
+ }
150
+ Completion.new(filtered, cursor.range)
151
+ end
152
+
153
+ # @return [Completion]
154
+ def tag_complete
155
+ result = []
156
+ # @sg-ignore Need to add nil check here
157
+ match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i)
158
+ if match
159
+ # @sg-ignore Need to add nil check here
160
+ full = match[1]
161
+ # @sg-ignore Need to add nil check here
162
+ if full.include?('::')
163
+ # @sg-ignore Need to add nil check here
164
+ if full.end_with?('::')
165
+ # @sg-ignore Need to add nil check here
166
+ result.concat api_map.get_constants(full[0..-3], *gates)
167
+ else
168
+ # @sg-ignore Need to add nil check here
169
+ result.concat api_map.get_constants(full.split('::')[0..-2].join('::'), *gates)
170
+ end
171
+ else
172
+ # @sg-ignore Need to add nil check here
173
+ result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
174
+ end
175
+ end
176
+ package_completions(result)
177
+ end
178
+
179
+ # @return [Completion]
180
+ def code_complete
181
+ result = []
182
+ result.concat complete_keyword_parameters
183
+ if cursor.chain.constant? || cursor.start_of_constant?
184
+ full = cursor.chain.links.first.word
185
+ type = if cursor.chain.undefined?
186
+ cursor.chain.base.infer(api_map, context_pin, locals)
187
+ else
188
+ if full.include?('::') && cursor.chain.links.length == 1
189
+ # @sg-ignore Need to add nil check here
190
+ ComplexType.try_parse(full.split('::')[0..-2].join('::'))
191
+ elsif cursor.chain.links.length > 1
192
+ ComplexType.try_parse(full)
193
+ else
194
+ ComplexType::UNDEFINED
195
+ end
196
+ end
197
+ if type.undefined?
198
+ if full.include?('::')
199
+ result.concat api_map.get_constants(full, *gates)
200
+ else
201
+ result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
202
+ end
203
+ else
204
+ result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
205
+ end
206
+ else
207
+ type = cursor.chain.base.infer(api_map, closure, locals)
208
+ result.concat api_map.get_complex_type_methods(type, closure.binder.namespace, cursor.chain.links.length == 1)
209
+ if cursor.chain.links.length == 1
210
+ if cursor.word.start_with?('@@')
211
+ return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
212
+ elsif cursor.word.start_with?('@')
213
+ return package_completions(api_map.get_instance_variable_pins(closure.full_context.namespace, closure.context.scope))
214
+ elsif cursor.word.start_with?('$')
215
+ return package_completions(api_map.get_global_variable_pins)
216
+ end
217
+ result.concat locals
218
+ result.concat file_global_methods unless closure.binder.namespace.empty?
219
+ result.concat api_map.get_constants(context_pin.context.namespace, *gates)
220
+ result.concat api_map.get_methods(closure.binder.namespace, scope: closure.binder.scope, visibility: [:public, :private, :protected])
221
+ result.concat api_map.get_methods('Kernel')
222
+ result.concat api_map.keyword_pins.to_a
223
+ end
224
+ end
225
+ package_completions(result)
226
+ end
227
+
228
+ # @return [Array<Pin::Base>]
229
+ def file_global_methods
230
+ return [] if cursor.word.empty?
231
+ source_map.pins.select do |pin|
232
+ pin.is_a?(Pin::Method) && pin.namespace == '' && pin.name.start_with?(cursor.word)
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
@@ -1,34 +1,37 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class SourceMap
5
- class Data
6
- # @param source [Solargraph::Source]
7
- def initialize source
8
- @source = source
9
- end
10
-
11
- # @return [Array<Solargraph::Pin::Base>]
12
- def pins
13
- generate
14
- @pins || []
15
- end
16
-
17
- # @return [Array<Solargraph::LocalVariable>]
18
- def locals
19
- generate
20
- @locals || []
21
- end
22
-
23
- private
24
-
25
- # @return [void]
26
- def generate
27
- return if @generated
28
-
29
- @generated = true
30
- @pins, @locals = Mapper.map(@source)
31
- end
32
- end
33
- end
34
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class SourceMap
5
+ class Data
6
+ # @param source [Solargraph::Source]
7
+ def initialize source
8
+ @source = source
9
+ end
10
+
11
+ # @sg-ignore Translate to something flow sensitive typing understands
12
+ # @return [Array<Solargraph::Pin::Base>]
13
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1100
14
+ def pins
15
+ generate
16
+ @pins || []
17
+ end
18
+
19
+ # @sg-ignore Translate to something flow sensitive typing understands
20
+ # @return [Array<Solargraph::Pin::LocalVariable>]
21
+ def locals
22
+ generate
23
+ @locals || []
24
+ end
25
+
26
+ private
27
+
28
+ # @return [void]
29
+ def generate
30
+ return if @generated
31
+
32
+ @generated = true
33
+ @pins, @locals = Mapper.map(@source)
34
+ end
35
+ end
36
+ end
37
+ end