solargraph 0.58.3 → 0.60.4

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 (238) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +12 -5
  4. data/.github/workflows/plugins.yml +53 -37
  5. data/.github/workflows/rspec.yml +18 -28
  6. data/.github/workflows/typecheck.yml +6 -3
  7. data/.rubocop.yml +39 -6
  8. data/.rubocop_todo.yml +53 -966
  9. data/CHANGELOG.md +67 -0
  10. data/Gemfile +6 -1
  11. data/README.md +3 -3
  12. data/Rakefile +26 -23
  13. data/bin/solargraph +2 -1
  14. data/lib/solargraph/api_map/cache.rb +3 -3
  15. data/lib/solargraph/api_map/constants.rb +13 -4
  16. data/lib/solargraph/api_map/index.rb +42 -20
  17. data/lib/solargraph/api_map/source_to_yard.rb +22 -9
  18. data/lib/solargraph/api_map/store.rb +61 -36
  19. data/lib/solargraph/api_map.rb +191 -78
  20. data/lib/solargraph/bench.rb +2 -3
  21. data/lib/solargraph/complex_type/conformance.rb +176 -0
  22. data/lib/solargraph/complex_type/type_methods.rb +31 -18
  23. data/lib/solargraph/complex_type/unique_type.rb +225 -63
  24. data/lib/solargraph/complex_type.rb +190 -59
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -111
  26. data/lib/solargraph/convention/base.rb +50 -50
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -1
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +7 -5
  29. data/lib/solargraph/convention/data_definition.rb +5 -2
  30. data/lib/solargraph/convention/gemfile.rb +1 -1
  31. data/lib/solargraph/convention/gemspec.rb +1 -1
  32. data/lib/solargraph/convention/rakefile.rb +1 -1
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -3
  35. data/lib/solargraph/convention/struct_definition.rb +8 -4
  36. data/lib/solargraph/convention.rb +2 -2
  37. data/lib/solargraph/converters/dd.rb +2 -0
  38. data/lib/solargraph/converters/dl.rb +2 -0
  39. data/lib/solargraph/converters/dt.rb +2 -0
  40. data/lib/solargraph/converters/misc.rb +2 -0
  41. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  42. data/lib/solargraph/diagnostics/rubocop.rb +11 -10
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  44. data/lib/solargraph/diagnostics/type_check.rb +11 -10
  45. data/lib/solargraph/diagnostics/update_errors.rb +4 -8
  46. data/lib/solargraph/diagnostics.rb +55 -55
  47. data/lib/solargraph/doc_map.rb +39 -39
  48. data/lib/solargraph/environ.rb +52 -52
  49. data/lib/solargraph/equality.rb +4 -4
  50. data/lib/solargraph/gem_pins.rb +4 -15
  51. data/lib/solargraph/language_server/error_codes.rb +10 -10
  52. data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
  53. data/lib/solargraph/language_server/host/dispatch.rb +3 -3
  54. data/lib/solargraph/language_server/host/message_worker.rb +4 -3
  55. data/lib/solargraph/language_server/host/sources.rb +2 -1
  56. data/lib/solargraph/language_server/host.rb +35 -28
  57. data/lib/solargraph/language_server/message/base.rb +1 -1
  58. data/lib/solargraph/language_server/message/client/register_capability.rb +1 -3
  59. data/lib/solargraph/language_server/message/completion_item/resolve.rb +6 -8
  60. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +12 -18
  61. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  62. data/lib/solargraph/language_server/message/extended/document_gems.rb +7 -7
  63. data/lib/solargraph/language_server/message/extended/download_core.rb +2 -1
  64. data/lib/solargraph/language_server/message/extended/environment.rb +25 -25
  65. data/lib/solargraph/language_server/message/extended/search.rb +1 -1
  66. data/lib/solargraph/language_server/message/initialize.rb +20 -14
  67. data/lib/solargraph/language_server/message/initialized.rb +28 -28
  68. data/lib/solargraph/language_server/message/text_document/completion.rb +10 -8
  69. data/lib/solargraph/language_server/message/text_document/definition.rb +41 -32
  70. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +17 -10
  71. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +29 -19
  72. data/lib/solargraph/language_server/message/text_document/formatting.rb +8 -6
  73. data/lib/solargraph/language_server/message/text_document/hover.rb +5 -5
  74. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +13 -6
  75. data/lib/solargraph/language_server/message/text_document/references.rb +17 -10
  76. data/lib/solargraph/language_server/message/text_document/rename.rb +20 -13
  77. data/lib/solargraph/language_server/message/text_document/signature_help.rb +3 -2
  78. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -17
  79. data/lib/solargraph/language_server/message/text_document.rb +28 -28
  80. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +34 -28
  81. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +38 -30
  82. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +23 -17
  83. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +27 -17
  84. data/lib/solargraph/language_server/message.rb +1 -1
  85. data/lib/solargraph/language_server/progress.rb +143 -143
  86. data/lib/solargraph/language_server/request.rb +4 -2
  87. data/lib/solargraph/language_server/transport/adapter.rb +68 -68
  88. data/lib/solargraph/language_server/transport/data_reader.rb +11 -13
  89. data/lib/solargraph/language_server/uri_helpers.rb +2 -2
  90. data/lib/solargraph/language_server.rb +20 -20
  91. data/lib/solargraph/library.rb +63 -40
  92. data/lib/solargraph/location.rb +17 -14
  93. data/lib/solargraph/logging.rb +22 -4
  94. data/lib/solargraph/page.rb +1 -1
  95. data/lib/solargraph/parser/comment_ripper.rb +19 -4
  96. data/lib/solargraph/parser/flow_sensitive_typing.rb +324 -108
  97. data/lib/solargraph/parser/node_processor/base.rb +34 -4
  98. data/lib/solargraph/parser/node_processor.rb +8 -7
  99. data/lib/solargraph/parser/parser_gem/class_methods.rb +30 -14
  100. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -1
  101. data/lib/solargraph/parser/parser_gem/node_chainer.rb +51 -25
  102. data/lib/solargraph/parser/parser_gem/node_methods.rb +222 -72
  103. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +24 -24
  104. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  105. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +13 -11
  106. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -12
  108. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +36 -36
  109. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +24 -24
  110. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +10 -3
  111. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +9 -8
  112. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +24 -24
  113. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  114. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +5 -3
  115. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  116. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  117. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +73 -40
  118. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +3 -3
  119. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  120. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  121. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  122. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -5
  123. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +124 -113
  124. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +20 -20
  125. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +1 -1
  126. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  127. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +6 -2
  128. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  129. data/lib/solargraph/parser/parser_gem.rb +2 -0
  130. data/lib/solargraph/parser/region.rb +9 -3
  131. data/lib/solargraph/parser/snippet.rb +3 -1
  132. data/lib/solargraph/parser.rb +2 -0
  133. data/lib/solargraph/pin/base.rb +157 -85
  134. data/lib/solargraph/pin/base_variable.rb +273 -24
  135. data/lib/solargraph/pin/block.rb +29 -6
  136. data/lib/solargraph/pin/breakable.rb +7 -1
  137. data/lib/solargraph/pin/callable.rb +67 -23
  138. data/lib/solargraph/pin/closure.rb +7 -10
  139. data/lib/solargraph/pin/common.rb +36 -6
  140. data/lib/solargraph/pin/compound_statement.rb +55 -0
  141. data/lib/solargraph/pin/constant.rb +3 -5
  142. data/lib/solargraph/pin/conversions.rb +10 -4
  143. data/lib/solargraph/pin/delegated_method.rb +19 -8
  144. data/lib/solargraph/pin/documenting.rb +4 -2
  145. data/lib/solargraph/pin/instance_variable.rb +5 -1
  146. data/lib/solargraph/pin/keyword.rb +0 -4
  147. data/lib/solargraph/pin/local_variable.rb +15 -59
  148. data/lib/solargraph/pin/method.rb +208 -113
  149. data/lib/solargraph/pin/method_alias.rb +8 -0
  150. data/lib/solargraph/pin/namespace.rb +19 -12
  151. data/lib/solargraph/pin/parameter.rb +102 -36
  152. data/lib/solargraph/pin/proxy_type.rb +4 -1
  153. data/lib/solargraph/pin/reference/override.rb +1 -1
  154. data/lib/solargraph/pin/reference/require.rb +14 -14
  155. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  156. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  157. data/lib/solargraph/pin/reference.rb +20 -0
  158. data/lib/solargraph/pin/search.rb +8 -7
  159. data/lib/solargraph/pin/signature.rb +15 -12
  160. data/lib/solargraph/pin/singleton.rb +11 -11
  161. data/lib/solargraph/pin/symbol.rb +2 -1
  162. data/lib/solargraph/pin/until.rb +2 -4
  163. data/lib/solargraph/pin/while.rb +2 -4
  164. data/lib/solargraph/pin.rb +2 -0
  165. data/lib/solargraph/pin_cache.rb +22 -19
  166. data/lib/solargraph/position.rb +17 -10
  167. data/lib/solargraph/range.rb +16 -15
  168. data/lib/solargraph/rbs_map/conversions.rb +227 -238
  169. data/lib/solargraph/rbs_map/core_fills.rb +18 -11
  170. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  171. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -5
  172. data/lib/solargraph/rbs_map.rb +76 -32
  173. data/lib/solargraph/rbs_translator.rb +206 -0
  174. data/lib/solargraph/server_methods.rb +1 -1
  175. data/lib/solargraph/shell.rb +330 -71
  176. data/lib/solargraph/source/chain/array.rb +3 -12
  177. data/lib/solargraph/source/chain/block_symbol.rb +13 -13
  178. data/lib/solargraph/source/chain/block_variable.rb +13 -13
  179. data/lib/solargraph/source/chain/call.rb +159 -89
  180. data/lib/solargraph/source/chain/class_variable.rb +1 -1
  181. data/lib/solargraph/source/chain/constant.rb +5 -1
  182. data/lib/solargraph/source/chain/global_variable.rb +1 -1
  183. data/lib/solargraph/source/chain/hash.rb +8 -5
  184. data/lib/solargraph/source/chain/head.rb +19 -19
  185. data/lib/solargraph/source/chain/if.rb +12 -10
  186. data/lib/solargraph/source/chain/instance_variable.rb +19 -1
  187. data/lib/solargraph/source/chain/link.rb +12 -22
  188. data/lib/solargraph/source/chain/literal.rb +22 -15
  189. data/lib/solargraph/source/chain/or.rb +10 -4
  190. data/lib/solargraph/source/chain/q_call.rb +2 -0
  191. data/lib/solargraph/source/chain/variable.rb +3 -1
  192. data/lib/solargraph/source/chain/z_super.rb +1 -3
  193. data/lib/solargraph/source/chain.rb +87 -43
  194. data/lib/solargraph/source/change.rb +12 -5
  195. data/lib/solargraph/source/cursor.rb +33 -18
  196. data/lib/solargraph/source/encoding_fixes.rb +6 -7
  197. data/lib/solargraph/source/source_chainer.rb +56 -32
  198. data/lib/solargraph/source/updater.rb +5 -1
  199. data/lib/solargraph/source.rb +71 -43
  200. data/lib/solargraph/source_map/clip.rb +54 -30
  201. data/lib/solargraph/source_map/data.rb +4 -1
  202. data/lib/solargraph/source_map/mapper.rb +30 -133
  203. data/lib/solargraph/source_map.rb +35 -9
  204. data/lib/solargraph/type_checker/problem.rb +3 -1
  205. data/lib/solargraph/type_checker/rules.rb +81 -8
  206. data/lib/solargraph/type_checker.rb +208 -125
  207. data/lib/solargraph/version.rb +1 -1
  208. data/lib/solargraph/workspace/config.rb +14 -11
  209. data/lib/solargraph/workspace/gemspecs.rb +373 -0
  210. data/lib/solargraph/workspace/require_paths.rb +1 -0
  211. data/lib/solargraph/workspace.rb +50 -28
  212. data/lib/solargraph/yard_map/cache.rb +25 -25
  213. data/lib/solargraph/yard_map/directives/attribute_directive.rb +65 -0
  214. data/lib/solargraph/yard_map/directives/domain_directive.rb +30 -0
  215. data/lib/solargraph/yard_map/directives/method_directive.rb +51 -0
  216. data/lib/solargraph/yard_map/directives/override_directive.rb +30 -0
  217. data/lib/solargraph/yard_map/directives/parse_directive.rb +53 -0
  218. data/lib/solargraph/yard_map/directives/visibility_directive.rb +70 -0
  219. data/lib/solargraph/yard_map/directives.rb +35 -0
  220. data/lib/solargraph/yard_map/helpers.rb +8 -3
  221. data/lib/solargraph/yard_map/macro.rb +113 -0
  222. data/lib/solargraph/yard_map/mapper/to_constant.rb +28 -28
  223. data/lib/solargraph/yard_map/mapper/to_method.rb +13 -7
  224. data/lib/solargraph/yard_map/mapper/to_namespace.rb +2 -1
  225. data/lib/solargraph/yard_map/mapper.rb +65 -9
  226. data/lib/solargraph/yard_map.rb +19 -18
  227. data/lib/solargraph/yard_tags.rb +2 -2
  228. data/lib/solargraph/yardoc.rb +7 -4
  229. data/lib/solargraph.rb +34 -10
  230. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  231. data/rbs/shims/ast/0/node.rbs +1 -1
  232. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  233. data/solargraph.gemspec +39 -35
  234. metadata +77 -41
  235. data/lib/solargraph/type_checker/checks.rb +0 -124
  236. data/lib/solargraph/type_checker/param_def.rb +0 -37
  237. data/lib/solargraph/yard_map/to_method.rb +0 -89
  238. data/rbs/fills/tuple/tuple.rbs +0 -149
@@ -6,31 +6,38 @@ module Solargraph
6
6
  class Source
7
7
  class Chain
8
8
  class Literal < Link
9
- def word
10
- @word ||= "<#{@type}>"
11
- end
12
-
13
- attr_reader :value
9
+ attr_reader :word, :value
14
10
 
15
11
  # @param type [String]
16
12
  # @param node [Parser::AST::Node, Object]
17
13
  def initialize type, node
18
- if node.is_a?(::Parser::AST::Node)
19
- if node.type == :true
20
- @value = true
21
- elsif node.type == :false
22
- @value = false
23
- elsif [:int, :sym].include?(node.type)
24
- @value = node.children.first
25
- end
26
- end
14
+ super("<#{type}>")
15
+
16
+ # @todo We might be able to do some light inference from literals and
17
+ # tuples as long as literal values are intransitive.
18
+
19
+ # if node.is_a?(::Parser::AST::Node)
20
+ # # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
21
+ # if node.type == :true
22
+ # @value = true
23
+ # # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
24
+ # elsif node.type == :false
25
+ # @value = false
26
+ # # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
27
+ # elsif %i[int sym].include?(node.type)
28
+ # # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
29
+ # @value = node.children.first
30
+ # end
31
+ # end
27
32
  @type = type
28
- @literal_type = ComplexType.try_parse(@value.inspect)
33
+ # @literal_type = ComplexType.try_parse(@value.inspect)
34
+ @literal_type = ComplexType::UNDEFINED
29
35
  @complex_type = ComplexType.try_parse(type)
30
36
  end
31
37
 
32
38
  # @sg-ignore Fix "Not enough arguments to Module#protected"
33
39
  protected def equality_fields
40
+ # @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
34
41
  super + [@value, @type, @literal_type, @complex_type]
35
42
  end
36
43
 
@@ -4,18 +4,24 @@ module Solargraph
4
4
  class Source
5
5
  class Chain
6
6
  class Or < Link
7
- def word
8
- '<or>'
9
- end
7
+ attr_reader :links
10
8
 
11
9
  # @param links [::Array<Chain>]
12
10
  def initialize links
11
+ super('<or>')
12
+
13
13
  @links = links
14
14
  end
15
15
 
16
16
  def resolve api_map, name_pin, locals
17
17
  types = @links.map { |link| link.infer(api_map, name_pin, locals) }
18
- [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.new(types.uniq), source: :chain)]
18
+ combined_type = Solargraph::ComplexType.new(types)
19
+ unless types.all?(&:nullable?)
20
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
21
+ combined_type = combined_type.without_nil
22
+ end
23
+
24
+ [Solargraph::Pin::ProxyType.anonymous(combined_type, source: :chain)]
19
25
  end
20
26
  end
21
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Solargraph
2
4
  class Source
3
5
  class Chain
@@ -5,7 +5,9 @@ module Solargraph
5
5
  class Chain
6
6
  class Variable < Link
7
7
  def resolve api_map, name_pin, locals
8
- api_map.get_instance_variable_pins(name_pin.context.namespace, name_pin.context.scope).select{|p| p.name == word}
8
+ api_map.get_instance_variable_pins(name_pin.context.namespace, name_pin.context.scope).select do |p|
9
+ p.name == word
10
+ end
9
11
  end
10
12
  end
11
13
  end
@@ -11,9 +11,7 @@ module Solargraph
11
11
  attr_reader :arguments
12
12
 
13
13
  # @param word [String]
14
- # @param arguments [::Array<Chain>]
15
14
  # @param with_block [Boolean] True if the chain is inside a block
16
- # @param head [Boolean] True if the call is the start of its chain
17
15
  def initialize word, with_block = false
18
16
  super(word, nil, [], with_block)
19
17
  end
@@ -22,7 +20,7 @@ module Solargraph
22
20
  # @param name_pin [Pin::Base]
23
21
  # @param locals [::Array<Pin::Base>]
24
22
  def resolve api_map, name_pin, locals
25
- return super_pins(api_map, name_pin)
23
+ super_pins(api_map, name_pin)
26
24
  end
27
25
  end
28
26
  end
@@ -48,11 +48,6 @@ module Solargraph
48
48
 
49
49
  attr_reader :node
50
50
 
51
- # @sg-ignore Fix "Not enough arguments to Module#protected"
52
- protected def equality_fields
53
- [links, node]
54
- end
55
-
56
51
  # @param node [Parser::AST::Node, nil]
57
52
  # @param links [::Array<Chain::Link>]
58
53
  # @param splat [Boolean]
@@ -71,6 +66,7 @@ module Solargraph
71
66
 
72
67
  # @return [Chain]
73
68
  def base
69
+ # @sg-ignore Need to add nil check here
74
70
  @base ||= Chain.new(links[0..-2])
75
71
  end
76
72
 
@@ -78,25 +74,25 @@ module Solargraph
78
74
  #
79
75
  # @param api_map [ApiMap]
80
76
  #
81
- # @param name_pin [Pin::Base] A pin
82
- # representing the place in which expression is evaluated (e.g.,
83
- # a Method pin, or a Module or Class pin if not run within a
84
- # method - both in terms of the closure around the chain, as well
85
- # as the self type used for any method calls in head position.
77
+ # @param name_pin [Pin::Base] A pin representing the closure in
78
+ # which expression is evaluated (e.g., a Method pin, or a
79
+ # Module or Class pin if not run within a method - both in
80
+ # terms of the closure around the chain, as well as the self
81
+ # type used for any method calls in head position.
86
82
  #
87
83
  # Requirements for name_pin:
88
84
  #
89
85
  # * name_pin.context: This should be a type representing the
90
- # namespace where we can look up non-local variables and
91
- # method names. If it is a Class<X>, we will look up
92
- # :class scoped methods/variables.
86
+ # namespace where we can look up non-local variables. If
87
+ # it is a Class<X>, we will look up :class scoped
88
+ # instance variables.
93
89
  #
94
90
  # * name_pin.binder: Used for method call lookups only
95
91
  # (Chain::Call links). For method calls as the first
96
92
  # element in the chain, 'name_pin.binder' should be the
97
93
  # same as name_pin.context above. For method calls later
98
- # in the chain (e.g., 'b' in a.b.c), it should represent
99
- # 'a'.
94
+ # in the chain, it changes. (e.g., for 'b' in a.b.c, it
95
+ # should represent the type of 'a').
100
96
  #
101
97
  # @param locals [::Array<Pin::LocalVariable>] Any local
102
98
  # variables / method parameters etc visible by the statement
@@ -113,11 +109,14 @@ module Solargraph
113
109
  #
114
110
  # @todo ProxyType uses 'type' for the binder, but '
115
111
  working_pin = name_pin
112
+ # @sg-ignore Need to add nil check here
116
113
  links[0..-2].each do |link|
117
114
  pins = link.resolve(api_map, working_pin, locals)
118
115
  type = infer_from_definitions(pins, working_pin, api_map, locals)
119
116
  if type.undefined?
120
- logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) => [] - undefined type from #{link.desc}" }
117
+ logger.debug do
118
+ "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) => [] - undefined type from #{link.desc}"
119
+ end
121
120
  return []
122
121
  end
123
122
  # We continue to use the context from the head pin, in case
@@ -126,7 +125,9 @@ module Solargraph
126
125
  # for the binder, as this is chaining off of it, and the
127
126
  # binder is now the lhs of the rhs we are evaluating.
128
127
  working_pin = Pin::ProxyType.anonymous(name_pin.context, binder: type, closure: name_pin, source: :chain)
129
- logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) - after processing #{link.desc}, new working_pin=#{working_pin} with binder #{working_pin.binder}" }
128
+ logger.debug do
129
+ "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) - after processing #{link.desc}, new working_pin=#{working_pin} with binder #{working_pin.binder}"
130
+ end
130
131
  end
131
132
  links.last.last_context = working_pin
132
133
  links.last.resolve(api_map, working_pin, locals)
@@ -138,7 +139,8 @@ module Solargraph
138
139
  # @return [ComplexType]
139
140
  # @sg-ignore
140
141
  def infer api_map, name_pin, locals
141
- cache_key = [node, node&.location, links, name_pin&.return_type, locals]
142
+ # includes binder as it is mutable in Pin::Block
143
+ cache_key = [node, node&.location, links, name_pin&.return_type, name_pin&.binder, locals]
142
144
  if @@inference_invalidation_key == api_map.hash
143
145
  cached = @@inference_cache[cache_key]
144
146
  return cached if cached
@@ -147,23 +149,31 @@ module Solargraph
147
149
  @@inference_cache = {}
148
150
  end
149
151
  out = infer_uncached(api_map, name_pin, locals).downcast_to_literal_if_possible
150
- logger.debug { "Chain#infer() - caching result - cache_key_hash=#{cache_key.hash}, links.map(&:hash)=#{links.map(&:hash)}, links=#{links}, cache_key.map(&:hash) = #{cache_key.map(&:hash)}, cache_key=#{cache_key}" }
152
+ logger.debug do
153
+ "Chain#infer() - caching result - cache_key_hash=#{cache_key.hash}, links.map(&:hash)=#{links.map(&:hash)}, links=#{links}, cache_key.map(&:hash) = #{cache_key.map(&:hash)}, cache_key=#{cache_key}"
154
+ end
151
155
  @@inference_cache[cache_key] = out
152
156
  end
153
157
 
154
158
  # @param api_map [ApiMap]
155
159
  # @param name_pin [Pin::Base]
156
160
  # @param locals [::Array<Pin::LocalVariable>]
157
- # @return [ComplexType]
161
+ # @return [ComplexType, ComplexType::UniqueType]
158
162
  def infer_uncached api_map, name_pin, locals
159
163
  pins = define(api_map, name_pin, locals)
160
164
  if pins.empty?
161
- logger.debug { "Chain#infer_uncached(links=#{links.map(&:desc)}, locals=#{locals.map(&:desc)}) => undefined - no pins" }
165
+ logger.debug do
166
+ "Chain#infer_uncached(links=#{links.map(&:desc)}, locals=#{locals.map(&:desc)}) => undefined - no pins"
167
+ end
162
168
  return ComplexType::UNDEFINED
163
169
  end
164
170
  type = infer_from_definitions(pins, links.last.last_context, api_map, locals)
165
- out = maybe_nil(type)
166
- logger.debug { "Chain#infer_uncached(links=#{self.links.map(&:desc)}, locals=#{locals.map(&:desc)}, name_pin=#{name_pin}, name_pin.closure=#{name_pin.closure.inspect}, name_pin.binder=#{name_pin.binder}) => #{out.rooted_tags.inspect}" }
171
+ out = maybe_nil(type, api_map)
172
+ logger.debug do
173
+ "Chain#infer_uncached(links=#{links.map(&:desc)}, locals=#{locals.map(&:desc)}, " \
174
+ "name_pin=#{name_pin}, name_pin.closure=#{name_pin&.closure&.inspect}, " \
175
+ "name_pin.binder=#{name_pin&.binder}) => #{out.rooted_tags.inspect}"
176
+ end
167
177
  out
168
178
  end
169
179
 
@@ -189,8 +199,38 @@ module Solargraph
189
199
  @splat
190
200
  end
191
201
 
192
- def nullable?
193
- links.any?(&:nullable?)
202
+ # Whether this chain's inferred type should have nil added to it
203
+ # because a `&.` earlier in the chain might have short-circuited
204
+ # evaluation to nil.
205
+ #
206
+ # A `&.` only makes the *immediate* call nil-or-normal-result; a
207
+ # later, non-safe-navigated call in the same chain is still
208
+ # invoked on whatever that produced. If receiver is nil at that
209
+ # point, Ruby calls the method on nil itself instead of skipping
210
+ # it - so nil only continues to flow through subsequent links
211
+ # that NilClass defines as returning `self` (e.g., #tap,
212
+ # #itself). Any other subsequent call resolves to a concrete,
213
+ # non-nil-including type (e.g. NilClass#== returns Boolean), and
214
+ # nil no longer needs to be tracked past that point (unless a
215
+ # later `&.` reintroduces it).
216
+ #
217
+ # @param api_map [ApiMap]
218
+ # @return [Boolean]
219
+ def nullable? api_map
220
+ currently_nullable = false
221
+ links.each do |link|
222
+ if link.nullable?
223
+ currently_nullable = true
224
+ next
225
+ end
226
+ next unless currently_nullable
227
+ next unless link.is_a?(Chain::Call)
228
+
229
+ pin = api_map.get_method_stack('NilClass', link.word, scope: :instance).first
230
+ # @sg-ignore Need to add nil check here
231
+ currently_nullable = pin.nil? || pin.return_type.tag == 'self'
232
+ end
233
+ currently_nullable
194
234
  end
195
235
 
196
236
  include Logging
@@ -209,12 +249,12 @@ module Solargraph
209
249
  private
210
250
 
211
251
  # @param pins [::Array<Pin::Base>]
212
- # @param context [Pin::Base]
252
+ # @param name_pin [Pin::Base]
213
253
  # @param api_map [ApiMap]
214
254
  # @param locals [::Enumerable<Pin::LocalVariable>]
215
- # @return [ComplexType]
216
- def infer_from_definitions pins, context, api_map, locals
217
- # @type [::Array<ComplexType>]
255
+ # @return [ComplexType, ComplexType::UniqueType]
256
+ def infer_from_definitions pins, name_pin, api_map, locals
257
+ # @type [::Array<ComplexType, ComplexType::UniqueType>]
218
258
  types = []
219
259
  unresolved_pins = []
220
260
  # @todo this param tag shouldn't be needed to probe the type
@@ -232,7 +272,8 @@ module Solargraph
232
272
  # @todo even at strong, no typechecking complaint
233
273
  # happens when a [Pin::Base,nil] is passed into a method
234
274
  # that accepts only [Pin::Namespace] as an argument
235
- type = type.resolve_generics(pin.closure, context.binder)
275
+ # @sg-ignore Need to add nil check here
276
+ type = type.resolve_generics(pin.closure, name_pin.binder)
236
277
  end
237
278
  types << type
238
279
  else
@@ -241,17 +282,13 @@ module Solargraph
241
282
  end
242
283
 
243
284
  # Limit method inference recursion
244
- if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
245
- return ComplexType::UNDEFINED
246
- end
285
+ return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
247
286
 
248
287
  @@inference_depth += 1
249
288
  # @param pin [Pin::Base]
250
289
  unresolved_pins.each do |pin|
251
290
  # Avoid infinite recursion
252
- if @@inference_stack.include?(pin.identity)
253
- next
254
- end
291
+ next if @@inference_stack.include?(pin.identity)
255
292
 
256
293
  @@inference_stack.push(pin.identity)
257
294
  type = pin.probe(api_map)
@@ -271,21 +308,28 @@ module Solargraph
271
308
  else
272
309
  ComplexType.new(types)
273
310
  end
274
- if context.nil? || context.return_type.undefined?
311
+ if name_pin.nil? || name_pin.context.undefined?
275
312
  # up to downstream to resolve self type
276
313
  return type
277
314
  end
278
-
279
- type.self_to_type(context.return_type)
315
+ type.self_to_type(name_pin.context)
280
316
  end
281
317
 
282
- # @param type [ComplexType]
283
- # @return [ComplexType]
284
- def maybe_nil type
318
+ # @param type [ComplexType, ComplexType::UniqueType]
319
+ # @param api_map [ApiMap]
320
+ # @return [ComplexType, ComplexType::UniqueType]
321
+ def maybe_nil type, api_map
285
322
  return type if type.undefined? || type.void? || type.nullable?
286
- return type unless nullable?
323
+ return type unless nullable?(api_map)
287
324
  ComplexType.new(type.items + [ComplexType::NIL])
288
325
  end
326
+
327
+ protected
328
+
329
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
330
+ def equality_fields
331
+ [links, node]
332
+ end
289
333
  end
290
334
  end
291
335
  end
@@ -7,13 +7,13 @@ module Solargraph
7
7
  class Change
8
8
  include EncodingFixes
9
9
 
10
- # @return [Range]
10
+ # @return [Range, nil]
11
11
  attr_reader :range
12
12
 
13
13
  # @return [String]
14
14
  attr_reader :new_text
15
15
 
16
- # @param range [Range] The starting and ending positions of the change.
16
+ # @param range [Range, nil] The starting and ending positions of the change.
17
17
  # If nil, the original text will be overwritten.
18
18
  # @param new_text [String] The text to be changed.
19
19
  def initialize range, new_text
@@ -28,12 +28,14 @@ module Solargraph
28
28
  # syntax errors will be repaired.
29
29
  # @return [String] The updated text.
30
30
  def write text, nullable = false
31
- if nullable and !range.nil? and new_text.match(/[.\[{(@$:]$/)
31
+ if nullable && !range.nil? && new_text.match(/[.\[{(@$:]$/)
32
32
  [':', '@'].each do |dupable|
33
33
  next unless new_text == dupable
34
+ # @sg-ignore flow sensitive typing needs to handle attrs
34
35
  offset = Position.to_offset(text, range.start)
35
36
  if text[offset - 1] == dupable
36
37
  p = Position.from_offset(text, offset - 1)
38
+ # @sg-ignore flow sensitive typing needs to handle attrs
37
39
  r = Change.new(Range.new(p, range.start), ' ')
38
40
  text = r.write(text)
39
41
  end
@@ -58,10 +60,13 @@ module Solargraph
58
60
  fixed
59
61
  else
60
62
  result = commit text, fixed
63
+ # @sg-ignore flow sensitive typing needs to handle attrs
61
64
  off = Position.to_offset(text, range.start)
65
+ # @sg-ignore Need to add nil check here
62
66
  match = result[0, off].match(/[.:]+\z/)
63
67
  if match
64
- result = result[0, off].sub(/#{match[0]}\z/, ' ' * match[0].length) + result[off..-1]
68
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
69
+ result = result[0, off].sub(/#{match[0]}\z/, ' ' * match[0].length) + result[off..]
65
70
  end
66
71
  result
67
72
  end
@@ -73,9 +78,11 @@ module Solargraph
73
78
  # @param insert [String]
74
79
  # @return [String]
75
80
  def commit text, insert
81
+ # @sg-ignore Need to add nil check here
76
82
  start_offset = Position.to_offset(text, range.start)
83
+ # @sg-ignore Need to add nil check here
77
84
  end_offset = Position.to_offset(text, range.ending)
78
- (start_offset == 0 ? '' : text[0..start_offset-1].to_s) + normalize(insert) + text[end_offset..-1].to_s
85
+ (start_offset.zero? ? '' : text[0..(start_offset - 1)].to_s) + normalize(insert) + text[end_offset..].to_s
79
86
  end
80
87
  end
81
88
  end
@@ -19,7 +19,7 @@ module Solargraph
19
19
  @position = Position.normalize(position)
20
20
  end
21
21
 
22
- # @return [String]
22
+ # @return [String, nil]
23
23
  def filename
24
24
  source.filename
25
25
  end
@@ -35,13 +35,17 @@ module Solargraph
35
35
  # The part of the word before the current position. Given the text
36
36
  # `foo.bar`, the start_of_word at position(0, 6) is `ba`.
37
37
  #
38
+ # @sg-ignore Need to add nil check here
38
39
  # @return [String]
39
40
  def start_of_word
40
41
  @start_of_word ||= begin
41
- match = source.code[0..offset-1].to_s.match(start_word_pattern)
42
+ match = source.code[0..(offset - 1)].to_s.match(start_word_pattern)
42
43
  result = (match ? match[0] : '')
43
44
  # Including the preceding colon if the word appears to be a symbol
44
- result = ":#{result}" if source.code[0..offset-result.length-1].end_with?(':') and !source.code[0..offset-result.length-1].end_with?('::')
45
+ # @sg-ignore Need to add nil check here
46
+ if source.code[0..(offset - result.length - 1)].end_with?(':') && !source.code[0..(offset - result.length - 1)].end_with?('::')
47
+ result = ":#{result}"
48
+ end
45
49
  result
46
50
  end
47
51
  end
@@ -50,16 +54,17 @@ module Solargraph
50
54
  # `foo.bar`, the end_of_word at position (0,6) is `r`.
51
55
  #
52
56
  # @return [String]
57
+ # @sg-ignore Need to add nil check here
53
58
  def end_of_word
54
59
  @end_of_word ||= begin
55
- match = source.code[offset..-1].to_s.match(end_word_pattern)
60
+ match = source.code[offset..].to_s.match(end_word_pattern)
56
61
  match ? match[0] : ''
57
62
  end
58
63
  end
59
64
 
60
65
  # @return [Boolean]
61
66
  def start_of_constant?
62
- source.code[offset-2, 2] == '::'
67
+ source.code[offset - 2, 2] == '::'
63
68
  end
64
69
 
65
70
  # The range of the word at the current position.
@@ -110,7 +115,17 @@ module Solargraph
110
115
  def recipient
111
116
  @recipient ||= begin
112
117
  node = recipient_node
113
- node ? Cursor.new(source, Range.from_node(node).ending) : nil
118
+ if node.nil?
119
+ nil
120
+ else
121
+ rng = Range.from_node(node)
122
+ if rng
123
+ Cursor.new(source, rng.ending)
124
+ else
125
+ pos = Position.new(position.line, [position.column - 1, 0].max)
126
+ Cursor.new(source, pos)
127
+ end
128
+ end
114
129
  end
115
130
  end
116
131
  alias receiver recipient
@@ -122,18 +137,18 @@ module Solargraph
122
137
 
123
138
  # @return [Position]
124
139
  def node_position
125
- @node_position ||= begin
126
- if start_of_word.empty?
127
- match = source.code[0, offset].match(/\s*(\.|:+)\s*$/)
128
- if match
129
- Position.from_offset(source.code, offset - match[0].length)
130
- else
131
- position
132
- end
133
- else
134
- position
135
- end
136
- end
140
+ @node_position ||= if start_of_word.empty?
141
+ # @sg-ignore Need to add nil check here
142
+ match = source.code[0, offset].match(/\s*(\.|:+)\s*$/)
143
+ if match
144
+ # @sg-ignore Need to add nil check here
145
+ Position.from_offset(source.code, offset - match[0].length)
146
+ else
147
+ position
148
+ end
149
+ else
150
+ position
151
+ end
137
152
  end
138
153
 
139
154
  # @return [Parser::AST::Node, nil]
@@ -10,13 +10,12 @@ module Solargraph
10
10
  # @param string [String]
11
11
  # @return [String]
12
12
  def normalize string
13
- begin
14
- string.dup.force_encoding('UTF-8')
15
- rescue ::Encoding::CompatibilityError, ::Encoding::UndefinedConversionError, ::Encoding::InvalidByteSequenceError => e
16
- # @todo Improve error handling
17
- Solargraph::Logging.logger.warn "Normalize error: #{e.message}"
18
- string
19
- end
13
+ string.dup.force_encoding('UTF-8')
14
+ rescue ::Encoding::CompatibilityError, ::Encoding::UndefinedConversionError,
15
+ ::Encoding::InvalidByteSequenceError => e
16
+ # @todo Improve error handling
17
+ Solargraph::Logging.logger.warn "Normalize error: #{e.message}"
18
+ string
20
19
  end
21
20
  end
22
21
  end