steep 1.10.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +84 -1
- data/CLAUDE.md +114 -0
- data/README.md +1 -1
- data/Rakefile +15 -3
- data/Steepfile +13 -13
- data/lib/steep/annotation_parser.rb +5 -1
- data/lib/steep/annotations_helper.rb +12 -2
- data/lib/steep/ast/node/type_application.rb +22 -16
- data/lib/steep/ast/node/type_assertion.rb +7 -4
- data/lib/steep/ast/types/factory.rb +3 -2
- data/lib/steep/cli.rb +246 -2
- data/lib/steep/daemon/configuration.rb +19 -0
- data/lib/steep/daemon/server.rb +476 -0
- data/lib/steep/daemon.rb +201 -0
- data/lib/steep/diagnostic/ruby.rb +50 -8
- data/lib/steep/diagnostic/signature.rb +31 -8
- data/lib/steep/drivers/check.rb +301 -140
- data/lib/steep/drivers/print_project.rb +9 -10
- data/lib/steep/drivers/query.rb +102 -0
- data/lib/steep/drivers/start_server.rb +19 -0
- data/lib/steep/drivers/stop_server.rb +20 -0
- data/lib/steep/drivers/watch.rb +2 -2
- data/lib/steep/index/rbs_index.rb +38 -13
- data/lib/steep/index/signature_symbol_provider.rb +24 -3
- data/lib/steep/interface/builder.rb +48 -15
- data/lib/steep/interface/shape.rb +13 -5
- data/lib/steep/locator.rb +377 -0
- data/lib/steep/project/dsl.rb +26 -5
- data/lib/steep/project/group.rb +8 -2
- data/lib/steep/project/target.rb +16 -2
- data/lib/steep/project.rb +21 -2
- data/lib/steep/server/base_worker.rb +2 -2
- data/lib/steep/server/change_buffer.rb +2 -1
- data/lib/steep/server/custom_methods.rb +12 -0
- data/lib/steep/server/inline_source_change_detector.rb +94 -0
- data/lib/steep/server/interaction_worker.rb +51 -74
- data/lib/steep/server/lsp_formatter.rb +48 -12
- data/lib/steep/server/master.rb +100 -18
- data/lib/steep/server/target_group_files.rb +124 -151
- data/lib/steep/server/type_check_controller.rb +276 -123
- data/lib/steep/server/type_check_worker.rb +104 -3
- data/lib/steep/services/completion_provider/rbs.rb +74 -0
- data/lib/steep/services/completion_provider/ruby.rb +652 -0
- data/lib/steep/services/completion_provider/type_name.rb +243 -0
- data/lib/steep/services/completion_provider.rb +39 -662
- data/lib/steep/services/content_change.rb +14 -1
- data/lib/steep/services/file_loader.rb +4 -2
- data/lib/steep/services/goto_service.rb +271 -68
- data/lib/steep/services/hover_provider/content.rb +67 -0
- data/lib/steep/services/hover_provider/rbs.rb +8 -9
- data/lib/steep/services/hover_provider/ruby.rb +123 -64
- data/lib/steep/services/hover_provider/singleton_methods.rb +4 -0
- data/lib/steep/services/signature_service.rb +129 -54
- data/lib/steep/services/type_check_service.rb +72 -27
- data/lib/steep/signature/validator.rb +30 -18
- data/lib/steep/source/ignore_ranges.rb +14 -4
- data/lib/steep/source.rb +16 -2
- data/lib/steep/tagged_logging.rb +39 -0
- data/lib/steep/type_construction.rb +94 -21
- data/lib/steep/type_inference/block_params.rb +7 -7
- data/lib/steep/type_inference/context.rb +4 -2
- data/lib/steep/type_inference/logic_type_interpreter.rb +21 -3
- data/lib/steep/type_inference/method_call.rb +4 -0
- data/lib/steep/type_inference/type_env.rb +1 -1
- data/lib/steep/typing.rb +0 -2
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +42 -32
- data/manual/ruby-diagnostics.md +67 -0
- data/sample/Steepfile +1 -0
- data/sample/lib/conference.rb +1 -0
- data/sample/lib/deprecated.rb +6 -0
- data/sample/lib/inline.rb +43 -0
- data/sample/sig/generics.rbs +3 -0
- data/steep.gemspec +4 -5
- metadata +26 -26
- data/lib/steep/services/type_name_completion.rb +0 -236
|
@@ -1,57 +1,8 @@
|
|
|
1
1
|
module Steep
|
|
2
2
|
module Services
|
|
3
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
|
-
TypeAssertionContent = _ = Struct.new(:node, :original_type, :asserted_type, :location, keyword_init: true)
|
|
8
|
-
MethodCallContent = _ = Struct.new(:node, :method_call, :location, keyword_init: true)
|
|
9
|
-
DefinitionContent = _ = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true)
|
|
10
|
-
ConstantContent = _ = Struct.new(:location, :full_name, :type, :decl, keyword_init: true) do
|
|
11
|
-
# @implements ConstantContent
|
|
12
|
-
|
|
13
|
-
def comments
|
|
14
|
-
case
|
|
15
|
-
when decl = class_decl
|
|
16
|
-
decl.decls.map {|d| d.decl.comment }
|
|
17
|
-
when decl = class_alias
|
|
18
|
-
[decl.decl.comment]
|
|
19
|
-
when decl = constant_decl
|
|
20
|
-
[decl.decl.comment]
|
|
21
|
-
else
|
|
22
|
-
raise
|
|
23
|
-
end.compact
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def class_decl
|
|
27
|
-
case decl
|
|
28
|
-
when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
|
|
29
|
-
decl
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def class_alias
|
|
34
|
-
case decl
|
|
35
|
-
when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
|
|
36
|
-
decl
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def constant_decl
|
|
41
|
-
if decl.is_a?(::RBS::Environment::ConstantEntry)
|
|
42
|
-
decl
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def constant?
|
|
47
|
-
constant_decl ? true : false
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def class_or_module?
|
|
51
|
-
(class_decl || class_alias) ? true : false
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
4
|
|
|
5
|
+
class Ruby
|
|
55
6
|
attr_reader :service
|
|
56
7
|
|
|
57
8
|
def initialize(service:)
|
|
@@ -85,7 +36,10 @@ module Steep
|
|
|
85
36
|
source = source.without_unrelated_defs(line: line, column: column)
|
|
86
37
|
resolver = ::RBS::Resolver::ConstantResolver.new(builder: subtyping.factory.definition_builder)
|
|
87
38
|
pos = source.buffer.loc_to_pos([line, column])
|
|
88
|
-
|
|
39
|
+
[
|
|
40
|
+
Services::TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: resolver, cursor: pos),
|
|
41
|
+
subtyping
|
|
42
|
+
]
|
|
89
43
|
rescue
|
|
90
44
|
nil
|
|
91
45
|
end
|
|
@@ -112,10 +66,15 @@ module Steep
|
|
|
112
66
|
|
|
113
67
|
def content_for(target:, path:, line:, column:)
|
|
114
68
|
file = service.source_files[path] or return
|
|
115
|
-
typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
|
|
116
|
-
|
|
69
|
+
(typing, subtyping = typecheck(target, path: path, content: file.content, line: line, column: column)) or return
|
|
70
|
+
locator = Locator::Ruby.new(typing.source)
|
|
71
|
+
result = locator.find(line, column)
|
|
72
|
+
|
|
73
|
+
case result
|
|
74
|
+
when Locator::NodeResult
|
|
75
|
+
node = result.node
|
|
76
|
+
parents = result.parents
|
|
117
77
|
|
|
118
|
-
if node && parents
|
|
119
78
|
case node.type
|
|
120
79
|
when :lvar
|
|
121
80
|
var_name = node.children[0]
|
|
@@ -130,7 +89,7 @@ module Steep
|
|
|
130
89
|
)
|
|
131
90
|
|
|
132
91
|
when :lvasgn
|
|
133
|
-
var_name,
|
|
92
|
+
var_name, _rhs = node.children
|
|
134
93
|
context = typing.cursor_context.context or raise
|
|
135
94
|
type = context.type_env[var_name] || typing.type_of(node: node)
|
|
136
95
|
|
|
@@ -197,15 +156,6 @@ module Steep
|
|
|
197
156
|
decl: entry
|
|
198
157
|
)
|
|
199
158
|
end
|
|
200
|
-
when :assertion
|
|
201
|
-
original_node, _ = node.children
|
|
202
|
-
|
|
203
|
-
original_type = typing.type_of(node: original_node)
|
|
204
|
-
asserted_type = typing.type_of(node: node)
|
|
205
|
-
|
|
206
|
-
if original_type != asserted_type
|
|
207
|
-
return TypeAssertionContent.new(node: node, original_type: original_type, asserted_type: asserted_type, location: node.location.expression)
|
|
208
|
-
end
|
|
209
159
|
end
|
|
210
160
|
|
|
211
161
|
TypeContent.new(
|
|
@@ -213,8 +163,117 @@ module Steep
|
|
|
213
163
|
type: typing.type_of(node: node),
|
|
214
164
|
location: node.location.expression
|
|
215
165
|
)
|
|
166
|
+
|
|
167
|
+
when Locator::TypeAssertionResult
|
|
168
|
+
context = typing.cursor_context.context or raise
|
|
169
|
+
pos = typing.source.buffer.loc_to_pos([line, column])
|
|
170
|
+
|
|
171
|
+
nesting = context.module_context.nesting
|
|
172
|
+
type_vars = context.variable_context.type_params.map { _1.name }
|
|
173
|
+
|
|
174
|
+
if (name, location = result.locate_type_name(pos, nesting, subtyping, type_vars))
|
|
175
|
+
if content = type_name_content(subtyping.factory.env, name, location)
|
|
176
|
+
return content
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
assertion_node = result.node.node
|
|
181
|
+
original_node = assertion_node.children[0] or raise
|
|
182
|
+
|
|
183
|
+
original_type = typing.type_of(node: original_node)
|
|
184
|
+
asserted_type = typing.type_of(node: assertion_node)
|
|
185
|
+
|
|
186
|
+
if original_type != asserted_type
|
|
187
|
+
TypeAssertionContent.new(
|
|
188
|
+
node: assertion_node,
|
|
189
|
+
original_type: original_type,
|
|
190
|
+
asserted_type: asserted_type,
|
|
191
|
+
location: assertion_node.location.expression
|
|
192
|
+
)
|
|
193
|
+
else
|
|
194
|
+
TypeContent.new(
|
|
195
|
+
node: assertion_node,
|
|
196
|
+
type: typing.type_of(node: assertion_node),
|
|
197
|
+
location: assertion_node.location.expression
|
|
198
|
+
)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
when Locator::TypeApplicationResult
|
|
202
|
+
begin
|
|
203
|
+
context = typing.cursor_context.context or raise
|
|
204
|
+
pos = typing.source.buffer.loc_to_pos([line, column])
|
|
205
|
+
|
|
206
|
+
nesting = context.module_context.nesting
|
|
207
|
+
type_vars = context.variable_context.type_params.map { _1.name }
|
|
208
|
+
|
|
209
|
+
if (name, location = result.locate_type_name(pos, nesting, subtyping, type_vars))
|
|
210
|
+
if content = type_name_content(subtyping.factory.env, name, location)
|
|
211
|
+
return content
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
nil
|
|
216
|
+
rescue ::RBS::ParsingError
|
|
217
|
+
return nil
|
|
218
|
+
end
|
|
216
219
|
end
|
|
217
220
|
end
|
|
221
|
+
|
|
222
|
+
def type_name_content(environment, type_name, location)
|
|
223
|
+
case
|
|
224
|
+
when type_name.class?
|
|
225
|
+
if entry = environment.module_class_entry(type_name)
|
|
226
|
+
decl = case entry
|
|
227
|
+
when ::RBS::Environment::ModuleEntry, ::RBS::Environment::ClassEntry
|
|
228
|
+
entry.primary_decl
|
|
229
|
+
else
|
|
230
|
+
entry.decl
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
ClassTypeContent.new(
|
|
234
|
+
location: location,
|
|
235
|
+
decl: decl
|
|
236
|
+
)
|
|
237
|
+
end
|
|
238
|
+
when type_name.interface?
|
|
239
|
+
if entry = environment.interface_decls.fetch(type_name, nil)
|
|
240
|
+
InterfaceTypeContent.new(
|
|
241
|
+
location: location,
|
|
242
|
+
decl: entry.decl
|
|
243
|
+
)
|
|
244
|
+
end
|
|
245
|
+
when type_name.alias?
|
|
246
|
+
if entry = environment.type_alias_decls.fetch(type_name, nil)
|
|
247
|
+
TypeAliasContent.new(
|
|
248
|
+
location: location,
|
|
249
|
+
decl: entry.decl
|
|
250
|
+
)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def content_for_inline(target:, path:, line:, column:)
|
|
256
|
+
signature = service.signature_services.fetch(target.name)
|
|
257
|
+
source = signature.latest_env.sources.find do
|
|
258
|
+
if _1.is_a?(::RBS::Source::Ruby)
|
|
259
|
+
_1.buffer.name == path
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
return unless source.is_a?(::RBS::Source::Ruby)
|
|
264
|
+
|
|
265
|
+
locator = Locator::Inline.new(source)
|
|
266
|
+
result = locator.find(line, column)
|
|
267
|
+
|
|
268
|
+
case result
|
|
269
|
+
when Locator::InlineTypeNameResult
|
|
270
|
+
return type_name_content(signature.latest_env, result.type_name, result.location)
|
|
271
|
+
else
|
|
272
|
+
Steep.logger.fatal { { result: result.class }.inspect }
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
nil
|
|
276
|
+
end
|
|
218
277
|
end
|
|
219
278
|
end
|
|
220
279
|
end
|
|
@@ -6,6 +6,10 @@ module Steep
|
|
|
6
6
|
project = service.project
|
|
7
7
|
|
|
8
8
|
case
|
|
9
|
+
when target = project.target_for_inline_source_path(path)
|
|
10
|
+
service = Ruby.new(service: service)
|
|
11
|
+
service.content_for_inline(target: target, path: path, line: line, column: column) ||
|
|
12
|
+
service.content_for(target: target, path: path, line: line, column: column)
|
|
9
13
|
when target = project.target_for_source_path(path)
|
|
10
14
|
Ruby.new(service: service).content_for(target: target, path: path, line: line, column: column)
|
|
11
15
|
when target = project.target_for_signature_path(path)
|
|
@@ -76,19 +76,36 @@ module Steep
|
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
RBSFileStatus = _ = Struct.new(:path, :content, :source, keyword_init: true)
|
|
80
80
|
|
|
81
81
|
attr_reader :implicitly_returns_nil
|
|
82
82
|
|
|
83
|
-
def initialize(
|
|
84
|
-
|
|
85
|
-
@status = LoadedStatus.new(builder: builder, files: {}, implicitly_returns_nil: implicitly_returns_nil)
|
|
83
|
+
def initialize(status:, implicitly_returns_nil:)
|
|
84
|
+
@status = status
|
|
86
85
|
@implicitly_returns_nil = implicitly_returns_nil
|
|
87
86
|
end
|
|
88
87
|
|
|
89
88
|
def self.load_from(loader, implicitly_returns_nil:)
|
|
90
89
|
env = RBS::Environment.from_loader(loader).resolve_type_names
|
|
91
|
-
new(env: env
|
|
90
|
+
builder = RBS::DefinitionBuilder.new(env: env)
|
|
91
|
+
status = LoadedStatus.new(builder: builder, files: {}, implicitly_returns_nil: implicitly_returns_nil)
|
|
92
|
+
new(status: status, implicitly_returns_nil: implicitly_returns_nil)
|
|
93
|
+
rescue RBS::ParsingError => exn
|
|
94
|
+
# When library RBS contains syntax error, load only *core* libraries and set `SyntaxErrorStatus`.
|
|
95
|
+
core_loader = RBS::EnvironmentLoader.new(core_root: loader.core_root)
|
|
96
|
+
core_env = RBS::Environment.from_loader(core_loader).resolve_type_names
|
|
97
|
+
status = SyntaxErrorStatus.new(
|
|
98
|
+
files: {},
|
|
99
|
+
changed_paths: Set[],
|
|
100
|
+
diagnostics: [Diagnostic::Signature.from_rbs_error(exn, factory: _ = nil)],
|
|
101
|
+
last_builder: RBS::DefinitionBuilder.new(env: core_env)
|
|
102
|
+
)
|
|
103
|
+
service = new(status: status, implicitly_returns_nil: implicitly_returns_nil)
|
|
104
|
+
# Add the failed library path to env_rbs_paths so it's recognized as a library path by TypeCheckService
|
|
105
|
+
if exn.location
|
|
106
|
+
service.env_rbs_paths << Pathname(exn.location.buffer.name)
|
|
107
|
+
end
|
|
108
|
+
service
|
|
92
109
|
end
|
|
93
110
|
|
|
94
111
|
def env_rbs_paths
|
|
@@ -154,51 +171,101 @@ module Steep
|
|
|
154
171
|
def apply_changes(files, changes)
|
|
155
172
|
Steep.logger.tagged "#apply_changes" do
|
|
156
173
|
Steep.measure2 "Applying change" do |sampler|
|
|
157
|
-
changes.each.with_object({}) do |
|
|
158
|
-
path, cs = pair
|
|
174
|
+
changes.each.with_object({}) do |(path, cs), update| # $ Hash[Pathname, file_status]
|
|
159
175
|
sampler.sample "#{path}" do
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
old_file = files.fetch(path, nil)
|
|
177
|
+
|
|
178
|
+
case old_file
|
|
179
|
+
when RBSFileStatus
|
|
180
|
+
old_text = old_file.content
|
|
181
|
+
new_file = load_rbs_file(path, old_text, cs)
|
|
182
|
+
when RBS::Source::Ruby
|
|
183
|
+
old_text = old_file.buffer.content
|
|
184
|
+
new_file = load_ruby_file(path, old_text, cs)
|
|
185
|
+
when nil
|
|
186
|
+
# New file: Detect based on the file name
|
|
187
|
+
if path.extname == ".rbs"
|
|
188
|
+
# RBS File
|
|
189
|
+
new_file = load_rbs_file(path, "", cs)
|
|
190
|
+
else
|
|
191
|
+
# Ruby File
|
|
192
|
+
new_file = load_ruby_file(path, "", cs)
|
|
177
193
|
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
update[path] = new_file
|
|
178
197
|
end
|
|
179
198
|
end
|
|
180
199
|
end
|
|
181
200
|
end
|
|
182
201
|
end
|
|
183
202
|
|
|
203
|
+
def load_rbs_file(path, old_text, changes)
|
|
204
|
+
content = changes.reduce(old_text) do |text, change| # $ String
|
|
205
|
+
change.apply_to(text)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
buffer = RBS::Buffer.new(name: path, content: content)
|
|
209
|
+
source =
|
|
210
|
+
begin
|
|
211
|
+
_, dirs, decls = RBS::Parser.parse_signature(buffer)
|
|
212
|
+
RBS::Source::RBS.new(buffer, dirs, decls)
|
|
213
|
+
rescue ArgumentError => exn
|
|
214
|
+
Diagnostic::Signature::UnexpectedError.new(
|
|
215
|
+
message: exn.message,
|
|
216
|
+
location: RBS::Location.new(buffer: buffer, start_pos: 0, end_pos: content.size)
|
|
217
|
+
)
|
|
218
|
+
rescue RBS::ParsingError => exn
|
|
219
|
+
exn
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
RBSFileStatus.new(path: path, content: content, source: source)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def load_ruby_file(path, old_text, changes)
|
|
226
|
+
content = changes.reduce(old_text) do |text, change| # $ String
|
|
227
|
+
change.apply_to(text)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
buffer = RBS::Buffer.new(name: path, content: content)
|
|
231
|
+
prism = Prism.parse(buffer.content, filepath: path.to_s)
|
|
232
|
+
result = RBS::InlineParser.parse(buffer, prism)
|
|
233
|
+
RBS::Source::Ruby.new(buffer, prism, result.declarations, result.diagnostics)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def error_file?(file)
|
|
237
|
+
case file
|
|
238
|
+
when RBSFileStatus
|
|
239
|
+
!file.source.is_a?(RBS::Source::RBS)
|
|
240
|
+
when RBS::Source::Ruby
|
|
241
|
+
false
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
184
245
|
def update(changes)
|
|
185
246
|
Steep.logger.tagged "#update" do
|
|
186
247
|
updates = apply_changes(files, changes)
|
|
187
248
|
paths = Set.new(updates.each_key)
|
|
188
249
|
paths.merge(pending_changed_paths)
|
|
189
250
|
|
|
190
|
-
if updates.each_value.any? {|file|
|
|
251
|
+
if updates.each_value.any? {|file| error_file?(file) }
|
|
191
252
|
diagnostics = [] #: Array[Diagnostic::Signature::Base]
|
|
192
253
|
|
|
193
254
|
updates.each_value do |file|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
255
|
+
if error_file?(file)
|
|
256
|
+
if file.is_a?(RBSFileStatus)
|
|
257
|
+
diagnostic =
|
|
258
|
+
case file.source
|
|
259
|
+
when Diagnostic::Signature::Base
|
|
260
|
+
file.source
|
|
261
|
+
when RBS::ParsingError
|
|
262
|
+
Diagnostic::Signature.from_rbs_error(file.source, factory: _ = nil)
|
|
263
|
+
else
|
|
264
|
+
raise "file (#{file.path}) must be an error"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
diagnostics << diagnostic
|
|
268
|
+
end
|
|
202
269
|
end
|
|
203
270
|
end
|
|
204
271
|
|
|
@@ -235,30 +302,26 @@ module Steep
|
|
|
235
302
|
def update_env(updated_files, paths:)
|
|
236
303
|
Steep.logger.tagged "#update_env" do
|
|
237
304
|
errors = [] #: Array[RBS::BaseError]
|
|
238
|
-
new_decls = Set[].compare_by_identity #: Set[RBS::AST::Declarations::t]
|
|
305
|
+
new_decls = Set[].compare_by_identity #: Set[RBS::AST::Declarations::t | RBS::AST::Ruby::Declarations::t]
|
|
239
306
|
|
|
240
307
|
env =
|
|
241
308
|
Steep.measure "Deleting out of date decls" do
|
|
242
|
-
|
|
243
|
-
latest_env.unload(Set.new(bufs))
|
|
309
|
+
latest_env.unload(paths)
|
|
244
310
|
end
|
|
245
311
|
|
|
246
312
|
Steep.measure "Loading new decls" do
|
|
247
313
|
updated_files.each_value do |content|
|
|
248
|
-
case content
|
|
249
|
-
when
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
env.add_signature(buffer: buffer, directives: dirs, decls: decls)
|
|
257
|
-
new_decls.merge(decls)
|
|
258
|
-
rescue RBS::LoadingError => exn
|
|
259
|
-
errors << exn
|
|
260
|
-
end
|
|
314
|
+
case content
|
|
315
|
+
when RBSFileStatus
|
|
316
|
+
(source = content.source).is_a?(RBS::Source::RBS) or raise "Cannot be an error"
|
|
317
|
+
env.add_source(source)
|
|
318
|
+
new_decls.merge(source.declarations)
|
|
319
|
+
when RBS::Source::Ruby
|
|
320
|
+
env.add_source(content)
|
|
321
|
+
new_decls.merge(content.declarations)
|
|
261
322
|
end
|
|
323
|
+
rescue RBS::LoadingError => exn
|
|
324
|
+
errors << exn
|
|
262
325
|
end
|
|
263
326
|
end
|
|
264
327
|
|
|
@@ -339,13 +402,25 @@ module Steep
|
|
|
339
402
|
end
|
|
340
403
|
|
|
341
404
|
def type_names(paths:, env:)
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
405
|
+
|
|
406
|
+
Hash.new {}
|
|
407
|
+
set = Set[] #: Set[RBS::TypeName]
|
|
408
|
+
|
|
409
|
+
env.each_rbs_source do |source|
|
|
410
|
+
next unless paths.include?(source.buffer.name)
|
|
411
|
+
source.each_type_name do |type_name|
|
|
412
|
+
set << type_name
|
|
347
413
|
end
|
|
348
414
|
end
|
|
415
|
+
|
|
416
|
+
env.each_ruby_source do |source|
|
|
417
|
+
next unless paths.include?(source.buffer.name)
|
|
418
|
+
source.each_type_name do |type_name|
|
|
419
|
+
set << type_name
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
set
|
|
349
424
|
end
|
|
350
425
|
|
|
351
426
|
def const_decls(paths:, env:)
|
|
@@ -53,17 +53,40 @@ module Steep
|
|
|
53
53
|
errors
|
|
54
54
|
when typing && ignores
|
|
55
55
|
errors = [] #: Array[Diagnostic::Ruby::Base]
|
|
56
|
+
error_lines = [] #: Array[Integer]
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
used_comments = Set[].compare_by_identity #: Set[Source::IgnoreRanges::ignore]
|
|
59
|
+
|
|
60
|
+
typing.errors.each do |diagnostic|
|
|
61
|
+
case diagnostic.location
|
|
62
|
+
when ::Parser::Source::Range
|
|
63
|
+
error_lines |= (diagnostic.location.first_line..diagnostic.location.last_line).to_a
|
|
64
|
+
if ignore = ignores.ignore?(diagnostic.location.first_line, diagnostic.location.last_line, diagnostic.diagnostic_code)
|
|
65
|
+
used_comments << ignore
|
|
66
|
+
next
|
|
67
|
+
end
|
|
68
|
+
when RBS::Location
|
|
69
|
+
if ignore = ignores.ignore?(diagnostic.location.start_line, diagnostic.location.end_line, diagnostic.diagnostic_code)
|
|
70
|
+
used_comments << ignore
|
|
71
|
+
next
|
|
64
72
|
end
|
|
65
73
|
end
|
|
66
|
-
|
|
74
|
+
|
|
75
|
+
errors << diagnostic
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
ignores.each_ignore do |ignore|
|
|
79
|
+
next if used_comments.include?(ignore)
|
|
80
|
+
|
|
81
|
+
case ignore
|
|
82
|
+
when Array
|
|
83
|
+
location = RBS::Location.new(ignore[0].location.buffer, ignore[0].location.start_pos, ignore[1].location.end_pos)
|
|
84
|
+
else
|
|
85
|
+
location = ignore.location
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
errors << Diagnostic::Ruby::RedundantIgnoreComment.new(location: location)
|
|
89
|
+
end
|
|
67
90
|
|
|
68
91
|
ignores.error_ignores.each do |ignore|
|
|
69
92
|
errors << Diagnostic::Ruby::InvalidIgnoreComment.new(comment: ignore.comment)
|
|
@@ -119,10 +142,6 @@ module Steep
|
|
|
119
142
|
signature_diagnostics
|
|
120
143
|
end
|
|
121
144
|
|
|
122
|
-
def has_diagnostics?
|
|
123
|
-
each_diagnostics.count > 0
|
|
124
|
-
end
|
|
125
|
-
|
|
126
145
|
def diagnostics
|
|
127
146
|
each_diagnostics.to_h
|
|
128
147
|
end
|
|
@@ -156,7 +175,9 @@ module Steep
|
|
|
156
175
|
Steep.measure "validation" do
|
|
157
176
|
service = signature_services.fetch(target.name)
|
|
158
177
|
|
|
159
|
-
|
|
178
|
+
unless target.possible_signature_file?(path) || target.possible_inline_source_file?(path) || service.env_rbs_paths.include?(path)
|
|
179
|
+
raise "#{path} is not library nor signature of #{target.name}"
|
|
180
|
+
end
|
|
160
181
|
|
|
161
182
|
case service.status
|
|
162
183
|
when SignatureService::SyntaxErrorStatus
|
|
@@ -221,6 +242,14 @@ module Steep
|
|
|
221
242
|
end
|
|
222
243
|
end
|
|
223
244
|
|
|
245
|
+
source = service.status.files[path]
|
|
246
|
+
if source.is_a?(RBS::Source::Ruby)
|
|
247
|
+
source.diagnostics.each do |d|
|
|
248
|
+
diagnostic = Diagnostic::Signature::InlineDiagnostic.new(d)
|
|
249
|
+
diagnostics.push(diagnostic)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
224
253
|
signature_validation_diagnostics.fetch(target.name)[path] = diagnostics
|
|
225
254
|
end
|
|
226
255
|
end
|
|
@@ -240,6 +269,29 @@ module Steep
|
|
|
240
269
|
source_files[path] = file
|
|
241
270
|
|
|
242
271
|
file.diagnostics
|
|
272
|
+
else
|
|
273
|
+
# Signature loading failed. If the errors originate from library RBS files,
|
|
274
|
+
# they won't be reported by validate_signature (which filters by user file path).
|
|
275
|
+
# Report them on source files so the user knows type checking is broken. (#2176)
|
|
276
|
+
case signature_service.status
|
|
277
|
+
when SignatureService::SyntaxErrorStatus, SignatureService::AncestorErrorStatus
|
|
278
|
+
library_errors = signature_service.status.diagnostics.select do |diag|
|
|
279
|
+
diag_path = diag.location && Pathname(diag.location.buffer.name)
|
|
280
|
+
diag_path &&
|
|
281
|
+
signature_service.env_rbs_paths.include?(diag_path) &&
|
|
282
|
+
!signature_service.status.files.key?(diag_path)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
unless library_errors.empty?
|
|
286
|
+
text = source_files.fetch(path).content
|
|
287
|
+
buffer = RBS::Buffer.new(name: path, content: text)
|
|
288
|
+
location = RBS::Location.new(buffer: buffer, start_pos: 0, end_pos: text.size)
|
|
289
|
+
|
|
290
|
+
library_errors.map do |error|
|
|
291
|
+
Diagnostic::Ruby::LibraryRBSError.new(error: error, location: location)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
243
295
|
end
|
|
244
296
|
end
|
|
245
297
|
end
|
|
@@ -249,8 +301,9 @@ module Steep
|
|
|
249
301
|
Steep.logger.tagged "#update_signature" do
|
|
250
302
|
signature_targets = {} #: Hash[Pathname, Project::Target]
|
|
251
303
|
changes.each do |path, changes|
|
|
252
|
-
target = project.
|
|
253
|
-
|
|
304
|
+
if target = project.target_for_signature_path(path) || project.target_for_inline_source_path(path)
|
|
305
|
+
signature_targets[path] = target
|
|
306
|
+
end
|
|
254
307
|
end
|
|
255
308
|
|
|
256
309
|
project.targets.each do |target|
|
|
@@ -368,7 +421,10 @@ module Steep
|
|
|
368
421
|
end
|
|
369
422
|
|
|
370
423
|
def source_file?(path)
|
|
371
|
-
source_files.key?(path)
|
|
424
|
+
return true if source_files.key?(path)
|
|
425
|
+
return true if project.target_for_source_path(path)
|
|
426
|
+
return true if project.target_for_inline_source_path(path)
|
|
427
|
+
false
|
|
372
428
|
end
|
|
373
429
|
|
|
374
430
|
def signature_file?(path)
|
|
@@ -378,17 +434,6 @@ module Steep
|
|
|
378
434
|
targets.keys
|
|
379
435
|
end
|
|
380
436
|
end
|
|
381
|
-
|
|
382
|
-
def app_signature_file?(path)
|
|
383
|
-
target_names = signature_services.select {|_, sig| sig.files.key?(path) }.keys
|
|
384
|
-
unless target_names.empty?
|
|
385
|
-
target_names
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
|
|
389
|
-
def lib_signature_file?(path)
|
|
390
|
-
signature_services.each_value.any? {|sig| sig.env_rbs_paths.include?(path) }
|
|
391
|
-
end
|
|
392
437
|
end
|
|
393
438
|
end
|
|
394
439
|
end
|