lib/rubocop/cop/rbs/style/empty_argument.rb in rubocop-on-rbs-0.4.0 vs lib/rubocop/cop/rbs/style/empty_argument.rb in rubocop-on-rbs-0.5.0

- old
+ new

@@ -15,88 +15,155 @@ # def foo: () -> ^ -> void # # # good # def foo: () { () -> void } -> ^() -> void class EmptyArgument < RuboCop::RBS::CopBase - extend AutoCorrector + class MethodTypeChecker + include RuboCop::RBS::OnTypeHelper - MSG = 'Insert `()` when empty argument' + def initialize(base_type: nil, &block) + @base_type = base_type + @base = base_type.location.start_pos + @tokens = tokenize(base_type.location.source) + @block = block + end - def on_rbs_def(decl) - decl.overloads.each do |overload| - if !overload.method_type.location.source.start_with?('(') - range = range_between(overload.method_type.location.start_pos, overload.method_type.location.start_pos) - add_offense(range) do |corrector| - corrector.insert_before(range, '()') - end + def check + check_method_argument + if @base_type.block + check_block_argument end - if overload.method_type.block - tokens = tokenize(overload.method_type.location.source) - block_arrow_index = tokens.find_index { |t| t.type == :pARROW } or raise - if tokens[block_arrow_index - 1].type != :pRPAREN - range = range_between( - overload.method_type.location.start_pos + tokens[block_arrow_index].location.start_pos, - overload.method_type.location.start_pos + tokens[block_arrow_index].location.start_pos - ) - add_offense(range) do |corrector| - corrector.insert_before(range, '()') - end - end + @base_type.each_type do |type| + check_type(type) end + end - overload.method_type.each_type do |type| - check_type(type) + # [T] () -> void + def check_method_argument + if @base_type.type_params.empty? + will_lparen_token = @tokens[0] + else + rbracket_index = @tokens.index do |token| + token.location.start_pos + @base >= @base_type.type_params.last.location.end_pos + end or raise + raise unless @tokens[rbracket_index].type == :pRBRACKET + + will_lparen_token = @tokens[rbracket_index + 1] end + + if will_lparen_token.type != :pLPAREN + @block.call( + @base + will_lparen_token.location.start_pos, + @base + will_lparen_token.location.start_pos + 1 + ) + end end - end - def on_rbs_constant(const) - check_type(const.type) - end - alias on_rbs_global on_rbs_constant - alias on_rbs_type_alias on_rbs_constant - alias on_rbs_attribute on_rbs_constant + # { () [self: instance] -> void } -> void + def check_block_argument + return unless @base_type.block + return unless @base_type.block.type.each_param.first.nil? - def check_type(type) - case type - when ::RBS::Types::Proc - check_proc(type) - else - type.each_type do |t| - check_type(t) + if @base_type.block.self_type + self_type_index = bsearch_token_index(@base_type.block.self_type.location.start_pos) + # ) [self: + # ^ ^^ ^ => pRPAREN, pLBRACKET, kSELF, pCOLON + rparen = @tokens[self_type_index - 4] + after_rparen = @tokens[self_type_index - 3] + else + block_arrow_index = @tokens.find_index { |t| t.type == :pARROW } or raise + rparen = @tokens[block_arrow_index - 1] + after_rparen = @tokens[block_arrow_index] end + + if rparen.type != :pRPAREN + @block.call( + @base + after_rparen.location.start_pos, + @base + after_rparen.location.start_pos + 1 + ) + end end - end - def check_proc(type) - tokens = tokenize(type.location.source) - if tokens[1].type != :pLPAREN - range = range_between( - type.location.start_pos + tokens[0].location.end_pos, - type.location.start_pos + tokens[0].location.end_pos - ) - add_offense(range) do |corrector| - corrector.insert_after(range, '()') + def check_type(type = @base_type) + on_type([::RBS::Types::Proc], type) do |proc_type| + check_proc(proc_type) end end - if type.block - block_arrow_index = tokens.find_index { |t| t.type == :pARROW } or raise - if tokens[block_arrow_index - 1].type != :pRPAREN - range = range_between( - type.location.start_pos + tokens[block_arrow_index].location.start_pos, - type.location.start_pos + tokens[block_arrow_index].location.start_pos + def check_proc(type) + proc_start_index = bsearch_token_index(type.location.start_pos) + proc_end_index = bsearch_token_index(type.location.end_pos) + if @tokens[proc_start_index + 1].type != :pLPAREN + @block.call( + @base + @tokens[proc_start_index + 1].location.start_pos, + @base + @tokens[proc_start_index + 1].location.start_pos + 1 ) - add_offense(range) do |corrector| - corrector.insert_before(range, '()') + end + + if type.block + if type.block&.self_type + self_type_index = bsearch_token_index(type.block.self_type.location.start_pos) + # ) [self: + # ^ ^^ ^ => pRPAREN, pLBRACKET, kSELF, pCOLON + rparen = @tokens[self_type_index - 4] + after_rparen = @tokens[self_type_index - 3] + else + block_arrow_index = @tokens[proc_start_index...proc_end_index].find_index { |t| + t.type == :pARROW + } or raise + block_arrow_index += proc_start_index + rparen = @tokens[block_arrow_index - 1] + after_rparen = @tokens[block_arrow_index] end + + if rparen.type != :pRPAREN + @block.call( + @base + after_rparen.location.start_pos, + @base + after_rparen.location.start_pos + 1 + ) + end end end + + private + + def bsearch_token_index(pos) + @tokens.bsearch_index do |token| + token.location.start_pos + @base >= pos + end or raise + end + + def tokenize(source) + ::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA } + end end - def tokenize(source) - ::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA } + extend AutoCorrector + + MSG = 'Insert `()` when empty argument' + + def on_rbs_def(decl) + decl.overloads.each do |overload| + MethodTypeChecker.new(base_type: overload.method_type) do |s, e| + range = range_between(s, e) + add_offense(range) do |corrector| + corrector.insert_before(range, '() ') + end + end.check + end end + + def on_rbs_constant(const) + MethodTypeChecker.new(base_type: const.type) do |s, e| + range = range_between(s, e) + add_offense(range) do |corrector| + corrector.insert_before(range, '() ') + end + end.check_type + end + alias on_rbs_global on_rbs_constant + alias on_rbs_type_alias on_rbs_constant + alias on_rbs_attribute on_rbs_constant end end end end end