solargraph 0.47.2 → 0.54.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 (191) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/plugins.yml +40 -0
  4. data/.github/workflows/rspec.yml +4 -8
  5. data/.github/workflows/typecheck.yml +34 -0
  6. data/.yardopts +2 -2
  7. data/CHANGELOG.md +166 -3
  8. data/LICENSE +1 -1
  9. data/README.md +19 -16
  10. data/SPONSORS.md +2 -9
  11. data/lib/solargraph/api_map/cache.rb +50 -20
  12. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  13. data/lib/solargraph/api_map/store.rb +68 -15
  14. data/lib/solargraph/api_map.rb +238 -112
  15. data/lib/solargraph/bench.rb +3 -2
  16. data/lib/solargraph/cache.rb +77 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +116 -35
  18. data/lib/solargraph/complex_type/unique_type.rb +261 -33
  19. data/lib/solargraph/complex_type.rb +149 -30
  20. data/lib/solargraph/convention/rakefile.rb +17 -0
  21. data/lib/solargraph/convention.rb +2 -3
  22. data/lib/solargraph/converters/dd.rb +5 -0
  23. data/lib/solargraph/converters/dl.rb +3 -0
  24. data/lib/solargraph/converters/dt.rb +3 -0
  25. data/lib/solargraph/diagnostics/rubocop.rb +23 -8
  26. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  27. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  28. data/lib/solargraph/diagnostics.rb +2 -2
  29. data/lib/solargraph/doc_map.rb +187 -0
  30. data/lib/solargraph/gem_pins.rb +72 -0
  31. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  32. data/lib/solargraph/language_server/host/dispatch.rb +22 -5
  33. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  34. data/lib/solargraph/language_server/host/sources.rb +8 -65
  35. data/lib/solargraph/language_server/host.rb +88 -93
  36. data/lib/solargraph/language_server/message/base.rb +1 -1
  37. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  38. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  39. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  40. data/lib/solargraph/language_server/message/initialize.rb +27 -0
  41. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  42. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  43. data/lib/solargraph/language_server/message/text_document/formatting.rb +5 -4
  44. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  46. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  47. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  48. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  49. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  50. data/lib/solargraph/language_server/message.rb +1 -0
  51. data/lib/solargraph/language_server/progress.rb +118 -0
  52. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  53. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  54. data/lib/solargraph/language_server.rb +1 -0
  55. data/lib/solargraph/library.rb +231 -104
  56. data/lib/solargraph/location.rb +1 -0
  57. data/lib/solargraph/page.rb +6 -0
  58. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  59. data/lib/solargraph/parser/node_methods.rb +47 -7
  60. data/lib/solargraph/parser/node_processor/base.rb +11 -1
  61. data/lib/solargraph/parser/node_processor.rb +1 -0
  62. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
  63. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
  66. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  68. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +14 -4
  71. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  72. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/def_node.rb +7 -20
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  77. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
  78. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  79. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  80. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  81. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +42 -0
  82. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +7 -5
  83. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
  84. data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
  85. data/lib/solargraph/parser/parser_gem.rb +12 -0
  86. data/lib/solargraph/parser/region.rb +1 -1
  87. data/lib/solargraph/parser/snippet.rb +2 -0
  88. data/lib/solargraph/parser.rb +9 -10
  89. data/lib/solargraph/pin/base.rb +69 -11
  90. data/lib/solargraph/pin/base_variable.rb +40 -7
  91. data/lib/solargraph/pin/block.rb +81 -33
  92. data/lib/solargraph/pin/closure.rb +17 -2
  93. data/lib/solargraph/pin/common.rb +7 -3
  94. data/lib/solargraph/pin/conversions.rb +34 -8
  95. data/lib/solargraph/pin/delegated_method.rb +101 -0
  96. data/lib/solargraph/pin/documenting.rb +25 -32
  97. data/lib/solargraph/pin/instance_variable.rb +4 -0
  98. data/lib/solargraph/pin/local_variable.rb +13 -1
  99. data/lib/solargraph/pin/method.rb +273 -17
  100. data/lib/solargraph/pin/namespace.rb +17 -1
  101. data/lib/solargraph/pin/parameter.rb +40 -28
  102. data/lib/solargraph/pin/reference/override.rb +2 -2
  103. data/lib/solargraph/pin/reference.rb +8 -0
  104. data/lib/solargraph/pin/search.rb +4 -4
  105. data/lib/solargraph/pin/signature.rb +143 -0
  106. data/lib/solargraph/pin.rb +2 -1
  107. data/lib/solargraph/range.rb +4 -6
  108. data/lib/solargraph/rbs_map/conversions.rb +607 -0
  109. data/lib/solargraph/rbs_map/core_fills.rb +50 -0
  110. data/lib/solargraph/rbs_map/core_map.rb +28 -0
  111. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -0
  112. data/lib/solargraph/rbs_map.rb +92 -0
  113. data/lib/solargraph/shell.rb +85 -59
  114. data/lib/solargraph/source/chain/array.rb +32 -0
  115. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  116. data/lib/solargraph/source/chain/call.rb +125 -61
  117. data/lib/solargraph/source/chain/constant.rb +15 -1
  118. data/lib/solargraph/source/chain/if.rb +23 -0
  119. data/lib/solargraph/source/chain/link.rb +8 -2
  120. data/lib/solargraph/source/chain/or.rb +1 -1
  121. data/lib/solargraph/source/chain/z_super.rb +3 -3
  122. data/lib/solargraph/source/chain.rb +64 -14
  123. data/lib/solargraph/source/change.rb +3 -0
  124. data/lib/solargraph/source/cursor.rb +2 -0
  125. data/lib/solargraph/source/source_chainer.rb +8 -5
  126. data/lib/solargraph/source/updater.rb +1 -0
  127. data/lib/solargraph/source.rb +18 -63
  128. data/lib/solargraph/source_map/clip.rb +31 -23
  129. data/lib/solargraph/source_map/mapper.rb +23 -7
  130. data/lib/solargraph/source_map.rb +36 -11
  131. data/lib/solargraph/type_checker/checks.rb +10 -2
  132. data/lib/solargraph/type_checker.rb +229 -100
  133. data/lib/solargraph/version.rb +1 -1
  134. data/lib/solargraph/views/environment.erb +2 -2
  135. data/lib/solargraph/workspace/config.rb +15 -11
  136. data/lib/solargraph/workspace.rb +41 -17
  137. data/lib/solargraph/yard_map/cache.rb +6 -0
  138. data/lib/solargraph/yard_map/helpers.rb +1 -1
  139. data/lib/solargraph/yard_map/mapper/to_method.rb +23 -7
  140. data/lib/solargraph/yard_map/mapper.rb +1 -1
  141. data/lib/solargraph/yard_map/to_method.rb +11 -4
  142. data/lib/solargraph/yard_map.rb +1 -443
  143. data/lib/solargraph/yard_tags.rb +20 -0
  144. data/lib/solargraph/yardoc.rb +52 -0
  145. data/lib/solargraph.rb +8 -6
  146. data/solargraph.gemspec +19 -8
  147. metadata +164 -99
  148. data/.travis.yml +0 -19
  149. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  150. data/lib/solargraph/compat.rb +0 -37
  151. data/lib/solargraph/convention/rspec.rb +0 -30
  152. data/lib/solargraph/documentor.rb +0 -76
  153. data/lib/solargraph/language_server/host/cataloger.rb +0 -56
  154. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  155. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  156. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  157. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  158. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
  159. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +0 -63
  160. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +0 -21
  161. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  162. data/lib/solargraph/parser/legacy.rb +0 -12
  163. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -144
  164. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  165. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  166. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  167. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  168. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -22
  169. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -57
  170. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  171. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  172. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  173. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  174. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  175. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  176. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  177. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  178. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  179. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -21
  180. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  181. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -277
  182. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +0 -18
  183. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  184. data/lib/solargraph/parser/rubyvm.rb +0 -40
  185. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  186. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  187. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  188. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  189. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  190. data/lib/yard-solargraph.rb +0 -33
  191. data/yardoc/2.2.2.tar.gz +0 -0
@@ -3,70 +3,118 @@
3
3
  module Solargraph
4
4
  module Pin
5
5
  class Block < Closure
6
- # The signature of the method that receives this block.
7
- #
8
6
  # @return [Parser::AST::Node]
9
7
  attr_reader :receiver
10
8
 
11
- # @param args [Array<Parameter>]
12
- def initialize receiver: nil, args: [], context: nil, **splat
9
+ # @return [Parser::AST::Node]
10
+ attr_reader :node
11
+
12
+ # @param receiver [Parser::AST::Node, nil]
13
+ # @param node [Parser::AST::Node, nil]
14
+ # @param context [ComplexType, nil]
15
+ # @param args [::Array<Parameter>]
16
+ def initialize receiver: nil, args: [], context: nil, node: nil, **splat
13
17
  super(**splat)
14
18
  @receiver = receiver
15
19
  @context = context
16
20
  @parameters = args
21
+ @return_type = ComplexType.parse('::Proc')
22
+ @node = node
17
23
  end
18
24
 
19
25
  # @param api_map [ApiMap]
20
26
  # @return [void]
21
27
  def rebind api_map
22
- @binder ||= binder_or_nil(api_map)
28
+ @rebind ||= maybe_rebind(api_map)
23
29
  end
24
30
 
25
31
  def binder
26
- @binder || closure.binder
32
+ @rebind&.defined? ? @rebind : closure.binder
27
33
  end
28
34
 
29
- # @return [Array<Parameter>]
35
+ # @return [::Array<Parameter>]
30
36
  def parameters
31
37
  @parameters ||= []
32
38
  end
33
39
 
34
- # @return [Array<String>]
40
+ # @return [::Array<String>]
35
41
  def parameter_names
36
42
  @parameter_names ||= parameters.map(&:name)
37
43
  end
38
44
 
45
+ # @param yield_types [::Array<ComplexType>]
46
+ # @param parameters [::Array<Parameter>]
47
+ #
48
+ # @return [::Array<ComplexType>]
49
+ def destructure_yield_types(yield_types, parameters)
50
+ return yield_types if yield_types.length == parameters.length
51
+
52
+ # yielding a tuple into a block will destructure the tuple
53
+ if yield_types.length == 1
54
+ yield_type = yield_types.first
55
+ return yield_type.all_params if yield_type.tuple? && yield_type.all_params.length == parameters.length
56
+ end
57
+ parameters.map { ComplexType::UNDEFINED }
58
+ end
59
+
60
+ # @todo the next step with parameters, arguments, destructuring,
61
+ # kwargs, etc logic is probably either creating a Parameters
62
+ # or Callable pin that encapsulates and shares the logic
63
+ # between methods, blocks and signatures. It could live in
64
+ # Signature if Method didn't also own potentially different
65
+ # set of parameters, generics and return types.
66
+
67
+ # @param api_map [ApiMap]
68
+ # @return [::Array<ComplexType>]
69
+ def typify_parameters(api_map)
70
+ chain = Parser.chain(receiver, filename, node)
71
+ clip = api_map.clip_at(location.filename, location.range.start)
72
+ locals = clip.locals - [self]
73
+ meths = chain.define(api_map, closure, locals)
74
+ # @todo Convert logic to use signatures
75
+ meths.each do |meth|
76
+ next if meth.block.nil?
77
+
78
+ yield_types = meth.block.parameters.map(&:return_type)
79
+ # 'arguments' is what the method says it will yield to the
80
+ # block; 'parameters' is what the block accepts
81
+ argument_types = destructure_yield_types(yield_types, parameters)
82
+ param_types = argument_types.each_with_index.map do |arg_type, idx|
83
+ param = parameters[idx]
84
+ param_type = chain.base.infer(api_map, param, locals)
85
+ unless arg_type.nil?
86
+ if arg_type.generic? && param_type.defined?
87
+ namespace_pin = api_map.get_namespace_pins(meth.namespace, closure.namespace).first
88
+ arg_type.resolve_generics(namespace_pin, param_type)
89
+ else
90
+ arg_type.self_to(chain.base.infer(api_map, self, locals).namespace).qualify(api_map, meth.context.namespace)
91
+ end
92
+ end
93
+ end
94
+ return param_types if param_types.all?(&:defined?)
95
+ end
96
+ parameters.map { ComplexType::UNDEFINED }
97
+ end
98
+
39
99
  private
40
100
 
41
101
  # @param api_map [ApiMap]
42
- # @return [ComplexType, nil]
43
- def binder_or_nil api_map
44
- return nil unless receiver
45
- word = receiver.children.find { |c| c.is_a?(::Symbol) }.to_s
46
- return nil unless api_map.rebindable_method_names.include?(word)
102
+ # @return [ComplexType]
103
+ def maybe_rebind api_map
104
+ return ComplexType::UNDEFINED unless receiver
105
+
47
106
  chain = Parser.chain(receiver, location.filename)
48
107
  locals = api_map.source_map(location.filename).locals_at(location)
49
- links_last_word = chain.links.last.word
50
- if %w[instance_eval instance_exec class_eval class_exec module_eval module_exec].include?(links_last_word)
51
- return chain.base.infer(api_map, self, locals)
52
- end
53
- if 'define_method' == links_last_word and chain.define(api_map, self, locals).first&.path == 'Module#define_method' # change class type to instance type
54
- if chain.links.size > 1 # Class.define_method
55
- ty = chain.base.infer(api_map, self, locals)
56
- return Solargraph::ComplexType.parse(ty.namespace)
57
- else # define_method without self
58
- return Solargraph::ComplexType.parse(closure.binder.namespace)
59
- end
60
- end
61
- # other case without early return, read block yieldself tags
62
108
  receiver_pin = chain.define(api_map, self, locals).first
63
- if receiver_pin && receiver_pin.docstring
64
- ys = receiver_pin.docstring.tag(:yieldself)
65
- if ys && ys.types && !ys.types.empty?
66
- return ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
67
- end
68
- end
69
- nil
109
+ return ComplexType::UNDEFINED unless receiver_pin
110
+
111
+ types = receiver_pin.docstring.tag(:yieldreceiver)&.types
112
+ return ComplexType::UNDEFINED unless types&.any?
113
+
114
+ target = chain.base.infer(api_map, receiver_pin, locals)
115
+ target = full_context unless target.defined?
116
+
117
+ ComplexType.try_parse(*types).qualify(api_map, receiver_pin.context.namespace).self_to(target.to_s)
70
118
  end
71
119
  end
72
120
  end
@@ -6,9 +6,12 @@ module Solargraph
6
6
  # @return [::Symbol] :class or :instance
7
7
  attr_reader :scope
8
8
 
9
- def initialize scope: :class, **splat
9
+ # @param scope [::Symbol] :class or :instance
10
+ # @param generics [::Array<Pin::Parameter>, nil]
11
+ def initialize scope: :class, generics: nil, **splat
10
12
  super(**splat)
11
13
  @scope = scope
14
+ @generics = generics
12
15
  end
13
16
 
14
17
  def context
@@ -26,12 +29,24 @@ module Solargraph
26
29
  @binder || context
27
30
  end
28
31
 
29
- # @return [Array<String>]
32
+ # @return [::Array<String>]
30
33
  def gates
31
34
  # @todo This check might not be necessary. There should always be a
32
35
  # root pin
33
36
  closure ? closure.gates : ['']
34
37
  end
38
+
39
+ # @return [::Array<String>]
40
+ def generics
41
+ @generics ||= docstring.tags(:generic).map(&:name)
42
+ end
43
+
44
+ # @return [String]
45
+ def generics_as_rbs
46
+ return '' if generics.empty?
47
+
48
+ generics.join(', ') + ' '
49
+ end
35
50
  end
36
51
  end
37
52
  end
@@ -6,7 +6,7 @@ module Solargraph
6
6
  # @return [Location]
7
7
  attr_reader :location
8
8
 
9
- # @return [Pin::Base, nil]
9
+ # @return [Pin::Closure, nil]
10
10
  attr_reader :closure
11
11
 
12
12
  # @return [String]
@@ -19,7 +19,7 @@ module Solargraph
19
19
  @return_type ||= ComplexType::UNDEFINED
20
20
  end
21
21
 
22
- # @return [ComplexType]
22
+ # @return [ComplexType, Array<UniqueType>]
23
23
  def context
24
24
  # Get the static context from the nearest namespace
25
25
  @context ||= find_context
@@ -46,6 +46,10 @@ module Solargraph
46
46
  @path ||= name.empty? ? context.namespace : "#{context.namespace}::#{name}"
47
47
  end
48
48
 
49
+ protected
50
+
51
+ attr_writer :context
52
+
49
53
  private
50
54
 
51
55
  # @return [ComplexType]
@@ -56,7 +60,7 @@ module Solargraph
56
60
  return here.return_type
57
61
  elsif here.is_a?(Pin::Method)
58
62
  if here.scope == :instance
59
- return ComplexType.try_parse(here.context.namespace)
63
+ return ComplexType.try_parse(here.context.tag)
60
64
  else
61
65
  return here.context
62
66
  end
@@ -5,7 +5,35 @@ require 'cgi'
5
5
  module Solargraph
6
6
  module Pin
7
7
  # @todo Move this stuff. It should be the responsibility of the language server.
8
+ # @todo abstract methods below should be verified to be overridden
9
+ # by type checker when mixin included by non-abstract class
8
10
  module Conversions
11
+ # @!parse
12
+ # include Documenting
13
+ # include Common
14
+
15
+ # @return [Integer]
16
+ # @abstract
17
+ def completion_item_kind
18
+ raise NotImplementedError
19
+ end
20
+
21
+ # @abstract
22
+ # @return [Boolean]
23
+ def deprecated?
24
+ raise NotImplementedError
25
+ end
26
+
27
+ # @abstract
28
+ def probed?
29
+ raise NotImplementedError
30
+ end
31
+
32
+ # @abstract
33
+ def proxied?
34
+ raise NotImplementedError
35
+ end
36
+
9
37
  # @return [Hash]
10
38
  def completion_item
11
39
  @completion_item ||= {
@@ -34,20 +62,16 @@ module Solargraph
34
62
  end
35
63
  end
36
64
 
37
- # @return [Hash]
65
+ # @return [::Array<Hash>]
38
66
  def signature_help
39
- @signature_help ||= {
40
- label: name + '(' + parameters.map(&:full).join(', ') + ')',
41
- documentation: documentation
42
- }
67
+ []
43
68
  end
44
69
 
45
- # @return [String]
70
+ # @return [String, nil]
46
71
  def detail
47
72
  # This property is not cached in an instance variable because it can
48
73
  # change when pins get proxied.
49
74
  detail = String.new
50
- detail += "(#{parameters.map(&:full).join(', ')}) " unless !is_a?(Pin::Method) || parameters.empty?
51
75
  detail += "=#{probed? ? '~' : (proxied? ? '^' : '>')} #{return_type.to_s}" unless return_type.undefined?
52
76
  detail.strip!
53
77
  return nil if detail.empty?
@@ -61,12 +85,14 @@ module Solargraph
61
85
  @link_documentation ||= generate_link
62
86
  end
63
87
 
88
+ # @return [String, nil]
64
89
  def text_documentation
65
90
  this_path = path || return_type.tag
66
91
  return nil if this_path == 'undefined'
67
92
  escape_brackets this_path
68
93
  end
69
94
 
95
+ # @return [void]
70
96
  def reset_conversions
71
97
  @completion_item = nil
72
98
  @resolve_completion_item = nil
@@ -77,7 +103,7 @@ module Solargraph
77
103
 
78
104
  private
79
105
 
80
- # @return [String]
106
+ # @return [String, nil]
81
107
  def generate_link
82
108
  this_path = path || return_type.tag
83
109
  return nil if this_path == 'undefined'
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ # A DelegatedMethod is a more complicated version of a MethodAlias that
6
+ # allows aliasing a method from a different closure (class/module etc).
7
+ class DelegatedMethod < Pin::Method
8
+ # A DelegatedMethod can be constructed with either a :resolved_method
9
+ # pin, or a :receiver_chain. When a :receiver_chain is supplied, it
10
+ # will be used to *dynamically* resolve a receiver type within the
11
+ # given closure/scope, and the delegated method will then be resolved
12
+ # to a method pin on that type.
13
+ #
14
+ # @param method [Method, nil] an already resolved method pin.
15
+ # @param receiver [Source::Chain, nil] the source code used to resolve the receiver for this delegated method.
16
+ # @param name [String]
17
+ # @param receiver_method_name [String] the method name that will be called on the receiver (defaults to :name).
18
+ def initialize(method: nil, receiver: nil, name: method&.name, receiver_method_name: name, **splat)
19
+ raise ArgumentError, 'either :method or :receiver is required' if (method && receiver) || (!method && !receiver)
20
+ super(name: name, **splat)
21
+
22
+ @receiver_chain = receiver
23
+ @resolved_method = method
24
+ @receiver_method_name = receiver_method_name
25
+ end
26
+
27
+ %i[comments parameters return_type location].each do |method|
28
+ define_method(method) do
29
+ @resolved_method ? @resolved_method.send(method) : super()
30
+ end
31
+ end
32
+
33
+ %i[typify realize infer probe].each do |method|
34
+ # @param api_map [ApiMap]
35
+ define_method(method) do |api_map|
36
+ resolve_method(api_map)
37
+ @resolved_method ? @resolved_method.send(method, api_map) : super(api_map)
38
+ end
39
+ end
40
+
41
+ # @param api_map [ApiMap]
42
+ def resolvable?(api_map)
43
+ resolve_method(api_map)
44
+ !!@resolved_method
45
+ end
46
+
47
+ private
48
+
49
+ # Resolves the receiver chain and method name to a method pin, resetting any previously resolution.
50
+ #
51
+ # @param api_map [ApiMap]
52
+ # @return [Pin::Method, nil]
53
+ def resolve_method api_map
54
+ return if @resolved_method
55
+
56
+ resolver = @receiver_chain.define(api_map, self, []).first
57
+
58
+ unless resolver
59
+ Solargraph.logger.warn \
60
+ "Delegated receiver for #{path} was resolved to nil from `#{print_chain(@receiver_chain)}'"
61
+ return
62
+ end
63
+
64
+ receiver_type = resolver.return_type
65
+
66
+ return if receiver_type.undefined?
67
+
68
+ receiver_path, method_scope =
69
+ if @receiver_chain.constant?
70
+ # HACK: the `return_type` of a constant is Class<Whatever>, but looking up a method expects
71
+ # the arguments `"Whatever"` and `scope: :class`.
72
+ [receiver_type.to_s.sub(/^Class<(.+)>$/, '\1'), :class]
73
+ else
74
+ [receiver_type.to_s, :instance]
75
+ end
76
+
77
+ method_stack = api_map.get_method_stack(receiver_path, @receiver_method_name, scope: method_scope)
78
+ @resolved_method = method_stack.first
79
+ end
80
+
81
+ # helper to print a source chain as code, probably not 100% correct.
82
+ #
83
+ # @param chain [Source::Chain]
84
+ # @return [String]
85
+ def print_chain(chain)
86
+ out = +''
87
+ chain.links.each_with_index do |link, index|
88
+ if index > 0
89
+ if Source::Chain::Constant
90
+ out << '::' unless link.word.start_with?('::')
91
+ else
92
+ out << '.'
93
+ end
94
+ end
95
+ out << link.word
96
+ end
97
+ out
98
+ end
99
+ end
100
+ end
101
+ end
@@ -38,23 +38,20 @@ module Solargraph
38
38
  end
39
39
 
40
40
  def to_s
41
- return "\n```ruby\n#{@plaintext}#{@plaintext.end_with?("\n") ? '' : "\n"}```\n\n" if code?
42
- ReverseMarkdown.convert unescape_brackets(Kramdown::Document.new(escape_brackets(@plaintext), input: 'GFM').to_html)
41
+ return to_code if code?
42
+ to_markdown
43
43
  end
44
44
 
45
45
  private
46
46
 
47
- # @param text [String]
48
47
  # @return [String]
49
- def escape_brackets text
50
- # text.gsub(/(\[[^\]]*\])([^\(]|\z)/, '!!!^\1^!!!\2')
51
- text.gsub('[', '!!!!b').gsub(']', 'e!!!!')
48
+ def to_code
49
+ "\n```ruby\n#{Documenting.normalize_indentation(@plaintext)}#{@plaintext.end_with?("\n") ? '' : "\n"}```\n\n"
52
50
  end
53
51
 
54
- # @param text [String]
55
52
  # @return [String]
56
- def unescape_brackets text
57
- text.gsub('!!!!b', '[').gsub('e!!!!', ']')
53
+ def to_markdown
54
+ ReverseMarkdown.convert Kramdown::Document.new(@plaintext, input: 'GFM').to_html
58
55
  end
59
56
  end
60
57
 
@@ -65,40 +62,36 @@ module Solargraph
65
62
  # line and at least two spaces of indentation. This is a common
66
63
  # convention in Ruby core documentation, e.g., String#split.
67
64
  sections = [DocSection.new(false)]
68
- normalize_indentation(docstring.to_s).gsub(/\t/, ' ').lines.each do |l|
69
- if l.strip.empty?
70
- sections.last.concat l
71
- else
72
- if (l =~ /^ [^\s]/ && sections.last.plaintext =~ /(\r?\n[ \t]*?){2,}$/) || (l.start_with?(' ') && sections.last.code?)
73
- # Code block
74
- sections.push DocSection.new(true) unless sections.last.code?
75
- sections.last.concat l[2..-1]
76
- else
77
- # Regular documentation
78
- sections.push DocSection.new(false) if sections.last.code?
79
- sections.last.concat l
80
- end
65
+ Documenting.normalize_indentation(Documenting.strip_html_comments(docstring.to_s.gsub("\t", ' '))).lines.each do |l|
66
+ if l.start_with?(' ')
67
+ # Code block
68
+ sections.push DocSection.new(true) unless sections.last.code?
69
+ elsif sections.last.code?
70
+ # Regular documentation
71
+ sections.push DocSection.new(false)
81
72
  end
73
+ sections.last.concat l
82
74
  end
83
75
  sections.map(&:to_s).join.strip
84
76
  end
85
77
  end
86
78
 
87
- private
88
-
89
79
  # @param text [String]
90
80
  # @return [String]
91
- def normalize_indentation text
92
- text.lines.map { |l| remove_odd_spaces(l) }.join
81
+ def self.strip_html_comments text
82
+ text.gsub(/<!--([\s\S]*?)-->/, '').strip
93
83
  end
94
84
 
95
- # @param line [String]
85
+ # @param text [String]
96
86
  # @return [String]
97
- def remove_odd_spaces line
98
- return line unless line.start_with?(' ')
99
- spaces = line.match(/^ +/)[0].length
100
- return line unless spaces.odd?
101
- line[1..-1]
87
+ def self.normalize_indentation text
88
+ left = text.lines.map do |line|
89
+ match = line.match(/^ +/)
90
+ next 0 unless match
91
+ match[0].length
92
+ end.min
93
+ return text if left.nil? || left.zero?
94
+ text.lines.map { |line| line[left..] }.join
102
95
  end
103
96
  end
104
97
  end
@@ -3,14 +3,17 @@
3
3
  module Solargraph
4
4
  module Pin
5
5
  class InstanceVariable < BaseVariable
6
+ # @return [ComplexType]
6
7
  def binder
7
8
  closure.binder
8
9
  end
9
10
 
11
+ # @return [::Symbol]
10
12
  def scope
11
13
  closure.binder.scope
12
14
  end
13
15
 
16
+ # @return [ComplexType]
14
17
  def context
15
18
  @context ||= begin
16
19
  result = super
@@ -22,6 +25,7 @@ module Solargraph
22
25
  end
23
26
  end
24
27
 
28
+ # @param other [InstanceVariable]
25
29
  def nearly? other
26
30
  super && binder == other.binder
27
31
  end
@@ -6,12 +6,16 @@ module Solargraph
6
6
  # @return [Range]
7
7
  attr_reader :presence
8
8
 
9
+ # @param assignment [AST::Node, nil]
10
+ # @param presence [Range, nil]
11
+ # @param splat [Hash]
9
12
  def initialize assignment: nil, presence: nil, **splat
10
13
  super(**splat)
11
14
  @assignment = assignment
12
15
  @presence = presence
13
16
  end
14
17
 
18
+ # @param pin [self]
15
19
  def try_merge! pin
16
20
  return false unless super
17
21
  @presence = pin.presence
@@ -21,11 +25,16 @@ module Solargraph
21
25
  # @param other_closure [Pin::Closure]
22
26
  # @param other_loc [Location]
23
27
  def visible_at?(other_closure, other_loc)
24
- return true if location.filename == other_loc.filename &&
28
+ location.filename == other_loc.filename &&
25
29
  presence.include?(other_loc.range.start) &&
26
30
  match_named_closure(other_closure, closure)
27
31
  end
28
32
 
33
+ # @return [String]
34
+ def to_rbs
35
+ (name || '(anon)') + ' ' + (return_type&.to_rbs || 'untyped')
36
+ end
37
+
29
38
  private
30
39
 
31
40
  # @param tag1 [String]
@@ -40,6 +49,9 @@ module Solargraph
40
49
  (['', 'Class<>'].include?(tag1) && ['', 'Class<>'].include?(tag2))
41
50
  end
42
51
 
52
+ # @param needle [Pin::Base]
53
+ # @param haystack [Pin::Base]
54
+ # @return [Boolean]
43
55
  def match_named_closure needle, haystack
44
56
  return true if needle == haystack || haystack.is_a?(Pin::Block)
45
57
  cursor = haystack