lib/steep/services/hover_content.rb in steep-0.44.1 vs lib/steep/services/hover_content.rb in steep-0.45.0
- old
+ new
@@ -3,10 +3,14 @@
class HoverContent
TypeContent = Struct.new(:node, :type, :location, keyword_init: true)
VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
MethodCallContent = Struct.new(:node, :method_name, :type, :definition, :location, keyword_init: true)
DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true) do
+ TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
+ ClassContent = Struct.new(:location, :decl, keyword_init: true)
+ InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
+
def comment_string
if comments = definition&.comments
comments.map {|c| c.string.chomp }.uniq.join("\n----\n")
end
end
@@ -48,102 +52,150 @@
rescue
nil
end
def content_for(path:, line:, column:)
- target = project.target_for_source_path(path)
+ target_for_code, targets_for_sigs = project.targets_for_path(path)
- if target
- file = service.source_files[path]
- typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
+ case
+ when target = target_for_code
+ Steep.logger.info "target #{target}"
- node, *parents = typing.source.find_nodes(line: line, column: column)
+ hover_for_source(column, line, path, target)
- if node
- case node.type
- when :lvar
- var_name = node.children[0]
- context = typing.context_at(line: line, column: column)
- var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
+ when target = targets_for_sigs[0]
+ service = self.service.signature_services[target.name]
- VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
- when :lvasgn
- var_name, rhs = node.children
- context = typing.context_at(line: line, column: column)
- type = context.lvar_env[var_name] || typing.type_of(node: rhs)
+ _buffer, decls = service.latest_env.buffers_decls.find do |buffer, _|
+ Pathname(buffer.name) == path
+ end
- VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
- when :send
- receiver, method_name, *_ = node.children
+ return if decls.nil?
+ locator = RBS::Locator.new(decls: decls)
+ hd, tail = locator.find2(line: line, column: column)
- result_node = if parents[0]&.type == :block
- parents[0]
- else
- node
- end
+ case type = tail[0]
+ when RBS::Types::Alias
+ alias_decl = service.latest_env.alias_decls[type.name]&.decl or raise
- context = typing.context_at(line: line, column: column)
+ location = tail[0].location
+ TypeAliasContent.new(
+ location: location,
+ decl: alias_decl
+ )
+ when RBS::Types::ClassInstance, RBS::Types::ClassSingleton
+ if hd == :name
+ env = service.latest_env
+ class_decl = env.class_decls[type.name]&.decls[0]&.decl or raise
+ location = tail[0].location[:name]
+ ClassContent.new(
+ location: location,
+ decl: class_decl
+ )
+ end
+ when RBS::Types::Interface
+ env = service.latest_env
+ interface_decl = env.interface_decls[type.name]&.decl or raise
+ location = type.location[:name]
- receiver_type = if receiver
- typing.type_of(node: receiver)
- else
- context.self_type
- end
+ InterfaceContent.new(
+ location: location,
+ decl: interface_decl
+ )
+ end
+ end
+ end
- factory = context.type_env.subtyping.factory
- method_name, definition = case receiver_type
- when AST::Types::Name::Instance
- method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
- if method_definition&.defined_in
- owner_name = method_definition.defined_in
- [
- InstanceMethodName.new(owner_name, method_name),
- method_definition
- ]
- end
- when AST::Types::Name::Singleton
- method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
- if method_definition&.defined_in
- owner_name = method_definition.defined_in
- [
- SingletonMethodName.new(owner_name, method_name),
- method_definition
- ]
- end
- else
- nil
- end
+ def hover_for_source(column, line, path, target)
+ file = service.source_files[path]
+ typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
+ node, *parents = typing.source.find_nodes(line: line, column: column)
- MethodCallContent.new(
- node: node,
- method_name: method_name,
- type: typing.type_of(node: result_node),
- definition: definition,
- location: result_node.location.expression
- )
- when :def, :defs
- context = typing.context_at(line: line, column: column)
- method_context = context.method_context
+ if node
+ case node.type
+ when :lvar
+ var_name = node.children[0]
+ context = typing.context_at(line: line, column: column)
+ var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
- if method_context && method_context.method
- DefinitionContent.new(
- node: node,
- method_name: method_context.name,
- method_type: method_context.method_type,
- definition: method_context.method,
- location: node.loc.expression
- )
- end
- else
- type = typing.type_of(node: node)
+ VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
+ when :lvasgn
+ var_name, rhs = node.children
+ context = typing.context_at(line: line, column: column)
+ type = context.lvar_env[var_name] || typing.type_of(node: rhs)
- TypeContent.new(
+ VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
+ when :send
+ receiver, method_name, *_ = node.children
+
+
+ result_node = if parents[0]&.type == :block
+ parents[0]
+ else
+ node
+ end
+
+ context = typing.context_at(line: line, column: column)
+
+ receiver_type = if receiver
+ typing.type_of(node: receiver)
+ else
+ context.self_type
+ end
+
+ factory = context.type_env.subtyping.factory
+ method_name, definition = case receiver_type
+ when AST::Types::Name::Instance
+ method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
+ if method_definition&.defined_in
+ owner_name = method_definition.defined_in
+ [
+ InstanceMethodName.new(owner_name, method_name),
+ method_definition
+ ]
+ end
+ when AST::Types::Name::Singleton
+ method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
+ if method_definition&.defined_in
+ owner_name = method_definition.defined_in
+ [
+ SingletonMethodName.new(owner_name, method_name),
+ method_definition
+ ]
+ end
+ else
+ nil
+ end
+
+ MethodCallContent.new(
+ node: node,
+ method_name: method_name,
+ type: typing.type_of(node: result_node),
+ definition: definition,
+ location: result_node.location.expression
+ )
+ when :def, :defs
+ context = typing.context_at(line: line, column: column)
+ method_context = context.method_context
+
+ if method_context && method_context.method
+ DefinitionContent.new(
node: node,
- type: type,
- location: node.location.expression
+ method_name: method_context.name,
+ method_type: method_context.method_type,
+ definition: method_context.method,
+ location: node.loc.expression
)
end
+ else
+ type = typing.type_of(node: node)
+
+ TypeContent.new(
+ node: node,
+ type: type,
+ location: node.location.expression
+ )
end
end
end
end
end