rrubocop 0.8.15

10x faster RuboCop drop-in. Same output format and configs, without maintaining RuboCop gems.
use tree_sitter::Node;

use crate::cop::shared::{call_method_name, call_receiver};
use crate::parse::source::SourceFile;

use super::common::{binary_op, literal_or_const, sides, unwrap};

fn match_target<'a>(_source: &'a SourceFile, lhs: Node<'a>, rhs: Node<'a>) -> Option<Node<'a>> {
    if lhs.kind() == "regex" {
        return (rhs.kind() == "identifier").then_some(rhs);
    }
    if rhs.kind() == "regex" {
        return (lhs.kind() == "identifier").then_some(lhs);
    }
    None
}

fn equality_target<'a>(source: &'a SourceFile, l: Node<'a>, r: Node<'a>) -> Option<Node<'a>> {
    let l = unwrap(l);
    let r = unwrap(r);
    if literal_or_const(source, l) && r.kind() == "identifier" {
        return Some(r);
    }
    if literal_or_const(source, r) && l.kind() == "identifier" {
        return Some(l);
    }
    None
}

fn find_target_binary<'a>(source: &'a SourceFile, n: Node<'a>) -> Option<Node<'a>> {
    let op = binary_op(source, n)?;
    let (l, r) = sides(n)?;
    match op {
        b"=~" => match_target(source, l, r),
        b"==" | b"eql?" | b"equal?" | b"===" => equality_target(source, l, r),
        _ => None,
    }
}

fn find_target_call<'a>(source: &'a SourceFile, n: Node<'a>) -> Option<Node<'a>> {
    let meth = call_method_name(source, n)?;
    let recv = call_receiver(n)?;
    let arg = crate::cop::shared::argument_nodes(n).first().copied()?;
    match meth {
        b"=~" | b"match" | b"match?" => match_target(source, recv, arg),
        b"is_a?" if recv.kind() == "identifier" => Some(arg),
        b"include?" | b"cover?" if recv.kind() == "range" => Some(recv),
        _ => None,
    }
}

pub(super) fn find_target<'a>(source: &'a SourceFile, node: Node<'a>) -> Option<Node<'a>> {
    let n = unwrap(node);
    if n.kind() == "call" {
        return find_target_call(source, n);
    }
    if n.kind() != "binary" {
        return None;
    }
    if binary_op(source, n) == Some(b"||") {
        return find_target(source, sides(n)?.0);
    }
    find_target_binary(source, n)
}