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