solargraph 0.58.3 → 0.60.3

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 +54 -34
  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 +57 -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 +177 -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 +64 -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 +203 -111
  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 +92 -120
  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 +51 -38
  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 +31 -8
  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
@@ -5,11 +5,10 @@ module Solargraph
5
5
  #
6
6
  class TypeChecker
7
7
  autoload :Problem, 'solargraph/type_checker/problem'
8
- autoload :ParamDef, 'solargraph/type_checker/param_def'
9
8
  autoload :Rules, 'solargraph/type_checker/rules'
10
- autoload :Checks, 'solargraph/type_checker/checks'
11
9
 
12
- include Checks
10
+ # @!parse
11
+ # include Solargraph::Parser::ParserGem::NodeMethods
13
12
  include Parser::NodeMethods
14
13
 
15
14
  # @return [String]
@@ -26,8 +25,6 @@ module Solargraph
26
25
  # @param level [Symbol] Don't complain about anything above this level
27
26
  # @param workspace [Workspace, nil] Workspace to use for loading
28
27
  # type checker rules modified by user config
29
- # @param type_checker_rules [Hash{Symbol => Symbol}] Overrides for
30
- # type checker rules - e.g., :report_undefined => :strong
31
28
  # @param rules [Rules] Type checker rules object
32
29
  def initialize filename,
33
30
  api_map: nil,
@@ -36,7 +33,8 @@ module Solargraph
36
33
  rules: workspace ? workspace.rules(level) : Rules.new(level, {})
37
34
  @filename = filename
38
35
  # @todo Smarter directory resolution
39
- @api_map = api_map || Solargraph::ApiMap.load(File.dirname(filename))
36
+ @api_map = api_map || Solargraph::ApiMap.load(File.dirname(filename),
37
+ loose_unions: !rules.require_all_unique_types_support_call?)
40
38
  @rules = rules
41
39
  # @type [Array<Range>]
42
40
  @marked_ranges = []
@@ -49,18 +47,51 @@ module Solargraph
49
47
 
50
48
  # @return [Source]
51
49
  def source
52
- @source_map.source
50
+ source_map.source
51
+ end
52
+
53
+ # @param inferred [ComplexType, ComplexType::UniqueType]
54
+ # @param expected [ComplexType, ComplexType::UniqueType]
55
+ def return_type_conforms_to? inferred, expected
56
+ conforms_to?(inferred, expected, :return_type)
57
+ end
58
+
59
+ # @param inferred [ComplexType, ComplexType::UniqueType]
60
+ # @param expected [ComplexType, ComplexType::UniqueType]
61
+ def arg_conforms_to? inferred, expected
62
+ conforms_to?(inferred, expected, :method_call)
63
+ end
64
+
65
+ # @param inferred [ComplexType, ComplexType::UniqueType]
66
+ # @param expected [ComplexType, ComplexType::UniqueType]
67
+ def assignment_conforms_to? inferred, expected
68
+ conforms_to?(inferred, expected, :assignment)
69
+ end
70
+
71
+ # @param inferred [ComplexType, ComplexType::UniqueType]
72
+ # @param expected [ComplexType, ComplexType::UniqueType]
73
+ # @param scenario [Symbol]
74
+ def conforms_to? inferred, expected, scenario
75
+ rules_arr = []
76
+ rules_arr << :allow_empty_params unless rules.require_inferred_type_params?
77
+ rules_arr << :allow_any_match unless rules.require_all_unique_types_match_expected?
78
+ rules_arr << :allow_undefined unless rules.require_no_undefined_args?
79
+ rules_arr << :allow_unresolved_generic unless rules.require_generics_resolved?
80
+ rules_arr << :allow_unmatched_interface unless rules.require_interfaces_resolved?
81
+ rules_arr << :allow_reverse_match unless rules.require_downcasts?
82
+ inferred.conforms_to?(api_map, expected, scenario,
83
+ rules_arr)
53
84
  end
54
85
 
55
86
  # @return [Array<Problem>]
56
87
  def problems
57
88
  @problems ||= begin
58
- all = method_tag_problems
59
- .concat(variable_type_tag_problems)
60
- .concat(const_problems)
61
- .concat(call_problems)
62
- unignored = without_ignored(all)
63
- unignored.concat(unneeded_sgignore_problems)
89
+ all = method_tag_problems
90
+ .concat(variable_type_tag_problems)
91
+ .concat(const_problems)
92
+ .concat(call_problems)
93
+ unignored = without_ignored(all)
94
+ unignored.concat(unneeded_sgignore_problems)
64
95
  end
65
96
  end
66
97
 
@@ -70,20 +101,26 @@ module Solargraph
70
101
  # @return [self]
71
102
  def load filename, level = :normal
72
103
  source = Solargraph::Source.load(filename)
73
- api_map = Solargraph::ApiMap.new
104
+ rules = Rules.new(level, {})
105
+ api_map = Solargraph::ApiMap.new(loose_unions:
106
+ !rules.require_all_unique_types_support_call?)
74
107
  api_map.map(source)
75
- new(filename, api_map: api_map, level: level)
108
+ new(filename, api_map: api_map, level: level, rules: rules)
76
109
  end
77
110
 
78
111
  # @param code [String]
79
112
  # @param filename [String, nil]
80
113
  # @param level [Symbol]
114
+ # @param api_map [Solargraph::ApiMap, nil]
81
115
  # @return [self]
82
- def load_string code, filename = nil, level = :normal
116
+ def load_string code, filename = nil, level = :normal, api_map: nil
83
117
  source = Solargraph::Source.load_string(code, filename)
84
- api_map = Solargraph::ApiMap.new
118
+ rules = Rules.new(level, {})
119
+ api_map ||= Solargraph::ApiMap.new(loose_unions:
120
+ !rules.require_all_unique_types_support_call?)
121
+ # @sg-ignore flow sensitive typing needs better handling of ||= on lvars
85
122
  api_map.map(source)
86
- new(filename, api_map: api_map, level: level)
123
+ new(filename, api_map: api_map, level: level, rules: rules)
87
124
  end
88
125
  end
89
126
 
@@ -107,28 +144,43 @@ module Solargraph
107
144
  result = []
108
145
  declared = pin.typify(api_map).self_to_type(pin.full_context).qualify(api_map, *pin.gates)
109
146
  if declared.undefined?
147
+ # @sg-ignore Need to add nil check here
110
148
  if pin.return_type.undefined? && rules.require_type_tags?
111
149
  if pin.attribute?
112
150
  inferred = pin.probe(api_map).self_to_type(pin.full_context)
113
- result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin) unless inferred.defined?
151
+ unless inferred.defined?
152
+ result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}",
153
+ pin: pin)
154
+ end
114
155
  else
115
156
  result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
116
157
  end
158
+ # @sg-ignore Need to add nil check here
117
159
  elsif pin.return_type.defined? && !resolved_constant?(pin)
118
160
  result.push Problem.new(pin.location, "Unresolved return type #{pin.return_type} for #{pin.path}", pin: pin)
119
161
  elsif rules.must_tag_or_infer? && pin.probe(api_map).undefined?
120
162
  result.push Problem.new(pin.location, "Untyped method #{pin.path} could not be inferred")
121
163
  end
122
164
  elsif rules.validate_tags?
123
- unless pin.node.nil? || declared.void? || virtual_pin?(pin) || abstract?(pin)
165
+ # Attribute pins never have a node (attr_reader/attr_writer/attr_accessor are
166
+ # synthesized, not parsed method bodies), but their inferred type is still
167
+ # meaningful: #probe walks the backing ivar's assignments via infer_from_iv.
168
+ # Without this carve-out, a manually-written @return tag on an attribute is
169
+ # never cross-checked against how the ivar is actually assigned (e.g. a nilable
170
+ # default in the constructor), so a bad tag silently passes at every level.
171
+ unless (pin.node.nil? && !pin.attribute?) || declared.void? || virtual_pin?(pin) || abstract?(pin)
124
172
  inferred = pin.probe(api_map).self_to_type(pin.full_context)
125
173
  if inferred.undefined?
126
- unless rules.ignore_all_undefined? || external?(pin)
174
+ # An attribute with no locally-discoverable ivar assignment (set via a
175
+ # mixin, metaprogramming, etc.) isn't a tag/inference mismatch - just
176
+ # unproven. Only methods with an actual body get flagged for this.
177
+ unless rules.ignore_all_undefined? || external?(pin) || pin.attribute?
127
178
  result.push Problem.new(pin.location, "#{pin.path} return type could not be inferred", pin: pin)
128
179
  end
129
180
  else
130
- unless (rules.require_all_return_types_match_inferred? ? all_types_match?(api_map, inferred, declared) : any_types_match?(api_map, declared, inferred))
131
- result.push Problem.new(pin.location, "Declared return type #{declared.rooted_tags} does not match inferred type #{inferred.rooted_tags} for #{pin.path}", pin: pin)
181
+ unless return_type_conforms_to?(inferred, declared)
182
+ result.push Problem.new(pin.location,
183
+ "Declared return type #{declared.rooted_tags} does not match inferred type #{inferred.rooted_tags} for #{pin.path}", pin: pin)
132
184
  end
133
185
  end
134
186
  end
@@ -144,7 +196,7 @@ module Solargraph
144
196
  def resolved_constant? pin
145
197
  return true if pin.typify(api_map).defined?
146
198
  constant_pins = api_map.get_constants('', *pin.closure.gates)
147
- .select { |p| p.name == pin.return_type.namespace }
199
+ .select { |p| p.name == pin.return_type.namespace }
148
200
  return true if constant_pins.find { |p| p.typify(api_map).defined? }
149
201
  # will need to probe when a constant name is assigned to a
150
202
  # class/module (alias)
@@ -154,6 +206,7 @@ module Solargraph
154
206
 
155
207
  # @param pin [Pin::Base]
156
208
  def virtual_pin? pin
209
+ # @sg-ignore Need to add nil check here
157
210
  pin.location && source.comment_at?(pin.location.range.ending)
158
211
  end
159
212
 
@@ -165,19 +218,19 @@ module Solargraph
165
218
  pin.signatures.each do |sig|
166
219
  params = param_details_from_stack(sig, stack)
167
220
  if rules.require_type_tags?
168
- sig.parameters.each do |par|
169
- break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
170
- unless params[par.name]
171
- if pin.attribute?
172
- inferred = pin.probe(api_map).self_to_type(pin.full_context)
173
- if inferred.undefined?
174
- result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
175
- end
176
- else
221
+ sig.parameters.each do |par|
222
+ break if %i[restarg kwrestarg blockarg].include?(par.decl)
223
+ unless params[par.name]
224
+ if pin.attribute?
225
+ inferred = pin.probe(api_map).self_to_type(pin.full_context)
226
+ if inferred.undefined?
177
227
  result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
178
228
  end
229
+ else
230
+ result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
179
231
  end
180
232
  end
233
+ end
181
234
  end
182
235
  # @param name [String]
183
236
  # @param data [Hash{Symbol => BasicObject}]
@@ -185,7 +238,8 @@ module Solargraph
185
238
  # @type [ComplexType]
186
239
  type = data[:qualified]
187
240
  if type.undefined?
188
- result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
241
+ result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}",
242
+ pin: pin)
189
243
  end
190
244
  end
191
245
  end
@@ -201,6 +255,7 @@ module Solargraph
201
255
  def variable_type_tag_problems
202
256
  result = []
203
257
  all_variables.each do |pin|
258
+ # @sg-ignore Need to add nil check here
204
259
  if pin.return_type.defined?
205
260
  declared = pin.typify(api_map)
206
261
  next if declared.duck_type?
@@ -215,21 +270,21 @@ module Solargraph
215
270
  result.push Problem.new(pin.location, "Variable type could not be inferred for #{pin.name}", pin: pin)
216
271
  end
217
272
  else
218
- unless any_types_match?(api_map, declared, inferred)
219
- result.push Problem.new(pin.location, "Declared type #{declared} does not match inferred type #{inferred} for variable #{pin.name}", pin: pin)
273
+ unless assignment_conforms_to?(inferred, declared)
274
+ result.push Problem.new(pin.location,
275
+ "Declared type #{declared} does not match inferred type #{inferred} for variable #{pin.name}", pin: pin)
220
276
  end
221
277
  end
222
278
  elsif declared_externally?(pin)
223
279
  ignored_pins.push pin
224
280
  end
225
281
  elsif !pin.is_a?(Pin::Parameter) && !resolved_constant?(pin)
226
- result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}", pin: pin)
282
+ result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}",
283
+ pin: pin)
227
284
  end
228
285
  elsif pin.assignment
229
286
  inferred = pin.probe(api_map)
230
- if inferred.undefined? && declared_externally?(pin)
231
- ignored_pins.push pin
232
- end
287
+ ignored_pins.push pin if inferred.undefined? && declared_externally?(pin)
233
288
  end
234
289
  end
235
290
  result
@@ -237,7 +292,7 @@ module Solargraph
237
292
 
238
293
  # @return [Array<Pin::BaseVariable>]
239
294
  def all_variables
240
- source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.select { |pin| pin.is_a?(Pin::LocalVariable) }
295
+ source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.grep(Pin::LocalVariable)
241
296
  end
242
297
 
243
298
  # @return [Array<Problem>]
@@ -247,8 +302,10 @@ module Solargraph
247
302
  Solargraph::Parser::NodeMethods.const_nodes_from(source.node).each do |const|
248
303
  rng = Solargraph::Range.from_node(const)
249
304
  chain = Solargraph::Parser.chain(const, filename)
305
+ # @sg-ignore Need to add nil check here
250
306
  closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
251
307
  closure_pin.rebind(api_map)
308
+ # @sg-ignore Need to add nil check here
252
309
  location = Location.new(filename, rng)
253
310
  locals = source_map.locals_at(location)
254
311
  pins = chain.define(api_map, closure_pin, locals)
@@ -265,44 +322,54 @@ module Solargraph
265
322
  result = []
266
323
  Solargraph::Parser::NodeMethods.call_nodes_from(source.node).each do |call|
267
324
  rng = Solargraph::Range.from_node(call)
325
+ # @sg-ignore Need to add nil check here
268
326
  next if @marked_ranges.any? { |d| d.contain?(rng.start) }
269
327
  chain = Solargraph::Parser.chain(call, filename)
328
+ # @sg-ignore Need to add nil check here
270
329
  closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
271
- namespace_pin = closure_pin
272
330
  if call.type == :block
273
331
  # blocks in the AST include the method call as well, so the
274
332
  # node returned by #call_nodes_from needs to be backed out
275
333
  # one closure
334
+ # @todo Need to add nil check here
335
+ # @todo Should warn on nil deference here
276
336
  closure_pin = closure_pin.closure
277
337
  end
338
+ # @sg-ignore Need to add nil check here
278
339
  closure_pin.rebind(api_map)
340
+ # @sg-ignore Need to add nil check here
279
341
  location = Location.new(filename, rng)
280
342
  locals = source_map.locals_at(location)
343
+ # @sg-ignore Need to add nil check here
281
344
  type = chain.infer(api_map, closure_pin, locals)
282
345
  if type.undefined? && !rules.ignore_all_undefined?
283
346
  base = chain
284
347
  missing = chain
348
+ # @type [Solargraph::Pin::Base, nil]
285
349
  found = nil
286
- closest = ComplexType::UNDEFINED
350
+ # @type [Array<Solargraph::Pin::Base>]
351
+ all_found = []
287
352
  until base.links.first.undefined?
288
- found = base.define(api_map, closure_pin, locals).first
353
+ # @sg-ignore Need to add nil check here
354
+ all_found = base.define(api_map, closure_pin, locals)
355
+ found = all_found.first
289
356
  break if found
290
357
  missing = base
291
358
  base = base.base
292
359
  end
293
- closest = found.typify(api_map) if found
360
+ all_closest = all_found.map { |pin| pin.typify(api_map) }
361
+ closest = ComplexType.new(all_closest.flat_map(&:items).uniq)
294
362
  # @todo remove the internal_or_core? check at a higher-than-strict level
295
- if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
296
- unless closest.generic? || ignored_pins.include?(found)
297
- if closest.defined?
298
- result.push Problem.new(location, "Unresolved call to #{missing.links.last.word} on #{closest}")
299
- else
300
- result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
301
- end
302
- @marked_ranges.push rng
363
+ if (!found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))) && !(closest.generic? || ignored_pins.include?(found))
364
+ if closest.defined?
365
+ result.push Problem.new(location, "Unresolved call to #{missing.links.last.word} on #{closest}")
366
+ else
367
+ result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
303
368
  end
369
+ @marked_ranges.push rng
304
370
  end
305
371
  end
372
+ # @sg-ignore Need to add nil check here
306
373
  result.concat argument_problems_for(chain, api_map, closure_pin, locals, location)
307
374
  end
308
375
  result
@@ -311,13 +378,12 @@ module Solargraph
311
378
  # @param chain [Solargraph::Source::Chain]
312
379
  # @param api_map [Solargraph::ApiMap]
313
380
  # @param closure_pin [Solargraph::Pin::Closure]
314
- # @param locals [Array<Solargraph::Pin::Base>]
381
+ # @param locals [Array<Solargraph::Pin::LocalVariable>]
315
382
  # @param location [Solargraph::Location]
316
383
  # @return [Array<Problem>]
317
384
  def argument_problems_for chain, api_map, closure_pin, locals, location
318
385
  result = []
319
386
  base = chain
320
- # @type last_base_link [Solargraph::Source::Chain::Call]
321
387
  last_base_link = base.links.last
322
388
  return [] unless last_base_link.is_a?(Solargraph::Source::Chain::Call)
323
389
 
@@ -340,6 +406,8 @@ module Solargraph
340
406
  base.base.infer(api_map, closure_pin, locals).namespace
341
407
  end
342
408
  init = api_map.get_method_stack(fqns, 'initialize').first
409
+
410
+ # @type [::Array<Solargraph::TypeChecker::Problem>]
343
411
  init ? arity_problems_for(init, arguments, location) : []
344
412
  else
345
413
  arity_problems_for(pin, arguments, location)
@@ -348,7 +416,7 @@ module Solargraph
348
416
  return [] if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
349
417
 
350
418
  all_errors = []
351
- pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
419
+ pin.signatures.sort_by { |sig| sig.parameters.length }.each do |sig|
352
420
  params = param_details_from_stack(sig, pins)
353
421
 
354
422
  signature_errors = signature_argument_problems_for location, locals, closure_pin, params, arguments, sig, pin
@@ -368,11 +436,10 @@ module Solargraph
368
436
  # @param location [Location]
369
437
  # @param locals [Array<Pin::LocalVariable>]
370
438
  # @param closure_pin [Pin::Closure]
371
- # @param params [Hash{String => Hash{Symbol => String, Solargraph::ComplexType}}]
439
+ # @param params [Hash{String => undefined}]
372
440
  # @param arguments [Array<Source::Chain>]
373
441
  # @param sig [Pin::Signature]
374
442
  # @param pin [Pin::Method]
375
- # @param pins [Array<Pin::Method>]
376
443
  #
377
444
  # @return [Array<Problem>]
378
445
  def signature_argument_problems_for location, locals, closure_pin, params, arguments, sig, pin
@@ -382,31 +449,25 @@ module Solargraph
382
449
  # when possible, and when not, ensure provably
383
450
  # incorrect situations are detected.
384
451
  sig.parameters.each_with_index do |par, idx|
385
- return errors if par.decl == :restarg # bail out and assume the rest is valid pending better arg processing
452
+ return errors if par.decl == :restarg # bail out and assume the rest is valid pending better arg processing
386
453
  argchain = arguments[idx]
387
454
  if argchain.nil?
455
+ final_arg = arguments.last
388
456
  if par.decl == :arg
389
- final_arg = arguments.last
390
457
  if final_arg && final_arg.node.type == :splat
391
458
  argchain = final_arg
392
459
  return errors
393
460
  else
394
461
  errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
395
462
  end
396
- else
397
- final_arg = arguments.last
398
- argchain = final_arg if final_arg && [:kwsplat, :hash].include?(final_arg.node.type)
463
+ elsif final_arg && %i[kwsplat hash].include?(final_arg.node.type)
464
+ argchain = final_arg
399
465
  end
400
466
  end
401
467
  if argchain
402
- if par.decl != :arg
403
- errors.concat kwarg_problems_for sig, argchain, api_map, closure_pin, locals, location, pin, params, idx
404
- next
405
- else
406
- if argchain.node.type == :splat && argchain == arguments.last
407
- final_arg = argchain
408
- end
409
- if (final_arg && final_arg.node.type == :splat)
468
+ if par.decl == :arg
469
+ final_arg = argchain if argchain.node.type == :splat && argchain == arguments.last
470
+ if final_arg && final_arg.node.type == :splat
410
471
  # The final argument given has been seen and was a
411
472
  # splat, which doesn't give us useful types or
412
473
  # arities against positional parameters, so let's
@@ -426,15 +487,19 @@ module Solargraph
426
487
  ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
427
488
  ptype = ptype.self_to_type(par.context)
428
489
  if ptype.nil?
429
- # @todo Some level (strong, I guess) should require the param here
490
+ # @todo Some level (strong, I guess) should require the param here
430
491
  else
431
492
  argtype = argchain.infer(api_map, closure_pin, locals)
432
493
  argtype = argtype.self_to_type(closure_pin.context)
433
- if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
434
- errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
494
+ if argtype.defined? && ptype.defined? && !arg_conforms_to?(argtype, ptype)
495
+ errors.push Problem.new(location,
496
+ "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
435
497
  return errors
436
498
  end
437
499
  end
500
+ else
501
+ errors.concat kwarg_problems_for sig, argchain, api_map, closure_pin, locals, location, pin, params, idx
502
+ next
438
503
  end
439
504
  elsif par.decl == :kwarg
440
505
  errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
@@ -445,13 +510,13 @@ module Solargraph
445
510
  end
446
511
 
447
512
  # @param sig [Pin::Signature]
448
- # @param argchain [Source::Chain]
513
+ # @param argchain [Solargraph::Source::Chain]
449
514
  # @param api_map [ApiMap]
450
515
  # @param closure_pin [Pin::Closure]
451
516
  # @param locals [Array<Pin::LocalVariable>]
452
517
  # @param location [Location]
453
518
  # @param pin [Pin::Method]
454
- # @param params [Hash{String => Hash{Symbol => String, Solargraph::ComplexType}}]
519
+ # @param params [Hash{String => Hash{Symbol => undefined}}]
455
520
  # @param idx [Integer]
456
521
  #
457
522
  # @return [Array<Problem>]
@@ -459,29 +524,30 @@ module Solargraph
459
524
  result = []
460
525
  kwargs = convert_hash(argchain.node)
461
526
  par = sig.parameters[idx]
527
+ # @type [Solargraph::Source::Chain]
462
528
  argchain = kwargs[par.name.to_sym]
463
529
  if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
464
530
  result.concat kwrestarg_problems_for(api_map, closure_pin, locals, location, pin, params, kwargs)
465
- else
466
- if argchain
467
- data = params[par.name]
468
- if data.nil?
469
- # @todo Some level (strong, I guess) should require the param here
470
- else
471
- ptype = data[:qualified]
472
- ptype = ptype.self_to_type(pin.context)
473
- unless ptype.undefined?
474
- # @sg-ignore https://github.com/castwide/solargraph/pull/1127
475
- argtype = argchain.infer(api_map, closure_pin, locals).self_to_type(closure_pin.context)
476
- # @sg-ignore Unresolved call to defined?
477
- if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
478
- result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
479
- end
531
+ elsif argchain
532
+ data = params[par.name]
533
+ if data.nil?
534
+ # @todo Some level (strong, I guess) should require the param here
535
+ else
536
+ # @type [ComplexType, ComplexType::UniqueType]
537
+ ptype = data[:qualified]
538
+ ptype = ptype.self_to_type(pin.context)
539
+ unless ptype.undefined?
540
+ # @type [ComplexType]
541
+ argtype = argchain.infer(api_map, closure_pin, locals).self_to_type(closure_pin.context)
542
+ # @todo Unresolved call to defined?
543
+ if argtype.defined? && ptype && !arg_conforms_to?(argtype, ptype)
544
+ result.push Problem.new(location,
545
+ "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
480
546
  end
481
547
  end
482
- elsif par.decl == :kwarg
483
- result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
484
548
  end
549
+ elsif par.decl == :kwarg
550
+ result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
485
551
  end
486
552
  result
487
553
  end
@@ -491,19 +557,22 @@ module Solargraph
491
557
  # @param locals [Array<Pin::LocalVariable>]
492
558
  # @param location [Location]
493
559
  # @param pin [Pin::Method]
494
- # @param params [Hash{String => [nil, Hash]}]
560
+ # @param params [Hash{String => nil, Hash}]
495
561
  # @param kwargs [Hash{Symbol => Source::Chain}]
496
562
  # @return [Array<Problem>]
497
- def kwrestarg_problems_for(api_map, closure_pin, locals, location, pin, params, kwargs)
563
+ def kwrestarg_problems_for api_map, closure_pin, locals, location, pin, params, kwargs
498
564
  result = []
499
565
  kwargs.each_pair do |pname, argchain|
500
566
  next unless params.key?(pname.to_s)
501
- ptype = params[pname.to_s][:qualified]
502
- ptype = ptype.self_to_type(pin.context)
567
+ # @sg-ignore
568
+ # @type [ComplexType]
569
+ raw_ptype = params[pname.to_s][:qualified]
570
+ ptype = raw_ptype.self_to_type(pin.context)
503
571
  argtype = argchain.infer(api_map, closure_pin, locals)
504
572
  argtype = argtype.self_to_type(closure_pin.context)
505
- if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
506
- result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{pname} expected #{ptype}, received #{argtype}")
573
+ if argtype.defined? && ptype && !arg_conforms_to?(argtype, ptype)
574
+ result.push Problem.new(location,
575
+ "Wrong argument type for #{pin.path}: #{pname} expected #{ptype}, received #{argtype}")
507
576
  end
508
577
  end
509
578
  result
@@ -513,7 +582,7 @@ module Solargraph
513
582
  # @param pin [Pin::Method, Pin::Signature]
514
583
  # @param relevant_pin [Pin::Method, Pin::Signature] the pin which is under inspection
515
584
  # @return [void]
516
- def add_restkwarg_param_tag_details(param_details, pin, relevant_pin)
585
+ def add_restkwarg_param_tag_details param_details, pin, relevant_pin
517
586
  # see if we have additional tags to pay attention to from YARD -
518
587
  # e.g., kwargs in a **restkwargs splat
519
588
  tags = pin.docstring.tags(:param)
@@ -534,7 +603,7 @@ module Solargraph
534
603
 
535
604
  # @param pin [Pin::Signature]
536
605
  # @return [Hash{String => Hash{Symbol => String, ComplexType}}]
537
- def signature_param_details(pin)
606
+ def signature_param_details pin
538
607
  # @type [Hash{String => Hash{Symbol => String, ComplexType}}]
539
608
  result = {}
540
609
  pin.parameters.each do |param|
@@ -553,6 +622,7 @@ module Solargraph
553
622
  next if tag.types.nil?
554
623
  result[tag.name.to_s] = {
555
624
  tagged: tag.types.join(', '),
625
+ # @sg-ignore need to add a nil check here
556
626
  qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, *pin.closure.gates)
557
627
  }
558
628
  end
@@ -567,7 +637,7 @@ module Solargraph
567
637
  # @param new_param_details [Hash{String => Hash{Symbol => String, ComplexType}}]
568
638
  #
569
639
  # @return [void]
570
- def add_to_param_details(param_details, param_names, new_param_details)
640
+ def add_to_param_details param_details, param_names, new_param_details
571
641
  new_param_details.each do |param_name, details|
572
642
  next unless param_names.include?(param_name)
573
643
 
@@ -580,7 +650,7 @@ module Solargraph
580
650
  # @param signature [Pin::Signature]
581
651
  # @param method_pin_stack [Array<Pin::Method>]
582
652
  # @return [Hash{String => Hash{Symbol => String, ComplexType}}]
583
- def param_details_from_stack(signature, method_pin_stack)
653
+ def param_details_from_stack signature, method_pin_stack
584
654
  signature_type = signature.typify(api_map)
585
655
  signature = signature.proxy signature_type
586
656
  param_details = signature_param_details(signature)
@@ -602,6 +672,7 @@ module Solargraph
602
672
  # @param pin [Pin::Base]
603
673
  def internal? pin
604
674
  return false if pin.nil?
675
+ # @sg-ignore flow sensitive typing needs to handle attrs
605
676
  pin.location && api_map.bundled?(pin.location.filename)
606
677
  end
607
678
 
@@ -619,29 +690,32 @@ module Solargraph
619
690
 
620
691
  # @param pin [Pin::BaseVariable]
621
692
  def declared_externally? pin
622
- raise "No assignment found" if pin.assignment.nil?
693
+ raise 'No assignment found' if pin.assignment.nil?
623
694
 
624
695
  chain = Solargraph::Parser.chain(pin.assignment, filename)
696
+ # @sg-ignore flow sensitive typing needs to handle attrs
625
697
  rng = Solargraph::Range.from_node(pin.assignment)
698
+ # @sg-ignore Need to add nil check here
626
699
  closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
700
+ # @sg-ignore flow sensitive typing needs to handle "if foo.nil?"
627
701
  location = Location.new(filename, Range.from_node(pin.assignment))
628
702
  locals = source_map.locals_at(location)
629
703
  type = chain.infer(api_map, closure_pin, locals)
630
704
  if type.undefined? && !rules.ignore_all_undefined?
631
705
  base = chain
632
- missing = chain
706
+ # @type [Solargraph::Pin::Base, nil]
633
707
  found = nil
634
- closest = ComplexType::UNDEFINED
708
+ # @type [Array<Solargraph::Pin::Base>]
709
+ all_found = []
635
710
  until base.links.first.undefined?
636
- found = base.define(api_map, closure_pin, locals).first
711
+ all_found = base.define(api_map, closure_pin, locals)
712
+ found = all_found.first
637
713
  break if found
638
- missing = base
639
714
  base = base.base
640
715
  end
641
- closest = found.typify(api_map) if found
642
- if !found || closest.defined? || internal?(found)
643
- return false
644
- end
716
+ all_closest = all_found.map { |pin| pin.typify(api_map) }
717
+ closest = ComplexType.new(all_closest.flat_map(&:items).uniq)
718
+ return false if !found || closest.defined? || internal?(found)
645
719
  end
646
720
  true
647
721
  end
@@ -664,7 +738,7 @@ module Solargraph
664
738
  # @param arguments [Array<Source::Chain>]
665
739
  # @param location [Location]
666
740
  # @return [Array<Problem>]
667
- def parameterized_arity_problems_for(pin, parameters, arguments, location)
741
+ def parameterized_arity_problems_for pin, parameters, arguments, location
668
742
  return [] unless pin.explicit?
669
743
  return [] if parameters.empty? && arguments.empty?
670
744
  return [] if pin.anon_splat?
@@ -679,7 +753,7 @@ module Solargraph
679
753
  settled_kwargs = parameters.count(&:keyword?)
680
754
  else
681
755
  kwargs = convert_hash(unchecked.last.node)
682
- if parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
756
+ if parameters.any? { |param| %i[kwarg kwoptarg].include?(param.decl) || param.kwrestarg? }
683
757
  if kwargs.empty?
684
758
  add_params += 1
685
759
  else
@@ -708,10 +782,12 @@ module Solargraph
708
782
  return [] if parameters.any?(&:rest?)
709
783
  opt = optional_param_count(parameters)
710
784
  return [] if unchecked.length <= req + opt
711
- if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
785
+ if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && parameters.map(&:decl).intersect?(%i[
786
+ kwarg kwoptarg kwrestarg
787
+ ])
712
788
  return []
713
789
  end
714
- return [] if arguments.length - req == parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
790
+ return [] if arguments.length - req == parameters.select { |p| %i[optarg kwoptarg].include?(p.decl) }.length
715
791
  return [Problem.new(location, "Too many arguments to #{pin.path}")]
716
792
  elsif unchecked.length < req - settled_kwargs && (arguments.empty? || (!arguments.last.splat? && !arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash)))
717
793
  # HACK: Kernel#raise signature is incorrect in Ruby 2.7 core docs.
@@ -727,42 +803,48 @@ module Solargraph
727
803
  # @todo need to use generic types in method to choose correct
728
804
  # signature and generate Integer as return type
729
805
  # @return [Integer]
730
- def required_param_count(parameters)
806
+ def required_param_count parameters
731
807
  parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
732
808
  end
733
809
 
734
810
  # @param parameters [Enumerable<Pin::Parameter>]
735
- # @param pin [Pin::Method]
811
+ #
736
812
  # @return [Integer]
737
- def optional_param_count(parameters)
813
+ def optional_param_count parameters
738
814
  parameters.select { |p| p.decl == :optarg }.length
739
815
  end
740
816
 
741
817
  # @param pin [Pin::Method]
742
818
  def abstract? pin
743
819
  pin.docstring.has_tag?('abstract') ||
744
- (pin.closure && pin.closure.docstring.has_tag?('abstract'))
820
+ pin.closure&.docstring&.has_tag?('abstract')
745
821
  end
746
822
 
747
823
  # @param pin [Pin::Method]
748
824
  # @return [Array<Source::Chain>]
749
- def fake_args_for(pin)
825
+ def fake_args_for pin
750
826
  args = []
751
827
  with_opts = false
752
828
  with_block = false
829
+ # @param pin [Pin::Parameter]
753
830
  pin.parameters.each do |pin|
754
- if [:kwarg, :kwoptarg, :kwrestarg].include?(pin.decl)
831
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
832
+ if %i[kwarg kwoptarg kwrestarg].include?(pin.decl)
755
833
  with_opts = true
834
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
756
835
  elsif pin.decl == :block
757
836
  with_block = true
837
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
758
838
  elsif pin.decl == :restarg
759
839
  args.push Solargraph::Source::Chain.new([Solargraph::Source::Chain::Variable.new(pin.name)], nil, true)
760
840
  else
761
841
  args.push Solargraph::Source::Chain.new([Solargraph::Source::Chain::Variable.new(pin.name)])
762
842
  end
763
843
  end
764
- args.push Solargraph::Parser.chain_string('{}') if with_opts
765
- args.push Solargraph::Parser.chain_string('&') if with_block
844
+ pin_location = pin.location
845
+ starting_line = pin_location ? pin_location.range.start.line : 0
846
+ args.push Solargraph::Parser.chain_string('{}', filename, starting_line) if with_opts
847
+ args.push Solargraph::Parser.chain_string('&', filename, starting_line) if with_block
766
848
  args
767
849
  end
768
850
 
@@ -774,7 +856,8 @@ module Solargraph
774
856
  # @return [Set<Integer>]
775
857
  def all_sg_ignore_lines
776
858
  source.associated_comments.select do |_line, text|
777
- text.include?('@sg-ignore')
859
+ # @sg-ignore Need to add nil check here
860
+ text.any? { |t| t.include?('@sg-ignore') }
778
861
  end.keys.to_set
779
862
  end
780
863