lib/rbi/parser.rb in rbi-0.1.14 vs lib/rbi/parser.rb in rbi-0.2.0

- old
+ new

@@ -167,26 +167,42 @@ @tree = T.let(Tree.new, Tree) @scopes_stack = T.let([@tree], T::Array[Tree]) @last_node = T.let(nil, T.nilable(Prism::Node)) @last_sigs = T.let([], T::Array[RBI::Sig]) - @last_sigs_comments = T.let([], T::Array[Comment]) end sig { override.params(node: Prism::ClassNode).void } def visit_class_node(node) @last_node = node - scope = Class.new( - node_string!(node.constant_path), - superclass_name: node_string(node.superclass), - loc: node_loc(node), - comments: node_comments(node), - ) + superclass_name = node_string(node.superclass) + scope = case superclass_name + when /^(::)?T::Struct$/ + TStruct.new( + node_string!(node.constant_path), + loc: node_loc(node), + comments: node_comments(node), + ) + when /^(::)?T::Enum$/ + TEnum.new( + node_string!(node.constant_path), + loc: node_loc(node), + comments: node_comments(node), + ) + else + Class.new( + node_string!(node.constant_path), + superclass_name: superclass_name, + loc: node_loc(node), + comments: node_comments(node), + ) + end current_scope << scope @scopes_stack << scope visit(node.body) + scope.nodes.concat(current_sigs) collect_dangling_comments(node) @scopes_stack.pop @last_node = nil end @@ -238,16 +254,23 @@ end sig { override.params(node: Prism::DefNode).void } def visit_def_node(node) @last_node = node + + # We need to collect the comments with `current_sigs_comments` _before_ visiting the parameters to make sure + # the method comments are properly associated with the sigs and not the parameters. + sigs = current_sigs + comments = detach_comments_from_sigs(sigs) + node_comments(node) + params = parse_params(node.parameters) + current_scope << Method.new( node.name.to_s, - params: parse_params(node.parameters), - sigs: current_sigs, + params: params, + sigs: sigs, loc: node_loc(node), - comments: current_sigs_comments + node_comments(node), + comments: comments, is_singleton: !!node.receiver, ) @last_node = nil end @@ -261,20 +284,21 @@ ) current_scope << scope @scopes_stack << scope visit(node.body) + scope.nodes.concat(current_sigs) collect_dangling_comments(node) @scopes_stack.pop @last_node = nil end sig { override.params(node: Prism::ProgramNode).void } def visit_program_node(node) @last_node = node super - + @tree.nodes.concat(current_sigs) collect_orphan_comments separate_header_comments set_root_tree_loc @last_node = nil end @@ -288,10 +312,11 @@ ) current_scope << scope @scopes_stack << scope visit(node.body) + scope.nodes.concat(current_sigs) collect_dangling_comments(node) @scopes_stack.pop @last_node = nil end @@ -312,64 +337,68 @@ unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any? @last_node = nil return end + sigs = current_sigs + comments = detach_comments_from_sigs(sigs) + node_comments(node) + current_scope << AttrReader.new( *T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }), - sigs: current_sigs, + sigs: sigs, loc: node_loc(node), - comments: current_sigs_comments + node_comments(node), + comments: comments, ) when "attr_writer" args = node.arguments unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any? @last_node = nil return end + sigs = current_sigs + comments = detach_comments_from_sigs(sigs) + node_comments(node) + current_scope << AttrWriter.new( *T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }), - sigs: current_sigs, + sigs: sigs, loc: node_loc(node), - comments: current_sigs_comments + node_comments(node), + comments: comments, ) when "attr_accessor" args = node.arguments unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any? @last_node = nil return end + sigs = current_sigs + comments = detach_comments_from_sigs(sigs) + node_comments(node) + current_scope << AttrAccessor.new( *T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }), - sigs: current_sigs, + sigs: sigs, loc: node_loc(node), - comments: current_sigs_comments + node_comments(node), + comments: comments, ) when "enums" - block = node.block - - unless block.is_a?(Prism::BlockNode) - @last_node = nil - return + if node.block && node.arguments.nil? + scope = TEnumBlock.new(loc: node_loc(node), comments: node_comments(node)) + current_scope << scope + @scopes_stack << scope + visit(node.block) + @scopes_stack.pop + else + current_scope << Send.new( + message, + parse_send_args(node.arguments), + loc: node_loc(node), + comments: node_comments(node), + ) end - - body = block.body - - unless body.is_a?(Prism::StatementsNode) - @last_node = nil - return - end - - current_scope << TEnumBlock.new( - body.body.map { |stmt| T.cast(stmt, Prism::ConstantWriteNode).name.to_s }, - loc: node_loc(node), - comments: node_comments(node), - ) when "extend" args = node.arguments unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any? @last_node = nil @@ -413,10 +442,17 @@ visit(node.arguments) last_node = @scopes_stack.last&.nodes&.last case last_node when Method, Attr last_node.visibility = parse_visibility(node.name.to_s, node) + when Send + current_scope << Send.new( + message, + parse_send_args(node.arguments), + loc: node_loc(node), + comments: node_comments(node), + ) else raise ParseError.new( "Unexpected token `#{node.message}` before `#{last_node&.string&.strip}`", node_loc(node), ) @@ -468,11 +504,11 @@ first_line = node.location.start_line last_line = node.location.end_line last_node_last_line = node.child_nodes.last&.location&.end_line - last_line.downto(first_line) do |line| + first_line.upto(last_line) do |line| comment = @comments_by_line[line] next unless comment break if last_node_last_line && line <= last_node_last_line current_scope << parse_comment(comment) @@ -514,14 +550,19 @@ sigs = @last_sigs.dup @last_sigs.clear sigs end - sig { returns(T::Array[Comment]) } - def current_sigs_comments - comments = @last_sigs_comments.dup - @last_sigs_comments.clear + sig { params(sigs: T::Array[Sig]).returns(T::Array[Comment]) } + def detach_comments_from_sigs(sigs) + comments = T.let([], T::Array[Comment]) + + sigs.each do |sig| + comments += sig.comments.dup + sig.comments.clear + end + comments end sig { params(node: Prism::Node).returns(T::Array[Comment]) } def node_comments(node) @@ -644,15 +685,14 @@ params end sig { params(node: Prism::CallNode).returns(Sig) } def parse_sig(node) - @last_sigs_comments = node_comments(node) - builder = SigBuilder.new(@source, file: @file) builder.current.loc = node_loc(node) builder.visit_call_node(node) + builder.current.comments = node_comments(node) builder.current end sig { params(node: T.any(Prism::ConstantWriteNode, Prism::ConstantPathWriteNode)).returns(T.nilable(Struct)) } def parse_struct(node) @@ -743,15 +783,15 @@ sig { params(name: String, node: Prism::Node).returns(Visibility) } def parse_visibility(name, node) case name when "public" - Public.new(loc: node_loc(node)) + Public.new(loc: node_loc(node), comments: node_comments(node)) when "protected" - Protected.new(loc: node_loc(node)) + Protected.new(loc: node_loc(node), comments: node_comments(node)) when "private" - Private.new(loc: node_loc(node)) + Private.new(loc: node_loc(node), comments: node_comments(node)) else raise ParseError.new("Unexpected visibility `#{name}`", node_loc(node)) end end @@ -779,14 +819,11 @@ ) end sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) } def type_variable_definition?(node) - return false unless node.is_a?(Prism::CallNode) - return false unless node.block - - node.message == "type_member" || node.message == "type_template" + node.is_a?(Prism::CallNode) && (node.message == "type_member" || node.message == "type_template") end end class SigBuilder < Visitor extend T::Sig @@ -837,10 +874,10 @@ args.arguments.each do |arg| @current.type_params << node_string!(arg).delete_prefix(":") end end when "void" - @current.return_type = nil + @current.return_type = "void" end visit(node.receiver) visit(node.block) end