steep 0.39.0 → 0.40.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/Rakefile +5 -2
- data/bin/output_rebaseline.rb +49 -0
- data/bin/output_test.rb +93 -0
- data/lib/steep.rb +8 -3
- data/lib/steep/cli.rb +1 -1
- data/lib/steep/diagnostic/helper.rb +17 -0
- data/lib/steep/diagnostic/lsp_formatter.rb +16 -0
- data/lib/steep/diagnostic/ruby.rb +623 -0
- data/lib/steep/diagnostic/signature.rb +224 -0
- data/lib/steep/drivers/annotations.rb +13 -6
- data/lib/steep/drivers/check.rb +83 -60
- data/lib/steep/drivers/diagnostic_printer.rb +94 -0
- data/lib/steep/drivers/stats.rb +125 -29
- data/lib/steep/drivers/trace_printer.rb +5 -1
- data/lib/steep/drivers/validate.rb +13 -6
- data/lib/steep/drivers/watch.rb +26 -9
- data/lib/steep/drivers/worker.rb +5 -0
- data/lib/steep/project/options.rb +4 -4
- data/lib/steep/project/signature_file.rb +8 -2
- data/lib/steep/project/stats_calculator.rb +80 -0
- data/lib/steep/project/target.rb +64 -53
- data/lib/steep/range_extension.rb +29 -0
- data/lib/steep/server/base_worker.rb +42 -4
- data/lib/steep/server/code_worker.rb +37 -24
- data/lib/steep/server/interaction_worker.rb +1 -0
- data/lib/steep/server/master.rb +268 -82
- data/lib/steep/server/signature_worker.rb +7 -59
- data/lib/steep/server/worker_process.rb +9 -9
- data/lib/steep/signature/validator.rb +33 -9
- data/lib/steep/type_construction.rb +276 -194
- data/lib/steep/version.rb +1 -1
- data/smoke/alias/a.rb +0 -3
- data/smoke/alias/b.rb +0 -1
- data/smoke/alias/c.rb +0 -2
- data/smoke/alias/test.yaml +73 -0
- data/smoke/and/a.rb +0 -3
- data/smoke/and/test.yaml +24 -0
- data/smoke/array/a.rb +0 -3
- data/smoke/array/b.rb +0 -2
- data/smoke/array/c.rb +0 -1
- data/smoke/array/test.yaml +80 -0
- data/smoke/block/a.rb +0 -2
- data/smoke/block/b.rb +0 -2
- data/smoke/block/d.rb +0 -4
- data/smoke/block/test.yaml +96 -0
- data/smoke/broken/Steepfile +5 -0
- data/smoke/broken/broken.rb +0 -0
- data/smoke/broken/broken.rbs +0 -0
- data/smoke/broken/test.yaml +6 -0
- data/smoke/case/a.rb +0 -3
- data/smoke/case/test.yaml +36 -0
- data/smoke/class/a.rb +0 -3
- data/smoke/class/c.rb +0 -1
- data/smoke/class/f.rb +0 -1
- data/smoke/class/g.rb +0 -2
- data/smoke/class/i.rb +0 -2
- data/smoke/class/test.yaml +89 -0
- data/smoke/const/a.rb +0 -3
- data/smoke/const/b.rb +7 -0
- data/smoke/const/b.rbs +5 -0
- data/smoke/const/test.yaml +96 -0
- data/smoke/diagnostics-rbs-duplicated/Steepfile +5 -0
- data/smoke/diagnostics-rbs-duplicated/a.rbs +5 -0
- data/smoke/diagnostics-rbs-duplicated/test.yaml +10 -0
- data/smoke/diagnostics-rbs/Steepfile +5 -0
- data/smoke/diagnostics-rbs/duplicated-method-definition.rbs +20 -0
- data/smoke/diagnostics-rbs/generic-parameter-mismatch.rbs +7 -0
- data/smoke/diagnostics-rbs/invalid-method-overload.rbs +3 -0
- data/smoke/diagnostics-rbs/invalid-type-application.rbs +7 -0
- data/smoke/diagnostics-rbs/invalid_variance_annotation.rbs +3 -0
- data/smoke/diagnostics-rbs/recursive-alias.rbs +5 -0
- data/smoke/diagnostics-rbs/recursive-class.rbs +8 -0
- data/smoke/diagnostics-rbs/superclass-mismatch.rbs +7 -0
- data/smoke/diagnostics-rbs/test.yaml +142 -0
- data/smoke/diagnostics-rbs/unknown-method-alias.rbs +3 -0
- data/smoke/diagnostics-rbs/unknown-type-name.rbs +13 -0
- data/smoke/diagnostics/Steepfile +5 -0
- data/smoke/diagnostics/a.rbs +26 -0
- data/smoke/diagnostics/argument_type_mismatch.rb +1 -0
- data/smoke/diagnostics/block_body_type_mismatch.rb +1 -0
- data/smoke/diagnostics/block_type_mismatch.rb +3 -0
- data/smoke/diagnostics/break_type_mismatch.rb +1 -0
- data/smoke/diagnostics/else_on_exhaustive_case.rb +12 -0
- data/smoke/diagnostics/incompatible_annotation.rb +6 -0
- data/smoke/diagnostics/incompatible_argument.rb +1 -0
- data/smoke/diagnostics/incompatible_assignment.rb +8 -0
- data/smoke/diagnostics/method_arity_mismatch.rb +11 -0
- data/smoke/diagnostics/method_body_type_mismatch.rb +6 -0
- data/smoke/diagnostics/method_definition_missing.rb +2 -0
- data/smoke/diagnostics/method_return_type_annotation_mismatch.rb +7 -0
- data/smoke/diagnostics/missing_keyword.rb +1 -0
- data/smoke/diagnostics/no_method.rb +1 -0
- data/smoke/diagnostics/required_block_missing.rb +1 -0
- data/smoke/diagnostics/return_type_mismatch.rb +6 -0
- data/smoke/diagnostics/test.yaml +333 -0
- data/smoke/diagnostics/unexpected_block_given.rb +1 -0
- data/smoke/diagnostics/unexpected_dynamic_method.rb +3 -0
- data/smoke/diagnostics/unexpected_jump.rb +4 -0
- data/smoke/diagnostics/unexpected_jump_value.rb +3 -0
- data/smoke/diagnostics/unexpected_keyword.rb +1 -0
- data/smoke/diagnostics/unexpected_splat.rb +1 -0
- data/smoke/diagnostics/unexpected_yield.rb +6 -0
- data/smoke/diagnostics/unknown_constant_assigned.rb +7 -0
- data/smoke/diagnostics/unresolved_overloading.rb +1 -0
- data/smoke/diagnostics/unsatisfiable_constraint.rb +7 -0
- data/smoke/diagnostics/unsupported_syntax.rb +2 -0
- data/smoke/dstr/a.rb +0 -1
- data/smoke/dstr/test.yaml +10 -0
- data/smoke/ensure/a.rb +0 -4
- data/smoke/ensure/test.yaml +47 -0
- data/smoke/enumerator/a.rb +0 -6
- data/smoke/enumerator/b.rb +0 -3
- data/smoke/enumerator/test.yaml +100 -0
- data/smoke/extension/a.rb +0 -1
- data/smoke/extension/b.rb +0 -2
- data/smoke/extension/c.rb +0 -1
- data/smoke/extension/test.yaml +50 -0
- data/smoke/hash/b.rb +0 -1
- data/smoke/hash/c.rb +0 -3
- data/smoke/hash/d.rb +0 -1
- data/smoke/hash/e.rb +0 -1
- data/smoke/hash/test.yaml +62 -0
- data/smoke/hello/hello.rb +0 -2
- data/smoke/hello/test.yaml +18 -0
- data/smoke/if/a.rb +0 -2
- data/smoke/if/test.yaml +27 -0
- data/smoke/implements/a.rb +0 -2
- data/smoke/implements/test.yaml +16 -0
- data/smoke/initialize/test.yaml +4 -0
- data/smoke/integer/a.rb +0 -7
- data/smoke/integer/test.yaml +66 -0
- data/smoke/interface/a.rb +0 -2
- data/smoke/interface/test.yaml +16 -0
- data/smoke/kwbegin/a.rb +0 -1
- data/smoke/kwbegin/test.yaml +14 -0
- data/smoke/lambda/a.rb +1 -4
- data/smoke/lambda/test.yaml +28 -0
- data/smoke/literal/a.rb +0 -5
- data/smoke/literal/b.rb +0 -2
- data/smoke/literal/test.yaml +79 -0
- data/smoke/map/test.yaml +4 -0
- data/smoke/method/a.rb +0 -5
- data/smoke/method/b.rb +0 -1
- data/smoke/method/test.yaml +71 -0
- data/smoke/module/a.rb +0 -2
- data/smoke/module/b.rb +0 -2
- data/smoke/module/c.rb +0 -1
- data/smoke/module/d.rb +0 -1
- data/smoke/module/f.rb +0 -2
- data/smoke/module/test.yaml +51 -0
- data/smoke/regexp/a.rb +0 -38
- data/smoke/regexp/b.rb +0 -26
- data/smoke/regexp/test.yaml +372 -0
- data/smoke/regression/set_divide.rb +0 -4
- data/smoke/regression/test.yaml +38 -0
- data/smoke/rescue/a.rb +0 -5
- data/smoke/rescue/test.yaml +60 -0
- data/smoke/self/a.rb +0 -2
- data/smoke/self/test.yaml +16 -0
- data/smoke/skip/skip.rb +0 -2
- data/smoke/skip/test.yaml +16 -0
- data/smoke/stdout/test.yaml +4 -0
- data/smoke/super/a.rb +0 -4
- data/smoke/super/test.yaml +52 -0
- data/smoke/toplevel/a.rb +0 -1
- data/smoke/toplevel/test.yaml +12 -0
- data/smoke/tsort/a.rb +0 -3
- data/smoke/tsort/test.yaml +32 -0
- data/smoke/type_case/a.rb +0 -4
- data/smoke/type_case/test.yaml +33 -0
- data/smoke/yield/a.rb +0 -3
- data/smoke/yield/b.rb +6 -0
- data/smoke/yield/test.yaml +49 -0
- data/steep.gemspec +3 -3
- metadata +108 -17
- data/bin/smoke_runner.rb +0 -139
- data/lib/steep/drivers/signature_error_printer.rb +0 -25
- data/lib/steep/errors.rb +0 -594
- data/lib/steep/signature/errors.rb +0 -128
- data/lib/steep/type_assignability.rb +0 -367
data/lib/steep/drivers/stats.rb
CHANGED
@@ -22,45 +22,141 @@ module Steep
|
|
22
22
|
loader.load_sources(command_line_patterns)
|
23
23
|
loader.load_signatures()
|
24
24
|
|
25
|
-
|
25
|
+
stderr.puts Rainbow("# Calculating stats:").bold
|
26
|
+
stderr.puts
|
27
|
+
|
28
|
+
client_read, server_write = IO.pipe
|
29
|
+
server_read, client_write = IO.pipe
|
30
|
+
|
31
|
+
client_reader = LanguageServer::Protocol::Transport::Io::Reader.new(client_read)
|
32
|
+
client_writer = LanguageServer::Protocol::Transport::Io::Writer.new(client_write)
|
33
|
+
|
34
|
+
server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
|
35
|
+
server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)
|
36
|
+
|
37
|
+
interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, delay_shutdown: true)
|
38
|
+
signature_worker = Server::WorkerProcess.spawn_worker(:signature, name: "signature", steepfile: project.steepfile_path, delay_shutdown: true)
|
39
|
+
code_workers = Server::WorkerProcess.spawn_code_workers(steepfile: project.steepfile_path, delay_shutdown: true)
|
40
|
+
|
41
|
+
master = Server::Master.new(
|
42
|
+
project: project,
|
43
|
+
reader: server_reader,
|
44
|
+
writer: server_writer,
|
45
|
+
interaction_worker: interaction_worker,
|
46
|
+
signature_worker: signature_worker,
|
47
|
+
code_workers: code_workers
|
48
|
+
)
|
49
|
+
|
50
|
+
main_thread = Thread.start do
|
51
|
+
master.start()
|
52
|
+
end
|
53
|
+
main_thread.abort_on_exception = true
|
54
|
+
|
55
|
+
client_writer.write({ method: :initialize, id: 0 })
|
56
|
+
|
57
|
+
stats_id = -1
|
58
|
+
client_writer.write(
|
59
|
+
{
|
60
|
+
id: stats_id,
|
61
|
+
method: "workspace/executeCommand",
|
62
|
+
params: {
|
63
|
+
command: "steep/stats",
|
64
|
+
arguments: project.all_source_files.map {|path| project.absolute_path(path) }
|
65
|
+
}
|
66
|
+
})
|
67
|
+
|
68
|
+
stats_result = []
|
69
|
+
client_reader.read do |response|
|
70
|
+
if response[:id] == stats_id
|
71
|
+
stats_result.push(*response[:result])
|
72
|
+
break
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
shutdown_id = -2
|
77
|
+
client_writer.write({ method: :shutdown, id: shutdown_id })
|
78
|
+
|
79
|
+
client_reader.read do |response|
|
80
|
+
if response[:id] == shutdown_id
|
81
|
+
break
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
client_writer.write({ method: "exit" })
|
86
|
+
main_thread.join()
|
26
87
|
|
27
88
|
stdout.puts(
|
28
89
|
CSV.generate do |csv|
|
29
90
|
csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
total = 0
|
42
|
-
typing.method_calls.each_value do |call|
|
43
|
-
case call
|
44
|
-
when TypeInference::MethodCall::Typed
|
45
|
-
typed += 1
|
46
|
-
when TypeInference::MethodCall::Untyped
|
47
|
-
untyped += 1
|
48
|
-
end
|
49
|
-
|
50
|
-
total += 1
|
51
|
-
end
|
52
|
-
|
53
|
-
csv << format_stats(target, source_file.path, "success", typed, untyped, total)
|
54
|
-
when Project::SourceFile::TypeCheckErrorStatus
|
55
|
-
csv << format_stats(target, source_file.path, "error", 0, 0, 0)
|
91
|
+
stats_result.each do |row|
|
92
|
+
if row[:type] == "success"
|
93
|
+
csv << [
|
94
|
+
row[:target],
|
95
|
+
row[:path],
|
96
|
+
row[:type],
|
97
|
+
row[:typed_calls],
|
98
|
+
row[:untyped_calls],
|
99
|
+
row[:total_calls],
|
100
|
+
if row[:total_calls].nonzero?
|
101
|
+
(row[:typed_calls].to_f / row[:total_calls] * 100).to_i
|
56
102
|
else
|
57
|
-
|
103
|
+
100
|
58
104
|
end
|
59
|
-
|
105
|
+
]
|
106
|
+
else
|
107
|
+
csv << [
|
108
|
+
row[:target],
|
109
|
+
row[:path],
|
110
|
+
row[:type],
|
111
|
+
0,
|
112
|
+
0,
|
113
|
+
0,
|
114
|
+
0
|
115
|
+
]
|
60
116
|
end
|
61
117
|
end
|
62
118
|
end
|
63
119
|
)
|
120
|
+
#
|
121
|
+
# type_check(project)
|
122
|
+
#
|
123
|
+
# stdout.puts(
|
124
|
+
# CSV.generate do |csv|
|
125
|
+
# csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
|
126
|
+
#
|
127
|
+
# project.targets.each do |target|
|
128
|
+
# case (status = target.status)
|
129
|
+
# when Project::Target::TypeCheckStatus
|
130
|
+
# status.type_check_sources.each do |source_file|
|
131
|
+
# case source_file.status
|
132
|
+
# when Project::SourceFile::TypeCheckStatus
|
133
|
+
# typing = source_file.status.typing
|
134
|
+
#
|
135
|
+
# typed = 0
|
136
|
+
# untyped = 0
|
137
|
+
# total = 0
|
138
|
+
# typing.method_calls.each_value do |call|
|
139
|
+
# case call
|
140
|
+
# when TypeInference::MethodCall::Typed
|
141
|
+
# typed += 1
|
142
|
+
# when TypeInference::MethodCall::Untyped
|
143
|
+
# untyped += 1
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# total += 1
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# csv << format_stats(target, source_file.path, "success", typed, untyped, total)
|
150
|
+
# when Project::SourceFile::TypeCheckErrorStatus
|
151
|
+
# csv << format_stats(target, source_file.path, "error", 0, 0, 0)
|
152
|
+
# else
|
153
|
+
# csv << format_stats(target, source_file.path, "unknown (#{source_file.status.class.to_s.split(/::/).last})", 0, 0, 0)
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
# )
|
64
160
|
|
65
161
|
0
|
66
162
|
end
|
@@ -9,7 +9,7 @@ module Steep
|
|
9
9
|
|
10
10
|
def print(trace, level: 0)
|
11
11
|
trace.each.with_index do |t, i|
|
12
|
-
prefix = "
|
12
|
+
prefix = " " * (i + level)
|
13
13
|
case t[0]
|
14
14
|
when :type
|
15
15
|
io.puts "#{prefix}#{t[1]} <: #{t[2]}"
|
@@ -17,6 +17,10 @@ module Steep
|
|
17
17
|
io.puts "#{prefix}(#{t[3]}) #{t[1]} <: #{t[2]}"
|
18
18
|
when :method_type
|
19
19
|
io.puts "#{prefix}#{t[1]} <: #{t[2]}"
|
20
|
+
when :interface
|
21
|
+
# nop
|
22
|
+
else
|
23
|
+
Steep.logger.error { "Unexpected trace item: #{t[0]}" }
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -22,12 +22,19 @@ module Steep
|
|
22
22
|
project.targets.each do |target|
|
23
23
|
Steep.logger.tagged "target=#{target.name}" do
|
24
24
|
case (status = target.status)
|
25
|
-
when Project::Target::
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
when Project::Target::SignatureErrorStatus
|
26
|
+
formatter = Diagnostic::LSPFormatter.new
|
27
|
+
diagnostics = status.errors.group_by {|e| e.location.buffer }.transform_values do |errors|
|
28
|
+
errors.map {|error| formatter.format(error) }
|
29
|
+
end
|
30
|
+
|
31
|
+
diagnostics.each do |buffer, ds|
|
32
|
+
printer = DiagnosticPrinter.new(stdout: stdout, buffer: buffer)
|
33
|
+
ds.each do |d|
|
34
|
+
printer.print(d)
|
35
|
+
stdout.puts
|
36
|
+
end
|
37
|
+
end
|
31
38
|
end
|
32
39
|
end
|
33
40
|
end
|
data/lib/steep/drivers/watch.rb
CHANGED
@@ -8,6 +8,8 @@ module Steep
|
|
8
8
|
|
9
9
|
include Utils::DriverHelper
|
10
10
|
|
11
|
+
LSP = LanguageServer::Protocol
|
12
|
+
|
11
13
|
def initialize(stdout:, stderr:)
|
12
14
|
@dirs = []
|
13
15
|
@stdout = stdout
|
@@ -58,7 +60,7 @@ module Steep
|
|
58
60
|
|
59
61
|
Steep.logger.info "Watching #{dirs.join(", ")}..."
|
60
62
|
listener = Listen.to(*dirs.map(&:to_s)) do |modified, added, removed|
|
61
|
-
stdout.puts "🔬 Type checking updated files..."
|
63
|
+
stdout.puts Rainbow("🔬 Type checking updated files...").bold
|
62
64
|
|
63
65
|
version = Time.now.to_i
|
64
66
|
Steep.logger.tagged "watch" do
|
@@ -101,35 +103,50 @@ module Steep
|
|
101
103
|
end.tap(&:start)
|
102
104
|
|
103
105
|
begin
|
104
|
-
stdout.puts "👀 Watching directories, Ctrl-C to stop."
|
106
|
+
stdout.puts Rainbow("👀 Watching directories, Ctrl-C to stop.").bold
|
105
107
|
client_reader.read do |response|
|
106
108
|
case response[:method]
|
107
109
|
when "textDocument/publishDiagnostics"
|
108
110
|
uri = URI.parse(response[:params][:uri])
|
109
111
|
path = project.relative_path(Pathname(uri.path))
|
112
|
+
buffer = RBS::Buffer.new(content: path.read, name: path)
|
113
|
+
printer = DiagnosticPrinter.new(stdout: stdout, buffer: buffer)
|
110
114
|
|
111
115
|
diagnostics = response[:params][:diagnostics]
|
112
116
|
|
113
117
|
unless diagnostics.empty?
|
114
118
|
diagnostics.each do |diagnostic|
|
115
|
-
|
116
|
-
loc = "#{start[:line]+1}:#{start[:character]}"
|
117
|
-
message = diagnostic[:message].chomp.lines.join(" ")
|
118
|
-
|
119
|
-
stdout.puts "#{path}:#{loc}: #{message}"
|
119
|
+
printer.print(diagnostic)
|
120
120
|
end
|
121
121
|
end
|
122
|
+
when "window/showMessage"
|
123
|
+
# Assuming ERROR message means unrecoverable error.
|
124
|
+
message = response[:params]
|
125
|
+
if message[:type] == LSP::Constant::MessageType::ERROR
|
126
|
+
stdout.puts "Unexpected error reported... 🚨"
|
127
|
+
end
|
122
128
|
end
|
123
129
|
end
|
124
130
|
rescue Interrupt
|
131
|
+
shutdown_id = -1
|
125
132
|
stdout.puts "Shutting down workers..."
|
126
|
-
client_writer.write({ method: :shutdown, id:
|
133
|
+
client_writer.write({ method: :shutdown, id: shutdown_id })
|
134
|
+
client_reader.read do |response|
|
135
|
+
if response[:id] == shutdown_id
|
136
|
+
break
|
137
|
+
end
|
138
|
+
end
|
127
139
|
client_writer.write({ method: :exit })
|
128
140
|
client_writer.io.close()
|
129
141
|
end
|
130
142
|
|
131
143
|
listener.stop
|
132
|
-
|
144
|
+
begin
|
145
|
+
main_thread.join
|
146
|
+
rescue Interrupt
|
147
|
+
master.kill
|
148
|
+
main_thread.join
|
149
|
+
end
|
133
150
|
|
134
151
|
0
|
135
152
|
end
|
data/lib/steep/drivers/worker.rb
CHANGED
@@ -6,6 +6,7 @@ module Steep
|
|
6
6
|
attr_accessor :steepfile_path
|
7
7
|
attr_accessor :worker_type
|
8
8
|
attr_accessor :worker_name
|
9
|
+
attr_accessor :delay_shutdown
|
9
10
|
|
10
11
|
include Utils::DriverHelper
|
11
12
|
|
@@ -37,6 +38,10 @@ module Steep
|
|
37
38
|
raise "Unknown worker type: #{worker_type}"
|
38
39
|
end
|
39
40
|
|
41
|
+
unless delay_shutdown
|
42
|
+
worker.skip_jobs_after_shutdown!
|
43
|
+
end
|
44
|
+
|
40
45
|
Steep.logger.info "Starting #{worker_type} worker..."
|
41
46
|
|
42
47
|
worker.run()
|
@@ -40,13 +40,13 @@ module Steep
|
|
40
40
|
|
41
41
|
def error_to_report?(error)
|
42
42
|
case
|
43
|
-
when error.is_a?(
|
43
|
+
when error.is_a?(Diagnostic::Ruby::FallbackAny)
|
44
44
|
!allow_fallback_any
|
45
|
-
when error.is_a?(
|
45
|
+
when error.is_a?(Diagnostic::Ruby::MethodDefinitionMissing)
|
46
46
|
!allow_missing_definitions
|
47
|
-
when error.is_a?(
|
47
|
+
when error.is_a?(Diagnostic::Ruby::NoMethod)
|
48
48
|
!allow_unknown_method_calls
|
49
|
-
when error.is_a?(
|
49
|
+
when error.is_a?(Diagnostic::Ruby::UnknownConstantAssigned)
|
50
50
|
!allow_unknown_constant_assignment
|
51
51
|
else
|
52
52
|
true
|
@@ -5,8 +5,6 @@ module Steep
|
|
5
5
|
attr_reader :content
|
6
6
|
attr_reader :content_updated_at
|
7
7
|
|
8
|
-
attr_reader :status
|
9
|
-
|
10
8
|
ParseErrorStatus = Struct.new(:error, :timestamp, keyword_init: true)
|
11
9
|
DeclarationsStatus = Struct.new(:declarations, :timestamp, keyword_init: true)
|
12
10
|
|
@@ -21,6 +19,14 @@ module Steep
|
|
21
19
|
@status = nil
|
22
20
|
end
|
23
21
|
|
22
|
+
def status
|
23
|
+
unless @status
|
24
|
+
@status = DeclarationsStatus.new(declarations: [], timestamp: Time.now)
|
25
|
+
end
|
26
|
+
|
27
|
+
@status
|
28
|
+
end
|
29
|
+
|
24
30
|
def load!
|
25
31
|
buffer = RBS::Buffer.new(name: path, content: content)
|
26
32
|
decls = RBS::Parser.parse_signature(buffer)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Steep
|
2
|
+
class Project
|
3
|
+
class StatsCalculator
|
4
|
+
SuccessStats = Struct.new(:target, :path, :typed_calls_count, :untyped_calls_count, :error_calls_count, keyword_init: true) do
|
5
|
+
def as_json
|
6
|
+
{
|
7
|
+
type: "success",
|
8
|
+
target: target.name.to_s,
|
9
|
+
path: path.to_s,
|
10
|
+
typed_calls: typed_calls_count,
|
11
|
+
untyped_calls: untyped_calls_count,
|
12
|
+
error_calls: error_calls_count,
|
13
|
+
total_calls: typed_calls_count + untyped_calls_count + error_calls_count
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
ErrorStats = Struct.new(:target, :path, :status, keyword_init: true) do
|
18
|
+
def as_json
|
19
|
+
{
|
20
|
+
type: "error",
|
21
|
+
target: target.name.to_s,
|
22
|
+
path: path.to_s,
|
23
|
+
status: status.class.to_s
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :project
|
29
|
+
|
30
|
+
def initialize(project:)
|
31
|
+
@project = project
|
32
|
+
end
|
33
|
+
|
34
|
+
def calc_stats(target, path)
|
35
|
+
source_file = target.source_files[path] or raise
|
36
|
+
|
37
|
+
target.type_check(
|
38
|
+
target_sources: [source_file],
|
39
|
+
validate_signatures: false
|
40
|
+
)
|
41
|
+
|
42
|
+
if target.status.is_a?(Target::TypeCheckStatus)
|
43
|
+
case source_file.status
|
44
|
+
when SourceFile::TypeCheckStatus
|
45
|
+
typing = source_file.status.typing
|
46
|
+
|
47
|
+
typed = 0
|
48
|
+
untyped = 0
|
49
|
+
errors = 0
|
50
|
+
total = 0
|
51
|
+
typing.method_calls.each_value do |call|
|
52
|
+
case call
|
53
|
+
when TypeInference::MethodCall::Typed
|
54
|
+
typed += 1
|
55
|
+
when TypeInference::MethodCall::Untyped
|
56
|
+
untyped += 1
|
57
|
+
when TypeInference::MethodCall::Error, TypeInference::MethodCall::NoMethodError
|
58
|
+
errors += 1
|
59
|
+
else
|
60
|
+
raise
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
SuccessStats.new(
|
65
|
+
target: target,
|
66
|
+
path: path,
|
67
|
+
typed_calls_count: typed,
|
68
|
+
untyped_calls_count: untyped,
|
69
|
+
error_calls_count: errors
|
70
|
+
)
|
71
|
+
when SourceFile::TypeCheckErrorStatus, SourceFile::AnnotationSyntaxErrorStatus, SourceFile::ParseErrorStatus
|
72
|
+
ErrorStats.new(target: target, path: path, status: source_file.status)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
ErrorStats.new(target: target, path: path, status: target.status)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/steep/project/target.rb
CHANGED
@@ -13,9 +13,7 @@ module Steep
|
|
13
13
|
|
14
14
|
attr_reader :status
|
15
15
|
|
16
|
-
|
17
|
-
SignatureValidationErrorStatus = Struct.new(:timestamp, :errors, keyword_init: true)
|
18
|
-
SignatureOtherErrorStatus = Struct.new(:timestamp, :error, keyword_init: true)
|
16
|
+
SignatureErrorStatus = Struct.new(:timestamp, :errors, keyword_init: true)
|
19
17
|
TypeCheckStatus = Struct.new(:environment, :subtyping, :type_check_sources, :timestamp, keyword_init: true)
|
20
18
|
|
21
19
|
def initialize(name:, options:, source_patterns:, ignore_patterns:, signature_patterns:)
|
@@ -137,39 +135,77 @@ module Steep
|
|
137
135
|
@environment ||= RBS::Environment.from_loader(Target.construct_env_loader(options: options))
|
138
136
|
end
|
139
137
|
|
140
|
-
def
|
141
|
-
|
142
|
-
when TypeCheckStatus
|
143
|
-
status.timestamp
|
144
|
-
end
|
145
|
-
now = Time.now
|
146
|
-
|
147
|
-
updated_files = []
|
138
|
+
def parse_signatures(timestamp:)
|
139
|
+
updated_signature_files = []
|
148
140
|
|
149
141
|
signature_files.each_value do |file|
|
150
142
|
if !timestamp || file.content_updated_at >= timestamp
|
151
|
-
|
143
|
+
Steep.logger.debug { "Loading #{file.path}..."}
|
144
|
+
updated_signature_files << file
|
152
145
|
file.load!()
|
153
146
|
end
|
154
147
|
end
|
155
148
|
|
156
|
-
|
157
|
-
if status.is_a?(TypeCheckStatus) && updated_files.empty?
|
158
|
-
yield status.environment, status.subtyping, status.timestamp
|
159
|
-
else
|
160
|
-
begin
|
161
|
-
env = environment.dup
|
162
|
-
|
163
|
-
signature_files.each_value do |file|
|
164
|
-
if file.status.is_a?(SignatureFile::DeclarationsStatus)
|
165
|
-
file.status.declarations.each do |decl|
|
166
|
-
env << decl
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
149
|
+
error_sigs = signature_files.each_value.reject {|file| file.status.is_a?(SignatureFile::DeclarationsStatus) }
|
170
150
|
|
171
|
-
|
151
|
+
if error_sigs.empty?
|
152
|
+
yield updated_signature_files
|
153
|
+
else
|
154
|
+
errors = error_sigs.map do |file|
|
155
|
+
case error = file.status.error
|
156
|
+
when RBS::Parser::SemanticsError
|
157
|
+
Diagnostic::Signature::SyntaxError.new(error, location: error.location)
|
158
|
+
when RBS::Parser::SyntaxError
|
159
|
+
Diagnostic::Signature::SyntaxError.new(error, location: error.error_value.location)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
@status = SignatureErrorStatus.new(
|
164
|
+
errors: errors,
|
165
|
+
timestamp: Time.now
|
166
|
+
)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def load_decls(now:)
|
171
|
+
errors = []
|
172
|
+
env = environment.dup
|
173
|
+
|
174
|
+
signature_files.each_value do |file|
|
175
|
+
raise unless file.status.is_a?(SignatureFile::DeclarationsStatus)
|
176
|
+
|
177
|
+
file.status.declarations.each do |decl|
|
178
|
+
env << decl
|
179
|
+
rescue RBS::DuplicatedDeclarationError => exn
|
180
|
+
errors << Diagnostic::Signature::DuplicatedDeclaration.new(
|
181
|
+
type_name: exn.name,
|
182
|
+
location: exn.decls[0].location
|
183
|
+
)
|
184
|
+
end
|
185
|
+
end
|
172
186
|
|
187
|
+
if errors.empty?
|
188
|
+
yield env.resolve_type_names
|
189
|
+
else
|
190
|
+
@status = SignatureErrorStatus.new(
|
191
|
+
errors: errors,
|
192
|
+
timestamp: now
|
193
|
+
)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def load_signatures(validate:)
|
198
|
+
timestamp = case status
|
199
|
+
when TypeCheckStatus
|
200
|
+
status.timestamp
|
201
|
+
end
|
202
|
+
now = Time.now
|
203
|
+
|
204
|
+
parse_signatures(timestamp: timestamp) do |updated_signature_files|
|
205
|
+
if status.is_a?(TypeCheckStatus) && updated_signature_files.empty?
|
206
|
+
yield status.environment, status.subtyping, status.timestamp
|
207
|
+
else
|
208
|
+
load_decls(now: now) do |env|
|
173
209
|
definition_builder = RBS::DefinitionBuilder.new(env: env)
|
174
210
|
factory = AST::Types::Factory.new(builder: definition_builder)
|
175
211
|
check = Subtyping::Check.new(factory: factory)
|
@@ -181,7 +217,7 @@ module Steep
|
|
181
217
|
if validator.no_error?
|
182
218
|
yield env, check, now
|
183
219
|
else
|
184
|
-
@status =
|
220
|
+
@status = SignatureErrorStatus.new(
|
185
221
|
errors: validator.each_error.to_a,
|
186
222
|
timestamp: now
|
187
223
|
)
|
@@ -189,33 +225,8 @@ module Steep
|
|
189
225
|
else
|
190
226
|
yield env, check, Time.now
|
191
227
|
end
|
192
|
-
rescue RBS::DuplicatedDeclarationError => exn
|
193
|
-
@status = SignatureValidationErrorStatus.new(
|
194
|
-
errors: [
|
195
|
-
Signature::Errors::DuplicatedDeclarationError.new(
|
196
|
-
type_name: exn.name,
|
197
|
-
location: exn.decls[0].location
|
198
|
-
)
|
199
|
-
],
|
200
|
-
timestamp: now
|
201
|
-
)
|
202
|
-
rescue => exn
|
203
|
-
Steep.log_error exn
|
204
|
-
@status = SignatureOtherErrorStatus.new(error: exn, timestamp: now)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
else
|
209
|
-
errors = signature_files.each_value.with_object([]) do |file, errors|
|
210
|
-
if file.status.is_a?(SignatureFile::ParseErrorStatus)
|
211
|
-
errors << file.status.error
|
212
228
|
end
|
213
229
|
end
|
214
|
-
|
215
|
-
@status = SignatureSyntaxErrorStatus.new(
|
216
|
-
errors: errors,
|
217
|
-
timestamp: Time.now
|
218
|
-
)
|
219
230
|
end
|
220
231
|
end
|
221
232
|
|