solargraph 0.58.2 → 0.59.0.dev.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 (203) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +4 -5
  4. data/.github/workflows/plugins.yml +41 -34
  5. data/.github/workflows/rspec.yml +44 -23
  6. data/.github/workflows/typecheck.yml +2 -2
  7. data/.rubocop.yml +32 -5
  8. data/.rubocop_todo.yml +50 -966
  9. data/Gemfile +3 -1
  10. data/README.md +3 -3
  11. data/Rakefile +26 -23
  12. data/bin/solargraph +2 -1
  13. data/lib/solargraph/api_map/cache.rb +3 -3
  14. data/lib/solargraph/api_map/constants.rb +13 -3
  15. data/lib/solargraph/api_map/index.rb +23 -18
  16. data/lib/solargraph/api_map/source_to_yard.rb +22 -9
  17. data/lib/solargraph/api_map/store.rb +33 -28
  18. data/lib/solargraph/api_map.rb +150 -82
  19. data/lib/solargraph/bench.rb +44 -45
  20. data/lib/solargraph/complex_type/conformance.rb +176 -0
  21. data/lib/solargraph/complex_type/type_methods.rb +28 -17
  22. data/lib/solargraph/complex_type/unique_type.rb +218 -57
  23. data/lib/solargraph/complex_type.rb +170 -57
  24. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  25. data/lib/solargraph/convention/data_definition/data_definition_node.rb +7 -5
  26. data/lib/solargraph/convention/data_definition.rb +5 -2
  27. data/lib/solargraph/convention/gemfile.rb +15 -15
  28. data/lib/solargraph/convention/gemspec.rb +23 -23
  29. data/lib/solargraph/convention/rakefile.rb +17 -17
  30. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
  31. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -3
  32. data/lib/solargraph/convention/struct_definition.rb +8 -4
  33. data/lib/solargraph/convention.rb +78 -78
  34. data/lib/solargraph/converters/dd.rb +19 -17
  35. data/lib/solargraph/converters/dl.rb +17 -15
  36. data/lib/solargraph/converters/dt.rb +17 -15
  37. data/lib/solargraph/converters/misc.rb +3 -1
  38. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  39. data/lib/solargraph/diagnostics/rubocop.rb +11 -10
  40. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  41. data/lib/solargraph/diagnostics/type_check.rb +11 -10
  42. data/lib/solargraph/diagnostics/update_errors.rb +37 -41
  43. data/lib/solargraph/doc_map.rb +133 -373
  44. data/lib/solargraph/equality.rb +4 -4
  45. data/lib/solargraph/gem_pins.rb +21 -20
  46. data/lib/solargraph/language_server/error_codes.rb +20 -20
  47. data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
  48. data/lib/solargraph/language_server/host/dispatch.rb +3 -3
  49. data/lib/solargraph/language_server/host/message_worker.rb +4 -3
  50. data/lib/solargraph/language_server/host/sources.rb +2 -1
  51. data/lib/solargraph/language_server/host.rb +30 -22
  52. data/lib/solargraph/language_server/message/base.rb +97 -97
  53. data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
  54. data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
  55. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +12 -18
  56. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  57. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  58. data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
  59. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  60. data/lib/solargraph/language_server/message/initialize.rb +197 -191
  61. data/lib/solargraph/language_server/message/text_document/completion.rb +10 -8
  62. data/lib/solargraph/language_server/message/text_document/definition.rb +41 -32
  63. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
  64. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +29 -19
  65. data/lib/solargraph/language_server/message/text_document/formatting.rb +8 -6
  66. data/lib/solargraph/language_server/message/text_document/hover.rb +5 -5
  67. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
  68. data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
  69. data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
  70. data/lib/solargraph/language_server/message/text_document/signature_help.rb +3 -2
  71. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -17
  72. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
  73. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
  74. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
  75. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +27 -17
  76. data/lib/solargraph/language_server/message.rb +94 -94
  77. data/lib/solargraph/language_server/request.rb +29 -27
  78. data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
  79. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  80. data/lib/solargraph/library.rb +85 -44
  81. data/lib/solargraph/location.rb +17 -14
  82. data/lib/solargraph/logging.rb +24 -4
  83. data/lib/solargraph/page.rb +92 -92
  84. data/lib/solargraph/parser/comment_ripper.rb +19 -4
  85. data/lib/solargraph/parser/flow_sensitive_typing.rb +326 -108
  86. data/lib/solargraph/parser/node_processor/base.rb +34 -4
  87. data/lib/solargraph/parser/node_processor.rb +8 -7
  88. data/lib/solargraph/parser/parser_gem/class_methods.rb +32 -14
  89. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  90. data/lib/solargraph/parser/parser_gem/node_chainer.rb +50 -25
  91. data/lib/solargraph/parser/parser_gem/node_methods.rb +91 -70
  92. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  93. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +13 -11
  94. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  95. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +12 -12
  96. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +10 -3
  97. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
  98. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  99. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +5 -3
  100. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  101. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  102. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +3 -3
  103. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  104. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  105. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  106. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -5
  107. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +124 -113
  108. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  109. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  110. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +6 -2
  111. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  112. data/lib/solargraph/parser/parser_gem.rb +14 -12
  113. data/lib/solargraph/parser/region.rb +9 -3
  114. data/lib/solargraph/parser/snippet.rb +3 -1
  115. data/lib/solargraph/parser.rb +25 -23
  116. data/lib/solargraph/pin/base.rb +126 -80
  117. data/lib/solargraph/pin/base_variable.rb +273 -24
  118. data/lib/solargraph/pin/block.rb +29 -6
  119. data/lib/solargraph/pin/breakable.rb +7 -1
  120. data/lib/solargraph/pin/callable.rb +65 -21
  121. data/lib/solargraph/pin/closure.rb +7 -10
  122. data/lib/solargraph/pin/common.rb +24 -6
  123. data/lib/solargraph/pin/compound_statement.rb +55 -0
  124. data/lib/solargraph/pin/constant.rb +43 -45
  125. data/lib/solargraph/pin/conversions.rb +10 -4
  126. data/lib/solargraph/pin/delegated_method.rb +19 -8
  127. data/lib/solargraph/pin/documenting.rb +4 -2
  128. data/lib/solargraph/pin/instance_variable.rb +5 -1
  129. data/lib/solargraph/pin/keyword.rb +0 -4
  130. data/lib/solargraph/pin/local_variable.rb +15 -59
  131. data/lib/solargraph/pin/method.rb +153 -104
  132. data/lib/solargraph/pin/method_alias.rb +8 -0
  133. data/lib/solargraph/pin/namespace.rb +19 -12
  134. data/lib/solargraph/pin/parameter.rb +100 -36
  135. data/lib/solargraph/pin/proxy_type.rb +4 -1
  136. data/lib/solargraph/pin/reference/override.rb +1 -1
  137. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  138. data/lib/solargraph/pin/reference.rb +19 -0
  139. data/lib/solargraph/pin/search.rb +3 -2
  140. data/lib/solargraph/pin/signature.rb +15 -12
  141. data/lib/solargraph/pin/symbol.rb +2 -1
  142. data/lib/solargraph/pin/until.rb +2 -4
  143. data/lib/solargraph/pin/while.rb +2 -4
  144. data/lib/solargraph/pin.rb +2 -0
  145. data/lib/solargraph/pin_cache.rb +490 -73
  146. data/lib/solargraph/position.rb +14 -10
  147. data/lib/solargraph/range.rb +16 -15
  148. data/lib/solargraph/rbs_map/conversions.rb +343 -214
  149. data/lib/solargraph/rbs_map/core_fills.rb +91 -84
  150. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  151. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -5
  152. data/lib/solargraph/rbs_map.rb +77 -32
  153. data/lib/solargraph/server_methods.rb +16 -16
  154. data/lib/solargraph/shell.rb +128 -73
  155. data/lib/solargraph/source/chain/array.rb +39 -37
  156. data/lib/solargraph/source/chain/call.rb +96 -56
  157. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  158. data/lib/solargraph/source/chain/constant.rb +5 -1
  159. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  160. data/lib/solargraph/source/chain/hash.rb +8 -5
  161. data/lib/solargraph/source/chain/if.rb +12 -10
  162. data/lib/solargraph/source/chain/instance_variable.rb +24 -1
  163. data/lib/solargraph/source/chain/link.rb +99 -109
  164. data/lib/solargraph/source/chain/literal.rb +9 -6
  165. data/lib/solargraph/source/chain/or.rb +10 -4
  166. data/lib/solargraph/source/chain/q_call.rb +13 -11
  167. data/lib/solargraph/source/chain/variable.rb +15 -13
  168. data/lib/solargraph/source/chain/z_super.rb +28 -30
  169. data/lib/solargraph/source/chain.rb +49 -38
  170. data/lib/solargraph/source/change.rb +12 -5
  171. data/lib/solargraph/source/cursor.rb +23 -17
  172. data/lib/solargraph/source/encoding_fixes.rb +6 -7
  173. data/lib/solargraph/source/source_chainer.rb +56 -32
  174. data/lib/solargraph/source/updater.rb +5 -1
  175. data/lib/solargraph/source.rb +59 -35
  176. data/lib/solargraph/source_map/clip.rb +48 -29
  177. data/lib/solargraph/source_map/data.rb +4 -1
  178. data/lib/solargraph/source_map/mapper.rb +71 -42
  179. data/lib/solargraph/source_map.rb +21 -9
  180. data/lib/solargraph/type_checker/problem.rb +3 -1
  181. data/lib/solargraph/type_checker/rules.rb +81 -8
  182. data/lib/solargraph/type_checker.rb +195 -120
  183. data/lib/solargraph/version.rb +1 -1
  184. data/lib/solargraph/workspace/config.rb +13 -10
  185. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  186. data/lib/solargraph/workspace/require_paths.rb +1 -0
  187. data/lib/solargraph/workspace.rb +149 -30
  188. data/lib/solargraph/yard_map/helpers.rb +8 -3
  189. data/lib/solargraph/yard_map/mapper/to_method.rb +13 -7
  190. data/lib/solargraph/yard_map/mapper/to_namespace.rb +2 -1
  191. data/lib/solargraph/yard_map/mapper.rb +13 -8
  192. data/lib/solargraph/yard_tags.rb +20 -20
  193. data/lib/solargraph/yardoc.rb +33 -23
  194. data/lib/solargraph.rb +29 -8
  195. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  196. data/rbs/fills/tuple/tuple.rbs +28 -0
  197. data/rbs/shims/ast/0/node.rbs +1 -1
  198. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  199. data/solargraph.gemspec +36 -34
  200. metadata +38 -33
  201. data/lib/solargraph/type_checker/checks.rb +0 -124
  202. data/lib/solargraph/type_checker/param_def.rb +0 -37
  203. data/lib/solargraph/yard_map/to_method.rb +0 -89
@@ -12,7 +12,10 @@ module Solargraph
12
12
  @api_map = api_map
13
13
  @cursor = cursor
14
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)
15
+ # @sg-ignore Need to add nil check here
16
+ if closure_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(closure_pin.receiver).contain?(cursor.range.start)
17
+ closure_pin.rebind(api_map)
18
+ end
16
19
  end
17
20
 
18
21
  # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
@@ -20,7 +23,12 @@ module Solargraph
20
23
  return [] if cursor.comment? || cursor.chain.literal?
21
24
  result = cursor.chain.define(api_map, closure, locals)
22
25
  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?
26
+ if result.empty?
27
+ result.concat((source_map.pins + source_map.locals).select do |p|
28
+ # @sg-ignore Need to add nil check here
29
+ p.name == cursor.word && p.location.range.contain?(cursor.position)
30
+ end)
31
+ end
24
32
  result
25
33
  end
26
34
 
@@ -32,7 +40,9 @@ module Solargraph
32
40
  # @return [Completion]
33
41
  def complete
34
42
  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>'
43
+ if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
44
+ return package_completions(api_map.get_symbols)
45
+ end
36
46
  return Completion.new([], cursor.range) if cursor.chain.literal?
37
47
  if cursor.comment?
38
48
  tag_complete
@@ -78,7 +88,7 @@ module Solargraph
78
88
  # @param phrase [String]
79
89
  # @return [Array<Solargraph::Pin::Base>]
80
90
  def translate phrase
81
- chain = Parser.chain(Parser.parse(phrase))
91
+ chain = Parser.chain(Parser.parse(phrase, cursor.filename, cursor.position.line))
82
92
  chain.define(api_map, closure, locals)
83
93
  end
84
94
 
@@ -92,6 +102,7 @@ module Solargraph
92
102
 
93
103
  # @return [SourceMap]
94
104
  def source_map
105
+ # @sg-ignore Need to add nil check here
95
106
  @source_map ||= api_map.source_map(cursor.filename)
96
107
  end
97
108
 
@@ -125,12 +136,11 @@ module Solargraph
125
136
  next unless param.keyword?
126
137
  result.push Pin::KeywordParam.new(pin.location, "#{param.name}:")
127
138
  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
139
+ next unless !pin.parameters.empty? && pin.parameters.last.kwrestarg?
140
+ pin.docstring.tags(:param).each do |tag|
141
+ next if done.include?(tag.name)
142
+ done.push tag.name
143
+ result.push Pin::KeywordParam.new(pin.location, "#{tag.name}:")
134
144
  end
135
145
  end
136
146
  result
@@ -140,27 +150,34 @@ module Solargraph
140
150
  # @return [Completion]
141
151
  def package_completions result
142
152
  frag_start = cursor.start_of_word.to_s.downcase
143
- filtered = result.uniq(&:name).select { |s|
153
+ filtered = result.uniq(&:name).select do |s|
144
154
  s.name.downcase.start_with?(frag_start) &&
145
- (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
146
- }
155
+ (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(!|\?|=)?$/i))
156
+ end
147
157
  Completion.new(filtered, cursor.range)
148
158
  end
149
159
 
150
160
  # @return [Completion]
151
161
  def tag_complete
152
162
  result = []
153
- match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i)
163
+ # @sg-ignore Need to add nil check here
164
+ match = source_map.code[0..(cursor.offset - 1)].match(/[\[<, ]([a-z0-9_:]*)\z/i)
154
165
  if match
166
+ # @sg-ignore Need to add nil check here
155
167
  full = match[1]
168
+ # @sg-ignore Need to add nil check here
156
169
  if full.include?('::')
170
+ # @sg-ignore Need to add nil check here
157
171
  if full.end_with?('::')
172
+ # @sg-ignore Need to add nil check here
158
173
  result.concat api_map.get_constants(full[0..-3], *gates)
159
174
  else
175
+ # @sg-ignore Need to add nil check here
160
176
  result.concat api_map.get_constants(full.split('::')[0..-2].join('::'), *gates)
161
177
  end
162
178
  else
163
- result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
179
+ # @sg-ignore Need to add nil check here
180
+ result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) # .select { |pin| pin.name.start_with?(full) }
164
181
  end
165
182
  end
166
183
  package_completions(result)
@@ -173,24 +190,24 @@ module Solargraph
173
190
  if cursor.chain.constant? || cursor.start_of_constant?
174
191
  full = cursor.chain.links.first.word
175
192
  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
193
+ cursor.chain.base.infer(api_map, context_pin, locals)
194
+ elsif full.include?('::') && cursor.chain.links.length == 1
195
+ # @sg-ignore Need to add nil check here
196
+ ComplexType.try_parse(full.split('::')[0..-2].join('::'))
197
+ elsif cursor.chain.links.length > 1
198
+ ComplexType.try_parse(full)
199
+ else
200
+ ComplexType::UNDEFINED
201
+ end
186
202
  if type.undefined?
187
203
  if full.include?('::')
188
204
  result.concat api_map.get_constants(full, *gates)
189
205
  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) }
206
+ result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) # .select { |pin| pin.name.start_with?(full) }
191
207
  end
192
208
  else
193
- result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
209
+ result.concat api_map.get_constants(type.namespace,
210
+ cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
194
211
  end
195
212
  else
196
213
  type = cursor.chain.base.infer(api_map, closure, locals)
@@ -199,14 +216,16 @@ module Solargraph
199
216
  if cursor.word.start_with?('@@')
200
217
  return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
201
218
  elsif cursor.word.start_with?('@')
202
- return package_completions(api_map.get_instance_variable_pins(closure.binder.namespace, closure.binder.scope))
219
+ return package_completions(api_map.get_instance_variable_pins(closure.full_context.namespace,
220
+ closure.context.scope))
203
221
  elsif cursor.word.start_with?('$')
204
222
  return package_completions(api_map.get_global_variable_pins)
205
223
  end
206
224
  result.concat locals
207
225
  result.concat file_global_methods unless closure.binder.namespace.empty?
208
226
  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])
227
+ result.concat api_map.get_methods(closure.binder.namespace, scope: closure.binder.scope,
228
+ visibility: %i[public private protected])
210
229
  result.concat api_map.get_methods('Kernel')
211
230
  result.concat api_map.keyword_pins.to_a
212
231
  end
@@ -8,13 +8,16 @@ module Solargraph
8
8
  @source = source
9
9
  end
10
10
 
11
+ # @sg-ignore Translate to something flow sensitive typing understands
11
12
  # @return [Array<Solargraph::Pin::Base>]
13
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1100
12
14
  def pins
13
15
  generate
14
16
  @pins || []
15
17
  end
16
18
 
17
- # @return [Array<Solargraph::LocalVariable>]
19
+ # @sg-ignore Translate to something flow sensitive typing understands
20
+ # @return [Array<Solargraph::Pin::LocalVariable>]
18
21
  def locals
19
22
  generate
20
23
  @locals || []
@@ -12,7 +12,7 @@ module Solargraph
12
12
 
13
13
  private_class_method :new
14
14
 
15
- DIRECTIVE_REGEXP = /(@\!method|@\!attribute|@\!visibility|@\!domain|@\!macro|@\!parse|@\!override)/.freeze
15
+ DIRECTIVE_REGEXP = /(@!method|@!attribute|@!visibility|@!domain|@!macro|@!parse|@!override)/
16
16
 
17
17
  # Generate the data.
18
18
  #
@@ -24,14 +24,15 @@ module Solargraph
24
24
  @code = source.code
25
25
  @comments = source.comments
26
26
  @pins, @locals = Parser.map(source)
27
+ # @param p [Solargraph::Pin::Base]
27
28
  @pins.each { |p| p.source = :code }
28
29
  @locals.each { |l| l.source = :code }
29
30
  process_comment_directives
30
31
  [@pins, @locals]
31
- # rescue Exception => e
32
- # Solargraph.logger.warn "Error mapping #{source.filename}: [#{e.class}] #{e.message}"
33
- # Solargraph.logger.warn e.backtrace.join("\n")
34
- # [[], []]
32
+ # rescue Exception => e
33
+ # Solargraph.logger.warn "Error mapping #{source.filename}: [#{e.class}] #{e.message}"
34
+ # Solargraph.logger.warn e.backtrace.join("\n")
35
+ # [[], []]
35
36
  end
36
37
 
37
38
  # @param filename [String]
@@ -48,6 +49,7 @@ module Solargraph
48
49
  # @param source [Source]
49
50
  # @return [Array]
50
51
  def map source
52
+ # @sg-ignore Need to add nil check here
51
53
  return new.unmap(source.filename, source.code) unless source.parsed?
52
54
  new.map source
53
55
  end
@@ -61,8 +63,9 @@ module Solargraph
61
63
 
62
64
  # @param position [Solargraph::Position]
63
65
  # @return [Solargraph::Pin::Closure]
64
- def closure_at(position)
65
- pins.select{|pin| pin.is_a?(Pin::Closure) and pin.location.range.contain?(position)}.last
66
+ def closure_at position
67
+ # @sg-ignore Need to add nil check here
68
+ pins.select { |pin| pin.is_a?(Pin::Closure) and pin.location.range.contain?(position) }.last
66
69
  end
67
70
 
68
71
  # @param source_position [Position]
@@ -90,11 +93,13 @@ module Solargraph
90
93
  def find_directive_line_number comment, tag, start
91
94
  # Avoid overruning the index
92
95
  return start unless start < comment.lines.length
93
- num = comment.lines[start..-1].find_index do |line|
96
+ # @sg-ignore Need to add nil check here
97
+ num = comment.lines[start..].find_index do |line|
94
98
  # Legacy method directives might be `@method` instead of `@!method`
95
99
  # @todo Legacy syntax should probably emit a warning
96
100
  line.include?("@!#{tag}") || (tag == 'method' && line.include?("@#{tag}"))
97
101
  end
102
+ # @sg-ignore Need to add nil check here
98
103
  num.to_i + start
99
104
  end
100
105
 
@@ -103,35 +108,37 @@ module Solargraph
103
108
  # @param directive [YARD::Tags::Directive]
104
109
  # @return [void]
105
110
  def process_directive source_position, comment_position, directive
111
+ # @sg-ignore Need to add nil check here
106
112
  docstring = Solargraph::Source.parse_docstring(directive.tag.text).to_docstring
107
113
  location = Location.new(@filename, Range.new(comment_position, comment_position))
108
114
  case directive.tag.tag_name
109
115
  when 'method'
110
116
  namespace = closure_at(source_position) || @pins.first
111
- if namespace.location.range.start.line < comment_position.line
112
- namespace = closure_at(comment_position)
113
- end
117
+ # @sg-ignore Need to add nil check here
118
+ namespace = closure_at(comment_position) if namespace.location.range.start.line < comment_position.line
114
119
  begin
115
120
  src = Solargraph::Source.load_string("def #{directive.tag.name};end", @source.filename)
116
121
  region = Parser::Region.new(source: src, closure: namespace)
122
+ # @type [Array<Pin::Method>]
117
123
  method_gen_pins = Parser.process_node(src.node, region).first.select { |pin| pin.is_a?(Pin::Method) }
118
124
  gen_pin = method_gen_pins.last
119
125
  return if gen_pin.nil?
120
126
  # Move the location to the end of the line so it gets recognized
121
127
  # as originating from a comment
122
- shifted = Solargraph::Position.new(comment_position.line, @code.lines[comment_position.line].to_s.chomp.length)
128
+ shifted = Solargraph::Position.new(comment_position.line,
129
+ @code.lines[comment_position.line].to_s.chomp.length)
123
130
  # @todo: Smelly instance variable access
124
131
  gen_pin.instance_variable_set(:@comments, docstring.all.to_s)
125
132
  gen_pin.instance_variable_set(:@location, Solargraph::Location.new(@filename, Range.new(shifted, shifted)))
126
133
  gen_pin.instance_variable_set(:@explicit, false)
127
134
  @pins.push gen_pin
128
- rescue Parser::SyntaxError => e
135
+ rescue Parser::SyntaxError
129
136
  # @todo Handle error in directive
130
137
  end
131
138
  when 'attribute'
132
139
  return if directive.tag.name.nil?
133
140
  namespace = closure_at(source_position)
134
- t = (directive.tag.types.nil? || directive.tag.types.empty?) ? nil : directive.tag.types.flatten.join('')
141
+ t = directive.tag.types.nil? || directive.tag.types.empty? ? nil : directive.tag.types.join
135
142
  if t.nil? || t.include?('r')
136
143
  pins.push Solargraph::Pin::Method.new(
137
144
  location: location,
@@ -157,57 +164,68 @@ module Solargraph
157
164
  source: :source_map
158
165
  )
159
166
  pins.push method_pin
160
- method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last, source: :source_map)
167
+ method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last,
168
+ source: :source_map)
161
169
  if pins.last.return_type.defined?
162
- pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
170
+ pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '),
171
+ 'value')
163
172
  end
164
173
  end
165
174
  when 'visibility'
166
175
 
167
- kind = directive.tag.text&.to_sym
168
- return unless [:private, :protected, :public].include?(kind)
176
+ kind = directive.tag.text&.to_sym
177
+ # @sg-ignore Need to look at Tuple#include? handling
178
+ return unless %i[private protected public].include?(kind)
169
179
 
170
- name = directive.tag.name
171
- closure = closure_at(source_position) || @pins.first
172
- if closure.location.range.start.line < comment_position.line
173
- closure = closure_at(comment_position)
180
+ name = directive.tag.name
181
+ closure = closure_at(source_position) || @pins.first
182
+ # @sg-ignore Need to add nil check here
183
+ closure = closure_at(comment_position) if closure.location.range.start.line < comment_position.line
184
+ if closure.is_a?(Pin::Method) && no_empty_lines?(comment_position.line, source_position.line)
185
+ # @todo Smelly instance variable access
186
+ closure.instance_variable_set(:@visibility, kind)
187
+ else
188
+ matches = pins.select do |pin|
189
+ pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == namespace && pin.context.scope == namespace.is_a?(Pin::Singleton) ? :class : :instance
174
190
  end
175
- if closure.is_a?(Pin::Method) && no_empty_lines?(comment_position.line, source_position.line)
191
+ matches.each do |pin|
176
192
  # @todo Smelly instance variable access
177
- closure.instance_variable_set(:@visibility, kind)
178
- else
179
- matches = pins.select{ |pin| pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == namespace && pin.context.scope == namespace.is_a?(Pin::Singleton) ? :class : :instance }
180
- matches.each do |pin|
181
- # @todo Smelly instance variable access
182
- pin.instance_variable_set(:@visibility, kind)
183
- end
193
+ pin.instance_variable_set(:@visibility, kind)
184
194
  end
195
+ end
185
196
 
186
197
  when 'parse'
187
198
  begin
188
199
  ns = closure_at(source_position)
200
+ # @sg-ignore Need to add nil check here
189
201
  src = Solargraph::Source.load_string(directive.tag.text, @source.filename)
190
202
  region = Parser::Region.new(source: src, closure: ns)
191
203
  # @todo These pins may need to be marked not explicit
192
204
  index = @pins.length
193
205
  loff = if @code.lines[comment_position.line].strip.end_with?('@!parse')
194
- comment_position.line + 1
195
- else
196
- comment_position.line
197
- end
198
- Parser.process_node(src.node, region, @pins)
199
- @pins[index..-1].each do |p|
206
+ comment_position.line + 1
207
+ else
208
+ comment_position.line
209
+ end
210
+ locals = []
211
+ ivars = []
212
+ Parser.process_node(src.node, region, @pins, locals, ivars)
213
+ @pins.concat ivars
214
+ # @sg-ignore Need to add nil check here
215
+ @pins[index..].each do |p|
200
216
  # @todo Smelly instance variable access
201
217
  p.location.range.start.instance_variable_set(:@line, p.location.range.start.line + loff)
202
218
  p.location.range.ending.instance_variable_set(:@line, p.location.range.ending.line + loff)
203
219
  end
204
- rescue Parser::SyntaxError => e
220
+ rescue Parser::SyntaxError
205
221
  # @todo Handle parser errors in !parse directives
206
222
  end
207
223
  when 'domain'
208
224
  namespace = closure_at(source_position) || Pin::ROOT_PIN
225
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
209
226
  namespace.domains.concat directive.tag.types unless directive.tag.types.nil?
210
227
  when 'override'
228
+ # @sg-ignore Need to add nil check here
211
229
  pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags,
212
230
  source: :source_map)
213
231
  when 'macro'
@@ -217,7 +235,9 @@ module Solargraph
217
235
 
218
236
  # @param line1 [Integer]
219
237
  # @param line2 [Integer]
220
- def no_empty_lines?(line1, line2)
238
+ # @sg-ignore Need to add nil check here
239
+ def no_empty_lines? line1, line2
240
+ # @sg-ignore Need to add nil check here
221
241
  @code.lines[line1..line2].none? { |line| line.strip.empty? }
222
242
  end
223
243
 
@@ -227,7 +247,7 @@ module Solargraph
227
247
  ctxt = ''
228
248
  num = nil
229
249
  started = false
230
- comment.lines.each { |l|
250
+ comment.lines.each do |l|
231
251
  # Trim the comment and minimum leading whitespace
232
252
  p = l.encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#+/, '')
233
253
  if num.nil? && !p.strip.empty?
@@ -235,10 +255,11 @@ module Solargraph
235
255
  started = true
236
256
  elsif started && !p.strip.empty?
237
257
  cur = p.index(/[^ ]/)
258
+ # @sg-ignore Need to add nil check here
238
259
  num = cur if cur < num
239
260
  end
240
- ctxt += "#{p[num..-1]}" if started
241
- }
261
+ ctxt += p[num..].to_s if started
262
+ end
242
263
  ctxt
243
264
  end
244
265
 
@@ -247,7 +268,15 @@ module Solargraph
247
268
  return unless @code.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
248
269
  code_lines = @code.lines
249
270
  @source.associated_comments.each do |line, comments|
250
- src_pos = line ? Position.new(line, code_lines[line].to_s.chomp.index(/[^\s]/) || 0) : Position.new(code_lines.length, 0)
271
+ src_pos = if line
272
+ Position.new(line,
273
+ code_lines[line].to_s.chomp.index(/[^\s]/) || 0)
274
+ else
275
+ Position.new(
276
+ code_lines.length, 0
277
+ )
278
+ end
279
+ # @sg-ignore Need to add nil check here
251
280
  com_pos = Position.new(line + 1 - comments.lines.length, 0)
252
281
  process_comment(src_pos, com_pos, comments)
253
282
  end
@@ -34,6 +34,8 @@ module Solargraph
34
34
  # @param source [Source]
35
35
  def initialize source
36
36
  @source = source
37
+ # @type [Array<Pin::Base>, nil]
38
+ @convention_pins = nil
37
39
 
38
40
  conventions_environ.merge Convention.for_local(self) unless filename.nil?
39
41
  # FIXME: unmemoizing the document_symbols in case it was called and memoized from any of conventions above
@@ -60,10 +62,12 @@ module Solargraph
60
62
  #
61
63
  # @return [Integer]
62
64
  def api_hash
63
- @api_hash ||= (pins_by_class(Pin::Constant) + pins_by_class(Pin::Namespace).select { |pin| pin.namespace.to_s > '' } + pins_by_class(Pin::Reference) + pins_by_class(Pin::Method).map(&:node) + locals).hash
65
+ @api_hash ||= (pins_by_class(Pin::Constant) + pins_by_class(Pin::Namespace).select do |pin|
66
+ pin.namespace.to_s > ''
67
+ end + pins_by_class(Pin::Reference) + pins_by_class(Pin::Method).map(&:node) + locals).hash
64
68
  end
65
69
 
66
- # @return [String]
70
+ # @return [String, nil]
67
71
  def filename
68
72
  source.filename
69
73
  end
@@ -84,6 +88,7 @@ module Solargraph
84
88
  end
85
89
 
86
90
  # all pins except Solargraph::Pin::Reference::Reference
91
+ #
87
92
  # @return [Array<Pin::Base>]
88
93
  def document_symbols
89
94
  @document_symbols ||= (pins + convention_pins).select do |pin|
@@ -97,7 +102,7 @@ module Solargraph
97
102
  Pin::Search.new(document_symbols, query).results
98
103
  end
99
104
 
100
- # @param position [Position]
105
+ # @param position [Position, Array(Integer, Integer)]
101
106
  # @return [Source::Cursor]
102
107
  def cursor_at position
103
108
  Source::Cursor.new(source, position)
@@ -125,7 +130,7 @@ module Solargraph
125
130
 
126
131
  # @param line [Integer]
127
132
  # @param character [Integer]
128
- # @return [Pin::Namespace,Pin::Method,Pin::Block]
133
+ # @return [Pin::Closure]
129
134
  def locate_closure_pin line, character
130
135
  _locate_pin line, character, Pin::Closure
131
136
  end
@@ -141,9 +146,9 @@ module Solargraph
141
146
 
142
147
  # @param location [Location]
143
148
  # @return [Array<Pin::LocalVariable>]
144
- def locals_at(location)
149
+ def locals_at location
145
150
  return [] if location.filename != filename
146
- closure = locate_named_path_pin(location.range.start.line, location.range.start.character)
151
+ closure = locate_closure_pin(location.range.start.line, location.range.start.character)
147
152
  locals.select { |pin| pin.visible_at?(closure, location) }
148
153
  end
149
154
 
@@ -178,6 +183,7 @@ module Solargraph
178
183
 
179
184
  # @return [Hash{Class<Pin::Base> => Array<Pin::Base>}]
180
185
  def pin_class_hash
186
+ # @todo Need to support generic resolution in classify and transform_values
181
187
  @pin_class_hash ||= pins.to_set.classify(&:class).transform_values(&:to_a)
182
188
  end
183
189
 
@@ -191,10 +197,12 @@ module Solargraph
191
197
  @convention_pins || []
192
198
  end
193
199
 
200
+ # @generic T
194
201
  # @param line [Integer]
195
202
  # @param character [Integer]
196
- # @param klasses [Array<Class>]
197
- # @return [Pin::Base, nil]
203
+ # @param klasses [Array<Class<generic<T>>>]
204
+ # @return [generic<T>, nil]
205
+ # @sg-ignore Need better generic inference here
198
206
  def _locate_pin line, character, *klasses
199
207
  position = Position.new(line, character)
200
208
  found = nil
@@ -202,7 +210,11 @@ module Solargraph
202
210
  # @todo Attribute pins should not be treated like closures, but
203
211
  # there's probably a better way to handle it
204
212
  next if pin.is_a?(Pin::Method) && pin.attribute?
205
- found = pin if (klasses.empty? || klasses.any? { |kls| pin.is_a?(kls) } ) && pin.location.range.contain?(position)
213
+ found = pin if (klasses.empty? || klasses.any? do |kls|
214
+ pin.is_a?(kls)
215
+ # @sg-ignore Need to add nil check here
216
+ end) && pin.location.range.contain?(position)
217
+ # @sg-ignore Need to add nil check here
206
218
  break if pin.location.range.start.line > line
207
219
  end
208
220
  # Assuming the root pin is always valid
@@ -5,19 +5,21 @@ module Solargraph
5
5
  # A problem reported by TypeChecker.
6
6
  #
7
7
  class Problem
8
+ # @todo Missed nil violation
8
9
  # @return [Solargraph::Location]
9
10
  attr_reader :location
10
11
 
11
12
  # @return [String]
12
13
  attr_reader :message
13
14
 
15
+ # @todo Missed nil violation
14
16
  # @return [Pin::Base]
15
17
  attr_reader :pin
16
18
 
17
19
  # @return [String, nil]
18
20
  attr_reader :suggestion
19
21
 
20
- # @param location [Solargraph::Location]
22
+ # @param location [Solargraph::Location, nil]
21
23
  # @param message [String]
22
24
  # @param pin [Solargraph::Pin::Base, nil]
23
25
  # @param suggestion [String, nil]
@@ -23,11 +23,11 @@ module Solargraph
23
23
  # @param overrides [Hash{Symbol => Symbol}]
24
24
  def initialize level, overrides
25
25
  @rank = if LEVELS.key?(level)
26
- LEVELS[level]
27
- else
28
- Solargraph.logger.warn "Unrecognized TypeChecker level #{level}, assuming normal"
29
- 0
30
- end
26
+ LEVELS[level]
27
+ else
28
+ Solargraph.logger.warn "Unrecognized TypeChecker level #{level}, assuming normal"
29
+ 0
30
+ end
31
31
  @level = LEVELS[LEVELS.values.index(@rank)]
32
32
  @overrides = overrides
33
33
  end
@@ -60,8 +60,81 @@ module Solargraph
60
60
  report?(:validate_tags, :typed)
61
61
  end
62
62
 
63
- def require_all_return_types_match_inferred?
64
- report?(:require_all_return_types_match_inferred, :alpha)
63
+ def require_inferred_type_params?
64
+ report?(:require_inferred_type_params, :alpha)
65
+ end
66
+
67
+ #
68
+ # False negatives:
69
+ #
70
+ # @todo 4: Missed nil violation
71
+ #
72
+ # pending code fixes (277):
73
+ #
74
+ # @todo 281: Need to add nil check here
75
+ # @todo 22: Translate to something flow sensitive typing understands
76
+ # @todo 3: Need a downcast here
77
+ #
78
+ # flow sensitive typing could handle (96):
79
+ #
80
+ # @todo 36: flow sensitive typing needs to handle attrs
81
+ # @todo 29: flow sensitive typing should be able to handle redefinition
82
+ # @todo 19: flow sensitive typing needs to narrow down type with an if is_a? check
83
+ # @todo 13: Need to validate config
84
+ # @todo 8: flow sensitive typing should support .class == .class
85
+ # @todo 6: need boolish support for ? methods
86
+ # @todo 6: flow sensitive typing needs better handling of ||= on lvars
87
+ # @todo 5: literal arrays in this module turn into ::Solargraph::Source::Chain::Array
88
+ # @todo 5: flow sensitive typing needs to handle 'raise if'
89
+ # @todo 4: flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
90
+ # @todo 4: nil? support in flow sensitive typing
91
+ # @todo 3: flow sensitive typing ought to be able to handle 'when ClassName'
92
+ # @todo 2: downcast output of Enumerable#select
93
+ # @todo 2: flow sensitive typing should handle return nil if location&.name.nil?
94
+ # @todo 2: flow sensitive typing should handle is_a? and next
95
+ # @todo 2: Need to look at Tuple#include? handling
96
+ # @todo 2: Should better support meaning of '&' in RBS
97
+ # @todo 2: (*) flow sensitive typing needs to handle "if foo = bar"
98
+ # @todo 2: flow sensitive typing needs to handle "if foo = bar"
99
+ # @todo 2: Need to handle duck-typed method calls on union types
100
+ # @todo 2: Need better handling of #compact
101
+ # @todo 2: flow sensitive typing should allow shadowing of Kernel#caller
102
+ # @todo 1: flow sensitive typing not smart enough to handle this case
103
+ # @todo 1: flow sensitive typing needs to handle if foo = bar
104
+ # @todo 1: flow sensitive typing needs to handle "if foo.nil?"
105
+ # @todo 1: flow sensitive typing should support case/when
106
+ # @todo 1: flow sensitive typing should support ivars
107
+ # @todo 1: Need to support this in flow sensitive typing
108
+ # @todo 1: flow sensitive typing needs to handle self.class == other.class
109
+ # @todo 1: flow sensitive typing needs to remove literal with
110
+ # @todo 1: flow sensitive typing needs to understand reassignment
111
+ # @todo 1: flow sensitive typing should be able to identify more blocks that always return
112
+ # @todo 1: should warn on nil dereference below
113
+ # @todo 1: flow sensitive typing needs to create separate ranges for postfix if
114
+ # @todo 1: flow sensitive typing needs to handle constants
115
+ # @todo 1: flow sensitive typing needs to eliminate literal from union with return if foo == :bar
116
+ def require_all_unique_types_match_expected?
117
+ report?(:require_all_unique_types_match_expected, :strong)
118
+ end
119
+
120
+ def require_all_unique_types_support_call?
121
+ report?(:require_all_unique_types_support_call, :strong)
122
+ end
123
+
124
+ def require_no_undefined_args?
125
+ report?(:require_no_undefined_args, :alpha)
126
+ end
127
+
128
+ def require_generics_resolved?
129
+ report?(:require_generics_resolved, :alpha)
130
+ end
131
+
132
+ def require_interfaces_resolved?
133
+ report?(:require_interfaces_resolved, :alpha)
134
+ end
135
+
136
+ def require_downcasts?
137
+ report?(:require_downcasts, :alpha)
65
138
  end
66
139
 
67
140
  # We keep this at strong because if you added an @ sg-ignore to
@@ -76,7 +149,7 @@ module Solargraph
76
149
 
77
150
  # @param type [Symbol]
78
151
  # @param level [Symbol]
79
- def report?(type, level)
152
+ def report? type, level
80
153
  rank >= LEVELS[@overrides.fetch(type, level)]
81
154
  end
82
155
  end