solargraph 0.56.2 → 0.58.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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +127 -0
  3. data/.github/workflows/plugins.yml +183 -7
  4. data/.github/workflows/rspec.yml +55 -5
  5. data/.github/workflows/typecheck.yml +6 -3
  6. data/.gitignore +5 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +1279 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +69 -0
  13. data/README.md +8 -4
  14. data/Rakefile +125 -13
  15. data/bin/solargraph +8 -5
  16. data/lib/solargraph/api_map/cache.rb +3 -2
  17. data/lib/solargraph/api_map/constants.rb +279 -0
  18. data/lib/solargraph/api_map/index.rb +49 -31
  19. data/lib/solargraph/api_map/source_to_yard.rb +13 -4
  20. data/lib/solargraph/api_map/store.rb +144 -26
  21. data/lib/solargraph/api_map.rb +217 -245
  22. data/lib/solargraph/bench.rb +1 -0
  23. data/lib/solargraph/complex_type/type_methods.rb +6 -0
  24. data/lib/solargraph/complex_type/unique_type.rb +19 -12
  25. data/lib/solargraph/complex_type.rb +24 -3
  26. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  27. data/lib/solargraph/convention/base.rb +17 -0
  28. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -0
  29. data/lib/solargraph/convention/data_definition/data_definition_node.rb +4 -2
  30. data/lib/solargraph/convention/data_definition.rb +2 -1
  31. data/lib/solargraph/convention/gemspec.rb +1 -1
  32. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
  33. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +3 -1
  34. data/lib/solargraph/convention/struct_definition.rb +36 -13
  35. data/lib/solargraph/convention.rb +31 -2
  36. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  37. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  38. data/lib/solargraph/doc_map.rb +44 -13
  39. data/lib/solargraph/environ.rb +9 -2
  40. data/lib/solargraph/equality.rb +1 -0
  41. data/lib/solargraph/gem_pins.rb +21 -11
  42. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  43. data/lib/solargraph/language_server/host/message_worker.rb +3 -0
  44. data/lib/solargraph/language_server/host.rb +12 -5
  45. data/lib/solargraph/language_server/message/base.rb +2 -1
  46. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
  47. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/text_document/formatting.rb +19 -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 +4 -1
  53. data/lib/solargraph/library.rb +11 -18
  54. data/lib/solargraph/location.rb +3 -0
  55. data/lib/solargraph/logging.rb +11 -2
  56. data/lib/solargraph/page.rb +3 -0
  57. data/lib/solargraph/parser/comment_ripper.rb +8 -1
  58. data/lib/solargraph/parser/flow_sensitive_typing.rb +33 -5
  59. data/lib/solargraph/parser/node_processor/base.rb +1 -1
  60. data/lib/solargraph/parser/node_processor.rb +6 -2
  61. data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -13
  62. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  63. data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
  64. data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -16
  65. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +1 -0
  66. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
  67. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
  68. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -0
  69. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +64 -8
  70. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +12 -3
  71. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +36 -16
  72. data/lib/solargraph/parser/region.rb +3 -0
  73. data/lib/solargraph/parser/snippet.rb +2 -0
  74. data/lib/solargraph/pin/base.rb +77 -14
  75. data/lib/solargraph/pin/base_variable.rb +6 -5
  76. data/lib/solargraph/pin/block.rb +3 -2
  77. data/lib/solargraph/pin/callable.rb +14 -1
  78. data/lib/solargraph/pin/closure.rb +5 -7
  79. data/lib/solargraph/pin/common.rb +6 -2
  80. data/lib/solargraph/pin/constant.rb +2 -0
  81. data/lib/solargraph/pin/local_variable.rb +1 -2
  82. data/lib/solargraph/pin/method.rb +28 -9
  83. data/lib/solargraph/pin/method_alias.rb +3 -0
  84. data/lib/solargraph/pin/parameter.rb +24 -10
  85. data/lib/solargraph/pin/proxy_type.rb +5 -1
  86. data/lib/solargraph/pin/reference/override.rb +15 -1
  87. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  88. data/lib/solargraph/pin/reference.rb +17 -0
  89. data/lib/solargraph/pin/search.rb +6 -1
  90. data/lib/solargraph/pin/signature.rb +2 -0
  91. data/lib/solargraph/pin/symbol.rb +5 -0
  92. data/lib/solargraph/pin_cache.rb +64 -4
  93. data/lib/solargraph/position.rb +3 -0
  94. data/lib/solargraph/range.rb +5 -0
  95. data/lib/solargraph/rbs_map/conversions.rb +29 -6
  96. data/lib/solargraph/rbs_map/core_fills.rb +18 -0
  97. data/lib/solargraph/rbs_map/core_map.rb +14 -7
  98. data/lib/solargraph/rbs_map.rb +14 -1
  99. data/lib/solargraph/shell.rb +85 -1
  100. data/lib/solargraph/source/chain/call.rb +7 -3
  101. data/lib/solargraph/source/chain/constant.rb +3 -66
  102. data/lib/solargraph/source/chain/if.rb +1 -1
  103. data/lib/solargraph/source/chain/link.rb +11 -2
  104. data/lib/solargraph/source/chain/or.rb +1 -1
  105. data/lib/solargraph/source/chain.rb +11 -2
  106. data/lib/solargraph/source/change.rb +2 -2
  107. data/lib/solargraph/source/cursor.rb +2 -3
  108. data/lib/solargraph/source/source_chainer.rb +1 -1
  109. data/lib/solargraph/source.rb +6 -3
  110. data/lib/solargraph/source_map/clip.rb +18 -26
  111. data/lib/solargraph/source_map/data.rb +4 -0
  112. data/lib/solargraph/source_map/mapper.rb +2 -2
  113. data/lib/solargraph/source_map.rb +28 -16
  114. data/lib/solargraph/type_checker/param_def.rb +2 -0
  115. data/lib/solargraph/type_checker/rules.rb +30 -8
  116. data/lib/solargraph/type_checker.rb +301 -186
  117. data/lib/solargraph/version.rb +1 -1
  118. data/lib/solargraph/workspace/config.rb +21 -5
  119. data/lib/solargraph/workspace/require_paths.rb +97 -0
  120. data/lib/solargraph/workspace.rb +30 -67
  121. data/lib/solargraph/yard_map/mapper/to_method.rb +4 -3
  122. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  123. data/lib/solargraph/yard_map/to_method.rb +2 -1
  124. data/lib/solargraph/yardoc.rb +39 -3
  125. data/lib/solargraph.rb +2 -0
  126. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  127. data/rbs/fills/open3/0/open3.rbs +172 -0
  128. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  129. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  130. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  131. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  132. data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +2 -3
  133. data/rbs_collection.yaml +4 -4
  134. data/sig/shims/ast/0/node.rbs +5 -0
  135. data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
  136. data/sig/shims/ast/2.4/ast.rbs +73 -0
  137. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  138. data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
  139. data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
  140. data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  141. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  142. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  143. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  144. data/solargraph.gemspec +26 -5
  145. metadata +181 -13
  146. data/lib/.rubocop.yml +0 -22
  147. 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
@@ -22,6 +22,7 @@ module Solargraph
22
22
  # s(:def, :foo,
23
23
  # s(:args),
24
24
  # s(:send, nil, :bar))))
25
+ # @param node [::Parser::AST::Node]
25
26
  def match?(node)
26
27
  return false unless node&.type == :casgn
27
28
  return false if node.children[2].nil?
@@ -25,6 +25,8 @@ module Solargraph
25
25
  # s(:def, :foo,
26
26
  # s(:args),
27
27
  # s(:send, nil, :bar)))
28
+ #
29
+ # @param node [Parser::AST::Node]
28
30
  def match?(node)
29
31
  return false unless node&.type == :class
30
32
 
@@ -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
@@ -74,7 +76,7 @@ module Solargraph
74
76
  # @return [Parser::AST::Node]
75
77
  attr_reader :node
76
78
 
77
- # @return [Parser::AST::Node]
79
+ # @return [Parser::AST::Node, nil]
78
80
  def data_node
79
81
  node.children[1]
80
82
  end
@@ -35,7 +35,7 @@ module Solargraph
35
35
  comments: comments_for(node)
36
36
  )
37
37
 
38
- # TODO: Support both arg and kwarg initializers for Data.define
38
+ # @todo Support both arg and kwarg initializers for Data.define
39
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
40
  pins.push initialize_method_pin
41
41
 
@@ -88,6 +88,7 @@ module Solargraph
88
88
  end
89
89
 
90
90
  # @param attribute_node [Parser::AST::Node]
91
+ # @param attribute_name [String]
91
92
  # @return [String, nil]
92
93
  def attribute_comments(attribute_node, attribute_name)
93
94
  data_comments = comments_for(attribute_node)
@@ -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: [
@@ -22,6 +22,7 @@ module Solargraph
22
22
  # s(:def, :foo,
23
23
  # s(:args),
24
24
  # s(:send, nil, :bar))))
25
+ # @param node [Parser::AST::Node]
25
26
  def match?(node)
26
27
  return false unless node&.type == :casgn
27
28
  return false if node.children[2].nil?
@@ -25,6 +25,8 @@ module Solargraph
25
25
  # s(:def, :foo,
26
26
  # s(:args),
27
27
  # s(:send, nil, :bar)))
28
+ #
29
+ # @param node [Parser::AST::Node]
28
30
  def match?(node)
29
31
  return false unless node&.type == :class
30
32
 
@@ -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
@@ -20,7 +20,8 @@ module Solargraph
20
20
  name: struct_definition_node.class_name,
21
21
  docstring: docstring,
22
22
  visibility: :public,
23
- gates: region.closure.gates.freeze
23
+ gates: region.closure.gates.freeze,
24
+ source: :struct_definition
24
25
  )
25
26
  pins.push nspin
26
27
 
@@ -32,7 +33,8 @@ module Solargraph
32
33
  location: get_node_location(node),
33
34
  closure: nspin,
34
35
  visibility: :private,
35
- docstring: docstring
36
+ docstring: docstring,
37
+ source: :struct_definition
36
38
  )
37
39
 
38
40
  pins.push initialize_method_pin
@@ -43,7 +45,8 @@ module Solargraph
43
45
  name: attribute_name,
44
46
  decl: struct_definition_node.keyword_init? ? :kwarg : :arg,
45
47
  location: get_node_location(attribute_node),
46
- closure: initialize_method_pin
48
+ closure: initialize_method_pin,
49
+ source: :struct_definition
47
50
  )
48
51
  )
49
52
  end
@@ -53,29 +56,40 @@ module Solargraph
53
56
  [attribute_name, "#{attribute_name}="].each do |name|
54
57
  docs = docstring.tags.find { |t| t.tag_name == 'param' && t.name == attribute_name }
55
58
 
59
+ attribute_type = ComplexType.parse(tag_string(docs))
60
+ return_type_comment = attribute_comment(docs, false)
61
+ param_comment = attribute_comment(docs, true)
62
+
56
63
  method_pin = Pin::Method.new(
57
64
  name: name,
58
65
  parameters: [],
59
66
  scope: :instance,
60
67
  location: get_node_location(attribute_node),
61
68
  closure: nspin,
69
+ docstring: YARD::Docstring.new(return_type_comment),
62
70
  # even assignments return the value
63
- comments: attribute_comment(docs, false),
64
- visibility: :public
71
+ comments: return_type_comment,
72
+ return_type: attribute_type,
73
+ visibility: :public,
74
+ source: :struct_definition
65
75
  )
66
76
 
67
77
  if name.end_with?('=')
68
78
  method_pin.parameters << Pin::Parameter.new(
69
79
  name: attribute_name,
70
80
  location: get_node_location(attribute_node),
71
- closure: nspin,
72
- comments: attribute_comment(docs, true)
81
+ closure: method_pin,
82
+ return_type: attribute_type,
83
+ comments: param_comment,
84
+ source: :struct_definition
73
85
  )
74
86
 
75
87
  pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
76
- closure: method_pin,
77
- location: get_node_location(attribute_node),
78
- comments: attribute_comment(docs, false))
88
+ closure: method_pin,
89
+ location: get_node_location(attribute_node),
90
+ return_type: attribute_type,
91
+ comments: "@type [#{attribute_type.rooted_tags}]",
92
+ source: :struct_definition)
79
93
  end
80
94
 
81
95
  pins.push method_pin
@@ -88,7 +102,7 @@ module Solargraph
88
102
 
89
103
  private
90
104
 
91
- # @return [StructDefintionNode, nil]
105
+ # @return [StructDefintionNode, StructAssignmentNode, nil]
92
106
  def struct_definition_node
93
107
  @struct_definition_node ||= if StructDefintionNode.match?(node)
94
108
  StructDefintionNode.new(node)
@@ -113,7 +127,7 @@ module Solargraph
113
127
 
114
128
  # We should support specific comments for an attribute, and that can be either a @return on an @param
115
129
  # But since we merge into the struct_comments, then we should interpret either as a param
116
- comment = '@param ' + attr_name + comment[7..] if comment.start_with?('@return')
130
+ comment = "@param #{attr_name}#{comment[7..]}" if comment.start_with?('@return')
117
131
 
118
132
  struct_comments += "\n#{comment}"
119
133
  end
@@ -121,12 +135,21 @@ module Solargraph
121
135
  Solargraph::Source.parse_docstring(struct_comments).to_docstring
122
136
  end
123
137
 
138
+ # @param tag [YARD::Tags::Tag, nil] The param tag for this attribute.xtract_
139
+ #
140
+ # @return [String]
141
+ def tag_string(tag)
142
+ tag&.types&.join(',') || 'undefined'
143
+ end
144
+
124
145
  # @param tag [YARD::Tags::Tag, nil] The param tag for this attribute. If nil, this method is a no-op
125
146
  # @param for_setter [Boolean] If true, will return a @param tag instead of a @return tag
147
+ #
148
+ # @return [String] The formatted comment for the attribute
126
149
  def attribute_comment(tag, for_setter)
127
150
  return "" if tag.nil?
128
151
 
129
- suffix = "[#{tag.types&.join(',') || 'undefined'}] #{tag.text}"
152
+ suffix = "[#{tag_string(tag)}] #{tag.text}"
130
153
 
131
154
  if for_setter
132
155
  "@param #{tag.name} #{suffix}"
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  module Solargraph
5
4
  # Conventions provide a way to modify an ApiMap based on expectations about
6
5
  # one of its sources.
@@ -12,6 +11,7 @@ module Solargraph
12
11
  autoload :Rakefile, 'solargraph/convention/rakefile'
13
12
  autoload :StructDefinition, 'solargraph/convention/struct_definition'
14
13
  autoload :DataDefinition, 'solargraph/convention/data_definition'
14
+ autoload :ActiveSupportConcern, 'solargraph/convention/active_support_concern'
15
15
 
16
16
  # @type [Set<Convention::Base>]
17
17
  @@conventions = Set.new
@@ -22,6 +22,12 @@ module Solargraph
22
22
  @@conventions.add convention.new
23
23
  end
24
24
 
25
+ # @param convention [Class<Convention::Base>]
26
+ # @return [void]
27
+ def self.unregister convention
28
+ @@conventions.delete_if { |c| c.is_a?(convention) }
29
+ end
30
+
25
31
  # @param source_map [SourceMap]
26
32
  # @return [Environ]
27
33
  def self.for_local(source_map)
@@ -32,7 +38,7 @@ module Solargraph
32
38
  result
33
39
  end
34
40
 
35
- # @param yard_map [DocMap]
41
+ # @param doc_map [DocMap]
36
42
  # @return [Environ]
37
43
  def self.for_global(doc_map)
38
44
  result = Environ.new
@@ -42,8 +48,31 @@ module Solargraph
42
48
  result
43
49
  end
44
50
 
51
+ # Provides any additional method pins based on the described object.
52
+ #
53
+ # @param api_map [ApiMap]
54
+ # @param rooted_tag [String] A fully qualified namespace, with
55
+ # generic parameter values if applicable
56
+ # @param scope [Symbol] :class or :instance
57
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
58
+ # @param deep [Boolean]
59
+ # @param skip [Set<String>]
60
+ # @param no_core [Boolean] Skip core classes if true
61
+ #
62
+ # @return [Environ]
63
+ def self.for_object api_map, rooted_tag, scope, visibility,
64
+ deep, skip, no_core
65
+ result = Environ.new
66
+ @@conventions.each do |conv|
67
+ result.merge conv.object(api_map, rooted_tag, scope, visibility,
68
+ deep, skip, no_core)
69
+ end
70
+ result
71
+ end
72
+
45
73
  register Gemfile
46
74
  register Gemspec
47
75
  register Rakefile
76
+ register ActiveSupportConcern
48
77
  end
49
78
  end
@@ -28,7 +28,12 @@ module Solargraph
28
28
  options, paths = generate_options(source.filename, source.code)
29
29
  store = RuboCop::ConfigStore.new
30
30
  runner = RuboCop::Runner.new(options, store)
31
- result = redirect_stdout{ runner.run(paths) }
31
+ # Ensure only one instance of RuboCop::Runner is running at
32
+ # a time - it uses 'chdir' to read config files with ERB,
33
+ # which can conflict with other chdirs.
34
+ result = Solargraph::CHDIR_MUTEX.synchronize do
35
+ redirect_stdout{ runner.run(paths) }
36
+ end
32
37
 
33
38
  return [] if result.empty?
34
39