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
|
@@ -41,12 +41,25 @@ module Steep
|
|
|
41
41
|
new(text: string)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def self.from_lsp(changes)
|
|
45
|
+
changes.map do |change|
|
|
46
|
+
content_range =
|
|
47
|
+
if range = change[:range]
|
|
48
|
+
[
|
|
49
|
+
range[:start].yield_self {|pos| Services::ContentChange::Position.new(line: pos[:line] + 1, column: pos[:character]) },
|
|
50
|
+
end_pos = range[:end].yield_self {|pos| Services::ContentChange::Position.new(line: pos[:line] + 1, column: pos[:character]) }
|
|
51
|
+
] #: range
|
|
52
|
+
end
|
|
53
|
+
Services::ContentChange.new(range: content_range, text: change[:text])
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
44
57
|
def apply_to(text)
|
|
45
58
|
if range
|
|
46
59
|
text = text.dup
|
|
47
60
|
start_pos, end_pos = range
|
|
48
61
|
|
|
49
|
-
buf = RBS::Buffer.new(name:
|
|
62
|
+
buf = RBS::Buffer.new(name: Pathname("_"), content: text)
|
|
50
63
|
start_pos = buf.loc_to_pos([start_pos.line, start_pos.column])
|
|
51
64
|
end_pos = buf.loc_to_pos([end_pos.line, end_pos.column])
|
|
52
65
|
|
|
@@ -20,10 +20,12 @@ module Steep
|
|
|
20
20
|
|
|
21
21
|
target.groups.each do |group|
|
|
22
22
|
each_path_in_patterns(group.source_pattern, command_line_patterns, &handler)
|
|
23
|
+
each_path_in_patterns(group.inline_source_pattern, command_line_patterns, &handler)
|
|
23
24
|
each_path_in_patterns(group.signature_pattern, &handler)
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
each_path_in_patterns(target.source_pattern, command_line_patterns, &handler)
|
|
28
|
+
each_path_in_patterns(target.inline_source_pattern, command_line_patterns, &handler)
|
|
27
29
|
each_path_in_patterns(target.signature_pattern, &handler)
|
|
28
30
|
else
|
|
29
31
|
enum_for :each_path_in_target, target, command_line_patterns
|
|
@@ -35,14 +37,14 @@ module Steep
|
|
|
35
37
|
pats = commandline_patterns.empty? ? pattern.patterns : commandline_patterns
|
|
36
38
|
|
|
37
39
|
pats.each do |path|
|
|
38
|
-
Pathname.glob(
|
|
40
|
+
Pathname(base_dir).glob(path.to_s).each do |absolute_path|
|
|
39
41
|
if absolute_path.file?
|
|
40
42
|
relative_path = absolute_path.relative_path_from(base_dir)
|
|
41
43
|
if pattern =~ relative_path
|
|
42
44
|
yield relative_path
|
|
43
45
|
end
|
|
44
46
|
else
|
|
45
|
-
files = Pathname.glob("
|
|
47
|
+
files = Pathname(absolute_path).glob("**/*#{pattern.ext}")
|
|
46
48
|
|
|
47
49
|
files.sort.each do |source_path|
|
|
48
50
|
if source_path.file?
|
|
@@ -33,6 +33,126 @@ module Steep
|
|
|
33
33
|
type_check.project
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
# Parses a string representing a class/type/constant/method name into a query value.
|
|
37
|
+
#
|
|
38
|
+
# Supported formats:
|
|
39
|
+
#
|
|
40
|
+
# * `RBS::Location` -- type name (class, module, interface, type alias, class/module alias, or constant)
|
|
41
|
+
# * `::RBS::Location` -- type name, fully qualified
|
|
42
|
+
# * `RBS::Parser#parse_type` -- instance method
|
|
43
|
+
# * `RBS::Parser.parse_signature` -- singleton method
|
|
44
|
+
#
|
|
45
|
+
# Returns `nil` when the given string cannot be parsed as any of the above.
|
|
46
|
+
#
|
|
47
|
+
def self.parse_name(name_string)
|
|
48
|
+
return nil if name_string.nil? || name_string.empty?
|
|
49
|
+
|
|
50
|
+
if index = name_string.index("#")
|
|
51
|
+
type_part = name_string[0...index] or return nil
|
|
52
|
+
method_part = name_string[(index + 1)..] or return nil
|
|
53
|
+
return nil if type_part.empty? || method_part.empty?
|
|
54
|
+
|
|
55
|
+
type_name = parse_type_name(type_part) or return nil
|
|
56
|
+
InstanceMethodName.new(type_name: type_name, method_name: method_part.to_sym)
|
|
57
|
+
elsif index = find_singleton_method_dot(name_string)
|
|
58
|
+
type_part = name_string[0...index] or return nil
|
|
59
|
+
method_part = name_string[(index + 1)..] or return nil
|
|
60
|
+
return nil if type_part.empty? || method_part.empty?
|
|
61
|
+
|
|
62
|
+
type_name = parse_type_name(type_part) or return nil
|
|
63
|
+
SingletonMethodName.new(type_name: type_name, method_name: method_part.to_sym)
|
|
64
|
+
else
|
|
65
|
+
parse_type_name(name_string)
|
|
66
|
+
end
|
|
67
|
+
rescue RBS::ParsingError, StandardError
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Finds the index of a `.` that separates a type from a singleton method name.
|
|
72
|
+
#
|
|
73
|
+
# Returns the index of the last `.` that is *not* followed by another `.` (to avoid
|
|
74
|
+
# matching the empty string) and that is not part of `::`. Returns `nil` if none is found.
|
|
75
|
+
#
|
|
76
|
+
def self.find_singleton_method_dot(string)
|
|
77
|
+
index = string.length - 1
|
|
78
|
+
while index > 0
|
|
79
|
+
char = string[index]
|
|
80
|
+
if char == "."
|
|
81
|
+
prev = string[index - 1]
|
|
82
|
+
if prev != "." && prev != ":"
|
|
83
|
+
return index
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
index -= 1
|
|
87
|
+
end
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.parse_type_name(string)
|
|
92
|
+
string = "::#{string}" unless string.start_with?("::")
|
|
93
|
+
RBS::TypeName.parse(string)
|
|
94
|
+
rescue RBS::ParsingError, StandardError
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns array of locations that is a response to a *Query definition* request.
|
|
99
|
+
#
|
|
100
|
+
# Unlike `#definition`, this method takes a parsed name value instead of a source position.
|
|
101
|
+
# The caller is expected to parse the name via `.parse_name` before calling this method.
|
|
102
|
+
#
|
|
103
|
+
# Each returned entry is either an `RBS::Location` (for RBS declarations) or a
|
|
104
|
+
# `Parser::Source::Range` (for Ruby source locations).
|
|
105
|
+
#
|
|
106
|
+
def query_definition(name)
|
|
107
|
+
locations = [] #: Array[target_loc]
|
|
108
|
+
|
|
109
|
+
case name
|
|
110
|
+
when RBS::TypeName
|
|
111
|
+
# `constant_definition_in_rbs` covers classes, modules, class/module aliases,
|
|
112
|
+
# and plain constants (via `env.constant_entry`).
|
|
113
|
+
constant_definition_in_rbs(name, locations: locations)
|
|
114
|
+
constant_definition_in_ruby(name, locations: locations)
|
|
115
|
+
# Additional lookups for declarations that are not reachable via `env.constant_entry`.
|
|
116
|
+
interface_and_type_alias_locations(name, locations: locations)
|
|
117
|
+
when InstanceMethodName, SingletonMethodName
|
|
118
|
+
method_locations(name, in_ruby: true, in_rbs: true, locations: locations)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
locations.filter_map do |target, loc|
|
|
122
|
+
case loc
|
|
123
|
+
when RBS::Location
|
|
124
|
+
if assignment =~ [target, loc.name]
|
|
125
|
+
loc
|
|
126
|
+
end
|
|
127
|
+
else
|
|
128
|
+
loc
|
|
129
|
+
end
|
|
130
|
+
end.uniq
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def interface_and_type_alias_locations(name, locations:)
|
|
134
|
+
project.targets.each do |target|
|
|
135
|
+
signature = type_check.signature_services.fetch(target.name)
|
|
136
|
+
env = signature.latest_env
|
|
137
|
+
|
|
138
|
+
if entry = env.interface_decls[name]
|
|
139
|
+
decl = entry.decl
|
|
140
|
+
if loc = decl.location
|
|
141
|
+
locations << [target, loc[:name]]
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
if entry = env.type_alias_decls[name]
|
|
146
|
+
decl = entry.decl
|
|
147
|
+
if loc = decl.location
|
|
148
|
+
locations << [target, loc[:name]]
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
locations
|
|
154
|
+
end
|
|
155
|
+
|
|
36
156
|
def implementation(path:, line:, column:)
|
|
37
157
|
locations = [] #: Array[target_loc]
|
|
38
158
|
|
|
@@ -162,75 +282,46 @@ module Steep
|
|
|
162
282
|
relative_path = project.relative_path(path)
|
|
163
283
|
|
|
164
284
|
case
|
|
165
|
-
when target = type_check.project.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
285
|
+
when target = type_check.project.target_for_inline_source_path(relative_path)
|
|
286
|
+
signature = type_check.signature_services.fetch(target.name)
|
|
287
|
+
source = signature.latest_env.sources.find do
|
|
288
|
+
if _1.is_a?(::RBS::Source::Ruby)
|
|
289
|
+
_1.buffer.name == relative_path
|
|
290
|
+
end
|
|
291
|
+
end
|
|
170
292
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
named_location = (_ = node.location) #: Parser::AST::_NamedLocation
|
|
175
|
-
if test_ast_location(named_location.name, line: line, column: column)
|
|
176
|
-
if name = typing.source_index.reference(constant_node: node)
|
|
177
|
-
queries << ConstantQuery.new(name: name, from: :ruby)
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
when :def, :defs
|
|
181
|
-
named_location = (_ = node.location) #: Parser::AST::_NamedLocation
|
|
182
|
-
if test_ast_location(named_location.name, line: line, column: column)
|
|
183
|
-
if method_context = typing.cursor_context.context&.method_context
|
|
184
|
-
if method = method_context.method
|
|
185
|
-
method.defs.each do |defn|
|
|
186
|
-
singleton_method =
|
|
187
|
-
case defn.member
|
|
188
|
-
when RBS::AST::Members::MethodDefinition
|
|
189
|
-
defn.member.singleton?
|
|
190
|
-
when RBS::AST::Members::Attribute
|
|
191
|
-
defn.member.kind == :singleton
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
name =
|
|
195
|
-
if singleton_method
|
|
196
|
-
SingletonMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
|
|
197
|
-
else
|
|
198
|
-
InstanceMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
queries << MethodQuery.new(name: name, from: :ruby)
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
when :send
|
|
207
|
-
location = (_ = node.location) #: Parser::AST::_SelectorLocation
|
|
208
|
-
if test_ast_location(location.selector, line: line, column: column)
|
|
209
|
-
if (parent = parents[0]) && parent.type == :block && parent.children[0] == node
|
|
210
|
-
node = parents[0]
|
|
211
|
-
end
|
|
293
|
+
if source.is_a?(::RBS::Source::Ruby)
|
|
294
|
+
locator = Locator::Inline.new(source)
|
|
295
|
+
result = locator.find(line, column)
|
|
212
296
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
end
|
|
297
|
+
case result
|
|
298
|
+
when Locator::InlineTypeNameResult
|
|
299
|
+
queries << TypeNameQuery.new(name: result.type_name)
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
if queries.empty?
|
|
304
|
+
source = type_check.source_files.fetch(relative_path, nil) or return []
|
|
305
|
+
typing, signature, subtyping = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
|
|
306
|
+
if typing && signature && subtyping
|
|
307
|
+
queries.concat query_at_implementation(typing, subtyping, line: line, column: column)
|
|
225
308
|
end
|
|
226
309
|
end
|
|
310
|
+
when target = type_check.project.target_for_source_path(relative_path)
|
|
311
|
+
source = type_check.source_files.fetch(relative_path, nil) or return []
|
|
312
|
+
typing, _signature, subtyping = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
|
|
313
|
+
if typing && subtyping
|
|
314
|
+
queries.concat query_at_implementation(typing, subtyping, line: line, column: column)
|
|
315
|
+
end
|
|
227
316
|
when target_names = type_check.signature_file?(path) #: Array[Symbol]
|
|
228
317
|
target_names.each do |target_name|
|
|
229
318
|
signature_service = type_check.signature_services[target_name] #: SignatureService
|
|
230
319
|
|
|
231
320
|
env = signature_service.latest_env
|
|
232
|
-
|
|
233
|
-
|
|
321
|
+
source = env.each_rbs_source.find {|src| src.buffer.name == relative_path } or raise
|
|
322
|
+
buffer = source.buffer
|
|
323
|
+
dirs = source.directives
|
|
324
|
+
decls = source.declarations
|
|
234
325
|
|
|
235
326
|
locator = RBS::Locator.new(buffer: buffer, dirs: dirs, decls: decls)
|
|
236
327
|
last, nodes = locator.find2(line: line, column: column)
|
|
@@ -283,6 +374,93 @@ module Steep
|
|
|
283
374
|
queries
|
|
284
375
|
end
|
|
285
376
|
|
|
377
|
+
def query_at_implementation(typing, subtyping, line:, column:)
|
|
378
|
+
queries = [] #: Array[query]
|
|
379
|
+
|
|
380
|
+
locator = Locator::Ruby.new(typing.source)
|
|
381
|
+
result = locator.find(line, column)
|
|
382
|
+
|
|
383
|
+
case result
|
|
384
|
+
when Locator::NodeResult
|
|
385
|
+
node = result.node
|
|
386
|
+
parents = result.parents
|
|
387
|
+
|
|
388
|
+
case node.type
|
|
389
|
+
when :const, :casgn
|
|
390
|
+
named_location = (_ = node.location) #: Parser::AST::_NamedLocation
|
|
391
|
+
if test_ast_location(named_location.name, line: line, column: column)
|
|
392
|
+
if name = typing.source_index.reference(constant_node: node)
|
|
393
|
+
queries << ConstantQuery.new(name: name, from: :ruby)
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
when :def, :defs
|
|
397
|
+
named_location = (_ = node.location) #: Parser::AST::_NamedLocation
|
|
398
|
+
if test_ast_location(named_location.name, line: line, column: column)
|
|
399
|
+
if method_context = typing.cursor_context.context&.method_context
|
|
400
|
+
if method = method_context.method
|
|
401
|
+
method.defs.each do |defn|
|
|
402
|
+
singleton_method =
|
|
403
|
+
case defn.member
|
|
404
|
+
when RBS::AST::Members::MethodDefinition
|
|
405
|
+
defn.member.singleton?
|
|
406
|
+
when RBS::AST::Members::Attribute
|
|
407
|
+
defn.member.kind == :singleton
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
name =
|
|
411
|
+
if singleton_method
|
|
412
|
+
SingletonMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
|
|
413
|
+
else
|
|
414
|
+
InstanceMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
queries << MethodQuery.new(name: name, from: :ruby)
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
when :send
|
|
423
|
+
location = (_ = node.location) #: Parser::AST::_SelectorLocation
|
|
424
|
+
if test_ast_location(location.selector, line: line, column: column)
|
|
425
|
+
if (parent = parents[0]) && parent.type == :block && parent.children[0] === node
|
|
426
|
+
node = parents[0]
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
case call = typing.call_of(node: node)
|
|
430
|
+
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
|
431
|
+
call.method_decls.each do |decl|
|
|
432
|
+
queries << MethodQuery.new(name: decl.method_name, from: :ruby)
|
|
433
|
+
end
|
|
434
|
+
when TypeInference::MethodCall::Untyped
|
|
435
|
+
# nop
|
|
436
|
+
when TypeInference::MethodCall::NoMethodError
|
|
437
|
+
# nop
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
when Locator::TypeAssertionResult
|
|
442
|
+
context = typing.cursor_context.context or raise
|
|
443
|
+
nesting = context.module_context.nesting
|
|
444
|
+
type_vars = context.variable_context.type_params.map(&:name)
|
|
445
|
+
pos = typing.source.buffer.loc_to_pos([line, column])
|
|
446
|
+
|
|
447
|
+
if pair = result.locate_type_name(pos, nesting, subtyping, type_vars)
|
|
448
|
+
queries << TypeNameQuery.new(name: pair[0])
|
|
449
|
+
end
|
|
450
|
+
when Locator::TypeApplicationResult
|
|
451
|
+
context = typing.cursor_context.context or raise
|
|
452
|
+
nesting = context.module_context.nesting
|
|
453
|
+
type_vars = context.variable_context.type_params.map(&:name)
|
|
454
|
+
pos = typing.source.buffer.loc_to_pos([line, column])
|
|
455
|
+
|
|
456
|
+
if pair = result.locate_type_name(pos, nesting, subtyping, type_vars)
|
|
457
|
+
queries << TypeNameQuery.new(name: pair[0])
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
queries
|
|
462
|
+
end
|
|
463
|
+
|
|
286
464
|
def type_check_path(target:, path:, content:, line:, column:)
|
|
287
465
|
signature_service = type_check.signature_services.fetch(target.name)
|
|
288
466
|
subtyping = signature_service.current_subtyping or return
|
|
@@ -292,7 +470,8 @@ module Steep
|
|
|
292
470
|
loc = source.buffer.loc_to_pos([line, column])
|
|
293
471
|
[
|
|
294
472
|
Services::TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: resolver, cursor: loc),
|
|
295
|
-
signature_service
|
|
473
|
+
signature_service,
|
|
474
|
+
subtyping
|
|
296
475
|
]
|
|
297
476
|
rescue
|
|
298
477
|
nil
|
|
@@ -305,18 +484,36 @@ module Steep
|
|
|
305
484
|
|
|
306
485
|
case entry = env.constant_entry(name)
|
|
307
486
|
when RBS::Environment::ConstantEntry
|
|
308
|
-
|
|
309
|
-
|
|
487
|
+
case decl = entry.decl
|
|
488
|
+
when RBS::AST::Declarations::Constant
|
|
489
|
+
if entry.decl.location
|
|
490
|
+
locations << [target, entry.decl.location[:name]]
|
|
491
|
+
end
|
|
492
|
+
when RBS::AST::Ruby::Declarations::ConstantDecl
|
|
493
|
+
locations << [target, entry.decl.name_location]
|
|
494
|
+
else
|
|
495
|
+
raise "Unknown declaration: #{entry.decl.inspect}"
|
|
310
496
|
end
|
|
311
497
|
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
|
312
|
-
entry.
|
|
313
|
-
|
|
314
|
-
|
|
498
|
+
entry.each_decl do |decl|
|
|
499
|
+
case decl
|
|
500
|
+
when RBS::AST::Declarations::Base
|
|
501
|
+
if decl.location
|
|
502
|
+
locations << [target, decl.location[:name]]
|
|
503
|
+
end
|
|
504
|
+
when RBS::AST::Ruby::Declarations::ClassDecl, RBS::AST::Ruby::Declarations::ModuleDecl
|
|
505
|
+
locations << [target, decl.name_location]
|
|
506
|
+
else
|
|
507
|
+
raise "Unknown declaration: #{decl.inspect}"
|
|
315
508
|
end
|
|
316
509
|
end
|
|
317
510
|
when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
|
318
|
-
if entry.decl.
|
|
319
|
-
|
|
511
|
+
if entry.decl.is_a?(RBS::AST::Declarations::Base)
|
|
512
|
+
if entry.decl.location
|
|
513
|
+
locations << [target, entry.decl.location[:new_name]]
|
|
514
|
+
end
|
|
515
|
+
else
|
|
516
|
+
locations << [target, entry.decl.name_location]
|
|
320
517
|
end
|
|
321
518
|
end
|
|
322
519
|
end
|
|
@@ -404,6 +601,8 @@ module Steep
|
|
|
404
601
|
if decl.location
|
|
405
602
|
locations << [target, decl.location[:name]]
|
|
406
603
|
end
|
|
604
|
+
when RBS::AST::Ruby::Members::DefMember
|
|
605
|
+
locations << [target, decl.name_location]
|
|
407
606
|
end
|
|
408
607
|
end
|
|
409
608
|
end
|
|
@@ -428,6 +627,10 @@ module Steep
|
|
|
428
627
|
if decl.location
|
|
429
628
|
locations << [target, decl.location[:new_name]]
|
|
430
629
|
end
|
|
630
|
+
when RBS::AST::Ruby::Declarations::ClassDecl, RBS::AST::Ruby::Declarations::ModuleDecl
|
|
631
|
+
locations << [target, decl.name_location]
|
|
632
|
+
when RBS::AST::Ruby::Declarations::ClassModuleAliasDecl
|
|
633
|
+
locations << [target, decl.name_location]
|
|
431
634
|
else
|
|
432
635
|
raise
|
|
433
636
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Steep
|
|
2
|
+
module Services
|
|
3
|
+
module HoverProvider
|
|
4
|
+
TypeContent = _ = Struct.new(:node, :type, :location, keyword_init: true)
|
|
5
|
+
VariableContent = _ = Struct.new(:node, :name, :type, :location, keyword_init: true)
|
|
6
|
+
TypeAssertionContent = _ = Struct.new(:node, :original_type, :asserted_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
|
+
# @implements ConstantContent
|
|
11
|
+
|
|
12
|
+
def comments
|
|
13
|
+
case
|
|
14
|
+
when decl = class_decl
|
|
15
|
+
decl.each_decl.map do |decl|
|
|
16
|
+
case decl
|
|
17
|
+
when ::RBS::AST::Declarations::Base
|
|
18
|
+
decl.comment
|
|
19
|
+
when ::RBS::AST::Ruby::Declarations::Base
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
when decl = class_alias
|
|
25
|
+
[decl.decl.comment]
|
|
26
|
+
when decl = constant_decl
|
|
27
|
+
[decl.decl.comment]
|
|
28
|
+
else
|
|
29
|
+
raise
|
|
30
|
+
end.compact
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def class_decl
|
|
34
|
+
case decl
|
|
35
|
+
when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
|
|
36
|
+
decl
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def class_alias
|
|
41
|
+
case decl
|
|
42
|
+
when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
|
|
43
|
+
decl
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def constant_decl
|
|
48
|
+
if decl.is_a?(::RBS::Environment::ConstantEntry)
|
|
49
|
+
decl
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def constant?
|
|
54
|
+
constant_decl ? true : false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def class_or_module?
|
|
58
|
+
(class_decl || class_alias) ? true : false
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
TypeAliasContent = _ = Struct.new(:location, :decl, keyword_init: true)
|
|
63
|
+
ClassTypeContent = _ = Struct.new(:location, :decl, keyword_init: true)
|
|
64
|
+
InterfaceTypeContent = _ = Struct.new(:location, :decl, keyword_init: true)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
module Steep
|
|
2
2
|
module Services
|
|
3
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
4
|
|
|
5
|
+
class RBS
|
|
9
6
|
attr_reader :service
|
|
10
7
|
|
|
11
8
|
def initialize(service:)
|
|
@@ -20,8 +17,10 @@ module Steep
|
|
|
20
17
|
service = self.service.signature_services.fetch(target.name)
|
|
21
18
|
|
|
22
19
|
env = service.latest_env
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
source = env.each_rbs_source.find {|src| src.buffer.name == path } or return
|
|
21
|
+
buffer = source.buffer
|
|
22
|
+
dirs = source.directives
|
|
23
|
+
decls = source.declarations
|
|
25
24
|
|
|
26
25
|
locator = ::RBS::Locator.new(buffer: buffer, dirs: dirs, decls: decls)
|
|
27
26
|
loc_key, path = locator.find2(line: line, column: column) || return
|
|
@@ -68,18 +67,18 @@ module Steep
|
|
|
68
67
|
TypeAliasContent.new(location: location, decl: alias_decl)
|
|
69
68
|
when type_name.interface?
|
|
70
69
|
interface_decl = env.interface_decls[type_name]&.decl or return
|
|
71
|
-
|
|
70
|
+
InterfaceTypeContent.new(location: location, decl: interface_decl)
|
|
72
71
|
when type_name.class?
|
|
73
72
|
class_entry = env.module_class_entry(type_name) or return
|
|
74
73
|
|
|
75
74
|
case class_entry
|
|
76
75
|
when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
|
|
77
|
-
class_decl = class_entry.
|
|
76
|
+
class_decl = class_entry.primary_decl
|
|
78
77
|
when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
|
|
79
78
|
class_decl = class_entry.decl
|
|
80
79
|
end
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
ClassTypeContent.new(location: location, decl: class_decl)
|
|
83
82
|
end
|
|
84
83
|
end
|
|
85
84
|
end
|