solargraph 0.39.13 → 0.40.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -7
- data/CHANGELOG.md +984 -0
- data/Rakefile +12 -1
- data/SPONSORS.md +1 -0
- data/lib/solargraph.rb +2 -4
- data/lib/solargraph/api_map.rb +75 -74
- data/lib/solargraph/api_map/cache.rb +2 -2
- data/lib/solargraph/api_map/store.rb +4 -8
- data/lib/solargraph/{bundle.rb → bench.rb} +6 -2
- data/lib/solargraph/compat.rb +14 -0
- data/lib/solargraph/complex_type.rb +2 -2
- data/lib/solargraph/convention.rb +14 -5
- data/lib/solargraph/convention/base.rb +16 -8
- data/lib/solargraph/convention/gemfile.rb +2 -5
- data/lib/solargraph/convention/gemspec.rb +3 -6
- data/lib/solargraph/convention/rspec.rb +3 -6
- data/lib/solargraph/documentor.rb +2 -0
- data/lib/solargraph/environ.rb +11 -6
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +6 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
- data/lib/solargraph/library.rb +7 -7
- data/lib/solargraph/parser/legacy/node_chainer.rb +7 -7
- data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +1 -1
- data/lib/solargraph/parser/legacy/node_processors/send_node.rb +36 -23
- data/lib/solargraph/parser/node_processor/base.rb +3 -0
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +9 -9
- data/lib/solargraph/parser/rubyvm/node_methods.rb +1 -1
- data/lib/solargraph/parser/rubyvm/node_processors.rb +1 -0
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +35 -11
- data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +1 -1
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +40 -29
- data/lib/solargraph/pin.rb +0 -3
- data/lib/solargraph/pin/common.rb +1 -1
- data/lib/solargraph/pin/conversions.rb +3 -4
- data/lib/solargraph/pin/documenting.rb +3 -9
- data/lib/solargraph/pin/method.rb +141 -7
- data/lib/solargraph/pin/method_alias.rb +1 -1
- data/lib/solargraph/position.rb +2 -14
- data/lib/solargraph/shell.rb +1 -0
- data/lib/solargraph/source.rb +10 -6
- data/lib/solargraph/source/chain.rb +18 -5
- data/lib/solargraph/source_map.rb +4 -1
- data/lib/solargraph/source_map/clip.rb +3 -2
- data/lib/solargraph/source_map/mapper.rb +10 -6
- data/lib/solargraph/type_checker.rb +35 -39
- data/lib/solargraph/type_checker/param_def.rb +1 -1
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map.rb +40 -47
- data/lib/solargraph/yard_map/core_fills.rb +185 -0
- data/lib/solargraph/yard_map/helpers.rb +16 -0
- data/lib/solargraph/yard_map/mapper.rb +14 -8
- data/lib/solargraph/{pin/yard_pin/constant.rb → yard_map/mapper/to_constant.rb} +6 -6
- data/lib/solargraph/yard_map/mapper/to_method.rb +78 -0
- data/lib/solargraph/{pin/yard_pin/namespace.rb → yard_map/mapper/to_namespace.rb} +6 -6
- data/lib/solargraph/yard_map/rdoc_to_yard.rb +1 -1
- data/lib/solargraph/yard_map/stdlib_fills.rb +43 -0
- data/lib/solargraph/yard_map/to_method.rb +79 -0
- data/solargraph.gemspec +4 -4
- metadata +20 -34
- data/lib/solargraph/core_fills.rb +0 -159
- data/lib/solargraph/pin/attribute.rb +0 -49
- data/lib/solargraph/pin/base_method.rb +0 -141
- data/lib/solargraph/pin/yard_pin.rb +0 -12
- data/lib/solargraph/pin/yard_pin/method.rb +0 -80
- data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -20
- data/lib/solargraph/stdlib_fills.rb +0 -40
- data/travis-bundler.rb +0 -11
@@ -27,6 +27,7 @@ module Solargraph
|
|
27
27
|
@region = region
|
28
28
|
@pins = pins
|
29
29
|
@locals = locals
|
30
|
+
@processed_children = false
|
30
31
|
end
|
31
32
|
|
32
33
|
# Subclasses should override this method to generate new pins.
|
@@ -41,6 +42,8 @@ module Solargraph
|
|
41
42
|
# @param subregion [Region]
|
42
43
|
# @return [void]
|
43
44
|
def process_children subregion = region
|
45
|
+
return if @processed_children
|
46
|
+
@processed_children = true
|
44
47
|
node.children.each do |child|
|
45
48
|
next unless Parser.is_ast_node?(child)
|
46
49
|
NodeProcessor.process(child, subregion, pins, locals)
|
@@ -15,7 +15,7 @@ module Solargraph
|
|
15
15
|
def initialize node, filename = nil, in_block = false
|
16
16
|
@node = node
|
17
17
|
@filename = filename
|
18
|
-
@in_block = in_block
|
18
|
+
@in_block = in_block ? 1 : 0
|
19
19
|
end
|
20
20
|
|
21
21
|
# @return [Source::Chain]
|
@@ -52,27 +52,27 @@ module Solargraph
|
|
52
52
|
return generate_links(n.children[0]) if n.type == :SPLAT
|
53
53
|
result = []
|
54
54
|
if n.type == :ITER
|
55
|
-
@in_block
|
55
|
+
@in_block += 1
|
56
56
|
result.concat generate_links(n.children[0])
|
57
|
-
@in_block
|
57
|
+
@in_block -= 1
|
58
58
|
elsif n.type == :CALL || n.type == :OPCALL
|
59
59
|
n.children[0..-3].each do |c|
|
60
60
|
result.concat generate_links(c)
|
61
61
|
end
|
62
|
-
result.push Chain::Call.new(n.children[-2].to_s, node_to_argchains(n.children.last), @in_block || block_passed?(n))
|
62
|
+
result.push Chain::Call.new(n.children[-2].to_s, node_to_argchains(n.children.last), @in_block > 0 || block_passed?(n))
|
63
63
|
elsif n.type == :ATTRASGN
|
64
64
|
result.concat generate_links(n.children[0])
|
65
|
-
result.push Chain::Call.new(n.children[1].to_s, node_to_argchains(n.children[2]), @in_block || block_passed?(n))
|
65
|
+
result.push Chain::Call.new(n.children[1].to_s, node_to_argchains(n.children[2]), @in_block > 0 || block_passed?(n))
|
66
66
|
elsif n.type == :VCALL
|
67
|
-
result.push Chain::Call.new(n.children[0].to_s, [], @in_block || block_passed?(n))
|
67
|
+
result.push Chain::Call.new(n.children[0].to_s, [], @in_block > 0 || block_passed?(n))
|
68
68
|
elsif n.type == :FCALL
|
69
|
-
result.push Chain::Call.new(n.children[0].to_s, node_to_argchains(n.children[1]), @in_block || block_passed?(n))
|
69
|
+
result.push Chain::Call.new(n.children[0].to_s, node_to_argchains(n.children[1]), @in_block > 0 || block_passed?(n))
|
70
70
|
elsif n.type == :SELF
|
71
71
|
result.push Chain::Head.new('self')
|
72
72
|
elsif n.type == :ZSUPER
|
73
|
-
result.push Chain::ZSuper.new('super', @in_block || block_passed?(n))
|
73
|
+
result.push Chain::ZSuper.new('super', @in_block > 0 || block_passed?(n))
|
74
74
|
elsif n.type == :SUPER
|
75
|
-
result.push Chain::Call.new('super', node_to_argchains(n.children.last), @in_block || block_passed?(n))
|
75
|
+
result.push Chain::Call.new('super', node_to_argchains(n.children.last), @in_block > 0 || block_passed?(n))
|
76
76
|
elsif [:COLON2, :COLON3, :CONST].include?(n.type)
|
77
77
|
const = unpack_name(n)
|
78
78
|
result.push Chain::Constant.new(const)
|
@@ -197,7 +197,7 @@ module Solargraph
|
|
197
197
|
result.push node
|
198
198
|
result.concat get_return_nodes_only(node.children[1])
|
199
199
|
elsif node.type == :CASE
|
200
|
-
node.children.each do |cc|
|
200
|
+
node.children[1..-1].each do |cc|
|
201
201
|
result.concat reduce_to_value_nodes(cc.children[1..-1])
|
202
202
|
end
|
203
203
|
else
|
@@ -54,6 +54,7 @@ module Solargraph
|
|
54
54
|
register :KW_ARG, Rubyvm::NodeProcessors::KwArgNode
|
55
55
|
register :ITER, Rubyvm::NodeProcessors::BlockNode
|
56
56
|
register :LAMBDA, Rubyvm::NodeProcessors::BlockNode
|
57
|
+
register :FOR, Rubyvm::NodeProcessors::BlockNode
|
57
58
|
register :OP_ASGN_OR, Rubyvm::NodeProcessors::OrasgnNode
|
58
59
|
register :LIT, Rubyvm::NodeProcessors::LitNode
|
59
60
|
end
|
@@ -6,17 +6,31 @@ module Solargraph
|
|
6
6
|
module NodeProcessors
|
7
7
|
class ArgsNode < Parser::NodeProcessor::Base
|
8
8
|
def process
|
9
|
-
if region.closure.is_a?(Pin::
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
if region.closure.is_a?(Pin::Method) || region.closure.is_a?(Pin::Block)
|
10
|
+
if region.lvars[0].nil?
|
11
|
+
node.children[0].times do |i|
|
12
|
+
locals.push Solargraph::Pin::Parameter.new(
|
13
|
+
location: region.closure.location,
|
14
|
+
closure: region.closure,
|
15
|
+
comments: comments_for(node),
|
16
|
+
name: extract_name(node.children[i + 1]),
|
17
|
+
presence: region.closure.location.range,
|
18
|
+
decl: :arg
|
19
|
+
)
|
20
|
+
region.closure.parameters.push locals.last
|
21
|
+
end
|
22
|
+
else
|
23
|
+
node.children[0].times do |i|
|
24
|
+
locals.push Solargraph::Pin::Parameter.new(
|
25
|
+
location: region.closure.location,
|
26
|
+
closure: region.closure,
|
27
|
+
comments: comments_for(node),
|
28
|
+
name: region.lvars[i].to_s,
|
29
|
+
presence: region.closure.location.range,
|
30
|
+
decl: :arg
|
31
|
+
)
|
32
|
+
region.closure.parameters.push locals.last
|
33
|
+
end
|
20
34
|
end
|
21
35
|
# @todo Optional args, keyword args, etc.
|
22
36
|
if node.children[6]
|
@@ -55,6 +69,16 @@ module Solargraph
|
|
55
69
|
end
|
56
70
|
process_children
|
57
71
|
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def extract_name var
|
76
|
+
if Parser.is_ast_node?(var)
|
77
|
+
var.children[0].to_s
|
78
|
+
else
|
79
|
+
var.to_s
|
80
|
+
end
|
81
|
+
end
|
58
82
|
end
|
59
83
|
end
|
60
84
|
end
|
@@ -19,7 +19,7 @@ module Solargraph
|
|
19
19
|
if region.visibility == :module_function
|
20
20
|
rng = Range.from_node(node)
|
21
21
|
named_path = named_path_pin(rng.start)
|
22
|
-
if named_path.is_a?(Pin::
|
22
|
+
if named_path.is_a?(Pin::Method)
|
23
23
|
pins.push Solargraph::Pin::InstanceVariable.new(
|
24
24
|
location: loc,
|
25
25
|
closure: Pin::Namespace.new(type: :module, closure: region.closure.closure, name: region.closure.name),
|
@@ -9,21 +9,7 @@ module Solargraph
|
|
9
9
|
|
10
10
|
def process
|
11
11
|
if [:private, :public, :protected].include?(node.children[0])
|
12
|
-
|
13
|
-
node.children.last.children[0..-2].each do |child|
|
14
|
-
# next unless child.is_a?(AST::Node) && (child.type == :sym || child.type == :str)
|
15
|
-
next unless child.type == :LIT || child.type == :STR
|
16
|
-
name = child.children[0].to_s
|
17
|
-
matches = pins.select{ |pin| pin.is_a?(Pin::BaseMethod) && pin.name == name && pin.namespace == region.closure.full_context.namespace && pin.context.scope == (region.scope || :instance)}
|
18
|
-
matches.each do |pin|
|
19
|
-
# @todo Smelly instance variable access
|
20
|
-
pin.instance_variable_set(:@visibility, node.children[0])
|
21
|
-
end
|
22
|
-
end
|
23
|
-
else
|
24
|
-
# @todo Smelly instance variable access
|
25
|
-
region.instance_variable_set(:@visibility, node.children[0])
|
26
|
-
end
|
12
|
+
process_visibility
|
27
13
|
elsif node.children[0] == :module_function
|
28
14
|
process_module_function
|
29
15
|
elsif node.children[0] == :require
|
@@ -33,8 +19,7 @@ module Solargraph
|
|
33
19
|
elsif node.children[0] == :alias_method
|
34
20
|
process_alias_method
|
35
21
|
elsif node.children[0] == :private_class_method
|
36
|
-
|
37
|
-
return if process_private_class_method
|
22
|
+
process_private_class_method
|
38
23
|
elsif [:attr_reader, :attr_writer, :attr_accessor].include?(node.children[0])
|
39
24
|
process_attribute
|
40
25
|
elsif node.children[0] == :include
|
@@ -53,6 +38,28 @@ module Solargraph
|
|
53
38
|
|
54
39
|
private
|
55
40
|
|
41
|
+
# @return [void]
|
42
|
+
def process_visibility
|
43
|
+
if node.type == :FCALL && Parser.is_ast_node?(node.children.last)
|
44
|
+
node.children.last.children[0..-2].each do |child|
|
45
|
+
# next unless child.is_a?(AST::Node) && (child.type == :sym || child.type == :str)
|
46
|
+
if child.type == :LIT || child.type == :STR
|
47
|
+
name = child.children[0].to_s
|
48
|
+
matches = pins.select{ |pin| pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == region.closure.full_context.namespace && pin.context.scope == (region.scope || :instance)}
|
49
|
+
matches.each do |pin|
|
50
|
+
# @todo Smelly instance variable access
|
51
|
+
pin.instance_variable_set(:@visibility, node.children[0])
|
52
|
+
end
|
53
|
+
else
|
54
|
+
process_children region.update(visibility: node.children[0])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
# @todo Smelly instance variable access
|
59
|
+
region.instance_variable_set(:@visibility, node.children[0])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
56
63
|
# @return [void]
|
57
64
|
def process_attribute
|
58
65
|
return unless Parser.is_ast_node?(node.children[1])
|
@@ -62,26 +69,30 @@ module Solargraph
|
|
62
69
|
clos = region.closure
|
63
70
|
cmnt = comments_for(node)
|
64
71
|
if node.children[0] == :attr_reader || node.children[0] == :attr_accessor
|
65
|
-
pins.push Solargraph::Pin::
|
72
|
+
pins.push Solargraph::Pin::Method.new(
|
66
73
|
location: loc,
|
67
74
|
closure: clos,
|
68
75
|
name: a.children[0].to_s,
|
69
76
|
comments: cmnt,
|
70
|
-
access: :reader,
|
71
77
|
scope: region.scope || :instance,
|
72
|
-
visibility: region.visibility
|
78
|
+
visibility: region.visibility,
|
79
|
+
attribute: true
|
73
80
|
)
|
74
81
|
end
|
75
82
|
if node.children[0] == :attr_writer || node.children[0] == :attr_accessor
|
76
|
-
pins.push Solargraph::Pin::
|
83
|
+
pins.push Solargraph::Pin::Method.new(
|
77
84
|
location: loc,
|
78
85
|
closure: clos,
|
79
86
|
name: "#{a.children[0]}=",
|
80
87
|
comments: cmnt,
|
81
|
-
access: :writer,
|
82
88
|
scope: region.scope || :instance,
|
83
|
-
visibility: region.visibility
|
89
|
+
visibility: region.visibility,
|
90
|
+
attribute: true
|
84
91
|
)
|
92
|
+
pins.last.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
|
93
|
+
if pins.last.return_type.defined?
|
94
|
+
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
|
95
|
+
end
|
85
96
|
end
|
86
97
|
end
|
87
98
|
end
|
@@ -91,7 +102,8 @@ module Solargraph
|
|
91
102
|
return unless Parser.is_ast_node?(node.children.last)
|
92
103
|
node.children.last.children[0..-2].each do |i|
|
93
104
|
next unless [:COLON2, :COLON3, :CONST].include?(i.type)
|
94
|
-
|
105
|
+
type = region.scope == :class ? Pin::Reference::Extend : Pin::Reference::Include
|
106
|
+
pins.push type.new(
|
95
107
|
location: get_node_location(i),
|
96
108
|
closure: region.closure,
|
97
109
|
name: unpack_name(i)
|
@@ -165,7 +177,7 @@ module Solargraph
|
|
165
177
|
node.children.last.children[0..-2].each do |x|
|
166
178
|
next unless [:LIT, :STR].include?(x.type)
|
167
179
|
cn = x.children[0].to_s
|
168
|
-
ref = pins.select{|p|
|
180
|
+
ref = pins.select { |p| p.is_a?(Pin::Method) && p.namespace == region.closure.full_context.namespace && p.name == cn }.first
|
169
181
|
unless ref.nil?
|
170
182
|
pins.delete ref
|
171
183
|
mm = Solargraph::Pin::Method.new(
|
@@ -214,6 +226,7 @@ module Solargraph
|
|
214
226
|
|
215
227
|
# @return [void]
|
216
228
|
def process_private_constant
|
229
|
+
# @todo Bare `private_constant` causes an error
|
217
230
|
node.children.last.children[0..-2].each do |child|
|
218
231
|
if [:LIT, :STR].include?(child.type)
|
219
232
|
cn = child.children[0].to_s
|
@@ -241,20 +254,18 @@ module Solargraph
|
|
241
254
|
)
|
242
255
|
end
|
243
256
|
|
244
|
-
# @return [
|
257
|
+
# @return [void]
|
245
258
|
def process_private_class_method
|
246
259
|
return false unless Parser.is_ast_node?(node.children.last)
|
247
260
|
if node.children.last.children.first.type == :DEFN
|
248
261
|
process_children region.update(scope: :class, visibility: :private)
|
249
|
-
true
|
250
262
|
else
|
251
263
|
node.children.last.children[0..-2].each do |child|
|
252
264
|
if child.type == :LIT && child.children.first.is_a?(::Symbol)
|
253
265
|
sym_name = child.children.first.to_s
|
254
|
-
ref = pins.select{|p|
|
266
|
+
ref = pins.select { |p| p.is_a?(Pin::Method) && p.namespace == region.closure.full_context.namespace && p.name == sym_name }.first
|
255
267
|
# HACK: Smelly instance variable access
|
256
268
|
ref.instance_variable_set(:@visibility, :private) unless ref.nil?
|
257
|
-
false
|
258
269
|
end
|
259
270
|
end
|
260
271
|
end
|
data/lib/solargraph/pin.rb
CHANGED
@@ -9,10 +9,8 @@ module Solargraph
|
|
9
9
|
autoload :Common, 'solargraph/pin/common'
|
10
10
|
autoload :Conversions, 'solargraph/pin/conversions'
|
11
11
|
autoload :Base, 'solargraph/pin/base'
|
12
|
-
autoload :BaseMethod, 'solargraph/pin/base_method'
|
13
12
|
autoload :Method, 'solargraph/pin/method'
|
14
13
|
autoload :MethodAlias, 'solargraph/pin/method_alias'
|
15
|
-
autoload :Attribute, 'solargraph/pin/attribute'
|
16
14
|
autoload :BaseVariable, 'solargraph/pin/base_variable'
|
17
15
|
autoload :InstanceVariable, 'solargraph/pin/instance_variable'
|
18
16
|
autoload :ClassVariable, 'solargraph/pin/class_variable'
|
@@ -30,7 +28,6 @@ module Solargraph
|
|
30
28
|
autoload :Localized, 'solargraph/pin/localized'
|
31
29
|
autoload :ProxyType, 'solargraph/pin/proxy_type'
|
32
30
|
autoload :DuckMethod, 'solargraph/pin/duck_method'
|
33
|
-
autoload :YardPin, 'solargraph/pin/yard_pin'
|
34
31
|
autoload :Singleton, 'solargraph/pin/singleton'
|
35
32
|
autoload :KeywordParam, 'solargraph/pin/keyword_param'
|
36
33
|
|
@@ -54,7 +54,7 @@ module Solargraph
|
|
54
54
|
until here.nil?
|
55
55
|
if here.is_a?(Pin::Namespace)
|
56
56
|
return here.return_type
|
57
|
-
elsif here.is_a?(Pin::
|
57
|
+
elsif here.is_a?(Pin::Method)
|
58
58
|
if here.scope == :instance
|
59
59
|
return ComplexType.try_parse(here.context.namespace)
|
60
60
|
else
|
@@ -23,16 +23,15 @@ module Solargraph
|
|
23
23
|
|
24
24
|
# @return [Hash]
|
25
25
|
def resolve_completion_item
|
26
|
-
|
26
|
+
@resolve_completion_item ||= begin
|
27
27
|
extra = {}
|
28
28
|
alldoc = ''
|
29
29
|
# alldoc += link_documentation unless link_documentation.nil?
|
30
30
|
# alldoc += "\n\n" unless alldoc.empty?
|
31
31
|
alldoc += documentation unless documentation.nil?
|
32
32
|
extra[:documentation] = alldoc unless alldoc.empty?
|
33
|
-
|
33
|
+
completion_item.merge(extra)
|
34
34
|
end
|
35
|
-
@resolve_completion_item
|
36
35
|
end
|
37
36
|
|
38
37
|
# @return [Hash]
|
@@ -48,7 +47,7 @@ module Solargraph
|
|
48
47
|
# This property is not cached in an instance variable because it can
|
49
48
|
# change when pins get proxied.
|
50
49
|
detail = String.new
|
51
|
-
detail += "(#{parameters.map(&:full).join(', ')}) " unless !is_a?(Pin::
|
50
|
+
detail += "(#{parameters.map(&:full).join(', ')}) " unless !is_a?(Pin::Method) || parameters.empty?
|
52
51
|
detail += "=#{probed? ? '~' : (proxied? ? '^' : '>')} #{return_type.to_s}" unless return_type.undefined?
|
53
52
|
detail.strip!
|
54
53
|
return nil if detail.empty?
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'kramdown'
|
4
|
+
require 'kramdown-parser-gfm'
|
4
5
|
require 'yard'
|
5
6
|
require 'reverse_markdown'
|
6
7
|
require 'solargraph/converters/dl'
|
@@ -8,9 +9,6 @@ require 'solargraph/converters/dt'
|
|
8
9
|
require 'solargraph/converters/dd'
|
9
10
|
require 'solargraph/converters/misc'
|
10
11
|
|
11
|
-
# HACK: Setting :html_parser through `Maruku.new` does not work
|
12
|
-
MaRuKu::Globals[:html_parser] = 'nokogiri'
|
13
|
-
|
14
12
|
module Solargraph
|
15
13
|
module Pin
|
16
14
|
# A module to add the Pin::Base#documentation method.
|
@@ -41,11 +39,7 @@ module Solargraph
|
|
41
39
|
|
42
40
|
def to_s
|
43
41
|
return "\n```ruby\n#{@plaintext}#{@plaintext.end_with?("\n") ? '' : "\n"}```\n\n" if code?
|
44
|
-
ReverseMarkdown.convert unescape_brackets(
|
45
|
-
rescue MaRuKu::Exception
|
46
|
-
# Maruku exceptions usually indicate that the documentation is in
|
47
|
-
# RDoc syntax.
|
48
|
-
ReverseMarkdown.convert YARD::Templates::Helpers::Markup::RDocMarkup.new(@plaintext).to_html
|
42
|
+
ReverseMarkdown.convert unescape_brackets(Kramdown::Document.new(escape_brackets(@plaintext), input: 'GFM').to_html)
|
49
43
|
end
|
50
44
|
|
51
45
|
private
|
@@ -2,18 +2,29 @@
|
|
2
2
|
|
3
3
|
module Solargraph
|
4
4
|
module Pin
|
5
|
-
class
|
5
|
+
# The base class for method and attribute pins.
|
6
|
+
#
|
7
|
+
class Method < Closure
|
6
8
|
include Solargraph::Parser::NodeMethods
|
7
9
|
|
8
10
|
# @return [Array<Pin::Parameter>]
|
9
11
|
attr_reader :parameters
|
10
12
|
|
11
|
-
# @
|
12
|
-
|
13
|
-
|
13
|
+
# @return [::Symbol] :public, :private, or :protected
|
14
|
+
attr_reader :visibility
|
15
|
+
|
16
|
+
# @return [Parser::AST::Node]
|
17
|
+
attr_reader :node
|
18
|
+
|
19
|
+
# @param visibility [::Symbol] :public, :protected, or :private
|
20
|
+
# @param explicit [Boolean]
|
21
|
+
def initialize visibility: :public, explicit: true, parameters: [], node: nil, attribute: false, **splat
|
14
22
|
super(**splat)
|
23
|
+
@visibility = visibility
|
24
|
+
@explicit = explicit
|
15
25
|
@parameters = parameters
|
16
26
|
@node = node
|
27
|
+
@attribute = attribute
|
17
28
|
end
|
18
29
|
|
19
30
|
# @return [Array<String>]
|
@@ -22,11 +33,70 @@ module Solargraph
|
|
22
33
|
end
|
23
34
|
|
24
35
|
def completion_item_kind
|
25
|
-
Solargraph::LanguageServer::CompletionItemKinds::METHOD
|
36
|
+
attribute? ? Solargraph::LanguageServer::CompletionItemKinds::PROPERTY : Solargraph::LanguageServer::CompletionItemKinds::METHOD
|
26
37
|
end
|
27
38
|
|
28
39
|
def symbol_kind
|
29
|
-
LanguageServer::SymbolKinds::METHOD
|
40
|
+
attribute? ? Solargraph::LanguageServer::SymbolKinds::PROPERTY : LanguageServer::SymbolKinds::METHOD
|
41
|
+
end
|
42
|
+
|
43
|
+
def return_type
|
44
|
+
@return_type ||= generate_complex_type
|
45
|
+
end
|
46
|
+
|
47
|
+
def path
|
48
|
+
@path ||= "#{namespace}#{(scope == :instance ? '#' : '.')}#{name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def typify api_map
|
52
|
+
decl = super
|
53
|
+
return decl unless decl.undefined?
|
54
|
+
type = see_reference(api_map) || typify_from_super(api_map)
|
55
|
+
return type.qualify(api_map, namespace) unless type.nil?
|
56
|
+
name.end_with?('?') ? ComplexType::BOOLEAN : ComplexType::UNDEFINED
|
57
|
+
end
|
58
|
+
|
59
|
+
def documentation
|
60
|
+
if @documentation.nil?
|
61
|
+
@documentation ||= super || ''
|
62
|
+
param_tags = docstring.tags(:param)
|
63
|
+
unless param_tags.nil? or param_tags.empty?
|
64
|
+
@documentation += "\n\n" unless @documentation.empty?
|
65
|
+
@documentation += "Params:\n"
|
66
|
+
lines = []
|
67
|
+
param_tags.each do |p|
|
68
|
+
l = "* #{p.name}"
|
69
|
+
l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? or p.types.empty?
|
70
|
+
l += " #{p.text}"
|
71
|
+
lines.push l
|
72
|
+
end
|
73
|
+
@documentation += lines.join("\n")
|
74
|
+
end
|
75
|
+
return_tags = docstring.tags(:return)
|
76
|
+
unless return_tags.empty?
|
77
|
+
@documentation += "\n\n" unless @documentation.empty?
|
78
|
+
@documentation += "Returns:\n"
|
79
|
+
lines = []
|
80
|
+
return_tags.each do |r|
|
81
|
+
l = "*"
|
82
|
+
l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? or r.types.empty?
|
83
|
+
l += " #{r.text}"
|
84
|
+
lines.push l
|
85
|
+
end
|
86
|
+
@documentation += lines.join("\n")
|
87
|
+
end
|
88
|
+
@documentation += "\n\n" unless @documentation.empty?
|
89
|
+
@documentation += "Visibility: #{visibility}"
|
90
|
+
end
|
91
|
+
@documentation.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def explicit?
|
95
|
+
@explicit
|
96
|
+
end
|
97
|
+
|
98
|
+
def attribute?
|
99
|
+
@attribute
|
30
100
|
end
|
31
101
|
|
32
102
|
def nearly? other
|
@@ -37,7 +107,7 @@ module Solargraph
|
|
37
107
|
end
|
38
108
|
|
39
109
|
def probe api_map
|
40
|
-
infer_from_return_nodes(api_map)
|
110
|
+
attribute? ? infer_from_iv(api_map) : infer_from_return_nodes(api_map)
|
41
111
|
end
|
42
112
|
|
43
113
|
def try_merge! pin
|
@@ -70,6 +140,57 @@ module Solargraph
|
|
70
140
|
|
71
141
|
private
|
72
142
|
|
143
|
+
# @return [ComplexType]
|
144
|
+
def generate_complex_type
|
145
|
+
tags = docstring.tags(:return).map(&:types).flatten.reject(&:nil?)
|
146
|
+
return ComplexType::UNDEFINED if tags.empty?
|
147
|
+
ComplexType.try_parse *tags
|
148
|
+
end
|
149
|
+
|
150
|
+
# @param api_map [ApiMap]
|
151
|
+
# @return [ComplexType, nil]
|
152
|
+
def see_reference api_map
|
153
|
+
docstring.ref_tags.each do |ref|
|
154
|
+
next unless ref.tag_name == 'return' && ref.owner
|
155
|
+
result = resolve_reference(ref.owner.to_s, api_map)
|
156
|
+
return result unless result.nil?
|
157
|
+
end
|
158
|
+
match = comments.match(/^[ \t]*\(see (.*)\)/m)
|
159
|
+
return nil if match.nil?
|
160
|
+
resolve_reference match[1], api_map
|
161
|
+
end
|
162
|
+
|
163
|
+
# @param api_map [ApiMap]
|
164
|
+
# @return [ComplexType, nil]
|
165
|
+
def typify_from_super api_map
|
166
|
+
stack = api_map.get_method_stack(namespace, name, scope: scope).reject { |pin| pin.path == path }
|
167
|
+
return nil if stack.empty?
|
168
|
+
stack.each do |pin|
|
169
|
+
return pin.return_type unless pin.return_type.undefined?
|
170
|
+
end
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
|
174
|
+
# @param ref [String]
|
175
|
+
# @param api_map [ApiMap]
|
176
|
+
# @return [ComplexType]
|
177
|
+
def resolve_reference ref, api_map
|
178
|
+
parts = ref.split(/[\.#]/)
|
179
|
+
if parts.first.empty? || parts.one?
|
180
|
+
path = "#{namespace}#{ref}"
|
181
|
+
else
|
182
|
+
fqns = api_map.qualify(parts.first, namespace)
|
183
|
+
return ComplexType::UNDEFINED if fqns.nil?
|
184
|
+
path = fqns + ref[parts.first.length] + parts.last
|
185
|
+
end
|
186
|
+
pins = api_map.get_path_pins(path)
|
187
|
+
pins.each do |pin|
|
188
|
+
type = pin.typify(api_map)
|
189
|
+
return type unless type.undefined?
|
190
|
+
end
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
|
73
194
|
# @return [Parser::AST::Node, nil]
|
74
195
|
def method_body_node
|
75
196
|
return nil if node.nil?
|
@@ -106,6 +227,19 @@ module Solargraph
|
|
106
227
|
return ComplexType::UNDEFINED if result.empty?
|
107
228
|
ComplexType.try_parse(*result.map(&:tag).uniq)
|
108
229
|
end
|
230
|
+
|
231
|
+
def infer_from_iv api_map
|
232
|
+
types = []
|
233
|
+
varname = "@#{name.gsub(/=$/, '')}"
|
234
|
+
pins = api_map.get_instance_variable_pins(binder.namespace, binder.scope).select { |iv| iv.name == varname }
|
235
|
+
pins.each do |pin|
|
236
|
+
type = pin.typify(api_map)
|
237
|
+
type = pin.probe(api_map) if type.undefined?
|
238
|
+
types.push type if type.defined?
|
239
|
+
end
|
240
|
+
return ComplexType::UNDEFINED if types.empty?
|
241
|
+
ComplexType.try_parse(*types.map(&:tag).uniq)
|
242
|
+
end
|
109
243
|
end
|
110
244
|
end
|
111
245
|
end
|