solargraph 0.61.0 → 0.62.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +24 -2
  3. data/.github/workflows/plugins.yml +18 -0
  4. data/.github/workflows/rspec.yml +14 -1
  5. data/.github/workflows/typecheck.yml +6 -0
  6. data/CHANGELOG.md +38 -0
  7. data/lib/solargraph/api_map/index.rb +14 -3
  8. data/lib/solargraph/api_map/store.rb +6 -0
  9. data/lib/solargraph/api_map.rb +34 -2
  10. data/lib/solargraph/collection/gem.rb +12 -10
  11. data/lib/solargraph/collection.rb +0 -1
  12. data/lib/solargraph/complex_type/unique_type.rb +13 -0
  13. data/lib/solargraph/complex_type.rb +23 -3
  14. data/lib/solargraph/convention.rb +0 -4
  15. data/lib/solargraph/diagnostics/type_check.rb +0 -1
  16. data/lib/solargraph/external.rb +56 -28
  17. data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
  18. data/lib/solargraph/language_server/host/dispatch.rb +4 -2
  19. data/lib/solargraph/language_server/host.rb +10 -2
  20. data/lib/solargraph/language_server/message/completion_item/resolve.rb +10 -3
  21. data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
  22. data/lib/solargraph/library.rb +19 -33
  23. data/lib/solargraph/parser/node_processor/base.rb +6 -0
  24. data/lib/solargraph/parser/parser_gem/node_methods.rb +29 -6
  25. data/lib/solargraph/parser/parser_gem/node_processors/class_definition/class_assignment_node.rb +98 -0
  26. data/lib/solargraph/parser/parser_gem/node_processors/class_definition.rb +54 -0
  27. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +1 -0
  28. data/lib/solargraph/parser/parser_gem/node_processors/data_definition/data_assignment_node.rb +65 -0
  29. data/lib/solargraph/parser/parser_gem/node_processors/data_definition/data_definition_node.rb +97 -0
  30. data/lib/solargraph/parser/parser_gem/node_processors/data_definition.rb +110 -0
  31. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +1 -0
  32. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +2 -0
  33. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  34. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +185 -0
  35. data/lib/solargraph/parser/parser_gem/node_processors/struct_definition/struct_assignment_node.rb +66 -0
  36. data/lib/solargraph/parser/parser_gem/node_processors/struct_definition/struct_definition_node.rb +108 -0
  37. data/lib/solargraph/parser/parser_gem/node_processors/struct_definition.rb +170 -0
  38. data/lib/solargraph/parser/parser_gem/node_processors.rb +33 -29
  39. data/lib/solargraph/pin/base.rb +25 -1
  40. data/lib/solargraph/pin/base_variable.rb +31 -1
  41. data/lib/solargraph/pin/callable.rb +11 -2
  42. data/lib/solargraph/pin/delegated_method.rb +5 -0
  43. data/lib/solargraph/pin/duck_method.rb +36 -16
  44. data/lib/solargraph/pin/instance_variable.rb +45 -0
  45. data/lib/solargraph/pin/method.rb +10 -0
  46. data/lib/solargraph/pin/method_alias.rb +4 -0
  47. data/lib/solargraph/pin/parameter.rb +1 -1
  48. data/lib/solargraph/pin/reference/included_mixin.rb +22 -0
  49. data/lib/solargraph/pin/reference.rb +1 -0
  50. data/lib/solargraph/plugin/active_support.rb +100 -0
  51. data/lib/solargraph/plugin/addon.rb +16 -0
  52. data/lib/solargraph/plugin/base.rb +25 -0
  53. data/lib/solargraph/plugin/panel.rb +37 -0
  54. data/lib/solargraph/plugin.rb +26 -0
  55. data/lib/solargraph/rbs_collection.rb +119 -0
  56. data/lib/solargraph/rbs_map/conversions.rb +106 -47
  57. data/lib/solargraph/rbs_map/gem.rb +4 -1
  58. data/lib/solargraph/rbs_map/helpers.rb +7 -6
  59. data/lib/solargraph/rbs_translator.rb +105 -70
  60. data/lib/solargraph/repo.rb +1 -1
  61. data/lib/solargraph/source/chain/call.rb +32 -13
  62. data/lib/solargraph/source/node_map.rb +27 -0
  63. data/lib/solargraph/source.rb +17 -0
  64. data/lib/solargraph/source_map/call.rb +18 -0
  65. data/lib/solargraph/source_map/mapper.rb +1 -1
  66. data/lib/solargraph/source_map.rb +18 -4
  67. data/lib/solargraph/type_checker/rules.rb +2 -2
  68. data/lib/solargraph/type_checker.rb +4 -1
  69. data/lib/solargraph/version.rb +1 -1
  70. data/lib/solargraph/yard_map/macro.rb +51 -1
  71. data/lib/solargraph.rb +2 -0
  72. data/rbs/fills/boolean/0/boolean.rbs +12 -0
  73. data/solargraph.gemspec +1 -1
  74. metadata +21 -11
  75. data/lib/solargraph/collection/rbs.rb +0 -49
  76. data/lib/solargraph/convention/active_support_concern.rb +0 -111
  77. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +0 -61
  78. data/lib/solargraph/convention/data_definition/data_definition_node.rb +0 -93
  79. data/lib/solargraph/convention/data_definition.rb +0 -108
  80. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +0 -62
  81. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +0 -103
  82. data/lib/solargraph/convention/struct_definition.rb +0 -168
@@ -6,31 +6,34 @@ module Solargraph
6
6
  module Parser
7
7
  module ParserGem
8
8
  module NodeProcessors
9
- autoload :BeginNode, 'solargraph/parser/parser_gem/node_processors/begin_node'
10
- autoload :DefNode, 'solargraph/parser/parser_gem/node_processors/def_node'
11
- autoload :DefsNode, 'solargraph/parser/parser_gem/node_processors/defs_node'
12
- autoload :SendNode, 'solargraph/parser/parser_gem/node_processors/send_node'
13
- autoload :NamespaceNode, 'solargraph/parser/parser_gem/node_processors/namespace_node'
14
- autoload :SclassNode, 'solargraph/parser/parser_gem/node_processors/sclass_node'
15
- autoload :IvasgnNode, 'solargraph/parser/parser_gem/node_processors/ivasgn_node'
16
- autoload :IfNode, 'solargraph/parser/parser_gem/node_processors/if_node'
17
- autoload :CvasgnNode, 'solargraph/parser/parser_gem/node_processors/cvasgn_node'
18
- autoload :LvasgnNode, 'solargraph/parser/parser_gem/node_processors/lvasgn_node'
19
- autoload :GvasgnNode, 'solargraph/parser/parser_gem/node_processors/gvasgn_node'
20
- autoload :CasgnNode, 'solargraph/parser/parser_gem/node_processors/casgn_node'
21
- autoload :MasgnNode, 'solargraph/parser/parser_gem/node_processors/masgn_node'
22
- autoload :AliasNode, 'solargraph/parser/parser_gem/node_processors/alias_node'
23
- autoload :ArgsNode, 'solargraph/parser/parser_gem/node_processors/args_node'
24
- autoload :BlockNode, 'solargraph/parser/parser_gem/node_processors/block_node'
25
- autoload :OrasgnNode, 'solargraph/parser/parser_gem/node_processors/orasgn_node'
26
- autoload :OpasgnNode, 'solargraph/parser/parser_gem/node_processors/opasgn_node'
27
- autoload :SymNode, 'solargraph/parser/parser_gem/node_processors/sym_node'
28
- autoload :ResbodyNode, 'solargraph/parser/parser_gem/node_processors/resbody_node'
29
- autoload :UntilNode, 'solargraph/parser/parser_gem/node_processors/until_node'
30
- autoload :WhenNode, 'solargraph/parser/parser_gem/node_processors/when_node'
31
- autoload :WhileNode, 'solargraph/parser/parser_gem/node_processors/while_node'
32
- autoload :AndNode, 'solargraph/parser/parser_gem/node_processors/and_node'
33
- autoload :OrNode, 'solargraph/parser/parser_gem/node_processors/or_node'
9
+ autoload :BeginNode, 'solargraph/parser/parser_gem/node_processors/begin_node'
10
+ autoload :DefNode, 'solargraph/parser/parser_gem/node_processors/def_node'
11
+ autoload :DefsNode, 'solargraph/parser/parser_gem/node_processors/defs_node'
12
+ autoload :SendNode, 'solargraph/parser/parser_gem/node_processors/send_node'
13
+ autoload :NamespaceNode, 'solargraph/parser/parser_gem/node_processors/namespace_node'
14
+ autoload :SclassNode, 'solargraph/parser/parser_gem/node_processors/sclass_node'
15
+ autoload :IvasgnNode, 'solargraph/parser/parser_gem/node_processors/ivasgn_node'
16
+ autoload :IfNode, 'solargraph/parser/parser_gem/node_processors/if_node'
17
+ autoload :CvasgnNode, 'solargraph/parser/parser_gem/node_processors/cvasgn_node'
18
+ autoload :LvasgnNode, 'solargraph/parser/parser_gem/node_processors/lvasgn_node'
19
+ autoload :GvasgnNode, 'solargraph/parser/parser_gem/node_processors/gvasgn_node'
20
+ autoload :CasgnNode, 'solargraph/parser/parser_gem/node_processors/casgn_node'
21
+ autoload :MasgnNode, 'solargraph/parser/parser_gem/node_processors/masgn_node'
22
+ autoload :AliasNode, 'solargraph/parser/parser_gem/node_processors/alias_node'
23
+ autoload :ArgsNode, 'solargraph/parser/parser_gem/node_processors/args_node'
24
+ autoload :BlockNode, 'solargraph/parser/parser_gem/node_processors/block_node'
25
+ autoload :OrasgnNode, 'solargraph/parser/parser_gem/node_processors/orasgn_node'
26
+ autoload :OpasgnNode, 'solargraph/parser/parser_gem/node_processors/opasgn_node'
27
+ autoload :SymNode, 'solargraph/parser/parser_gem/node_processors/sym_node'
28
+ autoload :ResbodyNode, 'solargraph/parser/parser_gem/node_processors/resbody_node'
29
+ autoload :UntilNode, 'solargraph/parser/parser_gem/node_processors/until_node'
30
+ autoload :WhenNode, 'solargraph/parser/parser_gem/node_processors/when_node'
31
+ autoload :WhileNode, 'solargraph/parser/parser_gem/node_processors/while_node'
32
+ autoload :AndNode, 'solargraph/parser/parser_gem/node_processors/and_node'
33
+ autoload :OrNode, 'solargraph/parser/parser_gem/node_processors/or_node'
34
+ autoload :ClassDefinition, 'solargraph/parser/parser_gem/node_processors/class_definition'
35
+ autoload :StructDefinition, 'solargraph/parser/parser_gem/node_processors/struct_definition'
36
+ autoload :DataDefinition, 'solargraph/parser/parser_gem/node_processors/data_definition'
34
37
  end
35
38
  end
36
39
 
@@ -44,8 +47,8 @@ module Solargraph
44
47
  register :defs, ParserGem::NodeProcessors::DefsNode
45
48
  register :if, ParserGem::NodeProcessors::IfNode
46
49
  register :send, ParserGem::NodeProcessors::SendNode
47
- register :class, Convention::StructDefinition::NodeProcessors::StructNode
48
- register :class, Convention::DataDefinition::NodeProcessors::DataNode
50
+ register :class, ParserGem::NodeProcessors::StructDefinition::StructNode
51
+ register :class, ParserGem::NodeProcessors::DataDefinition::DataNode
49
52
  register :class, ParserGem::NodeProcessors::NamespaceNode
50
53
  register :module, ParserGem::NodeProcessors::NamespaceNode
51
54
  register :sclass, ParserGem::NodeProcessors::SclassNode
@@ -53,8 +56,9 @@ module Solargraph
53
56
  register :cvasgn, ParserGem::NodeProcessors::CvasgnNode
54
57
  register :lvasgn, ParserGem::NodeProcessors::LvasgnNode
55
58
  register :gvasgn, ParserGem::NodeProcessors::GvasgnNode
56
- register :casgn, Convention::StructDefinition::NodeProcessors::StructNode
57
- register :casgn, Convention::DataDefinition::NodeProcessors::DataNode
59
+ register :casgn, ParserGem::NodeProcessors::StructDefinition::StructNode
60
+ register :casgn, ParserGem::NodeProcessors::DataDefinition::DataNode
61
+ register :casgn, ParserGem::NodeProcessors::ClassDefinition::ClassNode
58
62
  register :casgn, ParserGem::NodeProcessors::CasgnNode
59
63
  register :masgn, ParserGem::NodeProcessors::MasgnNode
60
64
  register :alias, ParserGem::NodeProcessors::AliasNode
@@ -158,7 +158,17 @@ module Solargraph
158
158
  # @param other [self]
159
159
  # @return [Pin::Closure, nil]
160
160
  def combine_closure other
161
- choose_pin_attr_with_same_name(other, :closure)
161
+ chosen = choose_pin_attr_with_same_name(other, :closure)
162
+ return chosen unless chosen.is_a?(Pin::Namespace) && chosen.generics.empty?
163
+
164
+ # Combined types may name type parameters only the other closure declares
165
+ own = closure
166
+ return own if own.is_a?(Pin::Namespace) && !own.generics.empty?
167
+
168
+ theirs = other.closure
169
+ return theirs if theirs.is_a?(Pin::Namespace) && !theirs.generics.empty?
170
+
171
+ chosen
162
172
  end
163
173
 
164
174
  # @param other [self]
@@ -435,6 +445,7 @@ module Solargraph
435
445
  # @param context_type [ComplexType] The receiver type
436
446
  # @return [self]
437
447
  def resolve_generics definitions, context_type
448
+ definitions = declaring_definitions(definitions)
438
449
  transform_types { |t| t&.resolve_generics(definitions, context_type) }
439
450
  end
440
451
 
@@ -731,6 +742,19 @@ module Solargraph
731
742
 
732
743
  private
733
744
 
745
+ # Declarations of a reopened generic may spell its parameters
746
+ # differently, so bind by position against this pin's own one.
747
+ #
748
+ # @param definitions [Pin::Namespace, nil]
749
+ # @return [Pin::Namespace, nil]
750
+ def declaring_definitions definitions
751
+ own = closure
752
+ return definitions unless definitions.is_a?(Pin::Namespace) && own.is_a?(Pin::Namespace)
753
+ return definitions unless own.path == definitions.path && !own.generics.empty?
754
+
755
+ own
756
+ end
757
+
734
758
  # @return [void]
735
759
  def parse_comments
736
760
  # HACK: Avoid a NoMethodError on nil with empty overload tags
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rbs'
4
+
3
5
  module Solargraph
4
6
  module Pin
5
7
  class BaseVariable < Base
@@ -14,6 +16,9 @@ module Solargraph
14
16
  # @return [Range, nil]
15
17
  attr_reader :presence
16
18
 
19
+ # @return [String, nil]
20
+ attr_reader :type_assertion
21
+
17
22
  # @param return_type [ComplexType, nil]
18
23
  # @param assignment [Parser::AST::Node, nil] First assignment
19
24
  # that was made to this variable
@@ -45,12 +50,16 @@ module Solargraph
45
50
  # @see https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types
46
51
  # @see https://en.wikipedia.org/wiki/Intersection_type#TypeScript_example
47
52
  # @param presence [Range, nil]
53
+ # @param type_assertion [String, nil] RBS type from a trailing
54
+ # rbs-inline `#: TYPE` comment on the assignment
48
55
  # @param [Hash{Symbol => Object}] splat
49
56
  def initialize assignment: nil, assignments: [], mass_assignment: nil,
50
57
  presence: nil, return_type: nil,
51
58
  intersection_return_type: nil, exclude_return_type: nil,
59
+ type_assertion: nil,
52
60
  **splat
53
61
  super(**splat)
62
+ @type_assertion = type_assertion
54
63
  @assignments = (assignment.nil? ? [] : [assignment]) + assignments
55
64
  # @type [nil, ::Array(Parser::AST::Node, Integer)]
56
65
  @mass_assignment = mass_assignment
@@ -95,7 +104,8 @@ module Solargraph
95
104
  return_type: combine_return_type(other),
96
105
  intersection_return_type: combine_types(other, :intersection_return_type),
97
106
  exclude_return_type: combine_types(other, :exclude_return_type),
98
- presence: combine_presence(other)
107
+ presence: combine_presence(other),
108
+ type_assertion: choose(other, :type_assertion)
99
109
  })
100
110
  super(other, new_attrs)
101
111
  end
@@ -170,6 +180,9 @@ module Solargraph
170
180
  end
171
181
  end
172
182
  types
183
+ rescue FileNotFoundError
184
+ # @todo Necessary for pins from source maps that are not part of the workspace
185
+ [ComplexType::UNDEFINED]
173
186
  end
174
187
 
175
188
  # @param api_map [ApiMap]
@@ -364,12 +377,29 @@ module Solargraph
364
377
  :instance
365
378
  end
366
379
 
380
+ # An rbs-inline type assertion takes precedence over a @type tag,
381
+ # as inline RBS method signatures do over YARD tags.
382
+ #
367
383
  # @return [ComplexType, nil]
368
384
  def generate_complex_type
385
+ asserted = type_from_assertion
386
+ return asserted unless asserted.nil?
369
387
  tag = docstring.tag(:type)
370
388
  return ComplexType.try_parse(*tag.types) unless tag.nil? || tag.types.nil? || tag.types.empty?
371
389
  nil
372
390
  end
391
+
392
+ # @return [ComplexType, nil]
393
+ def type_from_assertion
394
+ assertion = type_assertion
395
+ return nil if assertion.nil? || assertion.empty?
396
+ @type_from_assertion ||= begin
397
+ rbs_type = RBS::Parser.parse_type(assertion, require_eof: true)
398
+ RbsTranslator.to_complex_type(rbs_type) unless rbs_type.nil?
399
+ rescue RBS::ParsingError
400
+ nil
401
+ end
402
+ end
373
403
  end
374
404
  end
375
405
  end
@@ -14,12 +14,15 @@ module Solargraph
14
14
  # @param block [Signature, nil]
15
15
  # @param return_type [ComplexType, nil]
16
16
  # @param parameters [::Array<Pin::Parameter>]
17
+ # @param block_required [Boolean] Whether callers must pass a block, per
18
+ # an RBS non-optional block (`{ ... }` rather than `?{ ... }`).
17
19
  # @param [Hash{Symbol => Object}] splat
18
- def initialize block: nil, return_type: nil, parameters: [], **splat
20
+ def initialize block: nil, return_type: nil, parameters: [], block_required: false, **splat
19
21
  super(**splat)
20
22
  @block = block
21
23
  @return_type = return_type
22
24
  @parameters = parameters
25
+ @block_required = block_required
23
26
  end
24
27
 
25
28
  def reset_generated!
@@ -55,6 +58,7 @@ module Solargraph
55
58
  def combine_with other, attrs = {}
56
59
  new_attrs = {
57
60
  block: combine_blocks(other),
61
+ block_required: block_required? || other.block_required?,
58
62
  return_type: combine_return_type(other)
59
63
  }.merge(attrs)
60
64
  new_attrs[:parameters] = choose_parameters(other).clone.freeze unless new_attrs.key?(:parameters)
@@ -241,7 +245,7 @@ module Solargraph
241
245
  argcount = arguments.length
242
246
  parcount = mandatory_positional_param_count
243
247
  parcount -= 1 if !parameters.empty? && parameters.last.block?
244
- return false if block? && !with_block
248
+ return false if block? && block_required? && !with_block
245
249
  # @todo this and its caller should be changed so that this can
246
250
  # look at the kwargs provided and check names against what
247
251
  # we acccept
@@ -267,6 +271,11 @@ module Solargraph
267
271
  !!@block
268
272
  end
269
273
 
274
+ # @return [Boolean]
275
+ def block_required?
276
+ !!@block_required
277
+ end
278
+
270
279
  protected
271
280
 
272
281
  attr_writer :block
@@ -5,6 +5,11 @@ module Solargraph
5
5
  # A DelegatedMethod is a more complicated version of a MethodAlias that
6
6
  # allows aliasing a method from a different closure (class/module etc).
7
7
  class DelegatedMethod < Pin::Method
8
+ # @return [Boolean]
9
+ def body?
10
+ false
11
+ end
12
+
8
13
  # A DelegatedMethod can be constructed with either a :resolved_method
9
14
  # pin, or a :receiver_chain. When a :receiver_chain is supplied, it
10
15
  # will be used to *dynamically* resolve a receiver type within the
@@ -1,16 +1,36 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Pin
5
- # DuckMethod pins are used to add completion items for type tags that
6
- # use duck typing, e.g., `@param file [#read]`.
7
- #
8
- class DuckMethod < Pin::Method
9
- # @param location [Solargraph::Location]
10
- # @param name [String]
11
- # def initialize location, name
12
- # # super(location, '', name, nil, :instance, :public, [])
13
- # end
14
- end
15
- end
16
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ # DuckMethod pins are used to add completion items for type tags that
6
+ # use duck typing, e.g., `@param file [#read]`.
7
+ #
8
+ class DuckMethod < Pin::Method
9
+ # A duck-type tag has no syntax for arguments, so the default empty
10
+ # #parameters would synthesize a zero-arg signature no real call matches.
11
+ #
12
+ # @param splat [Hash{Symbol => Object}]
13
+ def initialize **splat
14
+ super(parameters: accepts_any_arguments, **splat)
15
+ end
16
+
17
+ # @return [::Array<Pin::Parameter>]
18
+ def accepts_any_arguments
19
+ [
20
+ Pin::Parameter.new(decl: :restarg, name: 'args', closure: self, source: :api_map),
21
+ Pin::Parameter.new(decl: :kwrestarg, name: 'kwargs', closure: self, source: :api_map)
22
+ ]
23
+ end
24
+
25
+ # A synthetic pin sits in no ancestor chain and has no closure. Letting
26
+ # the inherited walk find a type sends #typify on to `closure.gates`,
27
+ # which raises.
28
+ #
29
+ # @param _api_map [ApiMap]
30
+ # @return [Array<Pin::Method>]
31
+ def rest_of_stack _api_map
32
+ []
33
+ end
34
+ end
35
+ end
36
+ end
@@ -33,6 +33,51 @@ module Solargraph
33
33
  def nearly? other
34
34
  super && binder == other.binder
35
35
  end
36
+
37
+ # Same-file requirement only applies when +presence+ is set; an
38
+ # unnarrowed ivar has none and can be assigned and read in
39
+ # different files (e.g. ancestor class's method vs. descendant's).
40
+ #
41
+ # @param other_closure [Pin::Closure]
42
+ # @param other_loc [Location]
43
+ def visible_at? other_closure, other_loc
44
+ return false if presence && location&.filename != other_loc.filename
45
+ # @sg-ignore flow sensitive typing needs to handle attrs
46
+ return false if presence && !presence.include?(other_loc.range.start)
47
+
48
+ visible_in_closure?(other_closure)
49
+ end
50
+
51
+ private
52
+
53
+ # Unlike BaseVariable, doesn't stop at a lexically-mismatched
54
+ # Namespace pin: #get_instance_variable_pins already restricts
55
+ # candidates to the reading namespace and its ancestors, so
56
+ # reaching one here means visible via inheritance.
57
+ #
58
+ # @param viewing_closure [Pin::Closure]
59
+ # @return [Boolean]
60
+ def visible_in_closure? viewing_closure
61
+ return false if closure.nil?
62
+
63
+ # top-level ivars aren't visible from within a method
64
+ # @sg-ignore Need to add nil check here
65
+ return false if viewing_closure.is_a?(Pin::Method) && closure.context.tags == 'Class<>'
66
+
67
+ # @sg-ignore Need to add nil check here
68
+ return true if viewing_closure.binder.namespace == closure.binder.namespace
69
+
70
+ # @sg-ignore Need to add nil check here
71
+ return true if viewing_closure.return_type == closure.context
72
+
73
+ return true if viewing_closure.is_a?(Pin::Namespace)
74
+
75
+ parent_of_viewing_closure = viewing_closure.closure
76
+
77
+ return false if parent_of_viewing_closure.nil?
78
+
79
+ visible_in_closure?(parent_of_viewing_closure)
80
+ end
36
81
  end
37
82
  end
38
83
  end
@@ -370,6 +370,13 @@ module Solargraph
370
370
  @explicit
371
371
  end
372
372
 
373
+ # False for method pins synthesized from a class-body statement rather than parsed from a def.
374
+ #
375
+ # @return [Boolean]
376
+ def body?
377
+ !attribute?
378
+ end
379
+
373
380
  def attribute?
374
381
  @attribute
375
382
  end
@@ -387,6 +394,9 @@ module Solargraph
387
394
 
388
395
  def probe api_map
389
396
  attribute? ? infer_from_iv(api_map) : infer_from_return_nodes(api_map)
397
+ rescue FileNotFoundError
398
+ # @todo Necessary for pins from source maps that are not part of the workspace
399
+ ComplexType::UNDEFINED
390
400
  end
391
401
 
392
402
  # @return [::Array<Pin::Signature>]
@@ -7,6 +7,10 @@ module Solargraph
7
7
  # methods from included modules.
8
8
  #
9
9
  class MethodAlias < Method
10
+ # @return [Boolean]
11
+ def body?
12
+ false
13
+ end
10
14
  # @return [::Symbol]
11
15
  attr_reader :scope
12
16
 
@@ -115,7 +115,7 @@ module Solargraph
115
115
  end
116
116
 
117
117
  def rest?
118
- %i[restarg kwrestarg].include?(decl)
118
+ %i[restarg kwrestarg forward_args].include?(decl)
119
119
  end
120
120
 
121
121
  def block?
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ class Reference
6
+ # A mixin that a module's +self.included+ hook applies to every class
7
+ # that includes the module, e.g. +base.extend ClassMethods+. The closure
8
+ # is the hooking module and the name is the mixed-in module.
9
+ class IncludedMixin < Reference
10
+ # @return [::Symbol] :include, :prepend or :extend
11
+ attr_reader :keyword
12
+
13
+ # @param keyword [::Symbol] :include, :prepend or :extend
14
+ # @param splat [Hash{Symbol => Object}]
15
+ def initialize keyword:, **splat
16
+ super(**splat)
17
+ @keyword = keyword
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -8,6 +8,7 @@ module Solargraph
8
8
  autoload :Include, 'solargraph/pin/reference/include'
9
9
  autoload :Prepend, 'solargraph/pin/reference/prepend'
10
10
  autoload :Extend, 'solargraph/pin/reference/extend'
11
+ autoload :IncludedMixin, 'solargraph/pin/reference/included_mixin'
11
12
  autoload :Override, 'solargraph/pin/reference/override'
12
13
  autoload :TypeAlias, 'solargraph/pin/reference/type_alias'
13
14
 
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Plugin
5
+ class ActiveSupport < Base
6
+ ATTRIBUTE_NAME = /\A[_A-Za-z]\w*\z/
7
+
8
+ def addon
9
+ return EMPTY_ADDON unless gem_names.include?('activesupport')
10
+
11
+ Addon.new(pins: classmethod_pins + attribute_pins)
12
+ end
13
+
14
+ private
15
+
16
+ def classmethod_pins
17
+ pins_by_class(Pin::Reference::Include).map do |inc|
18
+ Pin::Reference::Extend.new(name: "#{inc.name}::ClassMethods", closure: inc.closure)
19
+ end
20
+ end
21
+
22
+ def attribute_pins
23
+ source_maps.flat_map { |map| map.calls(:class_attribute, :mattr_accessor, :cattr_accessor, :mattr_reader, :cattr_reader, :mattr_writer, :cattr_writer, :config_accessor) }
24
+ .select { |call| call.closure.is_a?(Pin::Namespace) }
25
+ .flat_map { |call| generate_call_pins(call) }
26
+ .compact
27
+ end
28
+
29
+ # @param call [SourceMap::Call]
30
+ def generate_call_pins call
31
+ options = option_hash(call.chain.links.last.arguments.last)
32
+ method_names = call.chain.links.last.arguments.select(&:literal?).map { |arg| arg.links.last.value }.compact
33
+ .grep(ATTRIBUTE_NAME)
34
+ case call.chain.links.last.word
35
+ when 'class_attribute'
36
+ class_suffixes = ['', '=']
37
+ class_suffixes.push '?' if options[:instance_predicate]
38
+ instance_suffixes = []
39
+ instance_suffixes.push '' if options[:instance_accessor] && options[:instance_reader]
40
+ instance_suffixes.push '=' if options[:instance_accessor] && options[:instance_writer]
41
+ instance_suffixes.push '?' if options[:instance_accessor] && options[:instance_predicate]
42
+ method_names.flat_map { |name| method_pins(name, class_suffixes, instance_suffixes, call) }
43
+ when 'mattr_accessor', 'cattr_accessor', 'config_accessor'
44
+ class_suffixes = ['', '=']
45
+ instance_suffixes = []
46
+ instance_suffixes.push '' if options[:instance_accessor] && options[:instance_reader]
47
+ instance_suffixes.push '=' if options[:instance_accessor] && options[:instance_writer]
48
+ method_names.flat_map { |name| method_pins(name, class_suffixes, instance_suffixes, call) }
49
+ when 'mattr_reader', 'cattr_reader'
50
+ class_suffixes = ['']
51
+ instance_suffixes = []
52
+ instance_suffixes.push '' if options[:instance_accessor] && options[:instance_reader]
53
+ method_names.flat_map { |name| method_pins(name, class_suffixes, instance_suffixes, call) }
54
+ when 'mattr_writer', 'cattr_writer'
55
+ class_suffixes = ['=']
56
+ instance_suffixes = []
57
+ instance_suffixes.push '=' if options[:instance_accessor] && options[:instance_writer]
58
+ method_names.flat_map { |name| method_pins(name, class_suffixes, instance_suffixes, call) }
59
+ else
60
+ []
61
+ end
62
+ end
63
+
64
+ def option_hash args
65
+ defaults = {
66
+ instance_reader: true,
67
+ instance_writer: true,
68
+ instance_accessor: true,
69
+ instance_predicate: true
70
+ }
71
+ kwargs = Parser::ParserGem::NodeMethods.convert_hash(args.node)
72
+ .select { |_, val| val.literal? }
73
+ .transform_values { |val| val.links.last.value }
74
+ return defaults unless kwargs.is_a?(Hash)
75
+ defaults.merge(kwargs)
76
+ end
77
+
78
+ # @param call [SourceMap::Call]
79
+ # @param name [String]
80
+ # @param class_suffixes [Array<String>]
81
+ # @param instance_suffixes [Array<String>]
82
+ def method_pins name, class_suffixes, instance_suffixes, call
83
+ comments = call.source_map.source.comments_for(call.chain.node)
84
+ location = Solargraph::Location.new(call.closure.filename, Solargraph::Range.from_node(call.chain.node))
85
+ class_suffixes.map do |sfx|
86
+ Pin::Method.new(name: "#{name}#{sfx}", closure: call.closure, scope: :class, attribute: true, location: location, comments: comments).tap do |pin|
87
+ next unless sfx == '='
88
+ pin.parameters.push Pin::Parameter.new(name: 'value', closure: pin)
89
+ end
90
+ end +
91
+ instance_suffixes.map do |sfx|
92
+ Pin::Method.new(name: "#{name}#{sfx}", closure: call.closure, scope: :instance, attribute: true, location: location, comments: comments).tap do |pin|
93
+ next unless sfx == '='
94
+ pin.parameters.push Pin::Parameter.new(name: 'value', closure: pin)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Plugin
5
+ class Addon
6
+ attr_reader :gem_names, :pins
7
+
8
+ # @param gem_names [Array<String>]
9
+ # @param pins [Array<Pin::Base>]
10
+ def initialize gem_names: [], pins: []
11
+ @gem_names = gem_names
12
+ @pins = pins
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Solargraph
6
+ module Plugin
7
+ class Base
8
+ extend Forwardable
9
+
10
+ attr_reader :panel
11
+
12
+ def_delegators :@panel, :pins, :pins_by_class, :pins_by_path, :gem_names, :source_maps
13
+
14
+ # @param panel [Panel]
15
+ def initialize panel
16
+ @panel = panel
17
+ end
18
+
19
+ # @return [Addon]
20
+ def addon
21
+ EMPTY_ADDON
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Plugin
5
+ class Panel
6
+ attr_reader :source_maps, :live_map, :gem_names
7
+
8
+ def initialize source_maps: [], live_map: nil, gem_names: []
9
+ @source_maps = source_maps
10
+ @live_map = live_map
11
+ @gem_names = gem_names
12
+ end
13
+
14
+ def pins
15
+ @pins ||= source_maps.flat_map(&:pins)
16
+ end
17
+
18
+ def pins_by_class klass
19
+ pin_class_hash[klass] || []
20
+ end
21
+
22
+ def pins_by_path path
23
+ pin_path_hash[path] || []
24
+ end
25
+
26
+ private
27
+
28
+ def pin_class_hash
29
+ @pin_class_hash ||= pins.to_set.classify(&:class)
30
+ end
31
+
32
+ def pin_path_hash
33
+ @pin_path_hash ||= pins.to_set.classify(&:path)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Plugin
5
+ autoload :Addon, 'solargraph/plugin/addon'
6
+ autoload :Base, 'solargraph/plugin/base'
7
+ autoload :Panel, 'solargraph/plugin/panel'
8
+ autoload :ActiveSupport, 'solargraph/plugin/active_support'
9
+
10
+ EMPTY_ADDON = Addon.new.freeze
11
+
12
+ def self.registry
13
+ @registry ||= Set.new
14
+ end
15
+
16
+ def self.register klass
17
+ registry.add klass
18
+ end
19
+
20
+ def self.unregister klass
21
+ registry.delete klass
22
+ end
23
+
24
+ Plugin.register ActiveSupport
25
+ end
26
+ end