solargraph 0.54.4 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +125 -0
  3. data/.github/workflows/plugins.yml +149 -5
  4. data/.github/workflows/rspec.yml +39 -4
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +2627 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +104 -0
  13. data/README.md +20 -6
  14. data/Rakefile +125 -13
  15. data/lib/solargraph/api_map/cache.rb +3 -2
  16. data/lib/solargraph/api_map/constants.rb +218 -0
  17. data/lib/solargraph/api_map/index.rb +44 -42
  18. data/lib/solargraph/api_map/source_to_yard.rb +10 -4
  19. data/lib/solargraph/api_map/store.rb +165 -32
  20. data/lib/solargraph/api_map.rb +319 -243
  21. data/lib/solargraph/bench.rb +18 -1
  22. data/lib/solargraph/complex_type/type_methods.rb +7 -1
  23. data/lib/solargraph/complex_type/unique_type.rb +105 -16
  24. data/lib/solargraph/complex_type.rb +40 -7
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  26. data/lib/solargraph/convention/base.rb +20 -3
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  29. data/lib/solargraph/convention/data_definition.rb +105 -0
  30. data/lib/solargraph/convention/gemspec.rb +3 -2
  31. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  33. data/lib/solargraph/convention/struct_definition.rb +164 -0
  34. data/lib/solargraph/convention.rb +35 -4
  35. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  36. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
  37. data/lib/solargraph/doc_map.rb +313 -65
  38. data/lib/solargraph/environ.rb +9 -2
  39. data/lib/solargraph/gem_pins.rb +60 -38
  40. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  41. data/lib/solargraph/language_server/host/message_worker.rb +13 -7
  42. data/lib/solargraph/language_server/host.rb +14 -3
  43. data/lib/solargraph/language_server/message/base.rb +2 -1
  44. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  45. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  46. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  47. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
  49. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  50. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  51. data/lib/solargraph/language_server/progress.rb +8 -0
  52. data/lib/solargraph/language_server/request.rb +1 -0
  53. data/lib/solargraph/library.rb +53 -32
  54. data/lib/solargraph/location.rb +23 -0
  55. data/lib/solargraph/logging.rb +12 -2
  56. data/lib/solargraph/page.rb +4 -0
  57. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  58. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  59. data/lib/solargraph/parser/node_methods.rb +16 -2
  60. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  61. data/lib/solargraph/parser/node_processor.rb +26 -9
  62. data/lib/solargraph/parser/parser_gem/class_methods.rb +17 -15
  63. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  64. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +8 -4
  66. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  68. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  69. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  70. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  73. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  74. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  75. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  76. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  77. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
  79. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  80. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
  81. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  83. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  84. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +63 -30
  85. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  86. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  89. data/lib/solargraph/parser/region.rb +4 -1
  90. data/lib/solargraph/parser/snippet.rb +2 -0
  91. data/lib/solargraph/parser.rb +1 -0
  92. data/lib/solargraph/pin/base.rb +360 -30
  93. data/lib/solargraph/pin/base_variable.rb +16 -10
  94. data/lib/solargraph/pin/block.rb +2 -0
  95. data/lib/solargraph/pin/breakable.rb +9 -0
  96. data/lib/solargraph/pin/callable.rb +83 -3
  97. data/lib/solargraph/pin/closure.rb +20 -1
  98. data/lib/solargraph/pin/common.rb +10 -1
  99. data/lib/solargraph/pin/constant.rb +2 -0
  100. data/lib/solargraph/pin/delegated_method.rb +21 -1
  101. data/lib/solargraph/pin/documenting.rb +16 -0
  102. data/lib/solargraph/pin/keyword.rb +7 -2
  103. data/lib/solargraph/pin/local_variable.rb +18 -6
  104. data/lib/solargraph/pin/method.rb +175 -46
  105. data/lib/solargraph/pin/method_alias.rb +3 -0
  106. data/lib/solargraph/pin/namespace.rb +17 -9
  107. data/lib/solargraph/pin/parameter.rb +78 -19
  108. data/lib/solargraph/pin/proxy_type.rb +13 -6
  109. data/lib/solargraph/pin/reference/override.rb +24 -6
  110. data/lib/solargraph/pin/reference/require.rb +2 -2
  111. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  112. data/lib/solargraph/pin/reference.rb +26 -0
  113. data/lib/solargraph/pin/search.rb +3 -1
  114. data/lib/solargraph/pin/signature.rb +44 -0
  115. data/lib/solargraph/pin/singleton.rb +1 -1
  116. data/lib/solargraph/pin/symbol.rb +8 -2
  117. data/lib/solargraph/pin/until.rb +18 -0
  118. data/lib/solargraph/pin/while.rb +18 -0
  119. data/lib/solargraph/pin.rb +4 -1
  120. data/lib/solargraph/pin_cache.rb +245 -0
  121. data/lib/solargraph/position.rb +11 -0
  122. data/lib/solargraph/range.rb +10 -0
  123. data/lib/solargraph/rbs_map/conversions.rb +226 -70
  124. data/lib/solargraph/rbs_map/core_fills.rb +32 -16
  125. data/lib/solargraph/rbs_map/core_map.rb +37 -11
  126. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  127. data/lib/solargraph/rbs_map.rb +88 -18
  128. data/lib/solargraph/shell.rb +20 -18
  129. data/lib/solargraph/source/chain/array.rb +11 -7
  130. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  131. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  132. data/lib/solargraph/source/chain/call.rb +53 -23
  133. data/lib/solargraph/source/chain/constant.rb +1 -1
  134. data/lib/solargraph/source/chain/hash.rb +4 -3
  135. data/lib/solargraph/source/chain/head.rb +1 -1
  136. data/lib/solargraph/source/chain/if.rb +1 -1
  137. data/lib/solargraph/source/chain/link.rb +12 -1
  138. data/lib/solargraph/source/chain/literal.rb +22 -2
  139. data/lib/solargraph/source/chain/or.rb +1 -1
  140. data/lib/solargraph/source/chain/z_super.rb +1 -1
  141. data/lib/solargraph/source/chain.rb +84 -47
  142. data/lib/solargraph/source/change.rb +2 -2
  143. data/lib/solargraph/source/cursor.rb +2 -3
  144. data/lib/solargraph/source/source_chainer.rb +3 -3
  145. data/lib/solargraph/source.rb +5 -2
  146. data/lib/solargraph/source_map/clip.rb +4 -2
  147. data/lib/solargraph/source_map/data.rb +4 -0
  148. data/lib/solargraph/source_map/mapper.rb +13 -7
  149. data/lib/solargraph/source_map.rb +21 -31
  150. data/lib/solargraph/type_checker/checks.rb +4 -0
  151. data/lib/solargraph/type_checker/param_def.rb +2 -0
  152. data/lib/solargraph/type_checker/rules.rb +8 -0
  153. data/lib/solargraph/type_checker.rb +208 -128
  154. data/lib/solargraph/version.rb +1 -1
  155. data/lib/solargraph/views/_method.erb +10 -10
  156. data/lib/solargraph/views/_namespace.erb +3 -3
  157. data/lib/solargraph/views/document.erb +10 -10
  158. data/lib/solargraph/workspace/config.rb +1 -3
  159. data/lib/solargraph/workspace/require_paths.rb +98 -0
  160. data/lib/solargraph/workspace.rb +38 -52
  161. data/lib/solargraph/yard_map/helpers.rb +29 -1
  162. data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
  163. data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
  164. data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
  165. data/lib/solargraph/yard_map/mapper.rb +4 -3
  166. data/lib/solargraph/yard_map/to_method.rb +4 -2
  167. data/lib/solargraph/yardoc.rb +22 -10
  168. data/lib/solargraph.rb +34 -1
  169. data/rbs/fills/tuple.rbs +149 -0
  170. data/rbs_collection.yaml +19 -0
  171. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  172. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  173. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  174. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  175. data/solargraph.gemspec +15 -4
  176. metadata +157 -15
  177. data/lib/.rubocop.yml +0 -22
  178. data/lib/solargraph/cache.rb +0 -77
@@ -11,18 +11,35 @@ module Solargraph
11
11
  # @return [Workspace]
12
12
  attr_reader :workspace
13
13
 
14
+ # @return [SourceMap]
15
+ attr_reader :live_map
16
+
14
17
  # @return [Set<String>]
15
18
  attr_reader :external_requires
16
19
 
17
20
  # @param source_maps [Array<SourceMap>, Set<SourceMap>]
18
21
  # @param workspace [Workspace]
22
+ # @param live_map [SourceMap, nil]
19
23
  # @param external_requires [Array<String>, Set<String>]
20
- def initialize source_maps: [], workspace: Workspace.new, external_requires: []
24
+ def initialize source_maps: [], workspace: Workspace.new, live_map: nil, external_requires: []
21
25
  @source_maps = source_maps.to_set
22
26
  @workspace = workspace
27
+ @live_map = live_map
23
28
  @external_requires = external_requires.reject { |path| workspace.would_require?(path) }
24
29
  .compact
25
30
  .to_set
26
31
  end
32
+
33
+ # @return [Hash{String => SourceMap}]
34
+ def source_map_hash
35
+ # @todo Work around #to_h bug in current Ruby head (3.5) with #map#to_h
36
+ @source_map_hash ||= source_maps.map { |s| [s.filename, s] }
37
+ .to_h
38
+ end
39
+
40
+ # @return [Set<SourceMap>]
41
+ def icebox
42
+ @icebox ||= (source_maps - [live_map])
43
+ end
27
44
  end
28
45
  end
@@ -88,6 +88,7 @@ module Solargraph
88
88
  # @return [Symbol, nil]
89
89
  attr_reader :parameters_type
90
90
 
91
+ # @type [Hash{String => Symbol}]
91
92
  PARAMETERS_TYPE_BY_STARTING_TAG = {
92
93
  '{' => :hash,
93
94
  '(' => :fixed,
@@ -129,6 +130,7 @@ module Solargraph
129
130
  end.call
130
131
  end
131
132
 
133
+ # @return [self]
132
134
  def namespace_type
133
135
  return ComplexType.parse('::Object') if duck_type?
134
136
  return ComplexType.parse('::NilClass') if nil_type?
@@ -171,7 +173,11 @@ module Solargraph
171
173
  elsif fixed_parameters?
172
174
  "(#{subtypes_str})"
173
175
  else
174
- "<#{subtypes_str}>"
176
+ if name == 'Hash'
177
+ "<#{key_types_str}, #{subtypes_str}>"
178
+ else
179
+ "<#{key_types_str}#{subtypes_str}>"
180
+ end
175
181
  end
176
182
  end
177
183
 
@@ -27,7 +27,7 @@ module Solargraph
27
27
  # @return [UniqueType]
28
28
  def self.parse name, substring = '', make_rooted: nil
29
29
  if name.start_with?(':::')
30
- raise "Illegal prefix: #{name}"
30
+ raise ComplexTypeError, "Illegal prefix: #{name}"
31
31
  end
32
32
  if name.start_with?('::')
33
33
  name = name[2..-1]
@@ -48,12 +48,15 @@ module Solargraph
48
48
  subs = ComplexType.parse(substring[1..-2], partial: true)
49
49
  parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
50
50
  if parameters_type == :hash
51
- raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
52
- # @todo should be able to resolve map; both types have it
53
- # with same return type
54
- # @sg-ignore
51
+ raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring}" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
52
+ key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
53
+ subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
54
+ elsif parameters_type == :list && name == 'Hash'
55
+ # Treat Hash<A, B> as Hash{A => B}
56
+ if subs.length != 2
57
+ raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring} - must have exactly two parameters"
58
+ end
55
59
  key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
56
- # @sg-ignore
57
60
  subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
58
61
  else
59
62
  subtypes.concat subs
@@ -73,19 +76,66 @@ module Solargraph
73
76
  end
74
77
  raise "Please remove leading :: and set rooted instead - #{name.inspect}" if name.start_with?('::')
75
78
  @name = name
76
- @key_types = key_types
77
- @subtypes = subtypes
79
+ @parameters_type = parameters_type
80
+ if implicit_union?
81
+ @key_types = key_types.uniq
82
+ @subtypes = subtypes.uniq
83
+ else
84
+ @key_types = key_types
85
+ @subtypes = subtypes
86
+ end
78
87
  @rooted = rooted
79
88
  @all_params = []
80
- @all_params.concat key_types
81
- @all_params.concat subtypes
82
- @parameters_type = parameters_type
89
+ @all_params.concat @key_types
90
+ @all_params.concat @subtypes
91
+ end
92
+
93
+ def implicit_union?
94
+ # @todo use api_map to establish number of generics in type;
95
+ # if only one is allowed but multiple are passed in, treat
96
+ # those as implicit unions
97
+ ['Hash', 'Array', 'Set', '_ToAry', 'Enumerable', '_Each'].include?(name) && parameters_type != :fixed
83
98
  end
84
99
 
85
100
  def to_s
86
101
  tag
87
102
  end
88
103
 
104
+ # @return [self]
105
+ def simplify_literals
106
+ transform do |t|
107
+ next t unless t.literal?
108
+ t.recreate(new_name: t.non_literal_name)
109
+ end
110
+ end
111
+
112
+ def literal?
113
+ non_literal_name != name
114
+ end
115
+
116
+ # @return [String]
117
+ def non_literal_name
118
+ @non_literal_name ||= determine_non_literal_name
119
+ end
120
+
121
+ # @return [String]
122
+ def determine_non_literal_name
123
+ # https://github.com/ruby/rbs/blob/master/docs/syntax.md
124
+ #
125
+ # _literal_ ::= _string-literal_
126
+ # | _symbol-literal_
127
+ # | _integer-literal_
128
+ # | `true`
129
+ # | `false`
130
+ return name if name.empty?
131
+ return 'NilClass' if name == 'nil'
132
+ return 'Boolean' if ['true', 'false'].include?(name)
133
+ return 'Symbol' if name[0] == ':'
134
+ return 'String' if ['"', "'"].include?(name[0])
135
+ return 'Integer' if name.match?(/^-?\d+$/)
136
+ name
137
+ end
138
+
89
139
  def eql?(other)
90
140
  self.class == other.class &&
91
141
  @name == other.name &&
@@ -113,11 +163,14 @@ module Solargraph
113
163
  def rbs_name
114
164
  if name == 'undefined'
115
165
  'untyped'
166
+ elsif literal?
167
+ name
116
168
  else
117
169
  rooted_name
118
170
  end
119
171
  end
120
172
 
173
+ # @return [String]
121
174
  def desc
122
175
  rooted_tags
123
176
  end
@@ -183,9 +236,26 @@ module Solargraph
183
236
  name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
184
237
  end
185
238
 
239
+ # @param api_map [ApiMap] The ApiMap that performs qualification
240
+ # @param atype [ComplexType] type which may be assigned to this type
241
+ def can_assign?(api_map, atype)
242
+ logger.debug { "UniqueType#can_assign?(self=#{rooted_tags.inspect}, atype=#{atype.rooted_tags.inspect})" }
243
+ downcasted_atype = atype.downcast_to_literal_if_possible
244
+ out = downcasted_atype.all? do |autype|
245
+ autype.name == name || api_map.super_and_sub?(name, autype.name)
246
+ end
247
+ logger.debug { "UniqueType#can_assign?(self=#{rooted_tags.inspect}, atype=#{atype.rooted_tags.inspect}) => #{out}" }
248
+ out
249
+ end
250
+
251
+ # @return [UniqueType]
252
+ def downcast_to_literal_if_possible
253
+ SINGLE_SUBTYPE.fetch(rooted_tag, self)
254
+ end
255
+
186
256
  # @param generics_to_resolve [Enumerable<String>]
187
257
  # @param context_type [UniqueType, nil]
188
- # @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
258
+ # @param resolved_generic_values [Hash{String => ComplexType, ComplexType::UniqueType}] Added to as types are encountered or resolved
189
259
  # @return [UniqueType, ComplexType]
190
260
  def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
191
261
  if name == ComplexType::GENERIC_TAG_NAME
@@ -243,7 +313,8 @@ module Solargraph
243
313
 
244
314
  transform(name) do |t|
245
315
  if t.name == GENERIC_TAG_NAME
246
- idx = definitions.generics.index(t.subtypes.first&.name)
316
+ generic_name = t.subtypes.first&.name
317
+ idx = definitions.generics.index(generic_name)
247
318
  next t if idx.nil?
248
319
  if context_type.parameters_type == :hash
249
320
  if idx == 0
@@ -253,8 +324,14 @@ module Solargraph
253
324
  else
254
325
  next ComplexType::UNDEFINED
255
326
  end
327
+ elsif context_type.all?(&:implicit_union?)
328
+ if idx == 0 && !context_type.all_params.empty?
329
+ ComplexType.new(context_type.all_params)
330
+ else
331
+ ComplexType::UNDEFINED
332
+ end
256
333
  else
257
- context_type.all_params[idx] || ComplexType::UNDEFINED
334
+ context_type.all_params[idx] || definitions.generic_defaults[generic_name] || ComplexType::UNDEFINED
258
335
  end
259
336
  else
260
337
  t
@@ -276,9 +353,9 @@ module Solargraph
276
353
 
277
354
  # @param new_name [String, nil]
278
355
  # @param make_rooted [Boolean, nil]
279
- # @param new_key_types [Array<UniqueType>, nil]
356
+ # @param new_key_types [Array<ComplexType>, nil]
280
357
  # @param rooted [Boolean, nil]
281
- # @param new_subtypes [Array<UniqueType>, nil]
358
+ # @param new_subtypes [Array<ComplexType>, nil]
282
359
  # @return [self]
283
360
  def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
284
361
  raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
@@ -381,6 +458,18 @@ module Solargraph
381
458
 
382
459
  UNDEFINED = UniqueType.new('undefined', rooted: false)
383
460
  BOOLEAN = UniqueType.new('Boolean', rooted: true)
461
+ TRUE = UniqueType.new('true', rooted: true)
462
+ FALSE = UniqueType.new('false', rooted: true)
463
+ NIL = UniqueType.new('nil', rooted: true)
464
+ # @type [Hash{String => UniqueType}]
465
+ SINGLE_SUBTYPE = {
466
+ '::TrueClass' => UniqueType::TRUE,
467
+ '::FalseClass' => UniqueType::FALSE,
468
+ '::NilClass' => UniqueType::NIL
469
+ }.freeze
470
+
471
+
472
+ include Logging
384
473
  end
385
474
  end
386
475
  end
@@ -16,7 +16,13 @@ module Solargraph
16
16
  def initialize types = [UniqueType::UNDEFINED]
17
17
  # @todo @items here should not need an annotation
18
18
  # @type [Array<UniqueType>]
19
- @items = types.flat_map(&:items).uniq(&:to_s)
19
+ items = types.flat_map(&:items).uniq(&:to_s)
20
+ if items.any? { |i| i.name == 'false' } && items.any? { |i| i.name == 'true' }
21
+ items.delete_if { |i| i.name == 'false' || i.name == 'true' }
22
+ items.unshift(ComplexType::BOOLEAN)
23
+ end
24
+ items = [UniqueType::UNDEFINED] if items.any?(&:undefined?)
25
+ @items = items
20
26
  end
21
27
 
22
28
  # @sg-ignore Fix "Not enough arguments to Module#protected"
@@ -70,7 +76,7 @@ module Solargraph
70
76
  end
71
77
 
72
78
  # @yieldparam [UniqueType]
73
- # @return [Array]
79
+ # @return [Array<UniqueType>]
74
80
  def map &block
75
81
  @items.map &block
76
82
  end
@@ -93,6 +99,12 @@ module Solargraph
93
99
  end
94
100
  end
95
101
 
102
+ # @param atype [ComplexType] type which may be assigned to this type
103
+ # @param api_map [ApiMap] The ApiMap that performs qualification
104
+ def can_assign?(api_map, atype)
105
+ any? { |ut| ut.can_assign?(api_map, atype) }
106
+ end
107
+
96
108
  # @return [Integer]
97
109
  def length
98
110
  @items.length
@@ -103,10 +115,6 @@ module Solargraph
103
115
  @items
104
116
  end
105
117
 
106
- def tags
107
- @items.map(&:tag).join(', ')
108
- end
109
-
110
118
  # @param index [Integer]
111
119
  # @return [UniqueType]
112
120
  def [](index)
@@ -147,10 +155,31 @@ module Solargraph
147
155
  map(&:tag).join(', ')
148
156
  end
149
157
 
158
+ # @return [String]
159
+ def tags
160
+ map(&:tag).join(', ')
161
+ end
162
+
163
+ # @return [String]
164
+ def simple_tags
165
+ simplify_literals.tags
166
+ end
167
+
168
+ def literal?
169
+ @items.any?(&:literal?)
170
+ end
171
+
172
+ # @return [ComplexType]
173
+ def downcast_to_literal_if_possible
174
+ ComplexType.new(items.map(&:downcast_to_literal_if_possible))
175
+ end
176
+
177
+ # @return [String]
150
178
  def desc
151
179
  rooted_tags
152
180
  end
153
181
 
182
+ # @return [String]
154
183
  def rooted_tags
155
184
  map(&:rooted_tag).join(', ')
156
185
  end
@@ -175,6 +204,11 @@ module Solargraph
175
204
  any?(&:generic?)
176
205
  end
177
206
 
207
+ # @return [self]
208
+ def simplify_literals
209
+ ComplexType.new(map(&:simplify_literals))
210
+ end
211
+
178
212
  # @param new_name [String, nil]
179
213
  # @yieldparam t [UniqueType]
180
214
  # @yieldreturn [UniqueType]
@@ -270,7 +304,6 @@ module Solargraph
270
304
  # # @todo Need ability to use a literal true as a type below
271
305
  # # @param partial [Boolean] True if the string is part of a another type
272
306
  # # @return [Array<UniqueType>]
273
- # @sg-ignore
274
307
  # @todo To be able to select the right signature above,
275
308
  # Chain::Call needs to know the decl type (:arg, :optarg,
276
309
  # :kwarg, etc) of the arguments given, instead of just having
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ # ActiveSupport::Concern is syntactic sugar for a common
6
+ # pattern to include class methods while mixing-in a Module
7
+ # See https://api.rubyonrails.org/classes/ActiveSupport/Concern.html
8
+ class ActiveSupportConcern < Base
9
+ include Logging
10
+
11
+ # @return [Array<Pin::Base>]
12
+ attr_reader :pins
13
+
14
+ # @param api_map [ApiMap]
15
+ # @param rooted_tag [String]
16
+ # @param scope [Symbol] :class or :instance
17
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
18
+ # @param deep [Boolean] whether to include methods from included modules
19
+ # @param skip [Set<String>]
20
+ # @param _no_core [Boolean]n whether to skip core methods
21
+ def object api_map, rooted_tag, scope, visibility, deep, skip, _no_core
22
+ moo = ObjectProcessor.new(api_map, rooted_tag, scope, visibility, deep, skip)
23
+ moo.environ
24
+ end
25
+
26
+ # yard-activesupport-concern pulls methods inside
27
+ # 'class_methods' blocks into main class visible from YARD
28
+ #
29
+ # @param _doc_map [DocMap]
30
+ def global _doc_map
31
+ Environ.new(yard_plugins: ['activesupport-concern'])
32
+ end
33
+
34
+ # Process an object to add any class methods brought in via
35
+ # ActiveSupport::Concern
36
+ class ObjectProcessor
37
+ include Logging
38
+
39
+ attr_reader :environ
40
+
41
+ # @param api_map [ApiMap]
42
+ # @param rooted_tag [String] the tag of the class or module being processed
43
+ # @param scope [Symbol] :class or :instance
44
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
45
+ # @param deep [Boolean] whether to include methods from included modules
46
+ # @param skip [Set<String>] a set of tags to skip
47
+ def initialize api_map, rooted_tag, scope, visibility, deep, skip
48
+ @api_map = api_map
49
+ @rooted_tag = rooted_tag
50
+ @scope = scope
51
+ @visibility = visibility
52
+ @deep = deep
53
+ @skip = skip
54
+
55
+ @environ = Environ.new
56
+ return unless scope == :class
57
+
58
+ @rooted_type = ComplexType.parse(rooted_tag).force_rooted
59
+ @fqns = rooted_type.namespace
60
+ @namespace_pin = api_map.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
61
+
62
+ api_map.get_includes(fqns).reverse.each do |include_tag|
63
+ process_include include_tag
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ attr_reader :api_map, :rooted_tag, :rooted_type, :scope,
70
+ :visibility, :deep, :skip, :namespace_pin,
71
+ :fqns
72
+
73
+ # @param include_tag [Pin::Reference::Include] the include reference pin
74
+ #
75
+ # @return [void]
76
+ def process_include include_tag
77
+ rooted_include_tag = api_map.dereference(include_tag)
78
+ return if rooted_include_tag.nil?
79
+ logger.debug do
80
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
81
+ "Handling class include include_tag=#{include_tag}"
82
+ end
83
+ module_extends = api_map.get_extends(rooted_include_tag).map(&:parametrized_tag).map(&:to_s)
84
+ logger.debug do
85
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
86
+ "found module extends of #{rooted_include_tag}: #{module_extends}"
87
+ end
88
+ return unless module_extends.include? 'ActiveSupport::Concern'
89
+ included_class_pins = api_map.inner_get_methods_from_reference(rooted_include_tag, namespace_pin, rooted_type,
90
+ :class, visibility, deep, skip, true)
91
+ logger.debug do
92
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
93
+ "Found #{included_class_pins.length} inluded class methods for #{rooted_include_tag}"
94
+ end
95
+ environ.pins.concat included_class_pins
96
+ # another pattern is to put class methods inside a submodule
97
+ classmethods_include_tag = "#{rooted_include_tag}::ClassMethods"
98
+ included_classmethods_pins =
99
+ api_map.inner_get_methods_from_reference(classmethods_include_tag, namespace_pin, rooted_type,
100
+ :instance, visibility, deep, skip, true)
101
+ logger.debug do
102
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
103
+ "Found #{included_classmethods_pins.length} included classmethod " \
104
+ "class methods for #{classmethods_include_tag}"
105
+ end
106
+ environ.pins.concat included_classmethods_pins
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -20,12 +20,29 @@ module Solargraph
20
20
  EMPTY_ENVIRON
21
21
  end
22
22
 
23
- # The Environ for a YARD map.
23
+ # The Environ for a DocMap.
24
24
  # Subclasses can override this method.
25
25
  #
26
- # @param yard_map [YardMap]
26
+ # @param doc_map [DocMap]
27
27
  # @return [Environ]
28
- def global yard_map
28
+ def global doc_map
29
+ EMPTY_ENVIRON
30
+ end
31
+
32
+ # Provides any additional method pins based on e the described object.
33
+ #
34
+ # @param api_map [ApiMap]
35
+ # @param rooted_tag [String] A fully qualified namespace, with
36
+ # generic parameter values if applicable
37
+ # @param scope [Symbol] :class or :instance
38
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
39
+ # @param deep [Boolean]
40
+ # @param skip [Set<String>]
41
+ # @param no_core [Boolean] Skip core classes if true
42
+ #
43
+ # @return [Environ]
44
+ def object api_map, rooted_tag, scope, visibility,
45
+ deep, skip, no_core
29
46
  EMPTY_ENVIRON
30
47
  end
31
48
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module DataDefinition
6
+ # A node wrapper for a Data definition via const assignment.
7
+ # @example
8
+ # MyData = Data.new(:bar, :baz) do
9
+ # def foo
10
+ # end
11
+ # end
12
+ class DataAssignmentNode < DataDefintionNode
13
+ class << self
14
+ # @example
15
+ # s(:casgn, nil, :Foo,
16
+ # s(:block,
17
+ # s(:send,
18
+ # s(:const, nil, :Data), :define,
19
+ # s(:sym, :bar),
20
+ # s(:sym, :baz)),
21
+ # s(:args),
22
+ # s(:def, :foo,
23
+ # s(:args),
24
+ # s(:send, nil, :bar))))
25
+ # @param node [::Parser::AST::Node]
26
+ def match?(node)
27
+ return false unless node&.type == :casgn
28
+ return false if node.children[2].nil?
29
+
30
+ data_node = if node.children[2].type == :block
31
+ node.children[2].children[0]
32
+ else
33
+ node.children[2]
34
+ end
35
+
36
+ data_definition_node?(data_node)
37
+ end
38
+ end
39
+
40
+ def class_name
41
+ if node.children[0]
42
+ Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
43
+ else
44
+ node.children[1].to_s
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # @return [Parser::AST::Node]
51
+ def data_node
52
+ if node.children[2].type == :block
53
+ node.children[2].children[0]
54
+ else
55
+ node.children[2]
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module DataDefinition
6
+ # A node wrapper for a Data definition via inheritance.
7
+ # @example
8
+ # class MyData < Data.new(:bar, :baz)
9
+ # def foo
10
+ # end
11
+ # end
12
+ class DataDefintionNode
13
+ class << self
14
+ # @example
15
+ # s(:class,
16
+ # s(:const, nil, :Foo),
17
+ # s(:send,
18
+ # s(:const, nil, :Data), :define,
19
+ # s(:sym, :bar),
20
+ # s(:sym, :baz)),
21
+ # s(:hash,
22
+ # s(:pair,
23
+ # s(:sym, :keyword_init),
24
+ # s(:true)))),
25
+ # s(:def, :foo,
26
+ # s(:args),
27
+ # s(:send, nil, :bar)))
28
+ #
29
+ # @param node [Parser::AST::Node]
30
+ def match?(node)
31
+ return false unless node&.type == :class
32
+
33
+ data_definition_node?(node.children[1])
34
+ end
35
+
36
+ private
37
+
38
+ # @param data_node [Parser::AST::Node]
39
+ # @return [Boolean]
40
+ def data_definition_node?(data_node)
41
+ return false unless data_node.is_a?(::Parser::AST::Node)
42
+ return false unless data_node&.type == :send
43
+ return false unless data_node.children[0]&.type == :const
44
+ return false unless data_node.children[0].children[1] == :Data
45
+ return false unless data_node.children[1] == :define
46
+
47
+ true
48
+ end
49
+ end
50
+
51
+ # @param node [Parser::AST::Node]
52
+ def initialize(node)
53
+ @node = node
54
+ end
55
+
56
+ # @return [String]
57
+ def class_name
58
+ Parser::NodeMethods.unpack_name(node)
59
+ end
60
+
61
+ # @return [Array<Array(Parser::AST::Node, String)>]
62
+ def attributes
63
+ data_attribute_nodes.map do |data_def_param|
64
+ next unless data_def_param.type == :sym
65
+ [data_def_param, data_def_param.children[0].to_s]
66
+ end.compact
67
+ end
68
+
69
+ # @return [Parser::AST::Node]
70
+ def body_node
71
+ node.children[2]
72
+ end
73
+
74
+ private
75
+
76
+ # @return [Parser::AST::Node]
77
+ attr_reader :node
78
+
79
+ # @return [Parser::AST::Node]
80
+ def data_node
81
+ node.children[1]
82
+ end
83
+
84
+ # @return [Array<Parser::AST::Node>]
85
+ def data_attribute_nodes
86
+ data_node.children[2..-1]
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end