steep 0.43.1 → 0.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile +1 -0
- data/bin/output_test.rb +8 -2
- data/lib/steep.rb +1 -0
- data/lib/steep/index/source_index.rb +55 -5
- data/lib/steep/interface/block.rb +4 -0
- data/lib/steep/server/interaction_worker.rb +1 -1
- data/lib/steep/server/master.rb +22 -1
- data/lib/steep/server/type_check_worker.rb +68 -0
- data/lib/steep/services/goto_service.rb +321 -0
- data/lib/steep/services/type_check_service.rb +25 -0
- data/lib/steep/type_construction.rb +72 -27
- data/lib/steep/version.rb +1 -1
- data/smoke/const/test_expectations.yml +0 -10
- data/smoke/diagnostics-ruby-unsat/Steepfile +5 -0
- data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
- data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
- data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
- data/smoke/diagnostics/a.rbs +0 -4
- data/smoke/diagnostics/test_expectations.yml +0 -26
- data/smoke/regression/issue_372.rb +8 -0
- data/smoke/regression/issue_372.rbs +4 -0
- data/smoke/regression/test_expectations.yml +0 -12
- data/steep.gemspec +1 -1
- metadata +13 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f5bbaa95e53fda280f5b1c239c0c72093d51cbb6ca0699dbc5c580bcd857989
|
4
|
+
data.tar.gz: c9d4c6e70696e7f85d17b872ca6cec7088f9ee44d9768e9341564fc48e0b8f65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21fb7999c14382b1e6f3d2ad6dba6ec1db2c9169c4620ee66c76ecff8bee8d198b4f972e2afc181405ba8f8f378ae16d07c070a3886135e92e3d788257c93d94
|
7
|
+
data.tar.gz: e06a0f4d2d5e726a749c79c8828d86f0de2c5494126d208ddaddc320fa7911b89eb5e051a231db0c97078d0f844b35a04552d47cbd3c8fe001c7213bea90f0ac
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.44.0 (2021-04-22)
|
6
|
+
|
7
|
+
* Implement LSP go to definition/implementation ([#371](https://github.com/soutaro/steep/pull/371), [#375](https://github.com/soutaro/steep/pull/375))
|
8
|
+
* Fix typing on passing optional block ([#373](https://github.com/soutaro/steep/pull/373))
|
9
|
+
* Do not crash when completion request `context` is missing ([#370](https://github.com/soutaro/steep/pull/370))
|
10
|
+
* Update RBS ([#376](https://github.com/soutaro/steep/pull/376))
|
11
|
+
|
5
12
|
## 0.43.1 (2021-04-01)
|
6
13
|
|
7
14
|
* Fix LSP `textDocument/didSave` notification handling ([#368](https://github.com/soutaro/steep/issues/368))
|
data/Gemfile
CHANGED
data/bin/output_test.rb
CHANGED
@@ -16,6 +16,8 @@ end
|
|
16
16
|
|
17
17
|
failed_tests = []
|
18
18
|
|
19
|
+
ALLOW_FAILURE = ["diagnostics-ruby-unsat"]
|
20
|
+
|
19
21
|
test_dirs.each do |dir|
|
20
22
|
puts "Running test #{dir}..."
|
21
23
|
|
@@ -30,8 +32,12 @@ test_dirs.each do |dir|
|
|
30
32
|
output, status = Open3.capture2(*command, chdir: dir.to_s)
|
31
33
|
|
32
34
|
unless status.success?
|
33
|
-
|
34
|
-
|
35
|
+
unless ALLOW_FAILURE.include?(dir.basename.to_s)
|
36
|
+
failed_tests << dir.basename
|
37
|
+
puts " Failed! 🤕"
|
38
|
+
else
|
39
|
+
puts " Failed! 🤕 (ALLOW_FAILURE)"
|
40
|
+
end
|
35
41
|
else
|
36
42
|
puts " Succeed! 👍"
|
37
43
|
end
|
data/lib/steep.rb
CHANGED
@@ -104,6 +104,7 @@ require "steep/services/hover_content"
|
|
104
104
|
require "steep/services/completion_provider"
|
105
105
|
require "steep/services/stats_calculator"
|
106
106
|
require "steep/services/file_loader"
|
107
|
+
require "steep/services/goto_service"
|
107
108
|
|
108
109
|
require "steep/project"
|
109
110
|
require "steep/project/pattern"
|
@@ -43,8 +43,51 @@ module Steep
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
class MethodEntry
|
47
|
+
attr_reader :name
|
48
|
+
|
49
|
+
attr_reader :definitions
|
50
|
+
attr_reader :references
|
51
|
+
|
52
|
+
def initialize(name:)
|
53
|
+
@name = name
|
54
|
+
|
55
|
+
@definitions = Set[].compare_by_identity
|
56
|
+
@references = Set[].compare_by_identity
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_definition(node)
|
60
|
+
case node.type
|
61
|
+
when :def, :defs
|
62
|
+
@definitions << node
|
63
|
+
else
|
64
|
+
raise "Unexpected method definition: #{node.type}"
|
65
|
+
end
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_reference(node)
|
71
|
+
case node.type
|
72
|
+
when :send, :block
|
73
|
+
@references << node
|
74
|
+
else
|
75
|
+
raise "Unexpected method reference: #{node.type}"
|
76
|
+
end
|
77
|
+
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def merge!(other)
|
82
|
+
definitions.merge(other.definitions)
|
83
|
+
references.merge(other.references)
|
84
|
+
self
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
46
88
|
attr_reader :source
|
47
89
|
attr_reader :constant_index
|
90
|
+
attr_reader :method_index
|
48
91
|
|
49
92
|
attr_reader :parent
|
50
93
|
attr_reader :count
|
@@ -58,6 +101,7 @@ module Steep
|
|
58
101
|
@count = @parent_count || 0
|
59
102
|
|
60
103
|
@constant_index = {}
|
104
|
+
@method_index = {}
|
61
105
|
end
|
62
106
|
|
63
107
|
def new_child
|
@@ -72,25 +116,31 @@ module Steep
|
|
72
116
|
entry.merge!(child_entry)
|
73
117
|
end
|
74
118
|
|
119
|
+
method_index.merge!(child.method_index) do |_, entry, child_entry|
|
120
|
+
entry.merge!(child_entry)
|
121
|
+
end
|
122
|
+
|
75
123
|
@count = child.count + 1
|
76
124
|
end
|
77
125
|
|
78
|
-
def add_definition(constant
|
126
|
+
def add_definition(constant: nil, method: nil, definition:)
|
79
127
|
@count += 1
|
80
|
-
entry(constant: constant).add_definition(definition)
|
128
|
+
entry(constant: constant, method: method).add_definition(definition)
|
81
129
|
self
|
82
130
|
end
|
83
131
|
|
84
|
-
def add_reference(constant
|
132
|
+
def add_reference(constant: nil, method: nil, ref:)
|
85
133
|
@count += 1
|
86
|
-
entry(constant: constant).add_reference(ref)
|
134
|
+
entry(constant: constant, method: method).add_reference(ref)
|
87
135
|
self
|
88
136
|
end
|
89
137
|
|
90
|
-
def entry(constant:)
|
138
|
+
def entry(constant: nil, method: nil)
|
91
139
|
case
|
92
140
|
when constant
|
93
141
|
constant_index[constant] ||= ConstantEntry.new(name: constant)
|
142
|
+
when method
|
143
|
+
method_index[method] ||= MethodEntry.new(name: method)
|
94
144
|
else
|
95
145
|
raise
|
96
146
|
end
|
@@ -65,7 +65,7 @@ module Steep
|
|
65
65
|
uri = URI.parse(params[:textDocument][:uri])
|
66
66
|
path = project.relative_path(Pathname(uri.path))
|
67
67
|
line, column = params[:position].yield_self {|hash| [hash[:line]+1, hash[:character]] }
|
68
|
-
trigger = params
|
68
|
+
trigger = params.dig(:context, :triggerCharacter)
|
69
69
|
|
70
70
|
queue << CompletionJob.new(id: id, path: path, line: line, column: column, trigger: trigger)
|
71
71
|
end
|
data/lib/steep/server/master.rb
CHANGED
@@ -499,7 +499,11 @@ module Steep
|
|
499
499
|
trigger_characters: [".", "@"],
|
500
500
|
work_done_progress: true
|
501
501
|
),
|
502
|
-
workspace_symbol_provider: true
|
502
|
+
workspace_symbol_provider: true,
|
503
|
+
definition_provider: true,
|
504
|
+
declaration_provider: true,
|
505
|
+
implementation_provider: true,
|
506
|
+
type_definition_provider: true
|
503
507
|
)
|
504
508
|
)
|
505
509
|
}
|
@@ -584,6 +588,23 @@ module Steep
|
|
584
588
|
end
|
585
589
|
end
|
586
590
|
|
591
|
+
when "textDocument/definition", "textDocument/implementation"
|
592
|
+
result_controller << group_request do |group|
|
593
|
+
typecheck_workers.each do |worker|
|
594
|
+
group << send_request(method: message[:method], params: message[:params], worker: worker)
|
595
|
+
end
|
596
|
+
|
597
|
+
group.on_completion do |handlers|
|
598
|
+
links = handlers.flat_map(&:result)
|
599
|
+
job_queue << SendMessageJob.to_client(
|
600
|
+
message: {
|
601
|
+
id: message[:id],
|
602
|
+
result: links
|
603
|
+
}
|
604
|
+
)
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
587
608
|
when "$/typecheck"
|
588
609
|
request = controller.make_request(
|
589
610
|
guid: message[:params][:guid],
|
@@ -11,6 +11,31 @@ module Steep
|
|
11
11
|
TypeCheckCodeJob = Struct.new(:guid, :path, keyword_init: true)
|
12
12
|
ValidateAppSignatureJob = Struct.new(:guid, :path, keyword_init: true)
|
13
13
|
ValidateLibrarySignatureJob = Struct.new(:guid, :path, keyword_init: true)
|
14
|
+
GotoJob = Struct.new(:id, :kind, :params, keyword_init: true) do
|
15
|
+
def self.implementation(id:, params:)
|
16
|
+
new(
|
17
|
+
kind: :implementation,
|
18
|
+
id: id,
|
19
|
+
params: params
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.definition(id:, params:)
|
24
|
+
new(
|
25
|
+
kind: :definition,
|
26
|
+
id: id,
|
27
|
+
params: params
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def implementation?
|
32
|
+
kind == :implementation
|
33
|
+
end
|
34
|
+
|
35
|
+
def definition?
|
36
|
+
kind == :definition
|
37
|
+
end
|
38
|
+
end
|
14
39
|
|
15
40
|
include ChangeBuffer
|
16
41
|
|
@@ -44,6 +69,10 @@ module Steep
|
|
44
69
|
when "$/typecheck/start"
|
45
70
|
params = request[:params]
|
46
71
|
enqueue_typecheck_jobs(params)
|
72
|
+
when "textDocument/definition"
|
73
|
+
queue << GotoJob.definition(id: request[:id], params: request[:params])
|
74
|
+
when "textDocument/implementation"
|
75
|
+
queue << GotoJob.implementation(id: request[:id], params: request[:params])
|
47
76
|
end
|
48
77
|
end
|
49
78
|
|
@@ -179,6 +208,11 @@ module Steep
|
|
179
208
|
id: job.id,
|
180
209
|
result: stats_result().map(&:as_json)
|
181
210
|
)
|
211
|
+
when GotoJob
|
212
|
+
writer.write(
|
213
|
+
id: job.id,
|
214
|
+
result: goto(job)
|
215
|
+
)
|
182
216
|
end
|
183
217
|
end
|
184
218
|
|
@@ -231,6 +265,40 @@ module Steep
|
|
231
265
|
end
|
232
266
|
end
|
233
267
|
end
|
268
|
+
|
269
|
+
def goto(job)
|
270
|
+
path = Pathname(URI.parse(job.params[:textDocument][:uri]).path)
|
271
|
+
line = job.params[:position][:line] + 1
|
272
|
+
column = job.params[:position][:character]
|
273
|
+
|
274
|
+
goto_service = Services::GotoService.new(type_check: service)
|
275
|
+
locations =
|
276
|
+
case
|
277
|
+
when job.definition?
|
278
|
+
goto_service.definition(path: path, line: line, column: column)
|
279
|
+
when job.implementation?
|
280
|
+
goto_service.implementation(path: path, line: line, column: column)
|
281
|
+
else
|
282
|
+
raise
|
283
|
+
end
|
284
|
+
|
285
|
+
locations.map do |loc|
|
286
|
+
path =
|
287
|
+
case loc
|
288
|
+
when RBS::Location
|
289
|
+
Pathname(loc.buffer.name)
|
290
|
+
else
|
291
|
+
Pathname(loc.source_buffer.name)
|
292
|
+
end
|
293
|
+
|
294
|
+
path = project.absolute_path(path)
|
295
|
+
|
296
|
+
{
|
297
|
+
uri: URI.parse(path.to_s).tap {|uri| uri.scheme = "file" }.to_s,
|
298
|
+
range: loc.as_lsp_range
|
299
|
+
}
|
300
|
+
end
|
301
|
+
end
|
234
302
|
end
|
235
303
|
end
|
236
304
|
end
|
@@ -0,0 +1,321 @@
|
|
1
|
+
module Steep
|
2
|
+
module Services
|
3
|
+
class GotoService
|
4
|
+
include ModuleHelper
|
5
|
+
|
6
|
+
module SourceHelper
|
7
|
+
def from_ruby?
|
8
|
+
from == :ruby
|
9
|
+
end
|
10
|
+
|
11
|
+
def from_rbs?
|
12
|
+
from == :rbs
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ConstantQuery = Struct.new(:name, :from, keyword_init: true) do
|
17
|
+
include SourceHelper
|
18
|
+
end
|
19
|
+
MethodQuery = Struct.new(:name, :from, keyword_init: true) do
|
20
|
+
include SourceHelper
|
21
|
+
end
|
22
|
+
TypeNameQuery = Struct.new(:name, keyword_init: true)
|
23
|
+
|
24
|
+
attr_reader :type_check
|
25
|
+
|
26
|
+
def initialize(type_check:)
|
27
|
+
@type_check = type_check
|
28
|
+
end
|
29
|
+
|
30
|
+
def project
|
31
|
+
type_check.project
|
32
|
+
end
|
33
|
+
|
34
|
+
def implementation(path:, line:, column:)
|
35
|
+
locations = []
|
36
|
+
|
37
|
+
relative_path = project.relative_path(path)
|
38
|
+
|
39
|
+
queries = query_at(path: path, line: line, column: column)
|
40
|
+
queries.uniq!
|
41
|
+
|
42
|
+
queries.each do |query|
|
43
|
+
case query
|
44
|
+
when ConstantQuery
|
45
|
+
constant_definition_in_ruby(query.name, locations: locations)
|
46
|
+
when MethodQuery
|
47
|
+
method_locations(query.name, locations: locations, in_ruby: true, in_rbs: false)
|
48
|
+
when TypeNameQuery
|
49
|
+
type_name_locations(query.name, locations: locations)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
locations.uniq
|
54
|
+
end
|
55
|
+
|
56
|
+
def definition(path:, line:, column:)
|
57
|
+
locations = []
|
58
|
+
|
59
|
+
relative_path = project.relative_path(path)
|
60
|
+
|
61
|
+
queries = query_at(path: path, line: line, column: column)
|
62
|
+
queries.uniq!
|
63
|
+
|
64
|
+
queries.each do |query|
|
65
|
+
case query
|
66
|
+
when ConstantQuery
|
67
|
+
constant_definition_in_rbs(query.name, locations: locations) if query.from_ruby?
|
68
|
+
constant_definition_in_ruby(query.name, locations: locations) if query.from_rbs?
|
69
|
+
when MethodQuery
|
70
|
+
method_locations(
|
71
|
+
query.name,
|
72
|
+
locations: locations,
|
73
|
+
in_ruby: query.from_rbs?,
|
74
|
+
in_rbs: query.from_ruby?
|
75
|
+
)
|
76
|
+
when TypeNameQuery
|
77
|
+
type_name_locations(query.name, locations: locations)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
locations.uniq
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_ast_location(loc, line:, column:)
|
85
|
+
return false if line < loc.line
|
86
|
+
return false if line == loc.line && column < loc.column
|
87
|
+
return false if loc.last_line < line
|
88
|
+
return false if line == loc.last_line && loc.last_column < column
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
def query_at(path:, line:, column:)
|
93
|
+
queries = []
|
94
|
+
|
95
|
+
relative_path = project.relative_path(path)
|
96
|
+
|
97
|
+
case
|
98
|
+
when target = type_check.source_file?(relative_path)
|
99
|
+
source = type_check.source_files[relative_path]
|
100
|
+
typing, signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
|
101
|
+
if typing
|
102
|
+
node, *parents = typing.source.find_nodes(line: line, column: column)
|
103
|
+
if node
|
104
|
+
case node.type
|
105
|
+
when :const, :casgn
|
106
|
+
if test_ast_location(node.location.name, line: line, column: column)
|
107
|
+
if module_context = typing.context_at(line: line, column: column).module_context
|
108
|
+
const_env = module_context.const_env
|
109
|
+
const = const_env.lookup_constant(module_name_from_node(node))
|
110
|
+
queries << ConstantQuery.new(name: const.name, from: :ruby)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
when :def, :defs
|
114
|
+
if test_ast_location(node.location.name, line: line, column: column)
|
115
|
+
if method_context = typing.context_at(line: line, column: column).method_context
|
116
|
+
type_name = method_context.method.defined_in
|
117
|
+
name =
|
118
|
+
if method_context.method.defs.any? {|defn| defn.member.singleton? }
|
119
|
+
SingletonMethodName.new(type_name: type_name, method_name: method_context.name)
|
120
|
+
else
|
121
|
+
InstanceMethodName.new(type_name: type_name, method_name: method_context.name)
|
122
|
+
end
|
123
|
+
queries << MethodQuery.new(name: name, from: :ruby)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
when :send
|
127
|
+
if test_ast_location(node.location.selector, line: line, column: column)
|
128
|
+
case call = typing.call_of(node: node)
|
129
|
+
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
130
|
+
call.method_decls.each do |decl|
|
131
|
+
queries << MethodQuery.new(name: decl.method_name, from: :ruby)
|
132
|
+
end
|
133
|
+
when TypeInference::MethodCall::Untyped
|
134
|
+
# nop
|
135
|
+
when TypeInference::MethodCall::NoMethodError
|
136
|
+
# nop
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
when target_names = type_check.signature_file?(path)
|
143
|
+
target_names.each do |target_name|
|
144
|
+
signature_service = type_check.signature_services[target_name]
|
145
|
+
decls = signature_service.latest_env.declarations.select do |decl|
|
146
|
+
buffer_path = Pathname(decl.location.buffer.name)
|
147
|
+
buffer_path == relative_path || buffer_path == path
|
148
|
+
end
|
149
|
+
|
150
|
+
locator = RBS::Locator.new(decls: decls)
|
151
|
+
last, nodes = locator.find2(line: line, column: column)
|
152
|
+
case nodes[0]
|
153
|
+
when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
|
154
|
+
if last == :name
|
155
|
+
queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
|
156
|
+
end
|
157
|
+
when RBS::AST::Declarations::Constant
|
158
|
+
if last == :name
|
159
|
+
queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
|
160
|
+
end
|
161
|
+
when RBS::AST::Members::MethodDefinition
|
162
|
+
if last == :name
|
163
|
+
type_name = nodes[1].name
|
164
|
+
method_name = nodes[0].name
|
165
|
+
if nodes[0].instance?
|
166
|
+
queries << MethodQuery.new(
|
167
|
+
name: InstanceMethodName.new(type_name: type_name, method_name: method_name),
|
168
|
+
from: :rbs
|
169
|
+
)
|
170
|
+
end
|
171
|
+
if nodes[0].singleton?
|
172
|
+
queries << MethodQuery.new(
|
173
|
+
name: SingletonMethodName.new(type_name: type_name, method_name: method_name),
|
174
|
+
from: :rbs
|
175
|
+
)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
when RBS::AST::Members::Include, RBS::AST::Members::Extend, RBS::AST::Members::Prepend
|
179
|
+
if last == :name
|
180
|
+
queries << TypeNameQuery.new(name: nodes[0].name)
|
181
|
+
end
|
182
|
+
when RBS::Types::ClassInstance, RBS::Types::ClassSingleton, RBS::Types::Interface, RBS::Types::Alias
|
183
|
+
if last == :name
|
184
|
+
queries << TypeNameQuery.new(name: nodes[0].name)
|
185
|
+
end
|
186
|
+
when RBS::AST::Declarations::Class::Super, RBS::AST::Declarations::Module::Self
|
187
|
+
if last == :name
|
188
|
+
queries << TypeNameQuery.new(name: nodes[0].name)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
queries
|
195
|
+
end
|
196
|
+
|
197
|
+
def type_check_path(target:, path:, content:, line:, column:)
|
198
|
+
signature_service = type_check.signature_services[target.name]
|
199
|
+
subtyping = signature_service.current_subtyping or return
|
200
|
+
source = Source.parse(content, path: path, factory: subtyping.factory)
|
201
|
+
source = source.without_unrelated_defs(line: line, column: column)
|
202
|
+
[
|
203
|
+
Services::TypeCheckService.type_check(source: source, subtyping: subtyping),
|
204
|
+
signature_service
|
205
|
+
]
|
206
|
+
rescue
|
207
|
+
nil
|
208
|
+
end
|
209
|
+
|
210
|
+
def constant_definition_in_rbs(name, locations:)
|
211
|
+
type_check.signature_services.each_value do |signature|
|
212
|
+
env = signature.latest_env
|
213
|
+
|
214
|
+
if entry = env.class_decls[name]
|
215
|
+
entry.decls.each do |d|
|
216
|
+
locations << d.decl.location[:name]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
if entry = env.constant_decls[name]
|
221
|
+
locations << entry.decl.location[:name]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
locations
|
226
|
+
end
|
227
|
+
|
228
|
+
def constant_definition_in_ruby(name, locations:)
|
229
|
+
type_check.source_files.each do |path, source|
|
230
|
+
if typing = source.typing
|
231
|
+
entry = typing.source_index.entry(constant: name)
|
232
|
+
entry.definitions.each do |node|
|
233
|
+
case node.type
|
234
|
+
when :class, :module
|
235
|
+
locations << node.children[0].location.expression
|
236
|
+
when :casgn
|
237
|
+
parent = node.children[0]
|
238
|
+
location =
|
239
|
+
if parent
|
240
|
+
parent.location.expression.join(node.location.name)
|
241
|
+
else
|
242
|
+
node.location.name
|
243
|
+
end
|
244
|
+
locations << location
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
locations
|
251
|
+
end
|
252
|
+
|
253
|
+
def method_locations(name, in_ruby:, in_rbs:, locations:)
|
254
|
+
if in_ruby
|
255
|
+
type_check.source_files.each do |path, source|
|
256
|
+
if typing = source.typing
|
257
|
+
entry = typing.source_index.entry(method: name)
|
258
|
+
|
259
|
+
if entry.definitions.empty?
|
260
|
+
if name.is_a?(SingletonMethodName) && name.method_name == :new
|
261
|
+
initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
|
262
|
+
entry = typing.source_index.entry(method: initialize)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
entry.definitions.each do |node|
|
267
|
+
case node.type
|
268
|
+
when :def
|
269
|
+
locations << node.location.name
|
270
|
+
when :defs
|
271
|
+
locations << node.location.name
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
if in_rbs
|
279
|
+
type_check.signature_services.each_value do |signature|
|
280
|
+
index = signature.latest_rbs_index
|
281
|
+
|
282
|
+
entry = index.entry(method_name: name)
|
283
|
+
|
284
|
+
if entry.declarations.empty?
|
285
|
+
if name.is_a?(SingletonMethodName) && name.method_name == :new
|
286
|
+
initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
|
287
|
+
entry = index.entry(method_name: initialize)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
entry.declarations.each do |decl|
|
292
|
+
case decl
|
293
|
+
when RBS::AST::Members::MethodDefinition
|
294
|
+
locations << decl.location[:name]
|
295
|
+
when RBS::AST::Members::Alias
|
296
|
+
locations << decl.location[:new_name]
|
297
|
+
when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
|
298
|
+
locations << decl.location[:name]
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
locations
|
305
|
+
end
|
306
|
+
|
307
|
+
def type_name_locations(name, locations: [])
|
308
|
+
type_check.signature_services.each_value do |signature|
|
309
|
+
index = signature.latest_rbs_index
|
310
|
+
|
311
|
+
entry = index.entry(type_name: name)
|
312
|
+
entry.declarations.each do |decl|
|
313
|
+
locations << decl.location[:name]
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
locations
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
@@ -383,6 +383,31 @@ module Steep
|
|
383
383
|
|
384
384
|
typing
|
385
385
|
end
|
386
|
+
|
387
|
+
def source_file?(path)
|
388
|
+
if source_files.key?(path)
|
389
|
+
project.target_for_source_path(path)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
def signature_file?(path)
|
394
|
+
relative_path = project.relative_path(path)
|
395
|
+
targets = signature_services.select {|_, sig| sig.files.key?(relative_path) || sig.env_rbs_paths.include?(path) }
|
396
|
+
unless targets.empty?
|
397
|
+
targets.keys
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def app_signature_file?(path)
|
402
|
+
target_names = signature_services.select {|_, sig| sig.files.key?(path) }.keys
|
403
|
+
unless target_names.empty?
|
404
|
+
target_names
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def lib_signature_file?(path)
|
409
|
+
signature_services.each_value.any? {|sig| sig.env_rbs_paths.include?(path) }
|
410
|
+
end
|
386
411
|
end
|
387
412
|
end
|
388
413
|
end
|
@@ -944,14 +944,23 @@ module Steep
|
|
944
944
|
yield_self do
|
945
945
|
name, args_node, body_node = node.children
|
946
946
|
|
947
|
-
new = for_new_method(
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
947
|
+
new = for_new_method(
|
948
|
+
name,
|
949
|
+
node,
|
950
|
+
args: args_node.children,
|
951
|
+
self_type: module_context&.instance_type,
|
952
|
+
definition: module_context&.instance_definition
|
953
|
+
)
|
952
954
|
new.typing.add_context_for_node(node, context: new.context)
|
953
955
|
new.typing.add_context_for_body(node, context: new.context)
|
954
956
|
|
957
|
+
new.method_context.tap do |method_context|
|
958
|
+
if method_context.method
|
959
|
+
method_name = InstanceMethodName.new(type_name: method_context.method.implemented_in, method_name: name)
|
960
|
+
new.typing.source_index.add_definition(method: method_name, definition: node)
|
961
|
+
end
|
962
|
+
end
|
963
|
+
|
955
964
|
new = new.synthesize_children(args_node)
|
956
965
|
|
957
966
|
body_pair = if body_node
|
@@ -1006,24 +1015,43 @@ module Steep
|
|
1006
1015
|
when :defs
|
1007
1016
|
synthesize(node.children[0]).type.tap do |self_type|
|
1008
1017
|
self_type = expand_self(self_type)
|
1009
|
-
definition =
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1018
|
+
definition =
|
1019
|
+
case self_type
|
1020
|
+
when AST::Types::Name::Instance
|
1021
|
+
name = self_type.name
|
1022
|
+
checker.factory.definition_builder.build_instance(name)
|
1023
|
+
when AST::Types::Name::Singleton
|
1024
|
+
name = self_type.name
|
1025
|
+
checker.factory.definition_builder.build_singleton(name)
|
1026
|
+
end
|
1017
1027
|
|
1018
1028
|
args_node = node.children[2]
|
1019
|
-
new = for_new_method(
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1029
|
+
new = for_new_method(
|
1030
|
+
node.children[1],
|
1031
|
+
node,
|
1032
|
+
args: args_node.children,
|
1033
|
+
self_type: self_type,
|
1034
|
+
definition: definition
|
1035
|
+
)
|
1024
1036
|
new.typing.add_context_for_node(node, context: new.context)
|
1025
1037
|
new.typing.add_context_for_body(node, context: new.context)
|
1026
1038
|
|
1039
|
+
new.method_context.tap do |method_context|
|
1040
|
+
if method_context.method
|
1041
|
+
name_ = node.children[1]
|
1042
|
+
|
1043
|
+
method_name =
|
1044
|
+
case self_type
|
1045
|
+
when AST::Types::Name::Instance
|
1046
|
+
InstanceMethodName.new(type_name: method_context.method.implemented_in, method_name: name_)
|
1047
|
+
when AST::Types::Name::Singleton
|
1048
|
+
SingletonMethodName.new(type_name: method_context.method.implemented_in, method_name: name_)
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
new.typing.source_index.add_definition(method: method_name, definition: node)
|
1052
|
+
end
|
1053
|
+
end
|
1054
|
+
|
1027
1055
|
new = new.synthesize_children(args_node)
|
1028
1056
|
|
1029
1057
|
each_child_node(node.children[2]) do |arg|
|
@@ -1443,9 +1471,22 @@ module Steep
|
|
1443
1471
|
constr = self
|
1444
1472
|
|
1445
1473
|
name, _ = node.children
|
1446
|
-
|
1474
|
+
if name.type == :const
|
1475
|
+
# skip the last constant reference
|
1476
|
+
if const_parent = name.children[0]
|
1477
|
+
_, constr = constr.synthesize(const_parent)
|
1478
|
+
end
|
1479
|
+
else
|
1480
|
+
_, constr = constr.synthesize(name)
|
1481
|
+
end
|
1447
1482
|
|
1448
1483
|
for_module(node).yield_self do |constructor|
|
1484
|
+
if module_type = constructor.module_context&.module_type
|
1485
|
+
_, constructor = constructor.add_typing(name, type: module_type)
|
1486
|
+
else
|
1487
|
+
_, constructor = constructor.fallback_to_any(name)
|
1488
|
+
end
|
1489
|
+
|
1449
1490
|
constructor.typing.source_index.add_definition(
|
1450
1491
|
constant: constructor.module_context.class_name,
|
1451
1492
|
definition: node
|
@@ -3262,8 +3303,8 @@ module Steep
|
|
3262
3303
|
end
|
3263
3304
|
else
|
3264
3305
|
# block is not given
|
3265
|
-
if
|
3266
|
-
# Method
|
3306
|
+
if !method_type.block
|
3307
|
+
# Method doesn't accept blocks
|
3267
3308
|
unless args.block_pass_arg
|
3268
3309
|
# OK, without block
|
3269
3310
|
s = constraints.solution(
|
@@ -3297,12 +3338,16 @@ module Steep
|
|
3297
3338
|
end
|
3298
3339
|
end
|
3299
3340
|
else
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3341
|
+
# Method accepts block
|
3342
|
+
if !args.block_pass_arg
|
3343
|
+
# Block pass is not given
|
3344
|
+
if method_type.block.required?
|
3345
|
+
# Required block is missing
|
3346
|
+
errors << Diagnostic::Ruby::RequiredBlockMissing.new(
|
3347
|
+
node: node,
|
3348
|
+
method_type: method_type
|
3349
|
+
)
|
3350
|
+
end
|
3306
3351
|
|
3307
3352
|
s = constraints.solution(
|
3308
3353
|
checker,
|
data/lib/steep/version.rb
CHANGED
@@ -26,16 +26,6 @@
|
|
26
26
|
severity: ERROR
|
27
27
|
message: Cannot detect the type of the expression
|
28
28
|
code: Ruby::FallbackAny
|
29
|
-
- range:
|
30
|
-
start:
|
31
|
-
line: 8
|
32
|
-
character: 7
|
33
|
-
end:
|
34
|
-
line: 8
|
35
|
-
character: 8
|
36
|
-
severity: ERROR
|
37
|
-
message: Cannot detect the type of the expression
|
38
|
-
code: Ruby::FallbackAny
|
39
29
|
- range:
|
40
30
|
start:
|
41
31
|
line: 14
|
@@ -0,0 +1,27 @@
|
|
1
|
+
---
|
2
|
+
- file: unsatisfiable_constraint.rb
|
3
|
+
diagnostics:
|
4
|
+
- range:
|
5
|
+
start:
|
6
|
+
line: 3
|
7
|
+
character: 0
|
8
|
+
end:
|
9
|
+
line: 6
|
10
|
+
character: 3
|
11
|
+
severity: ERROR
|
12
|
+
message: |-
|
13
|
+
Unsatisfiable constraint `::Array[untyped] <: A(2) <: ::String` is generated through (A(2)) { (A(2)) -> void } -> B(3)
|
14
|
+
::Array[untyped] <: ::String
|
15
|
+
::Object <: ::String
|
16
|
+
::BasicObject <: ::String
|
17
|
+
code: Ruby::UnsatisfiableConstraint
|
18
|
+
- range:
|
19
|
+
start:
|
20
|
+
line: 5
|
21
|
+
character: 4
|
22
|
+
end:
|
23
|
+
line: 5
|
24
|
+
character: 7
|
25
|
+
severity: ERROR
|
26
|
+
message: Type `::String` does not have method `foo`
|
27
|
+
code: Ruby::NoMethod
|
data/smoke/diagnostics/a.rbs
CHANGED
@@ -436,32 +436,6 @@
|
|
436
436
|
| (::Rational) -> ::Rational
|
437
437
|
| (::Complex) -> ::Complex
|
438
438
|
code: Ruby::UnresolvedOverloading
|
439
|
-
- file: unsatisfiable_constraint.rb
|
440
|
-
diagnostics:
|
441
|
-
- range:
|
442
|
-
start:
|
443
|
-
line: 4
|
444
|
-
character: 0
|
445
|
-
end:
|
446
|
-
line: 7
|
447
|
-
character: 3
|
448
|
-
severity: ERROR
|
449
|
-
message: |-
|
450
|
-
Unsatisfiable constraint `::Array[untyped] <: A(1) <: ::String` is generated through (A(1)) { (A(1)) -> void } -> B(2)
|
451
|
-
::Array[untyped] <: ::String
|
452
|
-
::Object <: ::String
|
453
|
-
::BasicObject <: ::String
|
454
|
-
code: Ruby::UnsatisfiableConstraint
|
455
|
-
- range:
|
456
|
-
start:
|
457
|
-
line: 6
|
458
|
-
character: 4
|
459
|
-
end:
|
460
|
-
line: 6
|
461
|
-
character: 7
|
462
|
-
severity: ERROR
|
463
|
-
message: Type `::String` does not have method `foo`
|
464
|
-
code: Ruby::NoMethod
|
465
439
|
- file: unsupported_syntax.rb
|
466
440
|
diagnostics:
|
467
441
|
- range:
|
@@ -58,15 +58,3 @@
|
|
58
58
|
severity: ERROR
|
59
59
|
message: Type `::String` does not have method `ggggg`
|
60
60
|
code: Ruby::NoMethod
|
61
|
-
- file: thread.rb
|
62
|
-
diagnostics:
|
63
|
-
- range:
|
64
|
-
start:
|
65
|
-
line: 6
|
66
|
-
character: 13
|
67
|
-
end:
|
68
|
-
line: 7
|
69
|
-
character: 3
|
70
|
-
severity: ERROR
|
71
|
-
message: The method cannot be called with a block
|
72
|
-
code: Ruby::UnexpectedBlockGiven
|
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", "
|
36
|
+
spec.add_runtime_dependency "rbs", ">= 1.2.0"
|
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.
|
4
|
+
version: 0.44.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-04-
|
11
|
+
date: 2021-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -96,16 +96,16 @@ dependencies:
|
|
96
96
|
name: rbs
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
98
98
|
requirements:
|
99
|
-
- - "
|
99
|
+
- - ">="
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: 1.
|
101
|
+
version: 1.2.0
|
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: 1.
|
108
|
+
version: 1.2.0
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: parallel
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
@@ -236,6 +236,7 @@ files:
|
|
236
236
|
- lib/steep/services/completion_provider.rb
|
237
237
|
- lib/steep/services/content_change.rb
|
238
238
|
- lib/steep/services/file_loader.rb
|
239
|
+
- lib/steep/services/goto_service.rb
|
239
240
|
- lib/steep/services/hover_content.rb
|
240
241
|
- lib/steep/services/path_assignment.rb
|
241
242
|
- lib/steep/services/signature_service.rb
|
@@ -326,6 +327,10 @@ files:
|
|
326
327
|
- smoke/diagnostics-rbs/unknown-method-alias.rbs
|
327
328
|
- smoke/diagnostics-rbs/unknown-type-name-2.rbs
|
328
329
|
- smoke/diagnostics-rbs/unknown-type-name.rbs
|
330
|
+
- smoke/diagnostics-ruby-unsat/Steepfile
|
331
|
+
- smoke/diagnostics-ruby-unsat/a.rbs
|
332
|
+
- smoke/diagnostics-ruby-unsat/test_expectations.yml
|
333
|
+
- smoke/diagnostics-ruby-unsat/unsatisfiable_constraint.rb
|
329
334
|
- smoke/diagnostics/Steepfile
|
330
335
|
- smoke/diagnostics/a.rbs
|
331
336
|
- smoke/diagnostics/argument_type_mismatch.rb
|
@@ -354,7 +359,6 @@ files:
|
|
354
359
|
- smoke/diagnostics/unexpected_yield.rb
|
355
360
|
- smoke/diagnostics/unknown_constant_assigned.rb
|
356
361
|
- smoke/diagnostics/unresolved_overloading.rb
|
357
|
-
- smoke/diagnostics/unsatisfiable_constraint.rb
|
358
362
|
- smoke/diagnostics/unsupported_syntax.rb
|
359
363
|
- smoke/dstr/Steepfile
|
360
364
|
- smoke/dstr/a.rb
|
@@ -455,6 +459,8 @@ files:
|
|
455
459
|
- smoke/regression/issue_328.rbs
|
456
460
|
- smoke/regression/issue_332.rb
|
457
461
|
- smoke/regression/issue_332.rbs
|
462
|
+
- smoke/regression/issue_372.rb
|
463
|
+
- smoke/regression/issue_372.rbs
|
458
464
|
- smoke/regression/masgn.rb
|
459
465
|
- smoke/regression/poly_new.rb
|
460
466
|
- smoke/regression/poly_new.rbs
|