solargraph 0.55.4 → 0.55.5
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/.github/workflows/plugins.yml +2 -0
- data/.github/workflows/typecheck.yml +2 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +3 -0
- data/README.md +13 -3
- data/lib/solargraph/api_map/index.rb +23 -15
- data/lib/solargraph/api_map/store.rb +2 -1
- data/lib/solargraph/api_map.rb +53 -27
- data/lib/solargraph/complex_type/type_methods.rb +5 -1
- data/lib/solargraph/complex_type/unique_type.rb +7 -0
- data/lib/solargraph/convention/base.rb +3 -3
- data/lib/solargraph/convention.rb +3 -3
- data/lib/solargraph/doc_map.rb +189 -43
- data/lib/solargraph/gem_pins.rb +53 -38
- data/lib/solargraph/language_server/host.rb +9 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -0
- data/lib/solargraph/language_server/message/extended/document.rb +5 -2
- data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
- data/lib/solargraph/library.rb +7 -4
- data/lib/solargraph/location.rb +13 -0
- data/lib/solargraph/parser/parser_gem/class_methods.rb +5 -8
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +2 -2
- data/lib/solargraph/pin/base.rb +268 -24
- data/lib/solargraph/pin/base_variable.rb +9 -8
- data/lib/solargraph/pin/callable.rb +69 -0
- data/lib/solargraph/pin/closure.rb +12 -0
- data/lib/solargraph/pin/local_variable.rb +8 -5
- data/lib/solargraph/pin/method.rb +134 -17
- data/lib/solargraph/pin/parameter.rb +43 -6
- data/lib/solargraph/pin/signature.rb +38 -0
- data/lib/solargraph/pin_cache.rb +185 -0
- data/lib/solargraph/position.rb +9 -0
- data/lib/solargraph/range.rb +9 -0
- data/lib/solargraph/rbs_map/conversions.rb +19 -8
- data/lib/solargraph/rbs_map/core_map.rb +31 -9
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +74 -17
- data/lib/solargraph/shell.rb +11 -15
- data/lib/solargraph/source_map.rb +0 -17
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +10 -10
- data/lib/solargraph/views/_namespace.erb +3 -3
- data/lib/solargraph/views/document.erb +10 -10
- data/lib/solargraph/workspace.rb +15 -5
- data/lib/solargraph/yardoc.rb +3 -11
- data/lib/solargraph.rb +10 -12
- data/rbs_collection.yaml +19 -0
- data/solargraph.gemspec +1 -0
- metadata +19 -7
- data/lib/solargraph/cache.rb +0 -77
data/lib/solargraph/gem_pins.rb
CHANGED
@@ -7,60 +7,75 @@ module Solargraph
|
|
7
7
|
# documentation.
|
8
8
|
#
|
9
9
|
module GemPins
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
class << self
|
11
|
+
include Logging
|
12
|
+
end
|
13
|
+
|
14
14
|
# @param gemspec [Gem::Specification]
|
15
15
|
# @return [Array<Pin::Base>]
|
16
|
-
def self.
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def self.build_yard_pins(gemspec)
|
17
|
+
Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
|
18
|
+
yardoc = Yardoc.load!(gemspec)
|
19
|
+
YardMap::Mapper.new(yardoc, gemspec).map
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param pins [Array<Pin::Base>]
|
23
|
+
def self.combine_method_pins_by_path(pins)
|
24
|
+
# bad_pins = pins.select { |pin| pin.is_a?(Pin::Method) && pin.path == 'StringIO.open' && pin.source == :rbs }; raise "wtf: #{bad_pins}" if bad_pins.length > 1
|
25
|
+
method_pins, alias_pins = pins.partition { |pin| pin.class == Pin::Method }
|
26
|
+
by_path = method_pins.group_by(&:path)
|
27
|
+
by_path.transform_values! do |pins|
|
28
|
+
GemPins.combine_method_pins(*pins)
|
29
|
+
end
|
30
|
+
by_path.values + alias_pins
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.combine_method_pins(*pins)
|
34
|
+
out = pins.reduce(nil) do |memo, pin|
|
35
|
+
next pin if memo.nil?
|
36
|
+
if memo == pin && memo.source != :combined
|
37
|
+
# @todo we should track down situations where we are handled
|
38
|
+
# the same pin from the same source here and eliminate them -
|
39
|
+
# this is an efficiency workaround for now
|
40
|
+
next memo
|
41
|
+
end
|
42
|
+
memo.combine_with(pin)
|
43
|
+
end
|
44
|
+
logger.debug { "GemPins.combine_method_pins(pins.length=#{pins.length}, pins=#{pins}) => #{out.inspect}" }
|
45
|
+
out
|
20
46
|
end
|
21
47
|
|
22
48
|
# @param yard_pins [Array<Pin::Base>]
|
23
49
|
# @param rbs_map [RbsMap]
|
24
50
|
# @return [Array<Pin::Base>]
|
25
|
-
def self.combine(yard_pins,
|
51
|
+
def self.combine(yard_pins, rbs_pins)
|
26
52
|
in_yard = Set.new
|
27
|
-
|
28
|
-
|
29
|
-
|
53
|
+
rbs_api_map = Solargraph::ApiMap.new(pins: rbs_pins)
|
54
|
+
combined = yard_pins.map do |yard_pin|
|
55
|
+
in_yard.add yard_pin.path
|
56
|
+
rbs_pin = rbs_api_map.get_path_pins(yard_pin.path).filter { |pin| pin.is_a? Pin::Method }.first
|
57
|
+
next yard_pin unless rbs_pin && yard_pin.class == Pin::Method
|
30
58
|
|
31
|
-
|
32
|
-
|
59
|
+
unless rbs_pin
|
60
|
+
logger.debug { "GemPins.combine: No rbs pin for #{yard_pin.path} - using YARD's '#{yard_pin.inspect} (return_type=#{yard_pin.return_type}; signatures=#{yard_pin.signatures})" }
|
61
|
+
next yard_pin
|
62
|
+
end
|
33
63
|
|
34
|
-
|
35
|
-
yard.
|
36
|
-
|
37
|
-
closure: yard.closure,
|
38
|
-
name: yard.name,
|
39
|
-
comments: yard.comments,
|
40
|
-
scope: yard.scope,
|
41
|
-
parameters: rbs.parameters,
|
42
|
-
generics: rbs.generics,
|
43
|
-
node: yard.node,
|
44
|
-
signatures: yard.signatures,
|
45
|
-
return_type: best_return_type(rbs.return_type, yard.return_type),
|
46
|
-
source: :gem_pins
|
47
|
-
)
|
64
|
+
out = combine_method_pins(rbs_pin, yard_pin)
|
65
|
+
logger.debug { "GemPins.combine: Combining yard.path=#{yard_pin.path} - rbs=#{rbs_pin.inspect} with yard=#{yard_pin.inspect} into #{out}" }
|
66
|
+
out
|
48
67
|
end
|
49
|
-
|
50
|
-
|
68
|
+
in_rbs_only = rbs_pins.select do |pin|
|
69
|
+
pin.path.nil? || !in_yard.include?(pin.path)
|
70
|
+
end
|
71
|
+
out = combined + in_rbs_only
|
72
|
+
logger.debug { "GemPins#combine: Returning #{out.length} combined pins" }
|
73
|
+
out
|
51
74
|
end
|
52
75
|
|
53
76
|
class << self
|
54
77
|
private
|
55
78
|
|
56
|
-
# @param gemspec [Gem::Specification]
|
57
|
-
# @return [Array<Pin::Base>]
|
58
|
-
def build_yard_pins(gemspec)
|
59
|
-
Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
|
60
|
-
yardoc = Yardoc.load!(gemspec)
|
61
|
-
YardMap::Mapper.new(yardoc, gemspec).map
|
62
|
-
end
|
63
|
-
|
64
79
|
# Select the first defined type.
|
65
80
|
#
|
66
81
|
# @param choices [Array<ComplexType>]
|
@@ -299,6 +299,10 @@ module Solargraph
|
|
299
299
|
end
|
300
300
|
end
|
301
301
|
|
302
|
+
def command_path
|
303
|
+
options['commandPath'] || 'solargraph'
|
304
|
+
end
|
305
|
+
|
302
306
|
# Prepare multiple folders.
|
303
307
|
#
|
304
308
|
# @param array [Array<Hash{String => String}>]
|
@@ -598,7 +602,11 @@ module Solargraph
|
|
598
602
|
# @return [Array]
|
599
603
|
def document query
|
600
604
|
result = []
|
601
|
-
libraries.
|
605
|
+
if libraries.empty?
|
606
|
+
result.concat generic_library.document(query)
|
607
|
+
else
|
608
|
+
libraries.each { |lib| result.concat lib.document(query) }
|
609
|
+
end
|
602
610
|
result
|
603
611
|
end
|
604
612
|
|
@@ -6,12 +6,15 @@ module Solargraph
|
|
6
6
|
module Extended
|
7
7
|
class Document < Base
|
8
8
|
def process
|
9
|
-
|
9
|
+
api_map, pins = host.document(params['query'])
|
10
10
|
page = Solargraph::Page.new(host.options['viewsPath'])
|
11
|
-
content = page.render('document', layout: true, locals: {
|
11
|
+
content = page.render('document', layout: true, locals: { api_map: api_map, pins: pins })
|
12
12
|
set_result(
|
13
13
|
content: content
|
14
14
|
)
|
15
|
+
rescue StandardError => e
|
16
|
+
Solargraph.logger.warn "Error processing document: [#{e.class}] #{e.message}"
|
17
|
+
Solargraph.logger.debug e.backtrace.join("\n")
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -11,9 +11,9 @@ module Solargraph
|
|
11
11
|
#
|
12
12
|
class DocumentGems < Base
|
13
13
|
def process
|
14
|
-
cmd =
|
15
|
-
cmd
|
16
|
-
o, s = Open3.capture2(cmd)
|
14
|
+
cmd = [host.command_path, 'gems']
|
15
|
+
cmd.push '--rebuild' if params['rebuild']
|
16
|
+
o, s = Open3.capture2(*cmd)
|
17
17
|
if s != 0
|
18
18
|
host.show_message "An error occurred while building gem documentation.", LanguageServer::MessageTypes::ERROR
|
19
19
|
set_result({
|
data/lib/solargraph/library.rb
CHANGED
@@ -327,9 +327,10 @@ module Solargraph
|
|
327
327
|
|
328
328
|
# @param query [String]
|
329
329
|
# @return [Enumerable<YARD::CodeObjects::Base>]
|
330
|
+
# @return [Array(ApiMap, Enumerable<Pin::Base>)]
|
330
331
|
def document query
|
331
332
|
sync_catalog
|
332
|
-
mutex.synchronize { api_map.
|
333
|
+
mutex.synchronize { [api_map, api_map.get_path_pins(query)] }
|
333
334
|
end
|
334
335
|
|
335
336
|
# @param query [String]
|
@@ -586,8 +587,9 @@ module Solargraph
|
|
586
587
|
|
587
588
|
# @return [void]
|
588
589
|
def cache_next_gemspec
|
589
|
-
return if @
|
590
|
-
spec = api_map.
|
590
|
+
return if @cache_progres
|
591
|
+
spec = (api_map.uncached_yard_gemspecs + api_map.uncached_rbs_collection_gemspecs).
|
592
|
+
find { |spec| !cache_errors.include?(spec) }
|
591
593
|
return end_cache_progress unless spec
|
592
594
|
|
593
595
|
pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
|
@@ -654,7 +656,8 @@ module Solargraph
|
|
654
656
|
api_map.catalog bench
|
655
657
|
source_map_hash.values.each { |map| find_external_requires(map) }
|
656
658
|
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
657
|
-
logger.info "#{api_map.
|
659
|
+
logger.info "#{api_map.uncached_yard_gemspecs.length} uncached YARD gemspecs"
|
660
|
+
logger.info "#{api_map.uncached_rbs_collection_gemspecs.length} uncached RBS collection gemspecs"
|
658
661
|
cache_next_gemspec
|
659
662
|
@sync_count = 0
|
660
663
|
end
|
data/lib/solargraph/location.rb
CHANGED
@@ -25,6 +25,19 @@ module Solargraph
|
|
25
25
|
[filename, range]
|
26
26
|
end
|
27
27
|
|
28
|
+
def <=>(other)
|
29
|
+
return nil unless other.is_a?(Location)
|
30
|
+
if filename == other.filename
|
31
|
+
range <=> other.range
|
32
|
+
else
|
33
|
+
filename <=> other.filename
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def rbs?
|
38
|
+
filename.end_with?('.rbs')
|
39
|
+
end
|
40
|
+
|
28
41
|
# @param location [self]
|
29
42
|
def contain? location
|
30
43
|
range.contain?(location.range.start) && range.contain?(location.range.ending) && filename == location.filename
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'parser/source/buffer'
|
3
|
+
require 'prism'
|
5
4
|
|
6
5
|
# Awaiting ability to use a version containing https://github.com/whitequark/parser/pull/1076
|
7
6
|
#
|
@@ -39,12 +38,10 @@ module Solargraph
|
|
39
38
|
|
40
39
|
# @return [::Parser::Base]
|
41
40
|
def parser
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
parser.diagnostics.ignore_warnings = true
|
47
|
-
parser
|
41
|
+
@parser ||= Prism::Translation::Parser.new(FlawedBuilder.new).tap do |parser|
|
42
|
+
parser.diagnostics.all_errors_are_fatal = true
|
43
|
+
parser.diagnostics.ignore_warnings = true
|
44
|
+
end
|
48
45
|
end
|
49
46
|
|
50
47
|
# @param source [Source]
|
@@ -30,8 +30,8 @@ module Solargraph
|
|
30
30
|
process_children
|
31
31
|
end
|
32
32
|
|
33
|
-
#
|
34
|
-
#
|
33
|
+
# @todo Move this out of [CasgnNode] once [Solargraph::Parser::NodeProcessor] supports
|
34
|
+
# multiple processors.
|
35
35
|
def process_struct_assignment
|
36
36
|
processor_klass = Convention::StructDefinition::NodeProcessors::StructNode
|
37
37
|
processor = processor_klass.new(node, region, pins, locals)
|
@@ -45,8 +45,8 @@ module Solargraph
|
|
45
45
|
process_children region.update(closure: nspin, visibility: :public)
|
46
46
|
end
|
47
47
|
|
48
|
-
#
|
49
|
-
#
|
48
|
+
# @todo Move this out of [NamespaceNode] once [Solargraph::Parser::NodeProcessor] supports
|
49
|
+
# multiple processors.
|
50
50
|
def process_struct_definition
|
51
51
|
processor_klass = Convention::StructDefinition::NodeProcessors::StructNode
|
52
52
|
processor = processor_klass.new(node, region, pins, locals)
|
data/lib/solargraph/pin/base.rb
CHANGED
@@ -8,6 +8,7 @@ module Solargraph
|
|
8
8
|
include Common
|
9
9
|
include Conversions
|
10
10
|
include Documenting
|
11
|
+
include Logging
|
11
12
|
|
12
13
|
# @return [YARD::CodeObjects::Base]
|
13
14
|
attr_reader :code_object
|
@@ -36,16 +37,273 @@ module Solargraph
|
|
36
37
|
# @param closure [Solargraph::Pin::Closure, nil]
|
37
38
|
# @param name [String]
|
38
39
|
# @param comments [String]
|
39
|
-
|
40
|
+
# @param source [Symbol, nil]
|
41
|
+
# @param docstring [YARD::Docstring, nil]
|
42
|
+
# @param directives [::Array<YARD::Tags::Directive>, nil]
|
43
|
+
def initialize location: nil, type_location: nil, closure: nil, source: nil, name: '', comments: '', docstring: nil, directives: nil
|
40
44
|
@location = location
|
41
45
|
@type_location = type_location
|
42
46
|
@closure = closure
|
43
47
|
@name = name
|
44
48
|
@comments = comments
|
45
49
|
@source = source
|
50
|
+
@identity = nil
|
51
|
+
@docstring = docstring
|
52
|
+
@directives = directives
|
46
53
|
assert_source_provided
|
47
54
|
end
|
48
55
|
|
56
|
+
# @param other [self]
|
57
|
+
# @param attrs [Hash{Symbol => Object}]
|
58
|
+
#
|
59
|
+
# @return [self]
|
60
|
+
def combine_with(other, attrs={})
|
61
|
+
raise "tried to combine #{other.class} with #{self.class}" unless other.class == self.class
|
62
|
+
type_location = choose(other, :type_location)
|
63
|
+
location = choose(other, :location)
|
64
|
+
combined_name = combine_name(other)
|
65
|
+
new_attrs = {
|
66
|
+
location: location,
|
67
|
+
type_location: type_location,
|
68
|
+
name: combined_name,
|
69
|
+
closure: choose_pin_attr_with_same_name(other, :closure),
|
70
|
+
comments: choose_longer(other, :comments),
|
71
|
+
source: :combined,
|
72
|
+
docstring: choose(other, :docstring),
|
73
|
+
directives: combine_directives(other),
|
74
|
+
}.merge(attrs)
|
75
|
+
assert_same_macros(other)
|
76
|
+
logger.debug { "Base#combine_with(path=#{path}) - other.comments=#{other.comments.inspect}, self.comments = #{self.comments}" }
|
77
|
+
out = self.class.new(**new_attrs)
|
78
|
+
out.reset_generated!
|
79
|
+
out
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param other [self]
|
83
|
+
# @param attr [::Symbol]
|
84
|
+
# @sg-ignore
|
85
|
+
# @return [undefined]
|
86
|
+
def choose_longer(other, attr)
|
87
|
+
# @type [undefined]
|
88
|
+
val1 = send(attr)
|
89
|
+
# @type [undefined]
|
90
|
+
val2 = other.send(attr)
|
91
|
+
return val1 if val1 == val2
|
92
|
+
return val2 if val1.nil?
|
93
|
+
# @sg-ignore
|
94
|
+
val1.length > val2.length ? val1 : val2
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param other [self]
|
98
|
+
# @return [::Array<YARD::Tags::Directive>, nil]
|
99
|
+
def combine_directives(other)
|
100
|
+
return self.directives if other.directives.empty?
|
101
|
+
return other.directives if directives.empty?
|
102
|
+
[directives + other.directives].uniq
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param other [self]
|
106
|
+
# @return [String]
|
107
|
+
def combine_name(other)
|
108
|
+
if needs_consistent_name? || other.needs_consistent_name?
|
109
|
+
assert_same(other, :name)
|
110
|
+
else
|
111
|
+
choose(other, :name)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# @return [void]
|
116
|
+
def reset_generated!
|
117
|
+
# @return_type doesn't go here as subclasses tend to assign it
|
118
|
+
# themselves in constructors, and they will deal with setting
|
119
|
+
# it in any methods that call this
|
120
|
+
#
|
121
|
+
# @docstring also doesn't go here, as there is code which
|
122
|
+
# directly manipulates docstring without editing comments
|
123
|
+
# (e.g., Api::Map::Store#index processes overrides that way
|
124
|
+
#
|
125
|
+
# Same with @directives, @macros, @maybe_directives, which
|
126
|
+
# regenerate docstring
|
127
|
+
@deprecated = nil
|
128
|
+
reset_conversions
|
129
|
+
end
|
130
|
+
|
131
|
+
def needs_consistent_name?
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
# @sg-ignore def should infer as symbol - "Not enough arguments to Module#protected"
|
136
|
+
protected def equality_fields
|
137
|
+
[name, location, type_location, closure, source]
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param other [self]
|
141
|
+
# @return [ComplexType]
|
142
|
+
def combine_return_type(other)
|
143
|
+
if return_type.undefined?
|
144
|
+
other.return_type
|
145
|
+
elsif other.return_type.undefined?
|
146
|
+
return_type
|
147
|
+
elsif dodgy_return_type_source? && !other.dodgy_return_type_source?
|
148
|
+
other.return_type
|
149
|
+
elsif other.dodgy_return_type_source? && !dodgy_return_type_source?
|
150
|
+
return_type
|
151
|
+
else
|
152
|
+
all_items = return_type.items + other.return_type.items
|
153
|
+
if all_items.any? { |item| item.selfy? } && all_items.any? { |item| item.rooted_tag == context.rooted_tag }
|
154
|
+
# assume this was a declaration that should have said 'self'
|
155
|
+
all_items.delete_if { |item| item.rooted_tag == context.rooted_tag }
|
156
|
+
end
|
157
|
+
ComplexType.new(all_items)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def dodgy_return_type_source?
|
162
|
+
# uses a lot of 'Object' instead of 'self'
|
163
|
+
location&.filename&.include?('core_ext/object/')
|
164
|
+
end
|
165
|
+
|
166
|
+
# when choices are arbitrary, make sure the choice is consistent
|
167
|
+
#
|
168
|
+
# @param other [Pin::Base]
|
169
|
+
# @param attr [::Symbol]
|
170
|
+
#
|
171
|
+
# @return [Object, nil]
|
172
|
+
def choose(other, attr)
|
173
|
+
results = [self, other].map(&attr).compact
|
174
|
+
# true and false are different classes and can't be sorted
|
175
|
+
return true if results.any? { |r| r == true || r == false }
|
176
|
+
results.min
|
177
|
+
rescue
|
178
|
+
STDERR.puts("Problem handling #{attr} for \n#{self.inspect}\n and \n#{other.inspect}\n\n#{self.send(attr).inspect} vs #{other.send(attr).inspect}")
|
179
|
+
raise
|
180
|
+
end
|
181
|
+
|
182
|
+
# @param other [self]
|
183
|
+
# @param attr [Symbol]
|
184
|
+
# @sg-ignore
|
185
|
+
# @return [undefined]
|
186
|
+
def choose_node(other, attr)
|
187
|
+
if other.object_id < attr.object_id
|
188
|
+
other.send(attr)
|
189
|
+
else
|
190
|
+
send(attr)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# @param other [self]
|
195
|
+
# @param attr [::Symbol]
|
196
|
+
# @sg-ignore
|
197
|
+
# @return [undefined]
|
198
|
+
def prefer_rbs_location(other, attr)
|
199
|
+
if rbs_location? && !other.rbs_location?
|
200
|
+
self.send(attr)
|
201
|
+
elsif !rbs_location? && other.rbs_location?
|
202
|
+
other.send(attr)
|
203
|
+
else
|
204
|
+
choose(other, attr)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def rbs_location?
|
209
|
+
type_location&.rbs?
|
210
|
+
end
|
211
|
+
|
212
|
+
# @param other [self]
|
213
|
+
# @return [void]
|
214
|
+
def assert_same_macros(other)
|
215
|
+
return unless self.source == :yardoc && other.source == :yardoc
|
216
|
+
assert_same_count(other, :macros)
|
217
|
+
assert_same_array_content(other, :macros) { |macro| macro.tag.name }
|
218
|
+
end
|
219
|
+
|
220
|
+
# @param other [self]
|
221
|
+
# @param attr [::Symbol]
|
222
|
+
# @return [void]
|
223
|
+
# @todo strong typechecking should complain when there are no block-related tags
|
224
|
+
def assert_same_array_content(other, attr, &block)
|
225
|
+
arr1 = send(attr)
|
226
|
+
raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable)
|
227
|
+
# @type arr1 [::Enumerable]
|
228
|
+
arr2 = other.send(attr)
|
229
|
+
raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable)
|
230
|
+
# @type arr2 [::Enumerable]
|
231
|
+
|
232
|
+
# @sg-ignore
|
233
|
+
# @type [undefined]
|
234
|
+
values1 = arr1.map(&block)
|
235
|
+
# @type [undefined]
|
236
|
+
values2 = arr2.map(&block)
|
237
|
+
# @sg-ignore
|
238
|
+
return arr1 if values1 == values2
|
239
|
+
Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
|
240
|
+
"Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self values = #{values1}\nother values =#{attr} = #{values2}")
|
241
|
+
arr1
|
242
|
+
end
|
243
|
+
|
244
|
+
# @param other [self]
|
245
|
+
# @param attr [::Symbol]
|
246
|
+
#
|
247
|
+
# @return [::Enumerable]
|
248
|
+
def assert_same_count(other, attr)
|
249
|
+
# @type [::Enumerable]
|
250
|
+
arr1 = self.send(attr)
|
251
|
+
raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable)
|
252
|
+
# @type [::Enumerable]
|
253
|
+
arr2 = other.send(attr)
|
254
|
+
raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable)
|
255
|
+
return arr1 if arr1.count == arr2.count
|
256
|
+
Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
|
257
|
+
"Inconsistent #{attr.inspect} count value between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{arr1.inspect}\nother.#{attr} = #{arr2.inspect}")
|
258
|
+
arr1
|
259
|
+
end
|
260
|
+
|
261
|
+
# @param other [self]
|
262
|
+
# @param attr [::Symbol]
|
263
|
+
#
|
264
|
+
# @return [Object, nil]
|
265
|
+
def assert_same(other, attr)
|
266
|
+
return false if other.nil?
|
267
|
+
val1 = send(attr)
|
268
|
+
val2 = other.send(attr)
|
269
|
+
return val1 if val1 == val2
|
270
|
+
Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
|
271
|
+
"Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
|
272
|
+
val1
|
273
|
+
end
|
274
|
+
|
275
|
+
# @param other [self]
|
276
|
+
# @param attr [::Symbol]
|
277
|
+
# @sg-ignore
|
278
|
+
# @return [undefined]
|
279
|
+
def choose_pin_attr_with_same_name(other, attr)
|
280
|
+
# @type [Pin::Base, nil]
|
281
|
+
val1 = send(attr)
|
282
|
+
# @type [Pin::Base, nil]
|
283
|
+
val2 = other.send(attr)
|
284
|
+
raise "Expected pin for #{attr} on\n#{self.inspect},\ngot #{val1.inspect}" unless val1.nil? || val1.is_a?(Pin::Base)
|
285
|
+
raise "Expected pin for #{attr} on\n#{other.inspect},\ngot #{val2.inspect}" unless val2.nil? || val2.is_a?(Pin::Base)
|
286
|
+
if val1&.name != val2&.name
|
287
|
+
Solargraph.assert_or_log("combine_with_#{attr}_name".to_sym,
|
288
|
+
"Inconsistent #{attr.inspect} name values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
|
289
|
+
end
|
290
|
+
choose_pin_attr(other, attr)
|
291
|
+
end
|
292
|
+
|
293
|
+
def choose_pin_attr(other, attr)
|
294
|
+
# @type [Pin::Base, nil]
|
295
|
+
val1 = send(attr)
|
296
|
+
# @type [Pin::Base, nil]
|
297
|
+
val2 = other.send(attr)
|
298
|
+
if val1.class != val2.class
|
299
|
+
Solargraph.assert_or_log("combine_with_#{attr}_class".to_sym,
|
300
|
+
"Inconsistent #{attr.inspect} class values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
|
301
|
+
return val1
|
302
|
+
end
|
303
|
+
# arbitrary way of choosing a pin
|
304
|
+
[val1, val2].compact.min_by { _1.best_location.to_s }
|
305
|
+
end
|
306
|
+
|
49
307
|
def assert_source_provided
|
50
308
|
Solargraph.assert_or_log(:source, "source not provided - #{@path} #{@source} #{self.class}") if source.nil?
|
51
309
|
end
|
@@ -144,6 +402,7 @@ module Solargraph
|
|
144
402
|
# Pin equality is determined using the #nearly? method and also
|
145
403
|
# requiring both pins to have the same location.
|
146
404
|
#
|
405
|
+
# @param other [self]
|
147
406
|
def == other
|
148
407
|
return false unless nearly? other
|
149
408
|
comments == other.comments && location == other.location
|
@@ -158,13 +417,13 @@ module Solargraph
|
|
158
417
|
|
159
418
|
# @return [YARD::Docstring]
|
160
419
|
def docstring
|
161
|
-
parse_comments unless
|
420
|
+
parse_comments unless @docstring
|
162
421
|
@docstring ||= Solargraph::Source.parse_docstring('').to_docstring
|
163
422
|
end
|
164
423
|
|
165
424
|
# @return [::Array<YARD::Tags::Directive>]
|
166
425
|
def directives
|
167
|
-
parse_comments unless
|
426
|
+
parse_comments unless @directives
|
168
427
|
@directives
|
169
428
|
end
|
170
429
|
|
@@ -182,7 +441,7 @@ module Solargraph
|
|
182
441
|
#
|
183
442
|
# @return [Boolean]
|
184
443
|
def maybe_directives?
|
185
|
-
return !@directives.empty? if defined?(@directives)
|
444
|
+
return !@directives.empty? if defined?(@directives) && @directives
|
186
445
|
@maybe_directives ||= comments.include?('@!')
|
187
446
|
end
|
188
447
|
|
@@ -221,26 +480,6 @@ module Solargraph
|
|
221
480
|
probe api_map
|
222
481
|
end
|
223
482
|
|
224
|
-
# Try to merge data from another pin. Merges are only possible if the
|
225
|
-
# pins are near matches (see the #nearly? method). The changes should
|
226
|
-
# not have any side effects on the API surface.
|
227
|
-
#
|
228
|
-
# @param pin [Pin::Base] The pin to merge into this one
|
229
|
-
# @return [Boolean] True if the pins were merged
|
230
|
-
def try_merge! pin
|
231
|
-
return false unless nearly?(pin)
|
232
|
-
@location = pin.location
|
233
|
-
@closure = pin.closure
|
234
|
-
return true if comments == pin.comments
|
235
|
-
@comments = pin.comments
|
236
|
-
@docstring = pin.docstring
|
237
|
-
@return_type = pin.return_type
|
238
|
-
@documentation = nil
|
239
|
-
@deprecated = nil
|
240
|
-
reset_conversions
|
241
|
-
true
|
242
|
-
end
|
243
|
-
|
244
483
|
def proxied?
|
245
484
|
@proxied ||= false
|
246
485
|
end
|
@@ -313,6 +552,7 @@ module Solargraph
|
|
313
552
|
"[#{inner_desc}]"
|
314
553
|
end
|
315
554
|
|
555
|
+
# @return [String]
|
316
556
|
def inspect
|
317
557
|
"#<#{self.class} `#{self.inner_desc}`#{all_location_text} via #{source.inspect}>"
|
318
558
|
end
|
@@ -343,6 +583,10 @@ module Solargraph
|
|
343
583
|
# @return [ComplexType]
|
344
584
|
attr_writer :return_type
|
345
585
|
|
586
|
+
attr_writer :docstring
|
587
|
+
|
588
|
+
attr_writer :directives
|
589
|
+
|
346
590
|
private
|
347
591
|
|
348
592
|
# @return [void]
|
@@ -21,6 +21,15 @@ module Solargraph
|
|
21
21
|
@return_type = return_type
|
22
22
|
end
|
23
23
|
|
24
|
+
def combine_with(other, attrs={})
|
25
|
+
attrs.merge({
|
26
|
+
assignment: assert_same(other, :assignment),
|
27
|
+
mass_assignment: assert_same(other, :mass_assignment),
|
28
|
+
return_type: combine_return_type(other),
|
29
|
+
})
|
30
|
+
super(other, attrs)
|
31
|
+
end
|
32
|
+
|
24
33
|
def completion_item_kind
|
25
34
|
Solargraph::LanguageServer::CompletionItemKinds::VARIABLE
|
26
35
|
end
|
@@ -99,14 +108,6 @@ module Solargraph
|
|
99
108
|
assignment == other.assignment
|
100
109
|
end
|
101
110
|
|
102
|
-
# @param pin [self]
|
103
|
-
def try_merge! pin
|
104
|
-
return false unless super
|
105
|
-
@assignment = pin.assignment
|
106
|
-
@return_type = pin.return_type
|
107
|
-
true
|
108
|
-
end
|
109
|
-
|
110
111
|
def type_desc
|
111
112
|
"#{super} = #{assignment&.type.inspect}"
|
112
113
|
end
|