solargraph 0.54.0 → 0.58.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 +127 -0
- data/.github/workflows/plugins.yml +184 -6
- data/.github/workflows/rspec.yml +55 -5
- data/.github/workflows/typecheck.yml +8 -3
- data/.gitignore +7 -0
- data/.overcommit.yml +72 -0
- data/.rspec +1 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +1279 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +171 -0
- data/README.md +20 -6
- data/Rakefile +125 -13
- data/bin/solargraph +8 -5
- data/lib/solargraph/api_map/cache.rb +13 -3
- data/lib/solargraph/api_map/constants.rb +279 -0
- data/lib/solargraph/api_map/index.rb +193 -0
- data/lib/solargraph/api_map/source_to_yard.rb +13 -4
- data/lib/solargraph/api_map/store.rb +207 -132
- data/lib/solargraph/api_map.rb +394 -261
- data/lib/solargraph/bench.rb +18 -1
- data/lib/solargraph/complex_type/type_methods.rb +29 -12
- data/lib/solargraph/complex_type/unique_type.rb +205 -26
- data/lib/solargraph/complex_type.rb +126 -26
- data/lib/solargraph/convention/active_support_concern.rb +111 -0
- data/lib/solargraph/convention/base.rb +20 -3
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
- data/lib/solargraph/convention/data_definition.rb +105 -0
- data/lib/solargraph/convention/gemspec.rb +3 -2
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
- data/lib/solargraph/convention/struct_definition.rb +164 -0
- data/lib/solargraph/convention.rb +36 -4
- data/lib/solargraph/diagnostics/rubocop.rb +6 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
- data/lib/solargraph/doc_map.rb +316 -64
- data/lib/solargraph/environ.rb +9 -2
- data/lib/solargraph/equality.rb +34 -0
- data/lib/solargraph/gem_pins.rb +64 -38
- data/lib/solargraph/language_server/host/dispatch.rb +2 -0
- data/lib/solargraph/language_server/host/message_worker.rb +54 -5
- data/lib/solargraph/language_server/host.rb +36 -18
- data/lib/solargraph/language_server/message/base.rb +20 -12
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -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/language_server/message/initialize.rb +3 -1
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +5 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +23 -2
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +4 -3
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +27 -2
- data/lib/solargraph/language_server/request.rb +4 -1
- data/lib/solargraph/library.rb +83 -73
- data/lib/solargraph/location.rb +45 -1
- data/lib/solargraph/logging.rb +12 -2
- data/lib/solargraph/page.rb +3 -0
- data/lib/solargraph/parser/comment_ripper.rb +20 -7
- data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
- data/lib/solargraph/parser/node_processor/base.rb +10 -5
- data/lib/solargraph/parser/node_processor.rb +26 -8
- data/lib/solargraph/parser/parser_gem/class_methods.rb +10 -18
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
- data/lib/solargraph/parser/parser_gem/node_methods.rb +10 -19
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +26 -20
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +14 -2
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +16 -6
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +64 -32
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
- data/lib/solargraph/parser/region.rb +4 -1
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/parser.rb +3 -5
- data/lib/solargraph/pin/base.rb +417 -42
- data/lib/solargraph/pin/base_variable.rb +21 -12
- data/lib/solargraph/pin/block.rb +9 -26
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +231 -0
- data/lib/solargraph/pin/closure.rb +30 -10
- data/lib/solargraph/pin/common.rb +12 -7
- data/lib/solargraph/pin/constant.rb +2 -0
- data/lib/solargraph/pin/conversions.rb +3 -2
- data/lib/solargraph/pin/delegated_method.rb +20 -1
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/instance_variable.rb +2 -2
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +15 -7
- data/lib/solargraph/pin/method.rb +241 -70
- data/lib/solargraph/pin/method_alias.rb +3 -0
- data/lib/solargraph/pin/namespace.rb +21 -13
- data/lib/solargraph/pin/parameter.rb +94 -32
- data/lib/solargraph/pin/proxy_type.rb +17 -7
- data/lib/solargraph/pin/reference/override.rb +24 -6
- data/lib/solargraph/pin/reference/require.rb +2 -2
- data/lib/solargraph/pin/reference/superclass.rb +5 -0
- data/lib/solargraph/pin/reference.rb +17 -0
- data/lib/solargraph/pin/search.rb +6 -1
- data/lib/solargraph/pin/signature.rb +39 -121
- data/lib/solargraph/pin/singleton.rb +1 -1
- data/lib/solargraph/pin/symbol.rb +8 -2
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +8 -2
- data/lib/solargraph/pin_cache.rb +245 -0
- data/lib/solargraph/position.rb +19 -0
- data/lib/solargraph/range.rb +23 -4
- data/lib/solargraph/rbs_map/conversions.rb +315 -99
- data/lib/solargraph/rbs_map/core_fills.rb +50 -16
- data/lib/solargraph/rbs_map/core_map.rb +41 -11
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +87 -16
- data/lib/solargraph/shell.rb +117 -17
- data/lib/solargraph/source/chain/array.rb +13 -8
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +135 -66
- data/lib/solargraph/source/chain/constant.rb +3 -66
- data/lib/solargraph/source/chain/hash.rb +9 -3
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +7 -2
- data/lib/solargraph/source/chain/link.rb +38 -6
- data/lib/solargraph/source/chain/literal.rb +27 -2
- data/lib/solargraph/source/chain/or.rb +2 -2
- data/lib/solargraph/source/chain/z_super.rb +1 -1
- data/lib/solargraph/source/chain.rb +140 -63
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/cursor.rb +4 -4
- data/lib/solargraph/source/source_chainer.rb +3 -3
- data/lib/solargraph/source.rb +110 -89
- data/lib/solargraph/source_map/clip.rb +22 -28
- data/lib/solargraph/source_map/data.rb +34 -0
- data/lib/solargraph/source_map/mapper.rb +11 -7
- data/lib/solargraph/source_map.rb +50 -43
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker/param_def.rb +2 -0
- data/lib/solargraph/type_checker/rules.rb +35 -8
- data/lib/solargraph/type_checker.rb +331 -189
- 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/views/environment.erb +3 -5
- data/lib/solargraph/workspace/config.rb +25 -5
- data/lib/solargraph/workspace/require_paths.rb +97 -0
- data/lib/solargraph/workspace.rb +53 -72
- data/lib/solargraph/yard_map/helpers.rb +29 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +8 -5
- data/lib/solargraph/yard_map/mapper/to_method.rb +55 -19
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +11 -7
- data/lib/solargraph/yard_map/mapper.rb +5 -3
- data/lib/solargraph/yard_map/to_method.rb +6 -3
- data/lib/solargraph/yardoc.rb +45 -10
- data/lib/solargraph.rb +35 -1
- data/rbs/fills/bundler/0/bundler.rbs +4271 -0
- data/rbs/fills/open3/0/open3.rbs +172 -0
- data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
- data/rbs/fills/rubygems/0/errors.rbs +364 -0
- data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
- data/rbs/fills/rubygems/0/specification.rbs +1753 -0
- data/rbs/fills/tuple/tuple.rbs +149 -0
- data/rbs_collection.yaml +19 -0
- data/sig/shims/ast/0/node.rbs +5 -0
- data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
- data/sig/shims/ast/2.4/ast.rbs +73 -0
- data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
- data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
- data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
- data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
- data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
- data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
- data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
- data/solargraph.gemspec +32 -10
- metadata +237 -37
- data/lib/.rubocop.yml +0 -22
- data/lib/solargraph/cache.rb +0 -77
- data/lib/solargraph/parser/node_methods.rb +0 -83
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
module Solargraph
|
|
2
|
+
module Parser
|
|
3
|
+
class FlowSensitiveTyping
|
|
4
|
+
include Solargraph::Parser::NodeMethods
|
|
5
|
+
|
|
6
|
+
# @param locals [Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
7
|
+
# @param enclosing_breakable_pin [Solargraph::Pin::Breakable, nil]
|
|
8
|
+
def initialize(locals, enclosing_breakable_pin = nil)
|
|
9
|
+
@locals = locals
|
|
10
|
+
@enclosing_breakable_pin = enclosing_breakable_pin
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @param and_node [Parser::AST::Node]
|
|
14
|
+
# @param true_ranges [Array<Range>]
|
|
15
|
+
#
|
|
16
|
+
# @return [void]
|
|
17
|
+
def process_and(and_node, true_ranges = [])
|
|
18
|
+
# @type [Parser::AST::Node]
|
|
19
|
+
lhs = and_node.children[0]
|
|
20
|
+
# @type [Parser::AST::Node]
|
|
21
|
+
rhs = and_node.children[1]
|
|
22
|
+
|
|
23
|
+
before_rhs_loc = rhs.location.expression.adjust(begin_pos: -1)
|
|
24
|
+
before_rhs_pos = Position.new(before_rhs_loc.line, before_rhs_loc.column)
|
|
25
|
+
|
|
26
|
+
rhs_presence = Range.new(before_rhs_pos,
|
|
27
|
+
get_node_end_position(rhs))
|
|
28
|
+
process_isa(lhs, true_ranges + [rhs_presence])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @param if_node [Parser::AST::Node]
|
|
32
|
+
#
|
|
33
|
+
# @return [void]
|
|
34
|
+
def process_if(if_node)
|
|
35
|
+
#
|
|
36
|
+
# See if we can refine a type based on the result of 'if foo.nil?'
|
|
37
|
+
#
|
|
38
|
+
# [3] pry(main)> require 'parser/current'; Parser::CurrentRuby.parse("if foo.is_a? Baz; then foo; else bar; end")
|
|
39
|
+
# => s(:if,
|
|
40
|
+
# s(:send,
|
|
41
|
+
# s(:send, nil, :foo), :is_a?,
|
|
42
|
+
# s(:const, nil, :Baz)),
|
|
43
|
+
# s(:send, nil, :foo),
|
|
44
|
+
# s(:send, nil, :bar))
|
|
45
|
+
# [4] pry(main)>
|
|
46
|
+
conditional_node = if_node.children[0]
|
|
47
|
+
# @type [Parser::AST::Node]
|
|
48
|
+
then_clause = if_node.children[1]
|
|
49
|
+
# @type [Parser::AST::Node]
|
|
50
|
+
else_clause = if_node.children[2]
|
|
51
|
+
|
|
52
|
+
true_ranges = []
|
|
53
|
+
if always_breaks?(else_clause)
|
|
54
|
+
unless enclosing_breakable_pin.nil?
|
|
55
|
+
rest_of_breakable_body = Range.new(get_node_end_position(if_node),
|
|
56
|
+
get_node_end_position(enclosing_breakable_pin.node))
|
|
57
|
+
true_ranges << rest_of_breakable_body
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
unless then_clause.nil?
|
|
62
|
+
#
|
|
63
|
+
# Add specialized locals for the then clause range
|
|
64
|
+
#
|
|
65
|
+
before_then_clause_loc = then_clause.location.expression.adjust(begin_pos: -1)
|
|
66
|
+
before_then_clause_pos = Position.new(before_then_clause_loc.line, before_then_clause_loc.column)
|
|
67
|
+
true_ranges << Range.new(before_then_clause_pos,
|
|
68
|
+
get_node_end_position(then_clause))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
process_conditional(conditional_node, true_ranges)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class << self
|
|
75
|
+
include Logging
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Find a variable pin by name and where it is used.
|
|
79
|
+
#
|
|
80
|
+
# Resolves our most specific view of this variable's type by
|
|
81
|
+
# preferring pins created by flow-sensitive typing when we have
|
|
82
|
+
# them based on the Closure and Location.
|
|
83
|
+
#
|
|
84
|
+
# @param pins [Array<Pin::LocalVariable>]
|
|
85
|
+
# @param name [String]
|
|
86
|
+
# @param closure [Pin::Closure]
|
|
87
|
+
# @param location [Location]
|
|
88
|
+
#
|
|
89
|
+
# @return [Array<Pin::LocalVariable>]
|
|
90
|
+
def self.visible_pins(pins, name, closure, location)
|
|
91
|
+
logger.debug { "FlowSensitiveTyping#visible_pins(name=#{name}, closure=#{closure}, location=#{location})" }
|
|
92
|
+
pins_with_name = pins.select { |p| p.name == name }
|
|
93
|
+
if pins_with_name.empty?
|
|
94
|
+
logger.debug { "FlowSensitiveTyping#visible_pins(name=#{name}, closure=#{closure}, location=#{location}) => [] - no pins with name" }
|
|
95
|
+
return []
|
|
96
|
+
end
|
|
97
|
+
pins_with_specific_visibility = pins.select { |p| p.name == name && p.presence && p.visible_at?(closure, location) }
|
|
98
|
+
if pins_with_specific_visibility.empty?
|
|
99
|
+
logger.debug { "FlowSensitiveTyping#visible_pins(name=#{name}, closure=#{closure}, location=#{location}) => #{pins_with_name} - no pins with specific visibility" }
|
|
100
|
+
return pins_with_name
|
|
101
|
+
end
|
|
102
|
+
visible_pins_specific_to_this_closure = pins_with_specific_visibility.select { |p| p.closure == closure }
|
|
103
|
+
if visible_pins_specific_to_this_closure.empty?
|
|
104
|
+
logger.debug { "FlowSensitiveTyping#visible_pins(name=#{name}, closure=#{closure}, location=#{location}) => #{pins_with_specific_visibility} - no visible pins specific to this closure (#{closure})}" }
|
|
105
|
+
return pins_with_specific_visibility
|
|
106
|
+
end
|
|
107
|
+
flow_defined_pins = pins_with_specific_visibility.select { |p| p.presence_certain? }
|
|
108
|
+
if flow_defined_pins.empty?
|
|
109
|
+
logger.debug { "FlowSensitiveTyping#visible_pins(name=#{name}, closure=#{closure}, location=#{location}) => #{visible_pins_specific_to_this_closure} - no flow-defined pins" }
|
|
110
|
+
return visible_pins_specific_to_this_closure
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
logger.debug { "FlowSensitiveTyping#visible_pins(name=#{name}, closure=#{closure}, location=#{location}) => #{flow_defined_pins}" }
|
|
114
|
+
|
|
115
|
+
flow_defined_pins
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
include Logging
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
# @param pin [Pin::LocalVariable]
|
|
123
|
+
# @param downcast_type_name [String]
|
|
124
|
+
# @param presence [Range]
|
|
125
|
+
#
|
|
126
|
+
# @return [void]
|
|
127
|
+
def add_downcast_local(pin, downcast_type_name, presence)
|
|
128
|
+
# @todo Create pin#update method
|
|
129
|
+
new_pin = Solargraph::Pin::LocalVariable.new(
|
|
130
|
+
location: pin.location,
|
|
131
|
+
closure: pin.closure,
|
|
132
|
+
name: pin.name,
|
|
133
|
+
assignment: pin.assignment,
|
|
134
|
+
comments: pin.comments,
|
|
135
|
+
presence: presence,
|
|
136
|
+
return_type: ComplexType.try_parse(downcast_type_name),
|
|
137
|
+
presence_certain: true,
|
|
138
|
+
source: :flow_sensitive_typing
|
|
139
|
+
)
|
|
140
|
+
locals.push(new_pin)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# @param facts_by_pin [Hash{Pin::LocalVariable => Array<Hash{Symbol => String}>}]
|
|
144
|
+
# @param presences [Array<Range>]
|
|
145
|
+
#
|
|
146
|
+
# @return [void]
|
|
147
|
+
def process_facts(facts_by_pin, presences)
|
|
148
|
+
#
|
|
149
|
+
# Add specialized locals for the rest of the block
|
|
150
|
+
#
|
|
151
|
+
facts_by_pin.each_pair do |pin, facts|
|
|
152
|
+
facts.each do |fact|
|
|
153
|
+
downcast_type_name = fact.fetch(:type)
|
|
154
|
+
presences.each do |presence|
|
|
155
|
+
add_downcast_local(pin, downcast_type_name, presence)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# @param conditional_node [Parser::AST::Node]
|
|
162
|
+
# @param true_ranges [Array<Range>]
|
|
163
|
+
#
|
|
164
|
+
# @return [void]
|
|
165
|
+
def process_conditional(conditional_node, true_ranges)
|
|
166
|
+
if conditional_node.type == :send
|
|
167
|
+
process_isa(conditional_node, true_ranges)
|
|
168
|
+
elsif conditional_node.type == :and
|
|
169
|
+
process_and(conditional_node, true_ranges)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# @param isa_node [Parser::AST::Node]
|
|
174
|
+
# @return [Array(String, String), nil]
|
|
175
|
+
def parse_isa(isa_node)
|
|
176
|
+
return unless isa_node&.type == :send && isa_node.children[1] == :is_a?
|
|
177
|
+
# Check if conditional node follows this pattern:
|
|
178
|
+
# s(:send,
|
|
179
|
+
# s(:send, nil, :foo), :is_a?,
|
|
180
|
+
# s(:const, nil, :Baz)),
|
|
181
|
+
isa_receiver = isa_node.children[0]
|
|
182
|
+
isa_type_name = type_name(isa_node.children[2])
|
|
183
|
+
return unless isa_type_name
|
|
184
|
+
|
|
185
|
+
# check if isa_receiver looks like this:
|
|
186
|
+
# s(:send, nil, :foo)
|
|
187
|
+
# and set variable_name to :foo
|
|
188
|
+
if isa_receiver&.type == :send && isa_receiver.children[0].nil? && isa_receiver.children[1].is_a?(Symbol)
|
|
189
|
+
variable_name = isa_receiver.children[1].to_s
|
|
190
|
+
end
|
|
191
|
+
# or like this:
|
|
192
|
+
# (lvar :repr)
|
|
193
|
+
variable_name = isa_receiver.children[0].to_s if isa_receiver&.type == :lvar
|
|
194
|
+
return unless variable_name
|
|
195
|
+
|
|
196
|
+
[isa_type_name, variable_name]
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# @param variable_name [String]
|
|
200
|
+
# @param position [Position]
|
|
201
|
+
#
|
|
202
|
+
# @return [Solargraph::Pin::LocalVariable, nil]
|
|
203
|
+
def find_local(variable_name, position)
|
|
204
|
+
pins = locals.select { |pin| pin.name == variable_name && pin.presence.include?(position) }
|
|
205
|
+
return unless pins.length == 1
|
|
206
|
+
pins.first
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# @param isa_node [Parser::AST::Node]
|
|
210
|
+
# @param true_presences [Array<Range>]
|
|
211
|
+
#
|
|
212
|
+
# @return [void]
|
|
213
|
+
def process_isa(isa_node, true_presences)
|
|
214
|
+
isa_type_name, variable_name = parse_isa(isa_node)
|
|
215
|
+
return if variable_name.nil? || variable_name.empty?
|
|
216
|
+
isa_position = Range.from_node(isa_node).start
|
|
217
|
+
|
|
218
|
+
pin = find_local(variable_name, isa_position)
|
|
219
|
+
return unless pin
|
|
220
|
+
|
|
221
|
+
if_true = {}
|
|
222
|
+
if_true[pin] ||= []
|
|
223
|
+
if_true[pin] << { type: isa_type_name }
|
|
224
|
+
process_facts(if_true, true_presences)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# @param node [Parser::AST::Node]
|
|
228
|
+
#
|
|
229
|
+
# @return [String, nil]
|
|
230
|
+
def type_name(node)
|
|
231
|
+
# e.g.,
|
|
232
|
+
# s(:const, nil, :Baz)
|
|
233
|
+
return unless node&.type == :const
|
|
234
|
+
module_node = node.children[0]
|
|
235
|
+
class_node = node.children[1]
|
|
236
|
+
|
|
237
|
+
return class_node.to_s if module_node.nil?
|
|
238
|
+
|
|
239
|
+
module_type_name = type_name(module_node)
|
|
240
|
+
return unless module_type_name
|
|
241
|
+
|
|
242
|
+
"#{module_type_name}::#{class_node}"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# @param clause_node [Parser::AST::Node]
|
|
246
|
+
def always_breaks?(clause_node)
|
|
247
|
+
clause_node&.type == :break
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
attr_reader :locals
|
|
251
|
+
|
|
252
|
+
attr_reader :enclosing_breakable_pin
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
@@ -13,7 +13,7 @@ module Solargraph
|
|
|
13
13
|
# @return [Array<Pin::Base>]
|
|
14
14
|
attr_reader :pins
|
|
15
15
|
|
|
16
|
-
# @return [Array<Pin::
|
|
16
|
+
# @return [Array<Pin::LocalVariable>]
|
|
17
17
|
attr_reader :locals
|
|
18
18
|
|
|
19
19
|
# @param node [Parser::AST::Node]
|
|
@@ -30,9 +30,12 @@ module Solargraph
|
|
|
30
30
|
|
|
31
31
|
# Subclasses should override this method to generate new pins.
|
|
32
32
|
#
|
|
33
|
-
# @return [
|
|
33
|
+
# @return [Boolean] continue processing the next processor of the same node type.
|
|
34
|
+
# @return [void] In case there is only one processor registered for the node type, it can be void.
|
|
34
35
|
def process
|
|
35
36
|
process_children
|
|
37
|
+
|
|
38
|
+
true
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
private
|
|
@@ -64,7 +67,9 @@ module Solargraph
|
|
|
64
67
|
# @param position [Solargraph::Position]
|
|
65
68
|
# @return [Pin::Closure, nil]
|
|
66
69
|
def named_path_pin position
|
|
67
|
-
pins.select
|
|
70
|
+
pins.select do |pin|
|
|
71
|
+
pin.is_a?(Pin::Closure) && pin.path && !pin.path.empty? && pin.location.range.contain?(position)
|
|
72
|
+
end.last
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
# @todo Candidate for deprecation
|
|
@@ -72,14 +77,14 @@ module Solargraph
|
|
|
72
77
|
# @return [Pin::Closure, nil]
|
|
73
78
|
def block_pin position
|
|
74
79
|
# @todo determine if this can return a Pin::Block
|
|
75
|
-
pins.select{|pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position)}.last
|
|
80
|
+
pins.select { |pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position) }.last
|
|
76
81
|
end
|
|
77
82
|
|
|
78
83
|
# @todo Candidate for deprecation
|
|
79
84
|
# @param position [Solargraph::Position]
|
|
80
85
|
# @return [Pin::Closure, nil]
|
|
81
86
|
def closure_pin position
|
|
82
|
-
pins.select{|pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position)}.last
|
|
87
|
+
pins.select { |pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position) }.last
|
|
83
88
|
end
|
|
84
89
|
end
|
|
85
90
|
end
|
|
@@ -9,15 +9,26 @@ module Solargraph
|
|
|
9
9
|
autoload :Base, 'solargraph/parser/node_processor/base'
|
|
10
10
|
|
|
11
11
|
class << self
|
|
12
|
+
# @type [Hash{Symbol => Array<Class<NodeProcessor::Base>>}]
|
|
12
13
|
@@processors ||= {}
|
|
13
14
|
|
|
14
|
-
# Register a processor for a node type.
|
|
15
|
+
# Register a processor for a node type. You can register multiple processors for the same type.
|
|
16
|
+
# If a node processor returns true, it will skip the next processor of the same node type.
|
|
15
17
|
#
|
|
16
18
|
# @param type [Symbol]
|
|
17
19
|
# @param cls [Class<NodeProcessor::Base>]
|
|
18
|
-
# @return [Class<NodeProcessor::Base
|
|
20
|
+
# @return [Array<Class<NodeProcessor::Base>>]
|
|
19
21
|
def register type, cls
|
|
20
|
-
@@processors[type]
|
|
22
|
+
@@processors[type] ||= []
|
|
23
|
+
@@processors[type] << cls
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @param type [Symbol]
|
|
27
|
+
# @param cls [Class<NodeProcessor::Base>]
|
|
28
|
+
#
|
|
29
|
+
# @return [void]
|
|
30
|
+
def deregister type, cls
|
|
31
|
+
@@processors[type].delete(cls)
|
|
21
32
|
end
|
|
22
33
|
end
|
|
23
34
|
|
|
@@ -30,14 +41,21 @@ module Solargraph
|
|
|
30
41
|
if pins.empty?
|
|
31
42
|
pins.push Pin::Namespace.new(
|
|
32
43
|
location: region.source.location,
|
|
33
|
-
name: ''
|
|
44
|
+
name: '',
|
|
45
|
+
source: :parser,
|
|
34
46
|
)
|
|
35
47
|
end
|
|
36
48
|
return [pins, locals] unless Parser.is_ast_node?(node)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
node_processor_classes = @@processors[node.type] || [NodeProcessor::Base]
|
|
50
|
+
|
|
51
|
+
node_processor_classes.each do |klass|
|
|
52
|
+
processor = klass.new(node, region, pins, locals)
|
|
53
|
+
process_next = processor.process
|
|
54
|
+
|
|
55
|
+
break unless process_next
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
[pins, locals]
|
|
41
59
|
end
|
|
42
60
|
end
|
|
43
61
|
end
|
|
@@ -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
|
module Solargraph
|
|
7
6
|
module Parser
|
|
@@ -9,15 +8,11 @@ module Solargraph
|
|
|
9
8
|
module ClassMethods
|
|
10
9
|
# @param code [String]
|
|
11
10
|
# @param filename [String, nil]
|
|
12
|
-
# @return [Array(Parser::AST::Node, Hash{Integer =>
|
|
11
|
+
# @return [Array(Parser::AST::Node, Hash{Integer => Solargraph::Parser::Snippet})]
|
|
13
12
|
def parse_with_comments code, filename = nil
|
|
14
|
-
|
|
15
|
-
buffer.source = code
|
|
16
|
-
node = parser.parse(buffer)
|
|
13
|
+
node = parse(code, filename)
|
|
17
14
|
comments = CommentRipper.new(code, filename, 0).parse
|
|
18
15
|
[node, comments]
|
|
19
|
-
rescue ::Parser::SyntaxError => e
|
|
20
|
-
raise Parser::SyntaxError, e.message
|
|
21
16
|
end
|
|
22
17
|
|
|
23
18
|
# @param code [String]
|
|
@@ -28,18 +23,16 @@ module Solargraph
|
|
|
28
23
|
buffer = ::Parser::Source::Buffer.new(filename, line)
|
|
29
24
|
buffer.source = code
|
|
30
25
|
parser.parse(buffer)
|
|
31
|
-
rescue ::Parser::SyntaxError => e
|
|
26
|
+
rescue ::Parser::SyntaxError, ::Parser::UnknownEncodingInMagicComment => e
|
|
32
27
|
raise Parser::SyntaxError, e.message
|
|
33
28
|
end
|
|
34
29
|
|
|
35
30
|
# @return [::Parser::Base]
|
|
36
31
|
def parser
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
parser.diagnostics.ignore_warnings = true
|
|
42
|
-
parser
|
|
32
|
+
@parser ||= Prism::Translation::Parser.new(FlawedBuilder.new).tap do |parser|
|
|
33
|
+
parser.diagnostics.all_errors_are_fatal = true
|
|
34
|
+
parser.diagnostics.ignore_warnings = true
|
|
35
|
+
end
|
|
43
36
|
end
|
|
44
37
|
|
|
45
38
|
# @param source [Source]
|
|
@@ -82,6 +75,7 @@ module Solargraph
|
|
|
82
75
|
# @param top [AST::Node]
|
|
83
76
|
# @return [Array<AST::Node>]
|
|
84
77
|
def inner_node_references name, top
|
|
78
|
+
# @type [Array<AST::Node>]
|
|
85
79
|
result = []
|
|
86
80
|
if top.is_a?(AST::Node) && top.to_s.include?(":#{name}")
|
|
87
81
|
result.push top if top.children.any? { |c| c.to_s == name }
|
|
@@ -135,9 +129,7 @@ module Solargraph
|
|
|
135
129
|
def string_ranges node
|
|
136
130
|
return [] unless is_ast_node?(node)
|
|
137
131
|
result = []
|
|
138
|
-
if node.type == :str
|
|
139
|
-
result.push Range.from_node(node)
|
|
140
|
-
end
|
|
132
|
+
result.push Range.from_node(node) if node.type == :str
|
|
141
133
|
node.children.each do |child|
|
|
142
134
|
result.concat string_ranges(child)
|
|
143
135
|
end
|
|
@@ -7,6 +7,7 @@ module Solargraph
|
|
|
7
7
|
#
|
|
8
8
|
class NodeChainer
|
|
9
9
|
include NodeMethods
|
|
10
|
+
|
|
10
11
|
Chain = Source::Chain
|
|
11
12
|
|
|
12
13
|
# @param node [Parser::AST::Node]
|
|
@@ -57,22 +58,22 @@ module Solargraph
|
|
|
57
58
|
elsif n.type == :send
|
|
58
59
|
if n.children[0].is_a?(::Parser::AST::Node)
|
|
59
60
|
result.concat generate_links(n.children[0])
|
|
60
|
-
result.push Chain::Call.new(n.children[1].to_s, node_args(n), passed_block(n))
|
|
61
|
+
result.push Chain::Call.new(n.children[1].to_s, Location.from_node(n), node_args(n), passed_block(n))
|
|
61
62
|
elsif n.children[0].nil?
|
|
62
63
|
args = []
|
|
63
64
|
n.children[2..-1].each do |c|
|
|
64
65
|
args.push NodeChainer.chain(c, @filename, n)
|
|
65
66
|
end
|
|
66
|
-
result.push Chain::Call.new(n.children[1].to_s, node_args(n), passed_block(n))
|
|
67
|
+
result.push Chain::Call.new(n.children[1].to_s, Location.from_node(n), node_args(n), passed_block(n))
|
|
67
68
|
else
|
|
68
69
|
raise "No idea what to do with #{n}"
|
|
69
70
|
end
|
|
70
71
|
elsif n.type == :csend
|
|
71
72
|
if n.children[0].is_a?(::Parser::AST::Node)
|
|
72
73
|
result.concat generate_links(n.children[0])
|
|
73
|
-
result.push Chain::QCall.new(n.children[1].to_s, node_args(n))
|
|
74
|
+
result.push Chain::QCall.new(n.children[1].to_s, Location.from_node(n), node_args(n))
|
|
74
75
|
elsif n.children[0].nil?
|
|
75
|
-
result.push Chain::QCall.new(n.children[1].to_s, node_args(n))
|
|
76
|
+
result.push Chain::QCall.new(n.children[1].to_s, Location.from_node(n), node_args(n))
|
|
76
77
|
else
|
|
77
78
|
raise "No idea what to do with #{n}"
|
|
78
79
|
end
|
|
@@ -82,15 +83,15 @@ module Solargraph
|
|
|
82
83
|
result.push Chain::ZSuper.new('super')
|
|
83
84
|
elsif n.type == :super
|
|
84
85
|
args = n.children.map { |c| NodeChainer.chain(c, @filename, n) }
|
|
85
|
-
result.push Chain::Call.new('super', args)
|
|
86
|
+
result.push Chain::Call.new('super', Location.from_node(n), args)
|
|
86
87
|
elsif n.type == :yield
|
|
87
88
|
args = n.children.map { |c| NodeChainer.chain(c, @filename, n) }
|
|
88
|
-
result.push Chain::Call.new('yield', args)
|
|
89
|
+
result.push Chain::Call.new('yield', Location.from_node(n), args)
|
|
89
90
|
elsif n.type == :const
|
|
90
91
|
const = unpack_name(n)
|
|
91
92
|
result.push Chain::Constant.new(const)
|
|
92
93
|
elsif [:lvar, :lvasgn].include?(n.type)
|
|
93
|
-
result.push Chain::Call.new(n.children[0].to_s)
|
|
94
|
+
result.push Chain::Call.new(n.children[0].to_s, Location.from_node(n))
|
|
94
95
|
elsif [:ivar, :ivasgn].include?(n.type)
|
|
95
96
|
result.push Chain::InstanceVariable.new(n.children[0].to_s)
|
|
96
97
|
elsif [:cvar, :cvasgn].include?(n.type)
|
|
@@ -98,7 +99,8 @@ module Solargraph
|
|
|
98
99
|
elsif [:gvar, :gvasgn].include?(n.type)
|
|
99
100
|
result.push Chain::GlobalVariable.new(n.children[0].to_s)
|
|
100
101
|
elsif n.type == :or_asgn
|
|
101
|
-
|
|
102
|
+
new_node = n.updated(n.children[0].type, n.children[0].children + [n.children[1]])
|
|
103
|
+
result.concat generate_links new_node
|
|
102
104
|
elsif [:class, :module, :def, :defs].include?(n.type)
|
|
103
105
|
# @todo Undefined or what?
|
|
104
106
|
result.push Chain::UNDEFINED_CALL
|
|
@@ -124,13 +126,13 @@ module Solargraph
|
|
|
124
126
|
end
|
|
125
127
|
end
|
|
126
128
|
elsif n.type == :hash
|
|
127
|
-
result.push Chain::Hash.new('::Hash', hash_is_splatted?(n))
|
|
129
|
+
result.push Chain::Hash.new('::Hash', n, hash_is_splatted?(n))
|
|
128
130
|
elsif n.type == :array
|
|
129
131
|
chained_children = n.children.map { |c| NodeChainer.chain(c) }
|
|
130
|
-
result.push Source::Chain::Array.new(chained_children)
|
|
132
|
+
result.push Source::Chain::Array.new(chained_children, n)
|
|
131
133
|
else
|
|
132
134
|
lit = infer_literal_node_type(n)
|
|
133
|
-
result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
|
|
135
|
+
result.push (lit ? Chain::Literal.new(lit, n) : Chain::Link.new)
|
|
134
136
|
end
|
|
135
137
|
result
|
|
136
138
|
end
|
|
@@ -3,20 +3,6 @@
|
|
|
3
3
|
require 'parser'
|
|
4
4
|
require 'ast'
|
|
5
5
|
|
|
6
|
-
# Teach AST::Node#children about its generic type
|
|
7
|
-
#
|
|
8
|
-
# @todo contribute back to https://github.com/ruby/gem_rbs_collection/blob/main/gems/ast/2.4/ast.rbs
|
|
9
|
-
#
|
|
10
|
-
# @!parse
|
|
11
|
-
# module ::AST
|
|
12
|
-
# class Node
|
|
13
|
-
# # New children
|
|
14
|
-
#
|
|
15
|
-
# # @return [Array<AST::Node>]
|
|
16
|
-
# attr_reader :children
|
|
17
|
-
# end
|
|
18
|
-
# end
|
|
19
|
-
|
|
20
6
|
# https://github.com/whitequark/parser
|
|
21
7
|
module Solargraph
|
|
22
8
|
module Parser
|
|
@@ -40,7 +26,7 @@ module Solargraph
|
|
|
40
26
|
if n.is_a?(AST::Node)
|
|
41
27
|
if n.type == :cbase
|
|
42
28
|
parts = [''] + pack_name(n)
|
|
43
|
-
|
|
29
|
+
elsif n.type == :const
|
|
44
30
|
parts += pack_name(n)
|
|
45
31
|
end
|
|
46
32
|
else
|
|
@@ -59,6 +45,8 @@ module Solargraph
|
|
|
59
45
|
return '::String'
|
|
60
46
|
elsif node.type == :array
|
|
61
47
|
return '::Array'
|
|
48
|
+
elsif node.type == :nil
|
|
49
|
+
return '::NilClass'
|
|
62
50
|
elsif node.type == :hash
|
|
63
51
|
return '::Hash'
|
|
64
52
|
elsif node.type == :int
|
|
@@ -118,7 +106,7 @@ module Solargraph
|
|
|
118
106
|
end
|
|
119
107
|
|
|
120
108
|
# @param node [Parser::AST::Node]
|
|
121
|
-
# @return [Hash{
|
|
109
|
+
# @return [Hash{Symbol => Chain}]
|
|
122
110
|
def convert_hash node
|
|
123
111
|
return {} unless Parser.is_ast_node?(node)
|
|
124
112
|
return convert_hash(node.children[0]) if node.type == :kwsplat
|
|
@@ -131,6 +119,7 @@ module Solargraph
|
|
|
131
119
|
result
|
|
132
120
|
end
|
|
133
121
|
|
|
122
|
+
# @sg-ignore Wrong argument type for AST::Node.new: type expected AST::_ToSym, received :nil
|
|
134
123
|
NIL_NODE = ::Parser::AST::Node.new(:nil)
|
|
135
124
|
|
|
136
125
|
# @param node [Parser::AST::Node]
|
|
@@ -177,6 +166,7 @@ module Solargraph
|
|
|
177
166
|
node.children[1..-1].each { |child| result.concat call_nodes_from(child) }
|
|
178
167
|
elsif node.type == :send
|
|
179
168
|
result.push node
|
|
169
|
+
result.concat call_nodes_from(node.children.first)
|
|
180
170
|
node.children[2..-1].each { |child| result.concat call_nodes_from(child) }
|
|
181
171
|
elsif [:super, :zsuper].include?(node.type)
|
|
182
172
|
result.push node
|
|
@@ -230,6 +220,7 @@ module Solargraph
|
|
|
230
220
|
else
|
|
231
221
|
source.tree_at(position.line, position.column - 1)
|
|
232
222
|
end
|
|
223
|
+
# @type [AST::Node, nil]
|
|
233
224
|
prev = nil
|
|
234
225
|
tree.each do |node|
|
|
235
226
|
if node.type == :send
|
|
@@ -240,7 +231,7 @@ module Solargraph
|
|
|
240
231
|
if source.synchronized?
|
|
241
232
|
return node if source.code[0..offset-1] =~ /\(\s*\z/ && source.code[offset..-1] =~ /^\s*\)/
|
|
242
233
|
else
|
|
243
|
-
return node if source.code[0..offset-1] =~ /\([
|
|
234
|
+
return node if source.code[0..offset-1] =~ /\([^(]*\z/
|
|
244
235
|
end
|
|
245
236
|
end
|
|
246
237
|
end
|
|
@@ -311,7 +302,7 @@ module Solargraph
|
|
|
311
302
|
# statements in value positions.
|
|
312
303
|
module DeepInference
|
|
313
304
|
class << self
|
|
314
|
-
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless
|
|
305
|
+
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless]
|
|
315
306
|
CONDITIONAL_ALL = [:or]
|
|
316
307
|
ONLY_ONE_CHILD = [:return]
|
|
317
308
|
FIRST_TWO_CHILDREN = [:rescue]
|
|
@@ -462,7 +453,7 @@ module Solargraph
|
|
|
462
453
|
result
|
|
463
454
|
end
|
|
464
455
|
|
|
465
|
-
# @param nodes [Enumerable<Parser::AST::Node,
|
|
456
|
+
# @param nodes [Enumerable<Parser::AST::Node, BasicObject>]
|
|
466
457
|
# @return [Array<Parser::AST::Node, nil>]
|
|
467
458
|
def reduce_to_value_nodes nodes
|
|
468
459
|
result = []
|
|
@@ -12,7 +12,8 @@ module Solargraph
|
|
|
12
12
|
closure: region.closure,
|
|
13
13
|
name: node.children[0].children[0].to_s,
|
|
14
14
|
original: node.children[1].children[0].to_s,
|
|
15
|
-
scope: region.scope || :instance
|
|
15
|
+
scope: region.scope || :instance,
|
|
16
|
+
source: :parser
|
|
16
17
|
)
|
|
17
18
|
process_children
|
|
18
19
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module Parser
|
|
5
|
+
module ParserGem
|
|
6
|
+
module NodeProcessors
|
|
7
|
+
class AndNode < Parser::NodeProcessor::Base
|
|
8
|
+
include ParserGem::NodeMethods
|
|
9
|
+
|
|
10
|
+
def process
|
|
11
|
+
process_children
|
|
12
|
+
|
|
13
|
+
position = get_node_start_position(node)
|
|
14
|
+
# @sg-ignore https://github.com/castwide/solargraph/pull/1114
|
|
15
|
+
enclosing_breakable_pin = pins.select{|pin| pin.is_a?(Pin::Breakable) && pin.location.range.contain?(position)}.last
|
|
16
|
+
FlowSensitiveTyping.new(locals, enclosing_breakable_pin).process_and(node)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|