solargraph 0.58.2 → 0.59.0.dev.2
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/.envrc +3 -0
- data/.github/workflows/linting.yml +4 -5
- data/.github/workflows/plugins.yml +41 -34
- data/.github/workflows/rspec.yml +44 -23
- data/.github/workflows/typecheck.yml +2 -2
- data/.rubocop.yml +32 -5
- data/.rubocop_todo.yml +50 -966
- data/Gemfile +3 -1
- data/README.md +3 -3
- data/Rakefile +26 -23
- data/bin/solargraph +2 -1
- data/lib/solargraph/api_map/cache.rb +3 -3
- data/lib/solargraph/api_map/constants.rb +13 -3
- data/lib/solargraph/api_map/index.rb +23 -18
- data/lib/solargraph/api_map/source_to_yard.rb +22 -9
- data/lib/solargraph/api_map/store.rb +33 -28
- data/lib/solargraph/api_map.rb +150 -82
- data/lib/solargraph/bench.rb +44 -45
- data/lib/solargraph/complex_type/conformance.rb +176 -0
- data/lib/solargraph/complex_type/type_methods.rb +28 -17
- data/lib/solargraph/complex_type/unique_type.rb +218 -57
- data/lib/solargraph/complex_type.rb +170 -57
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +7 -5
- data/lib/solargraph/convention/data_definition.rb +5 -2
- data/lib/solargraph/convention/gemfile.rb +15 -15
- data/lib/solargraph/convention/gemspec.rb +23 -23
- data/lib/solargraph/convention/rakefile.rb +17 -17
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -3
- data/lib/solargraph/convention/struct_definition.rb +8 -4
- data/lib/solargraph/convention.rb +78 -78
- data/lib/solargraph/converters/dd.rb +19 -17
- data/lib/solargraph/converters/dl.rb +17 -15
- data/lib/solargraph/converters/dt.rb +17 -15
- data/lib/solargraph/converters/misc.rb +3 -1
- data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop.rb +11 -10
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
- data/lib/solargraph/diagnostics/type_check.rb +11 -10
- data/lib/solargraph/diagnostics/update_errors.rb +37 -41
- data/lib/solargraph/doc_map.rb +133 -373
- data/lib/solargraph/equality.rb +4 -4
- data/lib/solargraph/gem_pins.rb +21 -20
- data/lib/solargraph/language_server/error_codes.rb +20 -20
- data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
- data/lib/solargraph/language_server/host/dispatch.rb +3 -3
- data/lib/solargraph/language_server/host/message_worker.rb +4 -3
- data/lib/solargraph/language_server/host/sources.rb +2 -1
- data/lib/solargraph/language_server/host.rb +30 -22
- data/lib/solargraph/language_server/message/base.rb +97 -97
- data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +12 -18
- data/lib/solargraph/language_server/message/extended/document.rb +1 -0
- data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
- data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
- data/lib/solargraph/language_server/message/extended/search.rb +20 -20
- data/lib/solargraph/language_server/message/initialize.rb +197 -191
- data/lib/solargraph/language_server/message/text_document/completion.rb +10 -8
- data/lib/solargraph/language_server/message/text_document/definition.rb +41 -32
- data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +29 -19
- data/lib/solargraph/language_server/message/text_document/formatting.rb +8 -6
- data/lib/solargraph/language_server/message/text_document/hover.rb +5 -5
- data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
- data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
- data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +3 -2
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -17
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +27 -17
- data/lib/solargraph/language_server/message.rb +94 -94
- data/lib/solargraph/language_server/request.rb +29 -27
- data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
- data/lib/solargraph/language_server/uri_helpers.rb +49 -49
- data/lib/solargraph/library.rb +85 -44
- data/lib/solargraph/location.rb +17 -14
- data/lib/solargraph/logging.rb +24 -4
- data/lib/solargraph/page.rb +92 -92
- data/lib/solargraph/parser/comment_ripper.rb +19 -4
- data/lib/solargraph/parser/flow_sensitive_typing.rb +326 -108
- data/lib/solargraph/parser/node_processor/base.rb +34 -4
- data/lib/solargraph/parser/node_processor.rb +8 -7
- data/lib/solargraph/parser/parser_gem/class_methods.rb +32 -14
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +50 -25
- data/lib/solargraph/parser/parser_gem/node_methods.rb +91 -70
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +13 -11
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +12 -12
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +10 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +5 -3
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +3 -3
- data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -5
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +124 -113
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
- data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +6 -2
- data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
- data/lib/solargraph/parser/parser_gem.rb +14 -12
- data/lib/solargraph/parser/region.rb +9 -3
- data/lib/solargraph/parser/snippet.rb +3 -1
- data/lib/solargraph/parser.rb +25 -23
- data/lib/solargraph/pin/base.rb +126 -80
- data/lib/solargraph/pin/base_variable.rb +273 -24
- data/lib/solargraph/pin/block.rb +29 -6
- data/lib/solargraph/pin/breakable.rb +7 -1
- data/lib/solargraph/pin/callable.rb +65 -21
- data/lib/solargraph/pin/closure.rb +7 -10
- data/lib/solargraph/pin/common.rb +24 -6
- data/lib/solargraph/pin/compound_statement.rb +55 -0
- data/lib/solargraph/pin/constant.rb +43 -45
- data/lib/solargraph/pin/conversions.rb +10 -4
- data/lib/solargraph/pin/delegated_method.rb +19 -8
- data/lib/solargraph/pin/documenting.rb +4 -2
- data/lib/solargraph/pin/instance_variable.rb +5 -1
- data/lib/solargraph/pin/keyword.rb +0 -4
- data/lib/solargraph/pin/local_variable.rb +15 -59
- data/lib/solargraph/pin/method.rb +153 -104
- data/lib/solargraph/pin/method_alias.rb +8 -0
- data/lib/solargraph/pin/namespace.rb +19 -12
- data/lib/solargraph/pin/parameter.rb +100 -36
- data/lib/solargraph/pin/proxy_type.rb +4 -1
- data/lib/solargraph/pin/reference/override.rb +1 -1
- data/lib/solargraph/pin/reference/superclass.rb +2 -0
- data/lib/solargraph/pin/reference.rb +19 -0
- data/lib/solargraph/pin/search.rb +3 -2
- data/lib/solargraph/pin/signature.rb +15 -12
- data/lib/solargraph/pin/symbol.rb +2 -1
- data/lib/solargraph/pin/until.rb +2 -4
- data/lib/solargraph/pin/while.rb +2 -4
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin_cache.rb +490 -73
- data/lib/solargraph/position.rb +14 -10
- data/lib/solargraph/range.rb +16 -15
- data/lib/solargraph/rbs_map/conversions.rb +343 -214
- data/lib/solargraph/rbs_map/core_fills.rb +91 -84
- data/lib/solargraph/rbs_map/core_map.rb +24 -17
- data/lib/solargraph/rbs_map/stdlib_map.rb +33 -5
- data/lib/solargraph/rbs_map.rb +77 -32
- data/lib/solargraph/server_methods.rb +16 -16
- data/lib/solargraph/shell.rb +128 -73
- data/lib/solargraph/source/chain/array.rb +39 -37
- data/lib/solargraph/source/chain/call.rb +96 -56
- data/lib/solargraph/source/chain/class_variable.rb +13 -13
- data/lib/solargraph/source/chain/constant.rb +5 -1
- data/lib/solargraph/source/chain/global_variable.rb +13 -13
- data/lib/solargraph/source/chain/hash.rb +8 -5
- data/lib/solargraph/source/chain/if.rb +12 -10
- data/lib/solargraph/source/chain/instance_variable.rb +24 -1
- data/lib/solargraph/source/chain/link.rb +99 -109
- data/lib/solargraph/source/chain/literal.rb +9 -6
- data/lib/solargraph/source/chain/or.rb +10 -4
- data/lib/solargraph/source/chain/q_call.rb +13 -11
- data/lib/solargraph/source/chain/variable.rb +15 -13
- data/lib/solargraph/source/chain/z_super.rb +28 -30
- data/lib/solargraph/source/chain.rb +49 -38
- data/lib/solargraph/source/change.rb +12 -5
- data/lib/solargraph/source/cursor.rb +23 -17
- data/lib/solargraph/source/encoding_fixes.rb +6 -7
- data/lib/solargraph/source/source_chainer.rb +56 -32
- data/lib/solargraph/source/updater.rb +5 -1
- data/lib/solargraph/source.rb +59 -35
- data/lib/solargraph/source_map/clip.rb +48 -29
- data/lib/solargraph/source_map/data.rb +4 -1
- data/lib/solargraph/source_map/mapper.rb +71 -42
- data/lib/solargraph/source_map.rb +21 -9
- data/lib/solargraph/type_checker/problem.rb +3 -1
- data/lib/solargraph/type_checker/rules.rb +81 -8
- data/lib/solargraph/type_checker.rb +195 -120
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +13 -10
- data/lib/solargraph/workspace/gemspecs.rb +367 -0
- data/lib/solargraph/workspace/require_paths.rb +1 -0
- data/lib/solargraph/workspace.rb +149 -30
- data/lib/solargraph/yard_map/helpers.rb +8 -3
- data/lib/solargraph/yard_map/mapper/to_method.rb +13 -7
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +2 -1
- data/lib/solargraph/yard_map/mapper.rb +13 -8
- data/lib/solargraph/yard_tags.rb +20 -20
- data/lib/solargraph/yardoc.rb +33 -23
- data/lib/solargraph.rb +29 -8
- data/rbs/fills/rubygems/0/dependency.rbs +193 -0
- data/rbs/fills/tuple/tuple.rbs +28 -0
- data/rbs/shims/ast/0/node.rbs +1 -1
- data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
- data/solargraph.gemspec +36 -34
- metadata +38 -33
- data/lib/solargraph/type_checker/checks.rb +0 -124
- data/lib/solargraph/type_checker/param_def.rb +0 -37
- data/lib/solargraph/yard_map/to_method.rb +0 -89
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'ripper'
|
|
2
4
|
|
|
3
5
|
module Solargraph
|
|
@@ -23,37 +25,50 @@ module Solargraph
|
|
|
23
25
|
# @sg-ignore
|
|
24
26
|
# @type [Array(Symbol, String, Array([Integer, nil], [Integer, nil]))]
|
|
25
27
|
result = super
|
|
28
|
+
# @sg-ignore Need to add nil check here
|
|
26
29
|
if @buffer_lines[result[2][0]][0..result[2][1]].strip =~ /^#/
|
|
27
30
|
chomped = result[1].chomp
|
|
28
|
-
if result[2][0]
|
|
31
|
+
if result[2][0].zero? && chomped.encode('UTF-8', 'binary', invalid: :replace, undef: :replace,
|
|
32
|
+
replace: '').match(/^#\s*frozen_string_literal:/)
|
|
29
33
|
chomped = '#'
|
|
30
34
|
end
|
|
31
|
-
@comments[result[2][0]] =
|
|
35
|
+
@comments[result[2][0]] =
|
|
36
|
+
Snippet.new(Range.from_to(result[2][0], result[2][1], result[2][0], result[2][1] + chomped.length), chomped)
|
|
32
37
|
end
|
|
33
38
|
result
|
|
34
39
|
end
|
|
35
40
|
|
|
36
41
|
# @param result [Array(Symbol, String, Array([Integer, nil], [Integer, nil]))]
|
|
37
42
|
# @return [void]
|
|
38
|
-
def create_snippet
|
|
43
|
+
def create_snippet result
|
|
39
44
|
chomped = result[1].chomp
|
|
40
|
-
@comments[result[2][0]] =
|
|
45
|
+
@comments[result[2][0]] =
|
|
46
|
+
Snippet.new(
|
|
47
|
+
Range.from_to(result[2][0] || 0, result[2][1] || 0, result[2][0] || 0,
|
|
48
|
+
(result[2][1] || 0) + chomped.length), chomped
|
|
49
|
+
)
|
|
41
50
|
end
|
|
42
51
|
|
|
52
|
+
# @sg-ignore @override is adding, not overriding
|
|
43
53
|
def on_embdoc_beg *args
|
|
44
54
|
result = super
|
|
55
|
+
# @sg-ignore @override is adding, not overriding
|
|
45
56
|
create_snippet(result)
|
|
46
57
|
result
|
|
47
58
|
end
|
|
48
59
|
|
|
60
|
+
# @sg-ignore @override is adding, not overriding
|
|
49
61
|
def on_embdoc *args
|
|
50
62
|
result = super
|
|
63
|
+
# @sg-ignore @override is adding, not overriding
|
|
51
64
|
create_snippet(result)
|
|
52
65
|
result
|
|
53
66
|
end
|
|
54
67
|
|
|
68
|
+
# @sg-ignore @override is adding, not overriding
|
|
55
69
|
def on_embdoc_end *args
|
|
56
70
|
result = super
|
|
71
|
+
# @sg-ignore @override is adding, not overriding
|
|
57
72
|
create_snippet(result)
|
|
58
73
|
result
|
|
59
74
|
end
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Solargraph
|
|
2
4
|
module Parser
|
|
3
5
|
class FlowSensitiveTyping
|
|
4
6
|
include Solargraph::Parser::NodeMethods
|
|
5
7
|
|
|
6
|
-
# @param locals [Array<Solargraph::Pin::LocalVariable
|
|
8
|
+
# @param locals [Array<Solargraph::Pin::LocalVariable>]
|
|
9
|
+
# @param ivars [Array<Solargraph::Pin::InstanceVariable>]
|
|
7
10
|
# @param enclosing_breakable_pin [Solargraph::Pin::Breakable, nil]
|
|
8
|
-
|
|
11
|
+
# @param enclosing_compound_statement_pin [Solargraph::Pin::CompoundStatement, nil]
|
|
12
|
+
def initialize locals, ivars, enclosing_breakable_pin, enclosing_compound_statement_pin
|
|
9
13
|
@locals = locals
|
|
14
|
+
@ivars = ivars
|
|
10
15
|
@enclosing_breakable_pin = enclosing_breakable_pin
|
|
16
|
+
@enclosing_compound_statement_pin = enclosing_compound_statement_pin
|
|
11
17
|
end
|
|
12
18
|
|
|
13
19
|
# @param and_node [Parser::AST::Node]
|
|
14
20
|
# @param true_ranges [Array<Range>]
|
|
21
|
+
# @param false_ranges [Array<Range>]
|
|
15
22
|
#
|
|
16
23
|
# @return [void]
|
|
17
|
-
def process_and
|
|
24
|
+
def process_and and_node, true_ranges = [], false_ranges = []
|
|
25
|
+
return unless and_node.type == :and
|
|
26
|
+
|
|
18
27
|
# @type [Parser::AST::Node]
|
|
19
28
|
lhs = and_node.children[0]
|
|
20
29
|
# @type [Parser::AST::Node]
|
|
@@ -25,13 +34,64 @@ module Solargraph
|
|
|
25
34
|
|
|
26
35
|
rhs_presence = Range.new(before_rhs_pos,
|
|
27
36
|
get_node_end_position(rhs))
|
|
28
|
-
|
|
37
|
+
|
|
38
|
+
# can't assume if an and is false that every single condition
|
|
39
|
+
# is false, so don't provide any false ranges to assert facts
|
|
40
|
+
# on
|
|
41
|
+
process_expression(lhs, true_ranges + [rhs_presence], [])
|
|
42
|
+
process_expression(rhs, true_ranges, [])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @param or_node [Parser::AST::Node]
|
|
46
|
+
# @param true_ranges [Array<Range>]
|
|
47
|
+
# @param false_ranges [Array<Range>]
|
|
48
|
+
#
|
|
49
|
+
# @return [void]
|
|
50
|
+
def process_or or_node, true_ranges = [], false_ranges = []
|
|
51
|
+
return unless or_node.type == :or
|
|
52
|
+
|
|
53
|
+
# @type [Parser::AST::Node]
|
|
54
|
+
lhs = or_node.children[0]
|
|
55
|
+
# @type [Parser::AST::Node]
|
|
56
|
+
rhs = or_node.children[1]
|
|
57
|
+
|
|
58
|
+
before_rhs_loc = rhs.location.expression.adjust(begin_pos: -1)
|
|
59
|
+
before_rhs_pos = Position.new(before_rhs_loc.line, before_rhs_loc.column)
|
|
60
|
+
|
|
61
|
+
rhs_presence = Range.new(before_rhs_pos,
|
|
62
|
+
get_node_end_position(rhs))
|
|
63
|
+
|
|
64
|
+
# can assume if an or is false that every single condition is
|
|
65
|
+
# false, so provide false ranges to assert facts on
|
|
66
|
+
|
|
67
|
+
# can't assume if an or is true that every single condition is
|
|
68
|
+
# true, so don't provide true ranges to assert facts on
|
|
69
|
+
|
|
70
|
+
process_expression(lhs, [], false_ranges + [rhs_presence])
|
|
71
|
+
process_expression(rhs, [], false_ranges)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @param node [Parser::AST::Node]
|
|
75
|
+
# @param true_presences [Array<Range>]
|
|
76
|
+
# @param false_presences [Array<Range>]
|
|
77
|
+
#
|
|
78
|
+
# @return [void]
|
|
79
|
+
def process_calls node, true_presences, false_presences
|
|
80
|
+
return unless node.type == :send
|
|
81
|
+
|
|
82
|
+
process_isa(node, true_presences, false_presences)
|
|
83
|
+
process_nilp(node, true_presences, false_presences)
|
|
84
|
+
process_bang(node, true_presences, false_presences)
|
|
29
85
|
end
|
|
30
86
|
|
|
31
87
|
# @param if_node [Parser::AST::Node]
|
|
88
|
+
# @param true_ranges [Array<Range>]
|
|
89
|
+
# @param false_ranges [Array<Range>]
|
|
32
90
|
#
|
|
33
91
|
# @return [void]
|
|
34
|
-
def process_if
|
|
92
|
+
def process_if if_node, true_ranges = [], false_ranges = []
|
|
93
|
+
return if if_node.type != :if
|
|
94
|
+
|
|
35
95
|
#
|
|
36
96
|
# See if we can refine a type based on the result of 'if foo.nil?'
|
|
37
97
|
#
|
|
@@ -44,23 +104,37 @@ module Solargraph
|
|
|
44
104
|
# s(:send, nil, :bar))
|
|
45
105
|
# [4] pry(main)>
|
|
46
106
|
conditional_node = if_node.children[0]
|
|
47
|
-
# @type [Parser::AST::Node]
|
|
107
|
+
# @type [Parser::AST::Node, nil]
|
|
48
108
|
then_clause = if_node.children[1]
|
|
49
|
-
# @type [Parser::AST::Node]
|
|
109
|
+
# @type [Parser::AST::Node, nil]
|
|
50
110
|
else_clause = if_node.children[2]
|
|
51
111
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
112
|
+
unless enclosing_breakable_pin.nil?
|
|
113
|
+
rest_of_breakable_body = Range.new(get_node_end_position(if_node),
|
|
114
|
+
get_node_end_position(enclosing_breakable_pin.node))
|
|
115
|
+
|
|
116
|
+
false_ranges << rest_of_breakable_body if always_breaks?(then_clause)
|
|
117
|
+
|
|
118
|
+
true_ranges << rest_of_breakable_body if always_breaks?(else_clause)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
unless enclosing_compound_statement_pin.node.nil?
|
|
122
|
+
rest_of_returnable_body = Range.new(get_node_end_position(if_node),
|
|
123
|
+
get_node_end_position(enclosing_compound_statement_pin.node))
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# if one of the clauses always leaves the compound
|
|
127
|
+
# statement, we can assume things about the rest of the
|
|
128
|
+
# compound statement
|
|
129
|
+
#
|
|
130
|
+
false_ranges << rest_of_returnable_body if always_leaves_compound_statement?(then_clause)
|
|
131
|
+
|
|
132
|
+
true_ranges << rest_of_returnable_body if always_leaves_compound_statement?(else_clause)
|
|
59
133
|
end
|
|
60
134
|
|
|
61
135
|
unless then_clause.nil?
|
|
62
136
|
#
|
|
63
|
-
#
|
|
137
|
+
# If the condition is true we can assume things about the then clause
|
|
64
138
|
#
|
|
65
139
|
before_then_clause_loc = then_clause.location.expression.adjust(begin_pos: -1)
|
|
66
140
|
before_then_clause_pos = Position.new(before_then_clause_loc.line, before_then_clause_loc.column)
|
|
@@ -68,170 +142,308 @@ module Solargraph
|
|
|
68
142
|
get_node_end_position(then_clause))
|
|
69
143
|
end
|
|
70
144
|
|
|
71
|
-
|
|
72
|
-
|
|
145
|
+
unless else_clause.nil?
|
|
146
|
+
#
|
|
147
|
+
# If the condition is true we can assume things about the else clause
|
|
148
|
+
#
|
|
149
|
+
before_else_clause_loc = else_clause.location.expression.adjust(begin_pos: -1)
|
|
150
|
+
before_else_clause_pos = Position.new(before_else_clause_loc.line, before_else_clause_loc.column)
|
|
151
|
+
false_ranges << Range.new(before_else_clause_pos,
|
|
152
|
+
get_node_end_position(else_clause))
|
|
153
|
+
end
|
|
73
154
|
|
|
74
|
-
|
|
75
|
-
include Logging
|
|
155
|
+
process_expression(conditional_node, true_ranges, false_ranges)
|
|
76
156
|
end
|
|
77
157
|
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
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]
|
|
158
|
+
# @param while_node [Parser::AST::Node]
|
|
159
|
+
# @param true_ranges [Array<Range>]
|
|
160
|
+
# @param false_ranges [Array<Range>]
|
|
88
161
|
#
|
|
89
|
-
# @return [
|
|
90
|
-
def
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
162
|
+
# @return [void]
|
|
163
|
+
def process_while while_node, true_ranges = [], false_ranges = []
|
|
164
|
+
return if while_node.type != :while
|
|
165
|
+
|
|
166
|
+
#
|
|
167
|
+
# See if we can refine a type based on the result of 'if foo.nil?'
|
|
168
|
+
#
|
|
169
|
+
# [3] pry(main)> Parser::CurrentRuby.parse("while a; b; c; end")
|
|
170
|
+
# => s(:while,
|
|
171
|
+
# s(:send, nil, :a),
|
|
172
|
+
# s(:begin,
|
|
173
|
+
# s(:send, nil, :b),
|
|
174
|
+
# s(:send, nil, :c)))
|
|
175
|
+
# [4] pry(main)>
|
|
176
|
+
conditional_node = while_node.children[0]
|
|
177
|
+
# @type [Parser::AST::Node, nil]
|
|
178
|
+
do_clause = while_node.children[1]
|
|
179
|
+
|
|
180
|
+
unless do_clause.nil?
|
|
181
|
+
#
|
|
182
|
+
# If the condition is true we can assume things about the do clause
|
|
183
|
+
#
|
|
184
|
+
before_do_clause_loc = do_clause.location.expression.adjust(begin_pos: -1)
|
|
185
|
+
before_do_clause_pos = Position.new(before_do_clause_loc.line, before_do_clause_loc.column)
|
|
186
|
+
true_ranges << Range.new(before_do_clause_pos,
|
|
187
|
+
get_node_end_position(do_clause))
|
|
111
188
|
end
|
|
112
189
|
|
|
113
|
-
|
|
190
|
+
process_expression(conditional_node, true_ranges, false_ranges)
|
|
191
|
+
end
|
|
114
192
|
|
|
115
|
-
|
|
193
|
+
class << self
|
|
194
|
+
include Logging
|
|
116
195
|
end
|
|
117
196
|
|
|
118
197
|
include Logging
|
|
119
198
|
|
|
120
199
|
private
|
|
121
200
|
|
|
122
|
-
# @param pin [Pin::
|
|
123
|
-
# @param downcast_type_name [String]
|
|
201
|
+
# @param pin [Pin::BaseVariable]
|
|
124
202
|
# @param presence [Range]
|
|
203
|
+
# @param downcast_type [ComplexType, nil]
|
|
204
|
+
# @param downcast_not_type [ComplexType, nil]
|
|
125
205
|
#
|
|
126
206
|
# @return [void]
|
|
127
|
-
def
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
# @param facts_by_pin [Hash{Pin::LocalVariable => Array<Hash{Symbol => String}>}]
|
|
207
|
+
def add_downcast_var pin, presence:, downcast_type:, downcast_not_type:
|
|
208
|
+
new_pin = pin.downcast(exclude_return_type: downcast_not_type,
|
|
209
|
+
intersection_return_type: downcast_type,
|
|
210
|
+
source: :flow_sensitive_typing,
|
|
211
|
+
presence: presence)
|
|
212
|
+
if pin.is_a?(Pin::LocalVariable)
|
|
213
|
+
locals.push(new_pin)
|
|
214
|
+
elsif pin.is_a?(Pin::InstanceVariable)
|
|
215
|
+
ivars.push(new_pin)
|
|
216
|
+
else
|
|
217
|
+
raise "Tried to add invalid pin type #{pin.class} in FlowSensitiveTyping"
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# @param facts_by_pin [Hash{Pin::BaseVariable => Array<Hash{:type, :not_type => ComplexType}>}]
|
|
144
222
|
# @param presences [Array<Range>]
|
|
145
223
|
#
|
|
146
224
|
# @return [void]
|
|
147
|
-
def process_facts
|
|
225
|
+
def process_facts facts_by_pin, presences
|
|
148
226
|
#
|
|
149
|
-
# Add specialized
|
|
227
|
+
# Add specialized vars for the rest of the block
|
|
150
228
|
#
|
|
151
229
|
facts_by_pin.each_pair do |pin, facts|
|
|
152
230
|
facts.each do |fact|
|
|
153
|
-
|
|
231
|
+
downcast_type = fact.fetch(:type, nil)
|
|
232
|
+
downcast_not_type = fact.fetch(:not_type, nil)
|
|
154
233
|
presences.each do |presence|
|
|
155
|
-
|
|
234
|
+
add_downcast_var(pin,
|
|
235
|
+
presence: presence,
|
|
236
|
+
downcast_type: downcast_type,
|
|
237
|
+
downcast_not_type: downcast_not_type)
|
|
156
238
|
end
|
|
157
239
|
end
|
|
158
240
|
end
|
|
159
241
|
end
|
|
160
242
|
|
|
161
|
-
# @param
|
|
243
|
+
# @param expression_node [Parser::AST::Node]
|
|
162
244
|
# @param true_ranges [Array<Range>]
|
|
245
|
+
# @param false_ranges [Array<Range>]
|
|
163
246
|
#
|
|
164
247
|
# @return [void]
|
|
165
|
-
def
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
end
|
|
248
|
+
def process_expression expression_node, true_ranges, false_ranges
|
|
249
|
+
process_calls(expression_node, true_ranges, false_ranges)
|
|
250
|
+
process_and(expression_node, true_ranges, false_ranges)
|
|
251
|
+
process_or(expression_node, true_ranges, false_ranges)
|
|
252
|
+
process_variable(expression_node, true_ranges, false_ranges)
|
|
171
253
|
end
|
|
172
254
|
|
|
173
|
-
# @param
|
|
174
|
-
# @
|
|
175
|
-
|
|
176
|
-
|
|
255
|
+
# @param call_node [Parser::AST::Node]
|
|
256
|
+
# @param method_name [Symbol]
|
|
257
|
+
# @return [Array(String, String), nil] Tuple of rgument to
|
|
258
|
+
# function, then receiver of function if it's a variable,
|
|
259
|
+
# otherwise nil if no simple variable receiver
|
|
260
|
+
def parse_call call_node, method_name
|
|
261
|
+
return unless call_node&.type == :send && call_node.children[1] == method_name
|
|
177
262
|
# Check if conditional node follows this pattern:
|
|
178
263
|
# s(:send,
|
|
179
264
|
# s(:send, nil, :foo), :is_a?,
|
|
180
265
|
# s(:const, nil, :Baz)),
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
266
|
+
#
|
|
267
|
+
call_receiver = call_node.children[0]
|
|
268
|
+
call_arg = type_name(call_node.children[2])
|
|
184
269
|
|
|
185
|
-
# check if
|
|
270
|
+
# check if call_receiver looks like this:
|
|
186
271
|
# s(:send, nil, :foo)
|
|
187
272
|
# and set variable_name to :foo
|
|
188
|
-
if
|
|
189
|
-
variable_name =
|
|
273
|
+
if call_receiver&.type == :send && call_receiver.children[0].nil? && call_receiver.children[1].is_a?(Symbol)
|
|
274
|
+
variable_name = call_receiver.children[1].to_s
|
|
190
275
|
end
|
|
191
276
|
# or like this:
|
|
192
277
|
# (lvar :repr)
|
|
193
|
-
|
|
278
|
+
# @sg-ignore Need to look at Tuple#include? handling
|
|
279
|
+
variable_name = call_receiver.children[0].to_s if %i[lvar ivar].include?(call_receiver&.type)
|
|
194
280
|
return unless variable_name
|
|
195
281
|
|
|
196
|
-
[
|
|
282
|
+
[call_arg, variable_name]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# @param isa_node [Parser::AST::Node]
|
|
286
|
+
# @return [Array(String, String), nil]
|
|
287
|
+
def parse_isa isa_node
|
|
288
|
+
call_type_name, variable_name = parse_call(isa_node, :is_a?)
|
|
289
|
+
|
|
290
|
+
return unless call_type_name
|
|
291
|
+
|
|
292
|
+
[call_type_name, variable_name]
|
|
197
293
|
end
|
|
198
294
|
|
|
199
295
|
# @param variable_name [String]
|
|
200
296
|
# @param position [Position]
|
|
201
297
|
#
|
|
202
|
-
# @
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
298
|
+
# @sg-ignore Solargraph::Parser::FlowSensitiveTyping#find_var
|
|
299
|
+
# return type could not be inferred
|
|
300
|
+
# @return [Solargraph::Pin::LocalVariable, Solargraph::Pin::InstanceVariable, nil]
|
|
301
|
+
def find_var variable_name, position
|
|
302
|
+
if variable_name.start_with?('@')
|
|
303
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
304
|
+
ivars.find { |ivar| ivar.name == variable_name && (!ivar.presence || ivar.presence.include?(position)) }
|
|
305
|
+
else
|
|
306
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
307
|
+
locals.find { |pin| pin.name == variable_name && (!pin.presence || pin.presence.include?(position)) }
|
|
308
|
+
end
|
|
207
309
|
end
|
|
208
310
|
|
|
209
311
|
# @param isa_node [Parser::AST::Node]
|
|
210
312
|
# @param true_presences [Array<Range>]
|
|
313
|
+
# @param false_presences [Array<Range>]
|
|
211
314
|
#
|
|
212
315
|
# @return [void]
|
|
213
|
-
def process_isa
|
|
316
|
+
def process_isa isa_node, true_presences, false_presences
|
|
214
317
|
isa_type_name, variable_name = parse_isa(isa_node)
|
|
215
318
|
return if variable_name.nil? || variable_name.empty?
|
|
319
|
+
# @sg-ignore Need to add nil check here
|
|
216
320
|
isa_position = Range.from_node(isa_node).start
|
|
217
321
|
|
|
218
|
-
pin =
|
|
322
|
+
pin = find_var(variable_name, isa_position)
|
|
323
|
+
return unless pin
|
|
324
|
+
|
|
325
|
+
# @type Hash{Pin::BaseVariable => Array<Hash{Symbol => ComplexType}>}
|
|
326
|
+
if_true = {}
|
|
327
|
+
if_true[pin] ||= []
|
|
328
|
+
if_true[pin] << { type: ComplexType.parse(isa_type_name) }
|
|
329
|
+
process_facts(if_true, true_presences)
|
|
330
|
+
|
|
331
|
+
# @type Hash{Pin::BaseVariable => Array<Hash{Symbol => ComplexType}>}
|
|
332
|
+
if_false = {}
|
|
333
|
+
if_false[pin] ||= []
|
|
334
|
+
if_false[pin] << { not_type: ComplexType.parse(isa_type_name) }
|
|
335
|
+
process_facts(if_false, false_presences)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# @param nilp_node [Parser::AST::Node]
|
|
339
|
+
# @return [Array(String, String), nil]
|
|
340
|
+
def parse_nilp nilp_node
|
|
341
|
+
parse_call(nilp_node, :nil?)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# @param nilp_node [Parser::AST::Node]
|
|
345
|
+
# @param true_presences [Array<Range>]
|
|
346
|
+
# @param false_presences [Array<Range>]
|
|
347
|
+
#
|
|
348
|
+
# @return [void]
|
|
349
|
+
def process_nilp nilp_node, true_presences, false_presences
|
|
350
|
+
nilp_arg, variable_name = parse_nilp(nilp_node)
|
|
351
|
+
return if variable_name.nil? || variable_name.empty?
|
|
352
|
+
# if .nil? got an argument, move on, this isn't the situation
|
|
353
|
+
# we're looking for and typechecking will cover any invalid
|
|
354
|
+
# ones
|
|
355
|
+
return unless nilp_arg.nil?
|
|
356
|
+
# @sg-ignore Need to add nil check here
|
|
357
|
+
nilp_position = Range.from_node(nilp_node).start
|
|
358
|
+
|
|
359
|
+
pin = find_var(variable_name, nilp_position)
|
|
219
360
|
return unless pin
|
|
220
361
|
|
|
362
|
+
# @type Hash{Pin::LocalVariable => Array<Hash{Symbol => ComplexType}>}
|
|
221
363
|
if_true = {}
|
|
222
364
|
if_true[pin] ||= []
|
|
223
|
-
if_true[pin] << { type:
|
|
365
|
+
if_true[pin] << { type: ComplexType::NIL }
|
|
224
366
|
process_facts(if_true, true_presences)
|
|
367
|
+
|
|
368
|
+
# @type Hash{Pin::LocalVariable => Array<Hash{Symbol => ComplexType}>}
|
|
369
|
+
if_false = {}
|
|
370
|
+
if_false[pin] ||= []
|
|
371
|
+
if_false[pin] << { not_type: ComplexType::NIL }
|
|
372
|
+
process_facts(if_false, false_presences)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# @param bang_node [Parser::AST::Node]
|
|
376
|
+
# @return [Array(String, String), nil]
|
|
377
|
+
def parse_bang bang_node
|
|
378
|
+
parse_call(bang_node, :!)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# @param bang_node [Parser::AST::Node]
|
|
382
|
+
# @param true_presences [Array<Range>]
|
|
383
|
+
# @param false_presences [Array<Range>]
|
|
384
|
+
#
|
|
385
|
+
# @return [void]
|
|
386
|
+
def process_bang bang_node, true_presences, false_presences
|
|
387
|
+
# pry(main)> require 'parser/current'; Parser::CurrentRuby.parse("!2")
|
|
388
|
+
# => s(:send,
|
|
389
|
+
# s(:int, 2), :!)
|
|
390
|
+
# end
|
|
391
|
+
return unless bang_node.type == :send && bang_node.children[1] == :!
|
|
392
|
+
|
|
393
|
+
receiver = bang_node.children[0]
|
|
394
|
+
|
|
395
|
+
# swap the two presences
|
|
396
|
+
process_expression(receiver, false_presences, true_presences)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# @param var_node [Parser::AST::Node]
|
|
400
|
+
#
|
|
401
|
+
# @return [String, nil] Variable name referenced
|
|
402
|
+
def parse_variable var_node
|
|
403
|
+
return if var_node.children.length != 1
|
|
404
|
+
|
|
405
|
+
var_node.children[0]&.to_s
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# @return [void]
|
|
409
|
+
# @param node [Parser::AST::Node]
|
|
410
|
+
# @param true_presences [Array<Range>]
|
|
411
|
+
# @param false_presences [Array<Range>]
|
|
412
|
+
def process_variable node, true_presences, false_presences
|
|
413
|
+
return unless %i[lvar ivar cvar gvar].include?(node.type)
|
|
414
|
+
|
|
415
|
+
variable_name = parse_variable(node)
|
|
416
|
+
return if variable_name.nil?
|
|
417
|
+
|
|
418
|
+
# @sg-ignore Need to add nil check here
|
|
419
|
+
var_position = Range.from_node(node).start
|
|
420
|
+
|
|
421
|
+
pin = find_var(variable_name, var_position)
|
|
422
|
+
return unless pin
|
|
423
|
+
|
|
424
|
+
# @type Hash{Pin::LocalVariable => Array<Hash{Symbol => ComplexType}>}
|
|
425
|
+
if_true = {}
|
|
426
|
+
if_true[pin] ||= []
|
|
427
|
+
if_true[pin] << { not_type: ComplexType::NIL }
|
|
428
|
+
process_facts(if_true, true_presences)
|
|
429
|
+
|
|
430
|
+
# @type Hash{Pin::LocalVariable => Array<Hash{Symbol => ComplexType}>}
|
|
431
|
+
if_false = {}
|
|
432
|
+
if_false[pin] ||= []
|
|
433
|
+
if_false[pin] << { type: ComplexType.parse('nil, false') }
|
|
434
|
+
process_facts(if_false, false_presences)
|
|
225
435
|
end
|
|
226
436
|
|
|
227
437
|
# @param node [Parser::AST::Node]
|
|
228
438
|
#
|
|
229
439
|
# @return [String, nil]
|
|
230
|
-
def type_name
|
|
440
|
+
def type_name node
|
|
231
441
|
# e.g.,
|
|
232
442
|
# s(:const, nil, :Baz)
|
|
233
443
|
return unless node&.type == :const
|
|
444
|
+
# @type [Parser::AST::Node, nil]
|
|
234
445
|
module_node = node.children[0]
|
|
446
|
+
# @type [Parser::AST::Node, nil]
|
|
235
447
|
class_node = node.children[1]
|
|
236
448
|
|
|
237
449
|
return class_node.to_s if module_node.nil?
|
|
@@ -242,14 +454,20 @@ module Solargraph
|
|
|
242
454
|
"#{module_type_name}::#{class_node}"
|
|
243
455
|
end
|
|
244
456
|
|
|
245
|
-
# @param clause_node [Parser::AST::Node]
|
|
246
|
-
|
|
457
|
+
# @param clause_node [Parser::AST::Node, nil]
|
|
458
|
+
# @sg-ignore need boolish support for ? methods
|
|
459
|
+
def always_breaks? clause_node
|
|
247
460
|
clause_node&.type == :break
|
|
248
461
|
end
|
|
249
462
|
|
|
250
|
-
|
|
463
|
+
# @param clause_node [Parser::AST::Node, nil]
|
|
464
|
+
def always_leaves_compound_statement? clause_node
|
|
465
|
+
# https://docs.ruby-lang.org/en/2.2.0/keywords_rdoc.html
|
|
466
|
+
# @sg-ignore Need to look at Tuple#include? handling
|
|
467
|
+
%i[return raise next redo retry].include?(clause_node&.type)
|
|
468
|
+
end
|
|
251
469
|
|
|
252
|
-
attr_reader :enclosing_breakable_pin
|
|
470
|
+
attr_reader :locals, :ivars, :enclosing_breakable_pin, :enclosing_compound_statement_pin
|
|
253
471
|
end
|
|
254
472
|
end
|
|
255
473
|
end
|