# frozen_string_literal: truemoduleRuboCopmoduleCopmodulePerformance# In Ruby 2.4, `String#match?`, `Regexp#match?` and `Symbol#match?`# have been added. The methods are faster than `match`.# Because the methods avoid creating a `MatchData` object or saving# backref.# So, when `MatchData` is not used, use `match?` instead of `match`.## @example# # bad# def foo# if x =~ /re/# do_something# end# end## # bad# def foo# if x !~ /re/# do_something# end# end## # bad# def foo# if x.match(/re/)# do_something# end# end## # bad# def foo# if /re/ === x# do_something# end# end## # good# def foo# if x.match?(/re/)# do_something# end# end## # good# def foo# if !x.match?(/re/)# do_something# end# end## # good# def foo# if x =~ /re/# do_something(Regexp.last_match)# end# end## # good# def foo# if x.match(/re/)# do_something($~)# end# end## # good# def foo# if /re/ === x# do_something($~)# end# endclassRegexpMatch<CopextendTargetRubyVersionminimum_target_ruby_version2.4# Constants are included in this list because it is unlikely that# someone will store `nil` as a constant and then use it for comparisonTYPES_IMPLEMENTING_MATCH=%i[const regexp str sym].freezeMSG='Use `match?` instead of `%<current>s` when `MatchData` '\'is not used.'.freezedef_node_matcher:match_method?,<<-PATTERN
{
(send _recv :match _)
(send _recv :match _ (int ...))
}
PATTERNdef_node_matcher:match_operator?,<<-PATTERN
(send !nil? {:=~ :!~} !nil?)
PATTERNdef_node_matcher:match_threequals?,<<-PATTERN
(send (regexp (str _) {(regopt) (regopt _)}) :=== !nil?)
PATTERNdefmatch_with_lvasgn?(node)returnfalseunlessnode.match_with_lvasgn_type?regexp,_rhs=*noderegexp.to_regexp.named_captures.empty?endMATCH_NODE_PATTERN=<<-PATTERN.freeze
{
#match_method?
#match_operator?
#match_threequals?
#match_with_lvasgn?
}
PATTERNdef_node_matcher:match_node?,MATCH_NODE_PATTERNdef_node_search:search_match_nodes,MATCH_NODE_PATTERNdef_node_search:last_matches,<<-PATTERN
{
(send (const nil? :Regexp) :last_match)
(send (const nil? :Regexp) :last_match _)
({back_ref nth_ref} _)
(gvar #match_gvar?)
}
PATTERNdefon_if(node)check_condition(node.condition)enddefon_case(node)returnifnode.conditionnode.each_whendo|when_node|when_node.each_conditiondo|condition|check_condition(condition)endendenddefautocorrect(node)lambdado|corrector|ifmatch_method?(node)corrector.replace(node.loc.selector,'match?')elsifmatch_operator?(node)||match_threequals?(node)recv,oper,arg=*nodecorrect_operator(corrector,recv,arg,oper)elsifmatch_with_lvasgn?(node)recv,arg=*nodecorrect_operator(corrector,recv,arg)endendendprivatedefcheck_condition(cond)match_node?(cond)doreturniflast_match_used?(cond)add_offense(cond)endenddefmessage(node)format(MSG,current: node.loc.selector.source)enddeflast_match_used?(match_node)scope_root=scope_root(match_node)body=scope_root?scope_body(scope_root):match_node.ancestors.lastreturntrueifmatch_node.parent.if_type?&&match_node.parent.modifier_form?match_node_pos=match_node.loc.expression.begin_posnext_match_pos=next_match_pos(body,match_node_pos,scope_root)range=match_node_pos..next_match_posfind_last_match(body,range,scope_root)enddefnext_match_pos(body,match_node_pos,scope_root)node=search_match_nodes(body).finddo|match|match.loc.expression.begin_pos>match_node_pos&&scope_root(match)==scope_rootendnode?node.loc.expression.begin_pos:Float::INFINITYenddeffind_last_match(body,range,scope_root)last_matches(body).finddo|ref|ref_pos=ref.loc.expression.begin_posrange.cover?(ref_pos)&&scope_root(ref)==scope_rootendenddefscope_body(node)children=node.childrencasenode.typewhen:modulechildren[1]when:defschildren[3]elsechildren[2]endenddefscope_root(node)node.each_ancestor.finddo|ancestor|ancestor.def_type?||ancestor.defs_type?||ancestor.class_type?||ancestor.module_type?endenddefmatch_gvar?(sym)%i[
$~
$MATCH
$PREMATCH
$POSTMATCH
$LAST_PAREN_MATCH
$LAST_MATCH_INFO
].include?(sym)enddefcorrect_operator(corrector,recv,arg,oper=nil)op_range=correction_range(recv,arg)ifTYPES_IMPLEMENTING_MATCH.include?(recv.type)corrector.replace(op_range,'.match?(')elsifTYPES_IMPLEMENTING_MATCH.include?(arg.type)corrector.replace(op_range,'.match?(')swap_receiver_and_arg(corrector,recv,arg)elsecorrector.replace(op_range,'&.match?(')endcorrector.insert_after(arg.loc.expression,')')corrector.insert_before(recv.loc.expression,'!')ifoper==:!~enddefswap_receiver_and_arg(corrector,recv,arg)corrector.replace(recv.loc.expression,arg.source)corrector.replace(arg.loc.expression,recv.source)enddefcorrection_range(recv,arg)buffer=processed_source.bufferop_begin_pos=recv.loc.expression.end_posop_end_pos=arg.loc.expression.begin_posParser::Source::Range.new(buffer,op_begin_pos,op_end_pos)endendendendend