solargraph 0.56.0 → 0.58.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/linting.yml +127 -0
  4. data/.github/workflows/plugins.yml +183 -7
  5. data/.github/workflows/rspec.yml +55 -5
  6. data/.github/workflows/typecheck.yml +6 -3
  7. data/.gitignore +5 -0
  8. data/.overcommit.yml +72 -0
  9. data/.rspec +1 -0
  10. data/.rubocop.yml +66 -0
  11. data/.rubocop_todo.yml +1279 -0
  12. data/.yardopts +1 -0
  13. data/CHANGELOG.md +86 -1
  14. data/README.md +8 -4
  15. data/Rakefile +125 -13
  16. data/bin/solargraph +3 -0
  17. data/lib/solargraph/api_map/cache.rb +3 -2
  18. data/lib/solargraph/api_map/constants.rb +279 -0
  19. data/lib/solargraph/api_map/index.rb +49 -31
  20. data/lib/solargraph/api_map/source_to_yard.rb +13 -4
  21. data/lib/solargraph/api_map/store.rb +144 -26
  22. data/lib/solargraph/api_map.rb +217 -245
  23. data/lib/solargraph/bench.rb +1 -0
  24. data/lib/solargraph/complex_type/type_methods.rb +6 -0
  25. data/lib/solargraph/complex_type/unique_type.rb +19 -12
  26. data/lib/solargraph/complex_type.rb +24 -3
  27. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  28. data/lib/solargraph/convention/base.rb +17 -0
  29. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  30. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  31. data/lib/solargraph/convention/data_definition.rb +105 -0
  32. data/lib/solargraph/convention/gemspec.rb +3 -2
  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 -2
  35. data/lib/solargraph/convention/struct_definition.rb +87 -24
  36. data/lib/solargraph/convention.rb +32 -2
  37. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  38. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  39. data/lib/solargraph/doc_map.rb +52 -18
  40. data/lib/solargraph/environ.rb +9 -2
  41. data/lib/solargraph/equality.rb +1 -0
  42. data/lib/solargraph/gem_pins.rb +21 -11
  43. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  44. data/lib/solargraph/language_server/host/message_worker.rb +3 -0
  45. data/lib/solargraph/language_server/host.rb +12 -5
  46. data/lib/solargraph/language_server/message/base.rb +2 -1
  47. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
  48. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  49. data/lib/solargraph/language_server/message/text_document/formatting.rb +19 -2
  50. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  51. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  52. data/lib/solargraph/language_server/progress.rb +8 -0
  53. data/lib/solargraph/language_server/request.rb +4 -1
  54. data/lib/solargraph/library.rb +50 -33
  55. data/lib/solargraph/location.rb +3 -0
  56. data/lib/solargraph/logging.rb +11 -2
  57. data/lib/solargraph/page.rb +3 -0
  58. data/lib/solargraph/parser/comment_ripper.rb +8 -1
  59. data/lib/solargraph/parser/flow_sensitive_typing.rb +33 -5
  60. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  61. data/lib/solargraph/parser/node_processor.rb +24 -8
  62. data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -13
  63. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  64. data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -16
  66. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +1 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
  68. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +1 -21
  69. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
  70. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +0 -22
  72. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +65 -8
  73. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  74. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +1 -0
  75. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +12 -3
  76. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +36 -16
  77. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +1 -0
  78. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  79. data/lib/solargraph/parser/region.rb +3 -0
  80. data/lib/solargraph/parser/snippet.rb +2 -0
  81. data/lib/solargraph/pin/base.rb +92 -14
  82. data/lib/solargraph/pin/base_variable.rb +6 -5
  83. data/lib/solargraph/pin/block.rb +3 -2
  84. data/lib/solargraph/pin/callable.rb +14 -1
  85. data/lib/solargraph/pin/closure.rb +5 -7
  86. data/lib/solargraph/pin/common.rb +6 -2
  87. data/lib/solargraph/pin/constant.rb +2 -0
  88. data/lib/solargraph/pin/local_variable.rb +1 -2
  89. data/lib/solargraph/pin/method.rb +32 -11
  90. data/lib/solargraph/pin/method_alias.rb +3 -0
  91. data/lib/solargraph/pin/parameter.rb +24 -10
  92. data/lib/solargraph/pin/proxy_type.rb +5 -1
  93. data/lib/solargraph/pin/reference/override.rb +15 -1
  94. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  95. data/lib/solargraph/pin/reference.rb +17 -0
  96. data/lib/solargraph/pin/search.rb +6 -1
  97. data/lib/solargraph/pin/signature.rb +2 -0
  98. data/lib/solargraph/pin/symbol.rb +5 -0
  99. data/lib/solargraph/pin_cache.rb +64 -4
  100. data/lib/solargraph/position.rb +3 -0
  101. data/lib/solargraph/range.rb +5 -0
  102. data/lib/solargraph/rbs_map/conversions.rb +68 -18
  103. data/lib/solargraph/rbs_map/core_fills.rb +18 -0
  104. data/lib/solargraph/rbs_map/core_map.rb +14 -7
  105. data/lib/solargraph/rbs_map.rb +14 -1
  106. data/lib/solargraph/shell.rb +85 -1
  107. data/lib/solargraph/source/chain/call.rb +7 -3
  108. data/lib/solargraph/source/chain/constant.rb +3 -66
  109. data/lib/solargraph/source/chain/if.rb +1 -1
  110. data/lib/solargraph/source/chain/link.rb +11 -2
  111. data/lib/solargraph/source/chain/or.rb +1 -1
  112. data/lib/solargraph/source/chain.rb +11 -2
  113. data/lib/solargraph/source/change.rb +2 -2
  114. data/lib/solargraph/source/cursor.rb +2 -3
  115. data/lib/solargraph/source/encoding_fixes.rb +23 -23
  116. data/lib/solargraph/source/source_chainer.rb +1 -1
  117. data/lib/solargraph/source.rb +6 -3
  118. data/lib/solargraph/source_map/clip.rb +18 -26
  119. data/lib/solargraph/source_map/data.rb +4 -0
  120. data/lib/solargraph/source_map/mapper.rb +2 -2
  121. data/lib/solargraph/source_map.rb +28 -16
  122. data/lib/solargraph/type_checker/param_def.rb +2 -0
  123. data/lib/solargraph/type_checker/rules.rb +30 -8
  124. data/lib/solargraph/type_checker.rb +301 -186
  125. data/lib/solargraph/version.rb +5 -5
  126. data/lib/solargraph/workspace/config.rb +22 -6
  127. data/lib/solargraph/workspace/require_paths.rb +97 -0
  128. data/lib/solargraph/workspace.rb +38 -67
  129. data/lib/solargraph/yard_map/helpers.rb +29 -1
  130. data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -5
  131. data/lib/solargraph/yard_map/mapper/to_method.rb +5 -9
  132. data/lib/solargraph/yard_map/mapper/to_namespace.rb +8 -7
  133. data/lib/solargraph/yard_map/to_method.rb +2 -1
  134. data/lib/solargraph/yardoc.rb +41 -3
  135. data/lib/solargraph.rb +15 -0
  136. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  137. data/rbs/fills/open3/0/open3.rbs +172 -0
  138. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  139. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  140. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  141. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  142. data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +2 -3
  143. data/rbs_collection.yaml +4 -4
  144. data/sig/shims/ast/0/node.rbs +5 -0
  145. data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
  146. data/sig/shims/ast/2.4/ast.rbs +73 -0
  147. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  148. data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
  149. data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
  150. data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  151. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  152. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  153. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  154. data/solargraph.gemspec +26 -5
  155. metadata +187 -15
  156. data/lib/.rubocop.yml +0 -22
  157. data/lib/solargraph/parser/node_methods.rb +0 -97
@@ -37,6 +37,7 @@ module Solargraph
37
37
  .to_h
38
38
  end
39
39
 
40
+ # @return [Set<SourceMap>]
40
41
  def icebox
41
42
  @icebox ||= (source_maps - [live_map])
42
43
  end
@@ -43,6 +43,10 @@ module Solargraph
43
43
  @rooted_tag ||= rooted_name + rooted_substring
44
44
  end
45
45
 
46
+ def interface?
47
+ name.start_with?('_')
48
+ end
49
+
46
50
  # @return [Boolean]
47
51
  def duck_type?
48
52
  @duck_type ||= name.start_with?('#')
@@ -130,6 +134,7 @@ module Solargraph
130
134
  end.call
131
135
  end
132
136
 
137
+ # @return [self]
133
138
  def namespace_type
134
139
  return ComplexType.parse('::Object') if duck_type?
135
140
  return ComplexType.parse('::NilClass') if nil_type?
@@ -189,6 +194,7 @@ module Solargraph
189
194
  # @param other [Object]
190
195
  def == other
191
196
  return false unless self.class == other.class
197
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
192
198
  tag == other.tag
193
199
  end
194
200
 
@@ -49,11 +49,7 @@ module Solargraph
49
49
  parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
50
50
  if parameters_type == :hash
51
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
- # @todo should be able to resolve map; both types have it
53
- # with same return type
54
- # @sg-ignore
55
52
  key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
56
- # @sg-ignore
57
53
  subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
58
54
  elsif parameters_type == :list && name == 'Hash'
59
55
  # Treat Hash<A, B> as Hash{A => B}
@@ -105,6 +101,7 @@ module Solargraph
105
101
  tag
106
102
  end
107
103
 
104
+ # @return [self]
108
105
  def simplify_literals
109
106
  transform do |t|
110
107
  next t unless t.literal?
@@ -116,10 +113,12 @@ module Solargraph
116
113
  non_literal_name != name
117
114
  end
118
115
 
116
+ # @return [String]
119
117
  def non_literal_name
120
118
  @non_literal_name ||= determine_non_literal_name
121
119
  end
122
120
 
121
+ # @return [String]
123
122
  def determine_non_literal_name
124
123
  # https://github.com/ruby/rbs/blob/master/docs/syntax.md
125
124
  #
@@ -139,11 +138,17 @@ module Solargraph
139
138
 
140
139
  def eql?(other)
141
140
  self.class == other.class &&
141
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
142
142
  @name == other.name &&
143
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
143
144
  @key_types == other.key_types &&
145
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
144
146
  @subtypes == other.subtypes &&
147
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
145
148
  @rooted == other.rooted? &&
149
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
146
150
  @all_params == other.all_params &&
151
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
147
152
  @parameters_type == other.parameters_type
148
153
  end
149
154
 
@@ -171,6 +176,7 @@ module Solargraph
171
176
  end
172
177
  end
173
178
 
179
+ # @return [String]
174
180
  def desc
175
181
  rooted_tags
176
182
  end
@@ -255,7 +261,7 @@ module Solargraph
255
261
 
256
262
  # @param generics_to_resolve [Enumerable<String>]
257
263
  # @param context_type [UniqueType, nil]
258
- # @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
264
+ # @param resolved_generic_values [Hash{String => ComplexType, ComplexType::UniqueType}] Added to as types are encountered or resolved
259
265
  # @return [UniqueType, ComplexType]
260
266
  def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
261
267
  if name == ComplexType::GENERIC_TAG_NAME
@@ -280,7 +286,7 @@ module Solargraph
280
286
  end
281
287
 
282
288
  # @param generics_to_resolve [Enumerable<String>]
283
- # @param context_type [UniqueType]
289
+ # @param context_type [UniqueType, nil]
284
290
  # @param resolved_generic_values [Hash{String => ComplexType}]
285
291
  # @yieldreturn [Array<ComplexType>]
286
292
  # @return [Array<ComplexType>]
@@ -353,9 +359,9 @@ module Solargraph
353
359
 
354
360
  # @param new_name [String, nil]
355
361
  # @param make_rooted [Boolean, nil]
356
- # @param new_key_types [Array<UniqueType>, nil]
362
+ # @param new_key_types [Array<ComplexType>, nil]
357
363
  # @param rooted [Boolean, nil]
358
- # @param new_subtypes [Array<UniqueType>, nil]
364
+ # @param new_subtypes [Array<ComplexType>, nil]
359
365
  # @return [self]
360
366
  def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
361
367
  raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
@@ -409,12 +415,12 @@ module Solargraph
409
415
  # @param api_map [ApiMap] The ApiMap that performs qualification
410
416
  # @param context [String] The namespace from which to resolve names
411
417
  # @return [self, ComplexType, UniqueType] The generated ComplexType
412
- def qualify api_map, context = ''
418
+ def qualify api_map, *gates
413
419
  transform do |t|
414
420
  next t if t.name == GENERIC_TAG_NAME
415
- next t if t.duck_type? || t.void? || t.undefined?
416
- recon = (t.rooted? ? '' : context)
417
- fqns = api_map.qualify(t.name, recon)
421
+ next t if t.duck_type? || t.void? || t.undefined? || t.literal?
422
+ open = t.rooted? ? [''] : gates
423
+ fqns = api_map.qualify(t.non_literal_name, *open)
418
424
  if fqns.nil?
419
425
  next UniqueType::BOOLEAN if t.tag == 'Boolean'
420
426
  next UniqueType::UNDEFINED
@@ -446,6 +452,7 @@ module Solargraph
446
452
  !can_root_name? || @rooted
447
453
  end
448
454
 
455
+ # @param name_to_check [String]
449
456
  def can_root_name?(name_to_check = name)
450
457
  self.class.can_root_name?(name_to_check)
451
458
  end
@@ -33,12 +33,12 @@ module Solargraph
33
33
  # @param api_map [ApiMap]
34
34
  # @param context [String]
35
35
  # @return [ComplexType]
36
- def qualify api_map, context = ''
36
+ def qualify api_map, *gates
37
37
  red = reduce_object
38
38
  types = red.items.map do |t|
39
39
  next t if ['nil', 'void', 'undefined'].include?(t.name)
40
40
  next t if ['::Boolean'].include?(t.rooted_name)
41
- t.qualify api_map, context
41
+ t.qualify api_map, *gates
42
42
  end
43
43
  ComplexType.new(types).reduce_object
44
44
  end
@@ -105,6 +105,21 @@ module Solargraph
105
105
  any? { |ut| ut.can_assign?(api_map, atype) }
106
106
  end
107
107
 
108
+ # @param new_name [String, nil]
109
+ # @param make_rooted [Boolean, nil]
110
+ # @param new_key_types [Array<ComplexType>, nil]
111
+ # @param rooted [Boolean, nil]
112
+ # @param new_subtypes [Array<ComplexType>, nil]
113
+ # @return [self]
114
+ def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
115
+ ComplexType.new(map do |ut|
116
+ ut.recreate(new_name: new_name,
117
+ make_rooted: make_rooted,
118
+ new_key_types: new_key_types,
119
+ new_subtypes: new_subtypes)
120
+ end)
121
+ end
122
+
108
123
  # @return [Integer]
109
124
  def length
110
125
  @items.length
@@ -155,10 +170,12 @@ module Solargraph
155
170
  map(&:tag).join(', ')
156
171
  end
157
172
 
173
+ # @return [String]
158
174
  def tags
159
175
  map(&:tag).join(', ')
160
176
  end
161
177
 
178
+ # @return [String]
162
179
  def simple_tags
163
180
  simplify_literals.tags
164
181
  end
@@ -172,10 +189,12 @@ module Solargraph
172
189
  ComplexType.new(items.map(&:downcast_to_literal_if_possible))
173
190
  end
174
191
 
192
+ # @return [String]
175
193
  def desc
176
194
  rooted_tags
177
195
  end
178
196
 
197
+ # @return [String]
179
198
  def rooted_tags
180
199
  map(&:rooted_tag).join(', ')
181
200
  end
@@ -200,6 +219,7 @@ module Solargraph
200
219
  any?(&:generic?)
201
220
  end
202
221
 
222
+ # @return [self]
203
223
  def simplify_literals
204
224
  ComplexType.new(map(&:simplify_literals))
205
225
  end
@@ -241,6 +261,7 @@ module Solargraph
241
261
  def reduce_class_type
242
262
  new_items = items.flat_map do |type|
243
263
  next type unless ['Module', 'Class'].include?(type.name)
264
+ next type if type.all_params.empty?
244
265
 
245
266
  type.all_params
246
267
  end
@@ -299,7 +320,6 @@ module Solargraph
299
320
  # # @todo Need ability to use a literal true as a type below
300
321
  # # @param partial [Boolean] True if the string is part of a another type
301
322
  # # @return [Array<UniqueType>]
302
- # @sg-ignore
303
323
  # @todo To be able to select the right signature above,
304
324
  # Chain::Call needs to know the decl type (:arg, :optarg,
305
325
  # :kwarg, etc) of the arguments given, instead of just having
@@ -319,6 +339,7 @@ module Solargraph
319
339
  paren_stack = 0
320
340
  base = String.new
321
341
  subtype_string = String.new
342
+ # @param char [String]
322
343
  type_string&.each_char do |char|
323
344
  if char == '='
324
345
  #raise ComplexTypeError, "Invalid = in type #{type_string}" unless curly_stack > 0
@@ -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(&:type).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
@@ -28,6 +28,23 @@ module Solargraph
28
28
  def global doc_map
29
29
  EMPTY_ENVIRON
30
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
46
+ EMPTY_ENVIRON
47
+ end
31
48
  end
32
49
  end
33
50
  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, nil]
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
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module DataDefinition
6
+ autoload :DataDefintionNode, 'solargraph/convention/data_definition/data_definition_node'
7
+ autoload :DataAssignmentNode, 'solargraph/convention/data_definition/data_assignment_node'
8
+
9
+ module NodeProcessors
10
+ class DataNode < Parser::NodeProcessor::Base
11
+ # @return [Boolean] continue processing the next processor of the same node.
12
+ def process
13
+ return true if data_definition_node.nil?
14
+
15
+ loc = get_node_location(node)
16
+ nspin = Solargraph::Pin::Namespace.new(
17
+ type: :class,
18
+ location: loc,
19
+ closure: region.closure,
20
+ name: data_definition_node.class_name,
21
+ comments: comments_for(node),
22
+ visibility: :public,
23
+ gates: region.closure.gates.freeze
24
+ )
25
+ pins.push nspin
26
+
27
+ # define initialize method
28
+ initialize_method_pin = Pin::Method.new(
29
+ name: 'initialize',
30
+ parameters: [],
31
+ scope: :instance,
32
+ location: get_node_location(node),
33
+ closure: nspin,
34
+ visibility: :private,
35
+ comments: comments_for(node)
36
+ )
37
+
38
+ # @todo Support both arg and kwarg initializers for Data.define
39
+ # Solargraph::SourceMap::Clip#complete_keyword_parameters does not seem to currently take into account [Pin::Method#signatures] hence we only one for :kwarg
40
+ pins.push initialize_method_pin
41
+
42
+ data_definition_node.attributes.map do |attribute_node, attribute_name|
43
+ initialize_method_pin.parameters.push(
44
+ Pin::Parameter.new(
45
+ name: attribute_name,
46
+ decl: :kwarg,
47
+ location: get_node_location(attribute_node),
48
+ closure: initialize_method_pin
49
+ )
50
+ )
51
+ end
52
+
53
+ # define attribute readers and instance variables
54
+ data_definition_node.attributes.each do |attribute_node, attribute_name|
55
+ name = attribute_name.to_s
56
+ method_pin = Pin::Method.new(
57
+ name: name,
58
+ parameters: [],
59
+ scope: :instance,
60
+ location: get_node_location(attribute_node),
61
+ closure: nspin,
62
+ comments: attribute_comments(attribute_node, attribute_name),
63
+ visibility: :public
64
+ )
65
+
66
+ pins.push method_pin
67
+
68
+ pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
69
+ closure: method_pin,
70
+ location: get_node_location(attribute_node),
71
+ comments: attribute_comments(attribute_node, attribute_name))
72
+ end
73
+
74
+ process_children region.update(closure: nspin, visibility: :public)
75
+
76
+ false
77
+ end
78
+
79
+ private
80
+
81
+ # @return [DataDefintionNode, nil]
82
+ def data_definition_node
83
+ @data_definition_node ||= if DataDefintionNode.match?(node)
84
+ DataDefintionNode.new(node)
85
+ elsif DataAssignmentNode.match?(node)
86
+ DataAssignmentNode.new(node)
87
+ end
88
+ end
89
+
90
+ # @param attribute_node [Parser::AST::Node]
91
+ # @param attribute_name [String]
92
+ # @return [String, nil]
93
+ def attribute_comments(attribute_node, attribute_name)
94
+ data_comments = comments_for(attribute_node)
95
+ return if data_comments.nil? || data_comments.empty?
96
+
97
+ data_comments.split("\n").find do |row|
98
+ row.include?(attribute_name)
99
+ end&.gsub('@param', '@return')&.gsub(attribute_name, '')
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -4,7 +4,7 @@ module Solargraph
4
4
  module Convention
5
5
  class Gemspec < Base
6
6
  def local source_map
7
- return EMPTY_ENVIRON unless File.basename(source_map.filename).end_with?('.gemspec')
7
+ return Convention::Base::EMPTY_ENVIRON unless File.basename(source_map.filename).end_with?('.gemspec')
8
8
  @environ ||= Environ.new(
9
9
  requires: ['rubygems'],
10
10
  pins: [
@@ -12,7 +12,8 @@ module Solargraph
12
12
  'Gem::Specification.new',
13
13
  %(
14
14
  @yieldparam [self]
15
- )
15
+ ),
16
+ source: :gemspec
16
17
  )
17
18
  ]
18
19
  )
@@ -22,7 +22,8 @@ module Solargraph
22
22
  # s(:def, :foo,
23
23
  # s(:args),
24
24
  # s(:send, nil, :bar))))
25
- def valid?(node)
25
+ # @param node [Parser::AST::Node]
26
+ def match?(node)
26
27
  return false unless node&.type == :casgn
27
28
  return false if node.children[2].nil?
28
29
 
@@ -25,7 +25,9 @@ module Solargraph
25
25
  # s(:def, :foo,
26
26
  # s(:args),
27
27
  # s(:send, nil, :bar)))
28
- def valid?(node)
28
+ #
29
+ # @param node [Parser::AST::Node]
30
+ def match?(node)
29
31
  return false unless node&.type == :class
30
32
 
31
33
  struct_definition_node?(node.children[1])
@@ -46,7 +48,7 @@ module Solargraph
46
48
  end
47
49
  end
48
50
 
49
- # @return [Parser::AST::Node]
51
+ # @param node [Parser::AST::Node]
50
52
  def initialize(node)
51
53
  @node = node
52
54
  end