steep 0.52.0 → 0.52.1
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/dependabot.yml +13 -6
- data/.github/workflows/ruby.yml +3 -1
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +4 -4
- data/lib/steep/ast/types/factory.rb +2 -1
- data/lib/steep/cli.rb +16 -7
- data/lib/steep/server/interaction_worker.rb +5 -151
- data/lib/steep/server/lsp_formatter.rb +234 -0
- data/lib/steep/services/hover_provider/rbs.rb +63 -0
- data/lib/steep/services/hover_provider/ruby.rb +168 -0
- data/lib/steep/services/hover_provider/singleton_methods.rb +21 -0
- data/lib/steep/subtyping/check.rb +2 -2
- data/lib/steep/type_construction.rb +5 -0
- data/lib/steep/type_inference/context.rb +4 -0
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +11 -8
- data/steep.gemspec +1 -1
- metadata +8 -5
- data/lib/steep/services/hover_content.rb +0 -254
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c373c6a4366397b2b014850a8993ce6d8a0c27bcdd8bc8c5135bb64b4132b162
|
4
|
+
data.tar.gz: '097245d5e3745ceb634a2f2bcd007cca0c549449c835b644feb62c23c3c6e3ed'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eadc49c7c81bce14e4e4c5f9adbcb0411669cd1f78eb290029953e26ea3997d15a65db53329124812e841f3fbe486d30f25bbf89d7bce74d528692176250c795
|
7
|
+
data.tar.gz: 3257fa14e2888e68afd6266e1c1d28dc95b8ef7e1ec499393994f35cb715abfc133f005d0ce79962fc6642f7fdeb0b28c35fa0d3bb5687972ea1b31d0a9d6c38
|
data/.github/dependabot.yml
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
version: 2
|
2
|
+
|
2
3
|
updates:
|
3
|
-
- package-ecosystem: bundler
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
- package-ecosystem: bundler
|
5
|
+
directory: "/"
|
6
|
+
schedule:
|
7
|
+
interval: daily
|
8
|
+
time: "20:00"
|
9
|
+
open-pull-requests-limit: 10
|
10
|
+
|
11
|
+
- package-ecosystem: "github-actions"
|
12
|
+
directory: "/"
|
13
|
+
schedule:
|
14
|
+
# Check for updates to GitHub Actions every weekday
|
15
|
+
interval: "daily"
|
data/.github/workflows/ruby.yml
CHANGED
@@ -14,6 +14,7 @@ jobs:
|
|
14
14
|
container_tag:
|
15
15
|
- "2.7"
|
16
16
|
- "3.0"
|
17
|
+
- "3.1"
|
17
18
|
- "master-nightly-focal"
|
18
19
|
task:
|
19
20
|
- test
|
@@ -22,9 +23,10 @@ jobs:
|
|
22
23
|
container:
|
23
24
|
image: rubylang/ruby:${{ matrix.container_tag }}
|
24
25
|
steps:
|
25
|
-
- uses: actions/checkout@
|
26
|
+
- uses: actions/checkout@v3
|
26
27
|
- name: Run test
|
27
28
|
run: |
|
29
|
+
git config --global --add safe.directory /__w/steep/steep
|
28
30
|
ruby -v
|
29
31
|
gem install bundler
|
30
32
|
bundle install --jobs 4 --retry 3
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.52.1 (2022-04-25)
|
6
|
+
|
7
|
+
* Better union type inference (it type checks `Array#filter_map` now!) ([\#531](https://github.com/soutaro/steep/pull/531))
|
8
|
+
* Improve method call hover message ([\#537](https://github.com/soutaro/steep/pull/537), [\#538](https://github.com/soutaro/steep/pull/538))
|
9
|
+
* Make `NilClass#!` a special method to improve flow-sensitive typing ([\#539](https://github.com/soutaro/steep/pull/539))
|
10
|
+
* Fix `steep binstub` ([\#540](https://github.com/soutaro/steep/pull/540), [\#541](https://github.com/soutaro/steep/pull/541))
|
11
|
+
|
5
12
|
## 0.52.0 (2022-04-05)
|
6
13
|
|
7
14
|
* Add `steep binstub` command ([\#527](https://github.com/soutaro/steep/pull/527))
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
steep (0.52.
|
4
|
+
steep (0.52.1)
|
5
5
|
activesupport (>= 5.1)
|
6
6
|
language_server-protocol (>= 3.15, < 4.0)
|
7
7
|
listen (~> 3.0)
|
8
8
|
parallel (>= 1.0.0)
|
9
9
|
parser (>= 3.0)
|
10
10
|
rainbow (>= 2.2.2, < 4.0)
|
11
|
-
rbs (>= 2.3.
|
11
|
+
rbs (>= 2.3.2)
|
12
12
|
terminal-table (>= 2, < 4)
|
13
13
|
|
14
14
|
PATH
|
@@ -44,14 +44,14 @@ GEM
|
|
44
44
|
minitest-slow_test (0.2.0)
|
45
45
|
minitest (>= 5.0)
|
46
46
|
parallel (1.22.1)
|
47
|
-
parser (3.1.
|
47
|
+
parser (3.1.2.0)
|
48
48
|
ast (~> 2.4.1)
|
49
49
|
rainbow (3.1.1)
|
50
50
|
rake (13.0.6)
|
51
51
|
rb-fsevent (0.11.1)
|
52
52
|
rb-inotify (0.10.1)
|
53
53
|
ffi (~> 1.0)
|
54
|
-
rbs (2.3.
|
54
|
+
rbs (2.3.2)
|
55
55
|
stackprof (0.2.19)
|
56
56
|
terminal-table (3.0.2)
|
57
57
|
unicode-display_width (>= 1.1.1, < 3)
|
@@ -431,7 +431,8 @@ module Steep
|
|
431
431
|
case defined_in
|
432
432
|
when RBS::BuiltinNames::BasicObject.name,
|
433
433
|
RBS::BuiltinNames::TrueClass.name,
|
434
|
-
RBS::BuiltinNames::FalseClass.name
|
434
|
+
RBS::BuiltinNames::FalseClass.name,
|
435
|
+
AST::Builtin::NilClass.module_name
|
435
436
|
return method_type.with(
|
436
437
|
type: method_type.type.with(
|
437
438
|
return_type: AST::Types::Logic::Not.new(location: method_type.type.return_type.location)
|
data/lib/steep/cli.rb
CHANGED
@@ -210,6 +210,7 @@ module Steep
|
|
210
210
|
|
211
211
|
def process_binstub
|
212
212
|
path = Pathname("bin/steep")
|
213
|
+
root_path = Pathname.pwd
|
213
214
|
force = false
|
214
215
|
|
215
216
|
OptionParser.new do |opts|
|
@@ -227,21 +228,28 @@ BANNER
|
|
227
228
|
path = Pathname(v)
|
228
229
|
end
|
229
230
|
|
231
|
+
opts.on("--root=PATH", "The repository root path (defaults to `.`)") do |v|
|
232
|
+
root_path = (Pathname.pwd + v).cleanpath
|
233
|
+
end
|
234
|
+
|
230
235
|
opts.on("--[no-]force", "Overwrite file (defaults to false)") do
|
231
236
|
force = true
|
232
237
|
end
|
233
238
|
end.parse!(argv)
|
234
239
|
|
235
|
-
path.
|
240
|
+
binstub_path = (Pathname.pwd + path).cleanpath
|
241
|
+
bindir_path = binstub_path.parent
|
242
|
+
|
243
|
+
bindir_path.mkpath
|
236
244
|
|
237
245
|
gemfile_path =
|
238
246
|
if defined?(Bundler)
|
239
|
-
Bundler.default_gemfile.relative_path_from(
|
247
|
+
Bundler.default_gemfile.relative_path_from(bindir_path)
|
240
248
|
else
|
241
249
|
Pathname("../Gemfile")
|
242
250
|
end
|
243
251
|
|
244
|
-
if
|
252
|
+
if binstub_path.file?
|
245
253
|
if force
|
246
254
|
stdout.puts Rainbow("#{path} already exists. Overwriting...").yellow
|
247
255
|
else
|
@@ -254,7 +262,8 @@ BANNER
|
|
254
262
|
#!/usr/bin/env bash
|
255
263
|
|
256
264
|
BINSTUB_DIR=$(cd $(dirname $0); pwd)
|
257
|
-
GEMFILE=${BINSTUB_DIR}/#{gemfile_path}
|
265
|
+
GEMFILE=$(readlink -f ${BINSTUB_DIR}/#{gemfile_path})
|
266
|
+
ROOT_DIR=$(readlink -f ${BINSTUB_DIR}/#{root_path.relative_path_from(bindir_path)})
|
258
267
|
|
259
268
|
STEEP="bundle exec --gemfile=${GEMFILE} steep"
|
260
269
|
|
@@ -262,15 +271,15 @@ if type "rbenv" > /dev/null 2>&1; then
|
|
262
271
|
STEEP="rbenv exec ${STEEP}"
|
263
272
|
else
|
264
273
|
if type "rvm" > /dev/null 2>&1; then
|
265
|
-
STEEP="rvm ${
|
274
|
+
STEEP="rvm ${ROOT_DIR} do ${STEEP}"
|
266
275
|
fi
|
267
276
|
fi
|
268
277
|
|
269
278
|
exec $STEEP $@
|
270
279
|
TEMPLATE
|
271
280
|
|
272
|
-
|
273
|
-
|
281
|
+
binstub_path.write(template)
|
282
|
+
binstub_path.chmod(0755)
|
274
283
|
|
275
284
|
stdout.puts Rainbow("Successfully generated executable #{path} 🎉").blue
|
276
285
|
|
@@ -78,8 +78,7 @@ module Steep
|
|
78
78
|
Steep.measure "Generating hover response" do
|
79
79
|
Steep.logger.info { "path=#{job.path}, line=#{job.line}, column=#{job.column}" }
|
80
80
|
|
81
|
-
|
82
|
-
content = hover.content_for(path: job.path, line: job.line, column: job.column)
|
81
|
+
content = Services::HoverProvider.content_for(service: service, path: job.path, line: job.line, column: job.column)
|
83
82
|
if content
|
84
83
|
range = content.location.yield_self do |location|
|
85
84
|
lsp_range = location.as_lsp_range
|
@@ -89,7 +88,10 @@ module Steep
|
|
89
88
|
end
|
90
89
|
|
91
90
|
LSP::Interface::Hover.new(
|
92
|
-
contents: {
|
91
|
+
contents: {
|
92
|
+
kind: "markdown",
|
93
|
+
value: LSPFormatter.format_hover_content(content).to_s
|
94
|
+
},
|
93
95
|
range: range
|
94
96
|
)
|
95
97
|
end
|
@@ -100,101 +102,6 @@ module Steep
|
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
103
|
-
def format_hover(content)
|
104
|
-
case content
|
105
|
-
when Services::HoverContent::TypeAliasContent
|
106
|
-
comment = content.decl.comment&.string || ''
|
107
|
-
|
108
|
-
<<-MD
|
109
|
-
#{comment}
|
110
|
-
|
111
|
-
```rbs
|
112
|
-
#{retrieve_decl_information(content.decl)}
|
113
|
-
```
|
114
|
-
MD
|
115
|
-
when Services::HoverContent::InterfaceContent
|
116
|
-
comment = content.decl.comment&.string || ''
|
117
|
-
|
118
|
-
<<-MD
|
119
|
-
#{comment}
|
120
|
-
|
121
|
-
```rbs
|
122
|
-
#{retrieve_decl_information(content.decl)}
|
123
|
-
```
|
124
|
-
MD
|
125
|
-
when Services::HoverContent::ClassContent
|
126
|
-
comment = content.decl.comment&.string || ''
|
127
|
-
|
128
|
-
<<-MD
|
129
|
-
#{comment}
|
130
|
-
|
131
|
-
```rbs
|
132
|
-
#{retrieve_decl_information(content.decl)}
|
133
|
-
```
|
134
|
-
MD
|
135
|
-
when Services::HoverContent::VariableContent
|
136
|
-
"`#{content.name}`: `#{content.type.to_s}`"
|
137
|
-
when Services::HoverContent::MethodCallContent
|
138
|
-
method_name = case content.method_name
|
139
|
-
when Services::HoverContent::InstanceMethodName
|
140
|
-
"#{content.method_name.class_name}##{content.method_name.method_name}"
|
141
|
-
when Services::HoverContent::SingletonMethodName
|
142
|
-
"#{content.method_name.class_name}.#{content.method_name.method_name}"
|
143
|
-
else
|
144
|
-
nil
|
145
|
-
end
|
146
|
-
|
147
|
-
if method_name
|
148
|
-
string = <<HOVER
|
149
|
-
```
|
150
|
-
#{method_name} ~> #{content.type}
|
151
|
-
```
|
152
|
-
HOVER
|
153
|
-
if content.definition
|
154
|
-
if content.definition.comments
|
155
|
-
string << "\n----\n\n#{content.definition.comments.map(&:string).join("\n\n")}"
|
156
|
-
end
|
157
|
-
|
158
|
-
string << "\n----\n\n#{content.definition.method_types.map {|x| "- `#{x}`\n" }.join()}"
|
159
|
-
end
|
160
|
-
else
|
161
|
-
"`#{content.type}`"
|
162
|
-
end
|
163
|
-
when Services::HoverContent::DefinitionContent
|
164
|
-
string = <<HOVER
|
165
|
-
```
|
166
|
-
def #{content.method_name}: #{content.method_type}
|
167
|
-
```
|
168
|
-
HOVER
|
169
|
-
if (comment = content.comment_string)
|
170
|
-
string << "\n----\n\n#{comment}\n"
|
171
|
-
end
|
172
|
-
|
173
|
-
if content.definition.method_types.size > 1
|
174
|
-
string << "\n----\n\n#{content.definition.method_types.map {|x| "- `#{x}`\n" }.join()}"
|
175
|
-
end
|
176
|
-
|
177
|
-
string
|
178
|
-
when Services::HoverContent::ConstantContent
|
179
|
-
ss = []
|
180
|
-
if content.class_or_module?
|
181
|
-
ss << ["```rbs", retrieve_decl_information(content.decl.primary.decl), "```"].join("\n")
|
182
|
-
end
|
183
|
-
|
184
|
-
if content.constant?
|
185
|
-
ss << ["```rbs", "#{content.full_name}: #{content.type}", "```"].join("\n")
|
186
|
-
end
|
187
|
-
|
188
|
-
if s = content.comment_string
|
189
|
-
ss << s
|
190
|
-
end
|
191
|
-
|
192
|
-
ss.join("\n\n----\n\n")
|
193
|
-
when Services::HoverContent::TypeContent
|
194
|
-
"`#{content.type}`"
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
105
|
def process_completion(job)
|
199
106
|
Steep.logger.tagged("#response_to_completion") do
|
200
107
|
Steep.measure "Generating response" do
|
@@ -356,59 +263,6 @@ HOVER
|
|
356
263
|
end
|
357
264
|
end
|
358
265
|
|
359
|
-
def name_and_params(name, params)
|
360
|
-
if params.empty?
|
361
|
-
"#{name}"
|
362
|
-
else
|
363
|
-
ps = params.each.map do |param|
|
364
|
-
s = ""
|
365
|
-
if param.unchecked?
|
366
|
-
s << "unchecked "
|
367
|
-
end
|
368
|
-
case param.variance
|
369
|
-
when :invariant
|
370
|
-
# nop
|
371
|
-
when :covariant
|
372
|
-
s << "out "
|
373
|
-
when :contravariant
|
374
|
-
s << "in "
|
375
|
-
end
|
376
|
-
s + param.name.to_s
|
377
|
-
end
|
378
|
-
|
379
|
-
"#{name}[#{ps.join(", ")}]"
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
def name_and_args(name, args)
|
384
|
-
if name && args
|
385
|
-
if args.empty?
|
386
|
-
"#{name}"
|
387
|
-
else
|
388
|
-
"#{name}[#{args.join(", ")}]"
|
389
|
-
end
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
def retrieve_decl_information(decl)
|
394
|
-
case decl
|
395
|
-
when RBS::AST::Declarations::Class
|
396
|
-
super_class = if super_class = decl.super_class
|
397
|
-
" < #{name_and_args(super_class.name, super_class.args)}"
|
398
|
-
end
|
399
|
-
"class #{name_and_params(decl.name, decl.type_params)}#{super_class}"
|
400
|
-
when RBS::AST::Declarations::Module
|
401
|
-
self_type = unless decl.self_types.empty?
|
402
|
-
" : #{decl.self_types.join(", ")}"
|
403
|
-
end
|
404
|
-
"module #{name_and_params(decl.name, decl.type_params)}#{self_type}"
|
405
|
-
when RBS::AST::Declarations::Alias
|
406
|
-
"type #{decl.name} = #{decl.type}"
|
407
|
-
when RBS::AST::Declarations::Interface
|
408
|
-
"interface #{name_and_params(decl.name, decl.type_params)}"
|
409
|
-
end
|
410
|
-
end
|
411
|
-
|
412
266
|
def format_completion_item(item)
|
413
267
|
range = LanguageServer::Protocol::Interface::Range.new(
|
414
268
|
start: LanguageServer::Protocol::Interface::Position.new(
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module Steep
|
2
|
+
module Server
|
3
|
+
module LSPFormatter
|
4
|
+
include Services
|
5
|
+
|
6
|
+
class CommentBuilder
|
7
|
+
def initialize
|
8
|
+
@array = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.build
|
12
|
+
builder = CommentBuilder.new
|
13
|
+
yield builder
|
14
|
+
builder.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
unless @array.empty?
|
19
|
+
@array.join("\n\n----\n\n")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def <<(string)
|
24
|
+
if string
|
25
|
+
s = string.rstrip.gsub(/^[ \t]*<!--(?~-->)-->\n/, "").gsub(/\A([ \t]*\n)+/, "")
|
26
|
+
unless @array.include?(s)
|
27
|
+
@array << s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def push
|
33
|
+
s = ""
|
34
|
+
yield s
|
35
|
+
self << s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module_function
|
40
|
+
|
41
|
+
def format_hover_content(content)
|
42
|
+
case content
|
43
|
+
when HoverProvider::Ruby::VariableContent
|
44
|
+
"`#{content.name}`: `#{content.type.to_s}`"
|
45
|
+
|
46
|
+
when HoverProvider::Ruby::MethodCallContent
|
47
|
+
CommentBuilder.build do |builder|
|
48
|
+
call = content.method_call
|
49
|
+
builder.push do |s|
|
50
|
+
case call
|
51
|
+
when TypeInference::MethodCall::Typed
|
52
|
+
mt = call.actual_method_type.with(
|
53
|
+
type: call.actual_method_type.type.with(return_type: call.return_type)
|
54
|
+
)
|
55
|
+
s << "```rbs\n#{mt.to_s}\n```\n\n"
|
56
|
+
when TypeInference::MethodCall::Error
|
57
|
+
s << "```rbs\n( ??? ) -> #{call.return_type.to_s}\n```\n\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
s << to_list(call.method_decls) do |decl|
|
61
|
+
"`#{decl.method_name}`"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
call.method_decls.each do |decl|
|
66
|
+
if comment = decl.method_def.comment
|
67
|
+
builder << <<EOM
|
68
|
+
**#{decl.method_name.to_s}**
|
69
|
+
|
70
|
+
```rbs
|
71
|
+
#{decl.method_type}
|
72
|
+
```
|
73
|
+
|
74
|
+
#{decl.method_def.comment.string.gsub(/\A([ \t]*\n)+/, "")}
|
75
|
+
EOM
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
when HoverProvider::Ruby::DefinitionContent
|
81
|
+
CommentBuilder.build do |builder|
|
82
|
+
builder << <<EOM
|
83
|
+
```
|
84
|
+
#{content.method_name}: #{content.method_type}
|
85
|
+
```
|
86
|
+
EOM
|
87
|
+
if comments = content.definition&.comments
|
88
|
+
comments.each do |comment|
|
89
|
+
builder << comment.string
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if content.definition.method_types.size > 1
|
94
|
+
builder << to_list(content.definition.method_types) {|type| "`#{type.to_s}`" }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
when HoverProvider::Ruby::ConstantContent
|
98
|
+
CommentBuilder.build do |builder|
|
99
|
+
if content.class_or_module?
|
100
|
+
builder << <<EOM
|
101
|
+
```rbs
|
102
|
+
#{declaration_summary(content.decl.primary.decl)}
|
103
|
+
```
|
104
|
+
EOM
|
105
|
+
end
|
106
|
+
|
107
|
+
if content.constant?
|
108
|
+
builder << <<EOM
|
109
|
+
```rbs
|
110
|
+
#{content.full_name}: #{content.type}
|
111
|
+
```
|
112
|
+
EOM
|
113
|
+
end
|
114
|
+
|
115
|
+
content.comments.each do |comment|
|
116
|
+
builder << comment.string
|
117
|
+
end
|
118
|
+
end
|
119
|
+
when HoverProvider::Ruby::TypeContent
|
120
|
+
"`#{content.type}`"
|
121
|
+
when HoverProvider::RBS::TypeAliasContent
|
122
|
+
CommentBuilder.build do |builder|
|
123
|
+
builder << <<EOM
|
124
|
+
```rbs
|
125
|
+
#{declaration_summary(content.decl)}
|
126
|
+
```
|
127
|
+
EOM
|
128
|
+
if comment = content.decl.comment
|
129
|
+
builder << comment.string
|
130
|
+
end
|
131
|
+
end
|
132
|
+
when HoverProvider::RBS::ClassContent
|
133
|
+
CommentBuilder.build do |builder|
|
134
|
+
builder << <<EOM
|
135
|
+
```rbs
|
136
|
+
#{declaration_summary(content.decl)}
|
137
|
+
```
|
138
|
+
EOM
|
139
|
+
if comment = content.decl.comment
|
140
|
+
builder << comment.string
|
141
|
+
end
|
142
|
+
end
|
143
|
+
when HoverProvider::RBS::InterfaceContent
|
144
|
+
CommentBuilder.build do |builder|
|
145
|
+
builder << <<EOM
|
146
|
+
```rbs
|
147
|
+
#{declaration_summary(content.decl)}
|
148
|
+
```
|
149
|
+
EOM
|
150
|
+
if comment = content.decl.comment
|
151
|
+
builder << comment.string
|
152
|
+
end
|
153
|
+
end
|
154
|
+
else
|
155
|
+
raise content.class.to_s
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def to_list(collection, &block)
|
160
|
+
buffer = ""
|
161
|
+
|
162
|
+
strings =
|
163
|
+
if block
|
164
|
+
collection.map(&block)
|
165
|
+
else
|
166
|
+
collection.map(&:to_s)
|
167
|
+
end
|
168
|
+
|
169
|
+
strings.each do |s|
|
170
|
+
buffer << "- #{s}\n"
|
171
|
+
end
|
172
|
+
|
173
|
+
buffer
|
174
|
+
end
|
175
|
+
|
176
|
+
def name_and_args(name, args)
|
177
|
+
if args.empty?
|
178
|
+
"#{name}"
|
179
|
+
else
|
180
|
+
"#{name}[#{args.map(&:to_s).join(", ")}]"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def name_and_params(name, params)
|
185
|
+
if params.empty?
|
186
|
+
"#{name}"
|
187
|
+
else
|
188
|
+
ps = params.each.map do |param|
|
189
|
+
s = ""
|
190
|
+
if param.unchecked?
|
191
|
+
s << "unchecked "
|
192
|
+
end
|
193
|
+
case param.variance
|
194
|
+
when :invariant
|
195
|
+
# nop
|
196
|
+
when :covariant
|
197
|
+
s << "out "
|
198
|
+
when :contravariant
|
199
|
+
s << "in "
|
200
|
+
end
|
201
|
+
s << param.name.to_s
|
202
|
+
|
203
|
+
if param.upper_bound
|
204
|
+
s << " < #{param.upper_bound.to_s}"
|
205
|
+
end
|
206
|
+
|
207
|
+
s
|
208
|
+
end
|
209
|
+
|
210
|
+
"#{name}[#{ps.join(", ")}]"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def declaration_summary(decl)
|
215
|
+
case decl
|
216
|
+
when RBS::AST::Declarations::Class
|
217
|
+
super_class = if super_class = decl.super_class
|
218
|
+
" < #{name_and_args(super_class.name, super_class.args)}"
|
219
|
+
end
|
220
|
+
"class #{name_and_params(decl.name, decl.type_params)}#{super_class}"
|
221
|
+
when RBS::AST::Declarations::Module
|
222
|
+
self_type = unless decl.self_types.empty?
|
223
|
+
" : #{decl.self_types.map {|s| name_and_args(s.name, s.args) }.join(", ")}"
|
224
|
+
end
|
225
|
+
"module #{name_and_params(decl.name, decl.type_params)}#{self_type}"
|
226
|
+
when RBS::AST::Declarations::Alias
|
227
|
+
"type #{decl.name} = #{decl.type}"
|
228
|
+
when RBS::AST::Declarations::Interface
|
229
|
+
"interface #{name_and_params(decl.name, decl.type_params)}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Steep
|
2
|
+
module Services
|
3
|
+
module HoverProvider
|
4
|
+
class RBS
|
5
|
+
TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
|
6
|
+
ClassContent = Struct.new(:location, :decl, keyword_init: true)
|
7
|
+
InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
|
8
|
+
|
9
|
+
attr_reader :service
|
10
|
+
|
11
|
+
def initialize(service:)
|
12
|
+
@service = service
|
13
|
+
end
|
14
|
+
|
15
|
+
def project
|
16
|
+
service.project
|
17
|
+
end
|
18
|
+
|
19
|
+
def content_for(target:, path:, line:, column:)
|
20
|
+
service = self.service.signature_services[target.name]
|
21
|
+
|
22
|
+
_, decls = service.latest_env.buffers_decls.find do |buffer, _|
|
23
|
+
Pathname(buffer.name) == path
|
24
|
+
end
|
25
|
+
|
26
|
+
return if decls.nil?
|
27
|
+
|
28
|
+
loc_key, path = ::RBS::Locator.new(decls: decls).find2(line: line, column: column) || return
|
29
|
+
head, *tail = path
|
30
|
+
|
31
|
+
case head
|
32
|
+
when ::RBS::Types::Alias
|
33
|
+
alias_decl = service.latest_env.alias_decls[head.name]&.decl or raise
|
34
|
+
|
35
|
+
TypeAliasContent.new(
|
36
|
+
location: head.location,
|
37
|
+
decl: alias_decl
|
38
|
+
)
|
39
|
+
when ::RBS::Types::ClassInstance, ::RBS::Types::ClassSingleton
|
40
|
+
if loc_key == :name
|
41
|
+
env = service.latest_env
|
42
|
+
class_decl = env.class_decls[head.name]&.decls[0]&.decl or raise
|
43
|
+
location = head.location[:name]
|
44
|
+
ClassContent.new(
|
45
|
+
location: location,
|
46
|
+
decl: class_decl
|
47
|
+
)
|
48
|
+
end
|
49
|
+
when ::RBS::Types::Interface
|
50
|
+
env = service.latest_env
|
51
|
+
interface_decl = env.interface_decls[head.name]&.decl or raise
|
52
|
+
location = head.location[:name]
|
53
|
+
|
54
|
+
InterfaceContent.new(
|
55
|
+
location: location,
|
56
|
+
decl: interface_decl
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Steep
|
2
|
+
module Services
|
3
|
+
module HoverProvider
|
4
|
+
class Ruby
|
5
|
+
TypeContent = Struct.new(:node, :type, :location, keyword_init: true)
|
6
|
+
VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
|
7
|
+
MethodCallContent = Struct.new(:node, :method_call, :location, keyword_init: true)
|
8
|
+
DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true)
|
9
|
+
ConstantContent = Struct.new(:location, :full_name, :type, :decl, keyword_init: true) do
|
10
|
+
def comments
|
11
|
+
case
|
12
|
+
when class_or_module?
|
13
|
+
decl.decls.filter_map {|d| d.decl.comment }
|
14
|
+
when constant?
|
15
|
+
[decl.decl.comment]
|
16
|
+
else
|
17
|
+
[]
|
18
|
+
end.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
def constant?
|
22
|
+
decl.is_a?(::RBS::Environment::SingleEntry)
|
23
|
+
end
|
24
|
+
|
25
|
+
def class_or_module?
|
26
|
+
decl.is_a?(::RBS::Environment::MultiEntry)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :service
|
31
|
+
|
32
|
+
def initialize(service:)
|
33
|
+
@service = service
|
34
|
+
end
|
35
|
+
|
36
|
+
def project
|
37
|
+
service.project
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_definition_for(factory, type_name, singleton_method: nil, instance_method: nil)
|
41
|
+
case
|
42
|
+
when instance_method
|
43
|
+
factory.definition_builder.build_instance(type_name).methods[instance_method]
|
44
|
+
when singleton_method
|
45
|
+
methods = factory.definition_builder.build_singleton(type_name).methods
|
46
|
+
|
47
|
+
if singleton_method == :new
|
48
|
+
methods[:new] || methods[:initialize]
|
49
|
+
else
|
50
|
+
methods[singleton_method]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def typecheck(target, path:, content:, line:, column:)
|
56
|
+
subtyping = service.signature_services[target.name].current_subtyping or return
|
57
|
+
source = Source.parse(content, path: path, factory: subtyping.factory)
|
58
|
+
source = source.without_unrelated_defs(line: line, column: column)
|
59
|
+
Services::TypeCheckService.type_check(source: source, subtyping: subtyping)
|
60
|
+
rescue
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def method_name_from_method(context, builder:)
|
65
|
+
defined_in = context.method.defined_in
|
66
|
+
method_name = context.name
|
67
|
+
|
68
|
+
case
|
69
|
+
when defined_in.class?
|
70
|
+
case
|
71
|
+
when builder.build_instance(defined_in).methods.key?(method_name)
|
72
|
+
InstanceMethodName.new(type_name: defined_in, method_name: method_name)
|
73
|
+
when builder.build_singleton(defined_in).methods.key?(method_name)
|
74
|
+
SingletonMethodName.new(type_name: defined_in, method_name: method_name)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
InstanceMethodName.new(type_name: defined_in, method_name: method_name)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def content_for(target:, path:, line:, column:)
|
82
|
+
file = service.source_files[path]
|
83
|
+
typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
|
84
|
+
node, *parents = typing.source.find_nodes(line: line, column: column)
|
85
|
+
|
86
|
+
if node
|
87
|
+
case node.type
|
88
|
+
when :lvar
|
89
|
+
var_name = node.children[0]
|
90
|
+
context = typing.context_at(line: line, column: column)
|
91
|
+
var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
|
92
|
+
|
93
|
+
return VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
|
94
|
+
|
95
|
+
when :lvasgn
|
96
|
+
var_name, rhs = node.children
|
97
|
+
context = typing.context_at(line: line, column: column)
|
98
|
+
type = context.lvar_env[var_name] || typing.type_of(node: rhs)
|
99
|
+
|
100
|
+
return VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
|
101
|
+
|
102
|
+
when :send, :csend
|
103
|
+
result_node =
|
104
|
+
case parents[0]&.type
|
105
|
+
when :block, :numblock
|
106
|
+
if node == parents[0].children[0]
|
107
|
+
parents[0]
|
108
|
+
else
|
109
|
+
node
|
110
|
+
end
|
111
|
+
else
|
112
|
+
node
|
113
|
+
end
|
114
|
+
|
115
|
+
case call = typing.call_of(node: result_node)
|
116
|
+
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
117
|
+
unless call.method_decls.empty?
|
118
|
+
return MethodCallContent.new(
|
119
|
+
node: result_node,
|
120
|
+
method_call: call,
|
121
|
+
location: node.location.selector
|
122
|
+
)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
when :def, :defs
|
127
|
+
context = typing.context_at(line: line, column: column)
|
128
|
+
method_context = context.method_context
|
129
|
+
|
130
|
+
if method_context && method_context.method
|
131
|
+
return DefinitionContent.new(
|
132
|
+
node: node,
|
133
|
+
method_name: method_name_from_method(method_context, builder: context.factory.definition_builder),
|
134
|
+
method_type: method_context.method_type,
|
135
|
+
definition: method_context.method,
|
136
|
+
location: node.loc.name
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
when :const, :casgn
|
141
|
+
context = typing.context_at(line: line, column: column)
|
142
|
+
|
143
|
+
type = typing.type_of(node: node)
|
144
|
+
const_name = typing.source_index.reference(constant_node: node)
|
145
|
+
|
146
|
+
if const_name
|
147
|
+
decl = context.env.class_decls[const_name] || context.env.constant_decls[const_name]
|
148
|
+
|
149
|
+
return ConstantContent.new(
|
150
|
+
location: node.location.name,
|
151
|
+
full_name: const_name,
|
152
|
+
type: type,
|
153
|
+
decl: decl
|
154
|
+
)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
TypeContent.new(
|
159
|
+
node: node,
|
160
|
+
type: typing.type_of(node: node),
|
161
|
+
location: node.location.expression
|
162
|
+
)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Steep
|
2
|
+
module Services
|
3
|
+
module HoverProvider
|
4
|
+
module SingletonMethods
|
5
|
+
def content_for(service:, path:, line:, column:)
|
6
|
+
project = service.project
|
7
|
+
target_for_code, targets_for_sigs = project.targets_for_path(path)
|
8
|
+
|
9
|
+
case
|
10
|
+
when target_for_code
|
11
|
+
Ruby.new(service: service).content_for(target: target_for_code, path: path, line: line, column: column)
|
12
|
+
when target = targets_for_sigs.first
|
13
|
+
RBS.new(service: service).content_for(target: target, path: path, line: line, column: column)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
extend SingletonMethods
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -347,7 +347,7 @@ module Steep
|
|
347
347
|
|
348
348
|
when relation.super_type.is_a?(AST::Types::Union)
|
349
349
|
Any(relation) do |result|
|
350
|
-
relation.super_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size :
|
350
|
+
relation.super_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size : -Float::INFINITY }.each do |super_type|
|
351
351
|
rel = Relation.new(sub_type: relation.sub_type, super_type: super_type)
|
352
352
|
result.add(rel) do
|
353
353
|
check_type(rel)
|
@@ -357,7 +357,7 @@ module Steep
|
|
357
357
|
|
358
358
|
when relation.sub_type.is_a?(AST::Types::Intersection)
|
359
359
|
Any(relation) do |result|
|
360
|
-
relation.sub_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size :
|
360
|
+
relation.sub_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size : -Float::INFINITY }.each do |sub_type|
|
361
361
|
rel = Relation.new(sub_type: sub_type, super_type: relation.super_type)
|
362
362
|
result.add(rel) do
|
363
363
|
check_type(rel)
|
@@ -2910,6 +2910,11 @@ module Steep
|
|
2910
2910
|
call = call.with_return_type(typing.type_of(node: arguments.last))
|
2911
2911
|
end
|
2912
2912
|
end
|
2913
|
+
|
2914
|
+
if node.type == :csend || ((node.type == :block || node.type == :numblock) && node.children[0].type == :csend)
|
2915
|
+
optional_type = AST::Types::Union.build(types: [call.return_type, AST::Builtin.nil_type])
|
2916
|
+
call = call.with_return_type(optional_type)
|
2917
|
+
end
|
2913
2918
|
else
|
2914
2919
|
error = Diagnostic::Ruby::UnresolvedOverloading.new(
|
2915
2920
|
node: node,
|
data/lib/steep/version.rb
CHANGED
data/lib/steep.rb
CHANGED
@@ -92,23 +92,26 @@ require "steep/index/rbs_index"
|
|
92
92
|
require "steep/index/signature_symbol_provider"
|
93
93
|
require "steep/index/source_index"
|
94
94
|
|
95
|
-
require "steep/server/change_buffer"
|
96
|
-
require "steep/server/base_worker"
|
97
|
-
require "steep/server/worker_process"
|
98
|
-
require "steep/server/interaction_worker"
|
99
|
-
require "steep/server/type_check_worker"
|
100
|
-
require "steep/server/master"
|
101
|
-
|
102
95
|
require "steep/services/content_change"
|
103
96
|
require "steep/services/path_assignment"
|
104
97
|
require "steep/services/signature_service"
|
105
98
|
require "steep/services/type_check_service"
|
106
|
-
require "steep/services/
|
99
|
+
require "steep/services/hover_provider/singleton_methods"
|
100
|
+
require "steep/services/hover_provider/ruby"
|
101
|
+
require "steep/services/hover_provider/rbs"
|
107
102
|
require "steep/services/completion_provider"
|
108
103
|
require "steep/services/stats_calculator"
|
109
104
|
require "steep/services/file_loader"
|
110
105
|
require "steep/services/goto_service"
|
111
106
|
|
107
|
+
require "steep/server/lsp_formatter"
|
108
|
+
require "steep/server/change_buffer"
|
109
|
+
require "steep/server/base_worker"
|
110
|
+
require "steep/server/worker_process"
|
111
|
+
require "steep/server/interaction_worker"
|
112
|
+
require "steep/server/type_check_worker"
|
113
|
+
require "steep/server/master"
|
114
|
+
|
112
115
|
require "steep/project"
|
113
116
|
require "steep/project/pattern"
|
114
117
|
require "steep/project/options"
|
data/steep.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_runtime_dependency "rainbow", ">= 2.2.2", "< 4.0"
|
34
34
|
spec.add_runtime_dependency "listen", "~> 3.0"
|
35
35
|
spec.add_runtime_dependency "language_server-protocol", ">= 3.15", "< 4.0"
|
36
|
-
spec.add_runtime_dependency "rbs", ">= 2.3.
|
36
|
+
spec.add_runtime_dependency "rbs", ">= 2.3.2"
|
37
37
|
spec.add_runtime_dependency "parallel", ">= 1.0.0"
|
38
38
|
spec.add_runtime_dependency "terminal-table", ">= 2", "< 4"
|
39
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.52.
|
4
|
+
version: 0.52.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -98,14 +98,14 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - ">="
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: 2.3.
|
101
|
+
version: 2.3.2
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version: 2.3.
|
108
|
+
version: 2.3.2
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: parallel
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
@@ -233,6 +233,7 @@ files:
|
|
233
233
|
- lib/steep/server/base_worker.rb
|
234
234
|
- lib/steep/server/change_buffer.rb
|
235
235
|
- lib/steep/server/interaction_worker.rb
|
236
|
+
- lib/steep/server/lsp_formatter.rb
|
236
237
|
- lib/steep/server/master.rb
|
237
238
|
- lib/steep/server/type_check_worker.rb
|
238
239
|
- lib/steep/server/worker_process.rb
|
@@ -240,7 +241,9 @@ files:
|
|
240
241
|
- lib/steep/services/content_change.rb
|
241
242
|
- lib/steep/services/file_loader.rb
|
242
243
|
- lib/steep/services/goto_service.rb
|
243
|
-
- lib/steep/services/
|
244
|
+
- lib/steep/services/hover_provider/rbs.rb
|
245
|
+
- lib/steep/services/hover_provider/ruby.rb
|
246
|
+
- lib/steep/services/hover_provider/singleton_methods.rb
|
244
247
|
- lib/steep/services/path_assignment.rb
|
245
248
|
- lib/steep/services/signature_service.rb
|
246
249
|
- lib/steep/services/stats_calculator.rb
|
@@ -1,254 +0,0 @@
|
|
1
|
-
module Steep
|
2
|
-
module Services
|
3
|
-
class HoverContent
|
4
|
-
TypeContent = Struct.new(:node, :type, :location, keyword_init: true)
|
5
|
-
VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
|
6
|
-
MethodCallContent = Struct.new(:node, :method_name, :type, :definition, :location, keyword_init: true)
|
7
|
-
DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true) do
|
8
|
-
def comment_string
|
9
|
-
if comments = definition&.comments
|
10
|
-
comments.map {|c| c.string.chomp }.uniq.join("\n----\n")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
ConstantContent = Struct.new(:location, :full_name, :type, :decl, keyword_init: true) do
|
15
|
-
def comment_string
|
16
|
-
if class_or_module?
|
17
|
-
comments = decl.decls.filter_map {|d| d.decl.comment&.string }
|
18
|
-
unless comments.empty?
|
19
|
-
return comments.join("\n----\n")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
if constant?
|
24
|
-
if comment = decl.decl.comment
|
25
|
-
return comment.string
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
|
32
|
-
def constant?
|
33
|
-
decl.is_a?(RBS::Environment::SingleEntry)
|
34
|
-
end
|
35
|
-
|
36
|
-
def class_or_module?
|
37
|
-
decl.is_a?(RBS::Environment::MultiEntry)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
|
42
|
-
ClassContent = Struct.new(:location, :decl, keyword_init: true)
|
43
|
-
InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
|
44
|
-
|
45
|
-
InstanceMethodName = Struct.new(:class_name, :method_name)
|
46
|
-
SingletonMethodName = Struct.new(:class_name, :method_name)
|
47
|
-
|
48
|
-
attr_reader :service
|
49
|
-
|
50
|
-
def initialize(service:)
|
51
|
-
@service = service
|
52
|
-
end
|
53
|
-
|
54
|
-
def project
|
55
|
-
service.project
|
56
|
-
end
|
57
|
-
|
58
|
-
def method_definition_for(factory, type_name, singleton_method: nil, instance_method: nil)
|
59
|
-
case
|
60
|
-
when instance_method
|
61
|
-
factory.definition_builder.build_instance(type_name).methods[instance_method]
|
62
|
-
when singleton_method
|
63
|
-
methods = factory.definition_builder.build_singleton(type_name).methods
|
64
|
-
|
65
|
-
if singleton_method == :new
|
66
|
-
methods[:new] || methods[:initialize]
|
67
|
-
else
|
68
|
-
methods[singleton_method]
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def typecheck(target, path:, content:, line:, column:)
|
74
|
-
subtyping = service.signature_services[target.name].current_subtyping or return
|
75
|
-
source = Source.parse(content, path: path, factory: subtyping.factory)
|
76
|
-
source = source.without_unrelated_defs(line: line, column: column)
|
77
|
-
Services::TypeCheckService.type_check(source: source, subtyping: subtyping)
|
78
|
-
rescue
|
79
|
-
nil
|
80
|
-
end
|
81
|
-
|
82
|
-
def content_for(path:, line:, column:)
|
83
|
-
target_for_code, targets_for_sigs = project.targets_for_path(path)
|
84
|
-
|
85
|
-
case
|
86
|
-
when target = target_for_code
|
87
|
-
Steep.logger.info "target #{target}"
|
88
|
-
|
89
|
-
hover_for_source(column, line, path, target)
|
90
|
-
|
91
|
-
when target = targets_for_sigs[0]
|
92
|
-
service = self.service.signature_services[target.name]
|
93
|
-
|
94
|
-
_buffer, decls = service.latest_env.buffers_decls.find do |buffer, _|
|
95
|
-
Pathname(buffer.name) == path
|
96
|
-
end
|
97
|
-
|
98
|
-
return if decls.nil?
|
99
|
-
|
100
|
-
locator = RBS::Locator.new(decls: decls)
|
101
|
-
hd, tail = locator.find2(line: line, column: column)
|
102
|
-
|
103
|
-
# Maybe hover on comment
|
104
|
-
return if tail.nil?
|
105
|
-
|
106
|
-
case type = tail[0]
|
107
|
-
when RBS::Types::Alias
|
108
|
-
alias_decl = service.latest_env.alias_decls[type.name]&.decl or raise
|
109
|
-
|
110
|
-
location = tail[0].location
|
111
|
-
TypeAliasContent.new(
|
112
|
-
location: location,
|
113
|
-
decl: alias_decl
|
114
|
-
)
|
115
|
-
when RBS::Types::ClassInstance, RBS::Types::ClassSingleton
|
116
|
-
if hd == :name
|
117
|
-
env = service.latest_env
|
118
|
-
class_decl = env.class_decls[type.name]&.decls[0]&.decl or raise
|
119
|
-
location = tail[0].location[:name]
|
120
|
-
ClassContent.new(
|
121
|
-
location: location,
|
122
|
-
decl: class_decl
|
123
|
-
)
|
124
|
-
end
|
125
|
-
when RBS::Types::Interface
|
126
|
-
env = service.latest_env
|
127
|
-
interface_decl = env.interface_decls[type.name]&.decl or raise
|
128
|
-
location = type.location[:name]
|
129
|
-
|
130
|
-
InterfaceContent.new(
|
131
|
-
location: location,
|
132
|
-
decl: interface_decl
|
133
|
-
)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def hover_for_source(column, line, path, target)
|
139
|
-
file = service.source_files[path]
|
140
|
-
typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
|
141
|
-
node, *parents = typing.source.find_nodes(line: line, column: column)
|
142
|
-
|
143
|
-
if node
|
144
|
-
case node.type
|
145
|
-
when :lvar
|
146
|
-
var_name = node.children[0]
|
147
|
-
context = typing.context_at(line: line, column: column)
|
148
|
-
var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
|
149
|
-
|
150
|
-
VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
|
151
|
-
when :lvasgn
|
152
|
-
var_name, rhs = node.children
|
153
|
-
context = typing.context_at(line: line, column: column)
|
154
|
-
type = context.lvar_env[var_name] || typing.type_of(node: rhs)
|
155
|
-
|
156
|
-
VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
|
157
|
-
when :send
|
158
|
-
receiver, method_name, *_ = node.children
|
159
|
-
|
160
|
-
result_node = case parents[0]&.type
|
161
|
-
when :block, :numblock
|
162
|
-
parents[0]
|
163
|
-
else
|
164
|
-
node
|
165
|
-
end
|
166
|
-
|
167
|
-
context = typing.context_at(line: line, column: column)
|
168
|
-
|
169
|
-
receiver_type = if receiver
|
170
|
-
typing.type_of(node: receiver)
|
171
|
-
else
|
172
|
-
context.self_type
|
173
|
-
end
|
174
|
-
|
175
|
-
factory = context.type_env.subtyping.factory
|
176
|
-
method_name, definition = case receiver_type
|
177
|
-
when AST::Types::Name::Instance
|
178
|
-
method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
|
179
|
-
if method_definition&.defined_in
|
180
|
-
owner_name = method_definition.defined_in
|
181
|
-
[
|
182
|
-
InstanceMethodName.new(owner_name, method_name),
|
183
|
-
method_definition
|
184
|
-
]
|
185
|
-
end
|
186
|
-
when AST::Types::Name::Singleton
|
187
|
-
method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
|
188
|
-
if method_definition&.defined_in
|
189
|
-
owner_name = method_definition.defined_in
|
190
|
-
[
|
191
|
-
SingletonMethodName.new(owner_name, method_name),
|
192
|
-
method_definition
|
193
|
-
]
|
194
|
-
end
|
195
|
-
else
|
196
|
-
nil
|
197
|
-
end
|
198
|
-
|
199
|
-
MethodCallContent.new(
|
200
|
-
node: node,
|
201
|
-
method_name: method_name,
|
202
|
-
type: typing.type_of(node: result_node),
|
203
|
-
definition: definition,
|
204
|
-
location: result_node.location.expression
|
205
|
-
)
|
206
|
-
when :def, :defs
|
207
|
-
context = typing.context_at(line: line, column: column)
|
208
|
-
method_context = context.method_context
|
209
|
-
|
210
|
-
if method_context && method_context.method
|
211
|
-
DefinitionContent.new(
|
212
|
-
node: node,
|
213
|
-
method_name: method_context.name,
|
214
|
-
method_type: method_context.method_type,
|
215
|
-
definition: method_context.method,
|
216
|
-
location: node.loc.expression
|
217
|
-
)
|
218
|
-
end
|
219
|
-
when :const, :casgn
|
220
|
-
context = typing.context_at(line: line, column: column)
|
221
|
-
|
222
|
-
type = typing.type_of(node: node)
|
223
|
-
const_name = typing.source_index.reference(constant_node: node)
|
224
|
-
|
225
|
-
if const_name
|
226
|
-
decl = context.env.class_decls[const_name] || context.env.constant_decls[const_name]
|
227
|
-
|
228
|
-
ConstantContent.new(
|
229
|
-
location: node.location.name,
|
230
|
-
full_name: const_name,
|
231
|
-
type: type,
|
232
|
-
decl: decl
|
233
|
-
)
|
234
|
-
else
|
235
|
-
TypeContent.new(
|
236
|
-
node: node,
|
237
|
-
type: type,
|
238
|
-
location: node.location.expression
|
239
|
-
)
|
240
|
-
end
|
241
|
-
else
|
242
|
-
type = typing.type_of(node: node)
|
243
|
-
|
244
|
-
TypeContent.new(
|
245
|
-
node: node,
|
246
|
-
type: type,
|
247
|
-
location: node.location.expression
|
248
|
-
)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|