solargraph 0.60.4 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/linting.yml +24 -2
- data/.github/workflows/plugins.yml +19 -1
- data/.github/workflows/rspec.yml +17 -2
- data/.github/workflows/typecheck.yml +6 -0
- data/CHANGELOG.md +54 -0
- data/Gemfile +0 -3
- data/lib/solargraph/api_map/index.rb +28 -4
- data/lib/solargraph/api_map/store.rb +19 -0
- data/lib/solargraph/api_map.rb +91 -80
- data/lib/solargraph/cache_dir.rb +58 -0
- data/lib/solargraph/collection/base.rb +50 -0
- data/lib/solargraph/collection/core.rb +17 -0
- data/lib/solargraph/collection/gem.rb +59 -0
- data/lib/solargraph/collection/stdlib.rb +25 -0
- data/lib/solargraph/collection.rb +30 -0
- data/lib/solargraph/complex_type/unique_type.rb +13 -0
- data/lib/solargraph/complex_type.rb +23 -3
- data/lib/solargraph/convention.rb +5 -7
- data/lib/solargraph/diagnostics/require_not_found.rb +0 -4
- data/lib/solargraph/diagnostics/type_check.rb +0 -1
- data/lib/solargraph/external.rb +187 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
- data/lib/solargraph/language_server/host/dispatch.rb +4 -2
- data/lib/solargraph/language_server/host.rb +10 -2
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +10 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +5 -2
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -2
- data/lib/solargraph/library.rb +26 -53
- data/lib/solargraph/metagem.rb +80 -0
- data/lib/solargraph/parser/node_processor/base.rb +6 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +22 -3
- data/lib/solargraph/parser/parser_gem/node_methods.rb +29 -6
- data/lib/solargraph/parser/parser_gem/node_processors/class_definition/class_assignment_node.rb +98 -0
- data/lib/solargraph/parser/parser_gem/node_processors/class_definition.rb +54 -0
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/data_definition/data_assignment_node.rb +65 -0
- data/lib/solargraph/parser/parser_gem/node_processors/data_definition/data_definition_node.rb +97 -0
- data/lib/solargraph/parser/parser_gem/node_processors/data_definition.rb +110 -0
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +185 -0
- data/lib/solargraph/parser/parser_gem/node_processors/struct_definition/struct_assignment_node.rb +66 -0
- data/lib/solargraph/parser/parser_gem/node_processors/struct_definition/struct_definition_node.rb +108 -0
- data/lib/solargraph/parser/parser_gem/node_processors/struct_definition.rb +170 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +33 -29
- data/lib/solargraph/pin/base.rb +25 -1
- data/lib/solargraph/pin/base_variable.rb +31 -1
- data/lib/solargraph/pin/callable.rb +11 -2
- data/lib/solargraph/pin/closure.rb +17 -0
- data/lib/solargraph/pin/delegated_method.rb +5 -0
- data/lib/solargraph/pin/duck_method.rb +36 -16
- data/lib/solargraph/pin/factory_parameter.rb +84 -0
- data/lib/solargraph/pin/instance_variable.rb +45 -0
- data/lib/solargraph/pin/method.rb +10 -0
- data/lib/solargraph/pin/method_alias.rb +4 -0
- data/lib/solargraph/pin/parameter.rb +1 -1
- data/lib/solargraph/pin/reference/included_mixin.rb +22 -0
- data/lib/solargraph/pin/reference.rb +1 -0
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/plugin/active_support.rb +100 -0
- data/lib/solargraph/plugin/addon.rb +16 -0
- data/lib/solargraph/plugin/base.rb +25 -0
- data/lib/solargraph/plugin/panel.rb +37 -0
- data/lib/solargraph/plugin.rb +26 -0
- data/lib/solargraph/rbs_collection.rb +119 -0
- data/lib/solargraph/rbs_map/base.rb +31 -0
- data/lib/solargraph/rbs_map/conversions.rb +109 -48
- data/lib/solargraph/rbs_map/{core_map.rb → core.rb} +18 -39
- data/lib/solargraph/rbs_map/core_fills.rb +1 -1
- data/lib/solargraph/rbs_map/gem.rb +16 -0
- data/lib/solargraph/rbs_map/helpers.rb +61 -0
- data/lib/solargraph/rbs_map/path.rb +19 -0
- data/lib/solargraph/rbs_map/stdlib.rb +24 -0
- data/lib/solargraph/rbs_map.rb +7 -198
- data/lib/solargraph/rbs_translator.rb +105 -70
- data/lib/solargraph/repo.rb +177 -0
- data/lib/solargraph/shell.rb +49 -99
- data/lib/solargraph/source/chain/call.rb +58 -14
- data/lib/solargraph/source/chain/literal.rb +17 -17
- data/lib/solargraph/source/chain/parameter.rb +79 -0
- data/lib/solargraph/source/chain.rb +8 -0
- data/lib/solargraph/source/node_map.rb +27 -0
- data/lib/solargraph/source/source_chainer.rb +40 -44
- data/lib/solargraph/source.rb +17 -0
- data/lib/solargraph/source_map/call.rb +18 -0
- data/lib/solargraph/source_map/clip.rb +5 -3
- data/lib/solargraph/source_map/mapper.rb +6 -2
- data/lib/solargraph/source_map.rb +28 -9
- data/lib/solargraph/type_checker/rules.rb +3 -2
- data/lib/solargraph/type_checker.rb +4 -1
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +0 -1
- data/lib/solargraph/yard_map/cache.rb +1 -1
- data/lib/solargraph/yard_map/directives/attribute_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/domain_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/method_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/override_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/parse_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives/scope_directive.rb +178 -0
- data/lib/solargraph/yard_map/directives/visibility_directive.rb +1 -1
- data/lib/solargraph/yard_map/directives.rb +5 -2
- data/lib/solargraph/yard_map/helpers.rb +1 -1
- data/lib/solargraph/yard_map/macro.rb +85 -6
- data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -1
- data/lib/solargraph/yard_map/mapper.rb +2 -2
- data/lib/solargraph/yard_map.rb +1 -1
- data/lib/solargraph/yardoc.rb +43 -60
- data/lib/solargraph.rb +8 -3
- data/rbs/fills/boolean/0/boolean.rbs +12 -0
- data/solargraph.gemspec +2 -2
- metadata +41 -18
- data/lib/solargraph/convention/active_support_concern.rb +0 -111
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +0 -61
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +0 -93
- data/lib/solargraph/convention/data_definition.rb +0 -108
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +0 -62
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +0 -103
- data/lib/solargraph/convention/struct_definition.rb +0 -168
- data/lib/solargraph/doc_map.rb +0 -439
- data/lib/solargraph/gem_pins.rb +0 -87
- data/lib/solargraph/pin_cache.rb +0 -248
- data/lib/solargraph/rbs_map/stdlib_map.rb +0 -71
- data/lib/solargraph/workspace/gemspecs.rb +0 -373
data/lib/solargraph/library.rb
CHANGED
|
@@ -576,14 +576,8 @@ module Solargraph
|
|
|
576
576
|
return unless source
|
|
577
577
|
# @sg-ignore Wrong argument type for Solargraph::Workspace#has_file?: filename expected String, received String, nil
|
|
578
578
|
return unless @current == source || workspace.has_file?(source.filename)
|
|
579
|
-
if
|
|
580
|
-
|
|
581
|
-
# @sg-ignore OK if source.filename is nil
|
|
582
|
-
source_map_hash[source.filename] = new_map
|
|
583
|
-
else
|
|
584
|
-
# @sg-ignore OK if source.filename is nil
|
|
585
|
-
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
|
586
|
-
end
|
|
579
|
+
# @sg-ignore OK if source.filename is nil
|
|
580
|
+
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
|
587
581
|
end
|
|
588
582
|
|
|
589
583
|
# @return [Set<Gem::Specification>]
|
|
@@ -595,57 +589,35 @@ module Solargraph
|
|
|
595
589
|
def cache_next_gemspec
|
|
596
590
|
return if @cache_progress
|
|
597
591
|
|
|
598
|
-
spec =
|
|
592
|
+
spec = (api_map.unloaded_gems - cache_errors).first
|
|
599
593
|
return end_cache_progress unless spec
|
|
600
594
|
|
|
601
|
-
pending = api_map.
|
|
595
|
+
pending = api_map.unloaded_gems.length - cache_errors.length - 1
|
|
602
596
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
return if pending - queued_gemspec_cache.length < 1
|
|
597
|
+
logger.info "Caching #{spec.name} #{spec.version}"
|
|
598
|
+
Thread.new do
|
|
599
|
+
report_cache_progress spec.name, pending
|
|
607
600
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
else
|
|
615
|
-
logger.info "Caching #{spec.name} #{spec.version}"
|
|
616
|
-
Thread.new do
|
|
617
|
-
report_cache_progress spec.name, pending
|
|
618
|
-
_o, e, s = Open3.capture3(workspace.command_path, 'cache', spec.name, spec.version.to_s)
|
|
619
|
-
if s.success?
|
|
620
|
-
logger.info "Cached #{spec.name} #{spec.version}"
|
|
621
|
-
else
|
|
622
|
-
cache_errors.add spec
|
|
623
|
-
logger.warn "Error caching gemspec #{spec.name} #{spec.version}"
|
|
624
|
-
logger.warn e
|
|
625
|
-
end
|
|
626
|
-
end_cache_progress
|
|
627
|
-
catalog
|
|
628
|
-
sync_catalog
|
|
601
|
+
cmd = [workspace.command_path, 'cache', spec.name]
|
|
602
|
+
cmd.push('--directory', workspace.directory) if workspace.directory
|
|
603
|
+
begin
|
|
604
|
+
_o, e, s = Open3.capture3(*cmd)
|
|
605
|
+
rescue SystemCallError => e
|
|
606
|
+
# The command could not start, e.g. Errno::ENOENT - handled below
|
|
629
607
|
end
|
|
608
|
+
if s&.success?
|
|
609
|
+
logger.info "Cached #{spec.name} #{spec.version}"
|
|
610
|
+
else
|
|
611
|
+
cache_errors.add spec
|
|
612
|
+
logger.warn "Error caching gemspec #{spec.name} #{spec.version}"
|
|
613
|
+
logger.warn e
|
|
614
|
+
end
|
|
615
|
+
end_cache_progress
|
|
616
|
+
catalog
|
|
617
|
+
sync_catalog
|
|
630
618
|
end
|
|
631
619
|
end
|
|
632
620
|
|
|
633
|
-
# @return [Array<Gem::Specification>]
|
|
634
|
-
def cacheable_specs
|
|
635
|
-
cacheable = api_map.uncached_yard_gemspecs +
|
|
636
|
-
api_map.uncached_rbs_collection_gemspecs -
|
|
637
|
-
queued_gemspec_cache -
|
|
638
|
-
cache_errors.to_a
|
|
639
|
-
return cacheable unless cacheable.empty?
|
|
640
|
-
|
|
641
|
-
queued_gemspec_cache
|
|
642
|
-
end
|
|
643
|
-
|
|
644
|
-
# @return [Array<Gem::Specification>]
|
|
645
|
-
def queued_gemspec_cache
|
|
646
|
-
@queued_gemspec_cache ||= []
|
|
647
|
-
end
|
|
648
|
-
|
|
649
621
|
# @param gem_name [String]
|
|
650
622
|
# @param pending [Integer]
|
|
651
623
|
# @return [void]
|
|
@@ -696,8 +668,9 @@ module Solargraph
|
|
|
696
668
|
source_map_hash.each_value { |map| find_external_requires(map) }
|
|
697
669
|
api_map.catalog bench
|
|
698
670
|
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
|
699
|
-
|
|
700
|
-
logger.info "#{api_map.
|
|
671
|
+
# @todo This needs work
|
|
672
|
+
# logger.info "#{api_map.uncached_yard_gemspecs.length} uncached YARD gemspecs"
|
|
673
|
+
# logger.info "#{api_map.uncached_rbs_collection_gemspecs.length} uncached RBS collection gemspecs"
|
|
701
674
|
cache_next_gemspec
|
|
702
675
|
@sync_count = 0
|
|
703
676
|
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
class Metagem
|
|
5
|
+
include Equality
|
|
6
|
+
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_reader :name
|
|
9
|
+
|
|
10
|
+
# @return [String]
|
|
11
|
+
attr_reader :full_path
|
|
12
|
+
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_reader :spec_file
|
|
15
|
+
|
|
16
|
+
# @return [String]
|
|
17
|
+
attr_reader :source
|
|
18
|
+
|
|
19
|
+
# @return [String]
|
|
20
|
+
attr_reader :version
|
|
21
|
+
|
|
22
|
+
# @return [Array<String>]
|
|
23
|
+
attr_reader :require_paths
|
|
24
|
+
|
|
25
|
+
# @return [Array<String>]
|
|
26
|
+
attr_reader :dependencies
|
|
27
|
+
|
|
28
|
+
# @return [String]
|
|
29
|
+
attr_reader :cache_name
|
|
30
|
+
|
|
31
|
+
def initialize name:, full_path:, spec_file:, source:, version:, require_paths:, dependencies:
|
|
32
|
+
@name = name
|
|
33
|
+
@full_path = full_path
|
|
34
|
+
@spec_file = spec_file
|
|
35
|
+
@source = source
|
|
36
|
+
@version = version
|
|
37
|
+
@require_paths = require_paths
|
|
38
|
+
@dependencies = dependencies
|
|
39
|
+
# @todo Possible change to cache names to make them more specific to sources
|
|
40
|
+
# @cache_name = "#{File.basename(full_path)}__#{source.gsub(/[^a-z0-9\-_]/i, '_')}" unless source.end_with?('Path')
|
|
41
|
+
# @todo Better path source detection
|
|
42
|
+
@cache_name = File.basename(full_path) unless source.start_with?('source at') || source.to_s.end_with?('::Path')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def cacheable?
|
|
46
|
+
!!@cache_name
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def require? path
|
|
50
|
+
require_paths.any? do |req|
|
|
51
|
+
File.file?(File.join(full_path, req, "#{path}.rb"))
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_specification
|
|
56
|
+
Gem::Specification.load(spec_file)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
alias full_gem_path full_path
|
|
60
|
+
|
|
61
|
+
# @return [Array]
|
|
62
|
+
def equality_fields
|
|
63
|
+
# A version arrives as a String from a bundle definition and as a
|
|
64
|
+
# Gem::Version from a specification, so compare its string form.
|
|
65
|
+
[name, version.to_s, full_path, source]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param gem [Gem::Specification]
|
|
69
|
+
# @return [Metagem]
|
|
70
|
+
def self.from_specification gem
|
|
71
|
+
Metagem.new(name: gem.name,
|
|
72
|
+
full_path: gem.full_gem_path,
|
|
73
|
+
spec_file: gem.spec_file,
|
|
74
|
+
source: gem.source.to_s,
|
|
75
|
+
version: gem.version,
|
|
76
|
+
require_paths: gem.require_paths,
|
|
77
|
+
dependencies: gem.runtime_dependencies.map(&:name))
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -91,6 +91,12 @@ module Solargraph
|
|
|
91
91
|
region.source.comments_for(node)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
+
# @param node [Parser::AST::Node]
|
|
95
|
+
# @return [String, nil]
|
|
96
|
+
def type_assertion_for node
|
|
97
|
+
region.source.type_assertion_for(node)
|
|
98
|
+
end
|
|
99
|
+
|
|
94
100
|
# @param position [Solargraph::Position]
|
|
95
101
|
# @return [Pin::Closure, nil]
|
|
96
102
|
def named_path_pin position
|
|
@@ -13,10 +13,12 @@ module Solargraph
|
|
|
13
13
|
# @param node [Parser::AST::Node]
|
|
14
14
|
# @param filename [String, nil]
|
|
15
15
|
# @param parent [Parser::AST::Node, nil]
|
|
16
|
-
|
|
16
|
+
# @param tree [Array<Parser::AST::Node>, nil]
|
|
17
|
+
def initialize node, filename = nil, parent = nil, tree = nil
|
|
17
18
|
@node = node
|
|
18
19
|
@filename = filename
|
|
19
20
|
@parent = parent
|
|
21
|
+
@tree = tree
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
# @return [Source::Chain]
|
|
@@ -29,9 +31,10 @@ module Solargraph
|
|
|
29
31
|
# @param node [Parser::AST::Node]
|
|
30
32
|
# @param filename [String, nil]
|
|
31
33
|
# @param parent [Parser::AST::Node, nil]
|
|
34
|
+
# @param tree [Parser::AST::Node, nil]
|
|
32
35
|
# @return [Source::Chain]
|
|
33
|
-
def chain node, filename = nil, parent = nil
|
|
34
|
-
NodeChainer.new(node, filename, parent).chain
|
|
36
|
+
def chain node, filename = nil, parent = nil, tree = nil
|
|
37
|
+
NodeChainer.new(node, filename, parent, tree).chain
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
# @param code [String]
|
|
@@ -150,6 +153,13 @@ module Solargraph
|
|
|
150
153
|
elsif n.type == :array
|
|
151
154
|
chained_children = n.children.map { |c| NodeChainer.chain(c) }
|
|
152
155
|
result.push Source::Chain::Array.new(chained_children, n)
|
|
156
|
+
elsif inside_method_call? # If the node is inside a method call, it may be a parameter.
|
|
157
|
+
lit = infer_literal_node_type(n)
|
|
158
|
+
if lit
|
|
159
|
+
method_call_chain = NodeChainer.chain(send_node, @filename, nil, [])
|
|
160
|
+
literal = Chain::Literal.new(lit, n)
|
|
161
|
+
result.push Chain::Parameter.new(literal, method_call_chain)
|
|
162
|
+
end
|
|
153
163
|
else
|
|
154
164
|
lit = infer_literal_node_type(n)
|
|
155
165
|
result.push(lit ? Chain::Literal.new(lit, n) : Chain::Link.new)
|
|
@@ -158,6 +168,15 @@ module Solargraph
|
|
|
158
168
|
result
|
|
159
169
|
end
|
|
160
170
|
|
|
171
|
+
def inside_method_call?
|
|
172
|
+
!send_node.nil? && send_node != @node
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @return [Parser::AST::Node, nil]
|
|
176
|
+
def send_node
|
|
177
|
+
@send_node ||= @tree&.find { |n| n.type == :send }
|
|
178
|
+
end
|
|
179
|
+
|
|
161
180
|
# @param node [Parser::AST::Node]
|
|
162
181
|
def hash_is_splatted? node
|
|
163
182
|
return false unless Parser.is_ast_node?(node) && node.type == :hash
|
|
@@ -197,6 +197,18 @@ module Solargraph
|
|
|
197
197
|
nodes.any? { |n| splatted_call?(n) }
|
|
198
198
|
end
|
|
199
199
|
|
|
200
|
+
# Anonymous `*`, `**` and `...` arguments pass on whatever the
|
|
201
|
+
# enclosing method received, so neither count nor types are known.
|
|
202
|
+
#
|
|
203
|
+
# @param nodes [Enumerable<Parser::AST::Node>]
|
|
204
|
+
def any_forwarded_args? nodes
|
|
205
|
+
nodes.any? do |n|
|
|
206
|
+
next false unless Parser.is_ast_node?(n)
|
|
207
|
+
next true if %i[forwarded_args forwarded_restarg].include?(n.type)
|
|
208
|
+
n.type == :hash && n.children.any? { |c| Parser.is_ast_node?(c) && c.type == :forwarded_kwrestarg }
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
200
212
|
# @todo Temporarily here for testing. Move to Solargraph::Parser.
|
|
201
213
|
# @param node [Parser::AST::Node]
|
|
202
214
|
# @return [Array<Parser::AST::Node>]
|
|
@@ -442,6 +454,11 @@ module Solargraph
|
|
|
442
454
|
CONDITIONAL_ALL_BUT_FIRST = %i[if unless].freeze
|
|
443
455
|
ONLY_ONE_CHILD = [:return].freeze
|
|
444
456
|
FIRST_TWO_CHILDREN = [:rescue].freeze
|
|
457
|
+
# :ensure's value is always its body's value (first
|
|
458
|
+
# child); the ensure clause itself (second child) never
|
|
459
|
+
# contributes to the method's return value unless it
|
|
460
|
+
# explicitly returns.
|
|
461
|
+
ENSURE = [:ensure].freeze
|
|
445
462
|
COMPOUND_STATEMENTS = %i[begin kwbegin].freeze
|
|
446
463
|
SKIPPABLE = %i[def defs class sclass module].freeze
|
|
447
464
|
FUNCTION_VALUE = [:block].freeze
|
|
@@ -488,6 +505,13 @@ module Solargraph
|
|
|
488
505
|
result.concat reduce_to_value_nodes([node.children[0]])
|
|
489
506
|
elsif FIRST_TWO_CHILDREN.include?(node.type)
|
|
490
507
|
result.concat reduce_to_value_nodes([node.children[0], node.children[1]])
|
|
508
|
+
elsif ENSURE.include?(node.type)
|
|
509
|
+
result.concat reduce_to_value_nodes([node.children[0]])
|
|
510
|
+
ensure_body = node.children[1]
|
|
511
|
+
if include_explicit_returns && ensure_body.is_a?(::Parser::AST::Node)
|
|
512
|
+
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
513
|
+
result.concat explicit_return_values_from_compound_statement(ensure_body)
|
|
514
|
+
end
|
|
491
515
|
elsif FUNCTION_VALUE.include?(node.type)
|
|
492
516
|
# the block itself is a first class value that could be returned
|
|
493
517
|
result.push node
|
|
@@ -605,14 +629,13 @@ module Solargraph
|
|
|
605
629
|
elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
|
|
606
630
|
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
607
631
|
result.concat reduce_to_value_nodes(node.children[1..])
|
|
608
|
-
|
|
609
|
-
elsif node.type == :return
|
|
632
|
+
elsif ONLY_ONE_CHILD.include?(node.type) || ENSURE.include?(node.type)
|
|
610
633
|
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
611
634
|
result.concat reduce_to_value_nodes([node.children[0]])
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
#
|
|
615
|
-
result.concat reduce_to_value_nodes(node.children)
|
|
635
|
+
elsif FIRST_TWO_CHILDREN.include?(node.type)
|
|
636
|
+
# a :rescue node's value is its body's value or the
|
|
637
|
+
# value of whichever resbody handled the exception
|
|
638
|
+
result.concat reduce_to_value_nodes([node.children[0], node.children[1]])
|
|
616
639
|
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
617
640
|
elsif node.type == :block
|
|
618
641
|
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
data/lib/solargraph/parser/parser_gem/node_processors/class_definition/class_assignment_node.rb
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module Parser
|
|
5
|
+
module ParserGem
|
|
6
|
+
module NodeProcessors
|
|
7
|
+
module ClassDefinition
|
|
8
|
+
# A node wrapper for a class definition via const assignment.
|
|
9
|
+
# @example
|
|
10
|
+
# MyError = Class.new(StandardError) do
|
|
11
|
+
# def retry_after; 5; end
|
|
12
|
+
# end
|
|
13
|
+
class ClassAssignmentNode
|
|
14
|
+
class << self
|
|
15
|
+
# @example
|
|
16
|
+
# s(:casgn, nil, :Foo,
|
|
17
|
+
# s(:block,
|
|
18
|
+
# s(:send,
|
|
19
|
+
# s(:const, nil, :Class), :new,
|
|
20
|
+
# s(:const, nil, :StandardError)),
|
|
21
|
+
# s(:args),
|
|
22
|
+
# s(:def, :retry_after, s(:args), s(:int, 5))))
|
|
23
|
+
#
|
|
24
|
+
# @param node [Parser::AST::Node]
|
|
25
|
+
# @return [Boolean]
|
|
26
|
+
def match? node
|
|
27
|
+
return false unless node&.type == :casgn
|
|
28
|
+
|
|
29
|
+
class_new_node?(new_node(node))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The `Class.new(...)` send node, whether or not a block is attached.
|
|
33
|
+
#
|
|
34
|
+
# @param node [Parser::AST::Node]
|
|
35
|
+
# @return [Parser::AST::Node, nil]
|
|
36
|
+
def new_node node
|
|
37
|
+
value = node.children[2]
|
|
38
|
+
return nil if value.nil?
|
|
39
|
+
return value unless value.type == :block
|
|
40
|
+
|
|
41
|
+
value.children[0]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# @param send_node [Parser::AST::Node, nil]
|
|
47
|
+
# @return [Boolean]
|
|
48
|
+
def class_new_node? send_node
|
|
49
|
+
return false if send_node.nil?
|
|
50
|
+
return false unless send_node.type == :send
|
|
51
|
+
return false unless send_node.children[1] == :new
|
|
52
|
+
|
|
53
|
+
receiver = send_node.children[0]
|
|
54
|
+
return false if receiver.nil?
|
|
55
|
+
return false unless receiver.type == :const
|
|
56
|
+
|
|
57
|
+
receiver.children[1] == :Class
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @param node [Parser::AST::Node]
|
|
62
|
+
def initialize node
|
|
63
|
+
@node = node
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [String]
|
|
67
|
+
def class_name
|
|
68
|
+
namespace = node.children[0]
|
|
69
|
+
return node.children[1].to_s if namespace.nil?
|
|
70
|
+
|
|
71
|
+
"#{Parser::NodeMethods.unpack_name(namespace)}::#{node.children[1]}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The superclass, when it is written as a constant. `Class.new(expr)`
|
|
75
|
+
# with a non-constant argument yields nil (superclass stays Object).
|
|
76
|
+
#
|
|
77
|
+
# @return [String, nil]
|
|
78
|
+
def superclass_name
|
|
79
|
+
send_node = self.class.new_node(node)
|
|
80
|
+
return nil if send_node.nil?
|
|
81
|
+
|
|
82
|
+
arg = send_node.children[2]
|
|
83
|
+
return nil if arg.nil?
|
|
84
|
+
return nil unless arg.type == :const
|
|
85
|
+
|
|
86
|
+
Parser::NodeMethods.unpack_name(arg)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# @return [Parser::AST::Node]
|
|
92
|
+
attr_reader :node
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module Parser
|
|
5
|
+
module ParserGem
|
|
6
|
+
module NodeProcessors
|
|
7
|
+
module ClassDefinition
|
|
8
|
+
autoload :ClassAssignmentNode, 'solargraph/parser/parser_gem/node_processors/class_definition/class_assignment_node'
|
|
9
|
+
|
|
10
|
+
class ClassNode < Parser::NodeProcessor::Base
|
|
11
|
+
# @return [Boolean] continue processing the next processor of the same node.
|
|
12
|
+
def process
|
|
13
|
+
definition_node = class_definition_node
|
|
14
|
+
return true if definition_node.nil?
|
|
15
|
+
|
|
16
|
+
loc = get_node_location(node)
|
|
17
|
+
nspin = Solargraph::Pin::Namespace.new(
|
|
18
|
+
type: :class,
|
|
19
|
+
location: loc,
|
|
20
|
+
closure: region.closure,
|
|
21
|
+
name: definition_node.class_name,
|
|
22
|
+
comments: comments_for(node),
|
|
23
|
+
visibility: :public,
|
|
24
|
+
gates: region.closure.gates.freeze,
|
|
25
|
+
source: :class_definition
|
|
26
|
+
)
|
|
27
|
+
pins.push nspin
|
|
28
|
+
|
|
29
|
+
superclass_name = definition_node.superclass_name
|
|
30
|
+
if superclass_name
|
|
31
|
+
pins.push Pin::Reference::Superclass.new(
|
|
32
|
+
location: loc,
|
|
33
|
+
closure: nspin,
|
|
34
|
+
name: superclass_name,
|
|
35
|
+
source: :class_definition
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
process_children region.update(closure: nspin, visibility: :public)
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# @return [ClassDefinition::ClassAssignmentNode, nil]
|
|
46
|
+
def class_definition_node
|
|
47
|
+
@class_definition_node ||= ClassAssignmentNode.new(node) if ClassAssignmentNode.match?(node)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module Parser
|
|
5
|
+
module ParserGem
|
|
6
|
+
module NodeProcessors
|
|
7
|
+
module DataDefinition
|
|
8
|
+
# A node wrapper for a Data definition via const assignment.
|
|
9
|
+
# @example
|
|
10
|
+
# MyData = Data.new(:bar, :baz) do
|
|
11
|
+
# def foo
|
|
12
|
+
# end
|
|
13
|
+
# end
|
|
14
|
+
class DataAssignmentNode < DataDefintionNode
|
|
15
|
+
class << self
|
|
16
|
+
# @example
|
|
17
|
+
# s(:casgn, nil, :Foo,
|
|
18
|
+
# s(:block,
|
|
19
|
+
# s(:send,
|
|
20
|
+
# s(:const, nil, :Data), :define,
|
|
21
|
+
# s(:sym, :bar),
|
|
22
|
+
# s(:sym, :baz)),
|
|
23
|
+
# s(:args),
|
|
24
|
+
# s(:def, :foo,
|
|
25
|
+
# s(:args),
|
|
26
|
+
# s(:send, nil, :bar))))
|
|
27
|
+
# @param node [::Parser::AST::Node]
|
|
28
|
+
def match? node
|
|
29
|
+
return false unless node&.type == :casgn
|
|
30
|
+
return false if node.children[2].nil?
|
|
31
|
+
|
|
32
|
+
data_node = if node.children[2].type == :block
|
|
33
|
+
node.children[2].children[0]
|
|
34
|
+
else
|
|
35
|
+
node.children[2]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
data_definition_node?(data_node)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def class_name
|
|
43
|
+
if node.children[0]
|
|
44
|
+
Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
|
|
45
|
+
else
|
|
46
|
+
node.children[1].to_s
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# @return [Parser::AST::Node]
|
|
53
|
+
def data_node
|
|
54
|
+
if node.children[2].type == :block
|
|
55
|
+
node.children[2].children[0]
|
|
56
|
+
else
|
|
57
|
+
node.children[2]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module Parser
|
|
5
|
+
module ParserGem
|
|
6
|
+
module NodeProcessors
|
|
7
|
+
module DataDefinition
|
|
8
|
+
# A node wrapper for a Data definition via inheritance.
|
|
9
|
+
# @example
|
|
10
|
+
# class MyData < Data.new(:bar, :baz)
|
|
11
|
+
# def foo
|
|
12
|
+
# end
|
|
13
|
+
# end
|
|
14
|
+
class DataDefintionNode
|
|
15
|
+
class << self
|
|
16
|
+
# @example
|
|
17
|
+
# s(:class,
|
|
18
|
+
# s(:const, nil, :Foo),
|
|
19
|
+
# s(:send,
|
|
20
|
+
# s(:const, nil, :Data), :define,
|
|
21
|
+
# s(:sym, :bar),
|
|
22
|
+
# s(:sym, :baz)),
|
|
23
|
+
# s(:hash,
|
|
24
|
+
# s(:pair,
|
|
25
|
+
# s(:sym, :keyword_init),
|
|
26
|
+
# s(:true)))),
|
|
27
|
+
# s(:def, :foo,
|
|
28
|
+
# s(:args),
|
|
29
|
+
# s(:send, nil, :bar)))
|
|
30
|
+
#
|
|
31
|
+
# @param node [Parser::AST::Node]
|
|
32
|
+
def match? node
|
|
33
|
+
return false unless node&.type == :class
|
|
34
|
+
|
|
35
|
+
data_definition_node?(node.children[1])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# @param data_node [Parser::AST::Node]
|
|
41
|
+
# @return [Boolean]
|
|
42
|
+
def data_definition_node? data_node
|
|
43
|
+
return false unless data_node.is_a?(::Parser::AST::Node)
|
|
44
|
+
return false unless data_node&.type == :send
|
|
45
|
+
return false unless data_node.children[0]&.type == :const
|
|
46
|
+
return false unless data_node.children[0].children[1] == :Data
|
|
47
|
+
return false unless data_node.children[1] == :define
|
|
48
|
+
|
|
49
|
+
true
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @param node [Parser::AST::Node]
|
|
54
|
+
def initialize node
|
|
55
|
+
@node = node
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [String]
|
|
59
|
+
def class_name
|
|
60
|
+
Parser::NodeMethods.unpack_name(node)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Array<Array(Parser::AST::Node, String)>]
|
|
64
|
+
def attributes
|
|
65
|
+
data_attribute_nodes.map do |data_def_param|
|
|
66
|
+
next unless data_def_param.type == :sym
|
|
67
|
+
[data_def_param, data_def_param.children[0].to_s]
|
|
68
|
+
end.compact
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @return [Parser::AST::Node, nil]
|
|
72
|
+
def body_node
|
|
73
|
+
node.children[2]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
# @return [Parser::AST::Node]
|
|
79
|
+
attr_reader :node
|
|
80
|
+
|
|
81
|
+
# @return [Parser::AST::Node, nil]
|
|
82
|
+
def data_node
|
|
83
|
+
node.children[1]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @sg-ignore Need to add nil check here
|
|
87
|
+
# @return [Array<Parser::AST::Node>]
|
|
88
|
+
def data_attribute_nodes
|
|
89
|
+
# @sg-ignore Need to add nil check here
|
|
90
|
+
data_node.children[2..]
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|