module RuboCop::Cop::Style::MethodCallWithArgsParentheses::OmitParentheses

def allowed_camel_case_method_call?(node)

def allowed_camel_case_method_call?(node)
  node.camel_case_method? &&
    (node.arguments.none? ||
    cop_config['AllowParenthesesInCamelCaseMethod'])
end

def allowed_chained_call_with_parentheses?(node)

def allowed_chained_call_with_parentheses?(node)
  return false unless cop_config['AllowParenthesesInChaining']
  previous = node.descendants.first
  return false unless previous&.send_type?
  previous.parenthesized? ||
    allowed_chained_call_with_parentheses?(previous)
end

def allowed_multiline_call_with_parentheses?(node)

def allowed_multiline_call_with_parentheses?(node)
  cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
end

def ambigious_literal?(node)

def ambigious_literal?(node)
  splat?(node) || ternary_if?(node) || regexp_slash_literal?(node) ||
    unary_literal?(node)
end

def assigned_before?(node, target)

def assigned_before?(node, target)
  node.assignment? &&
    node.loc.operator.begin < target.loc.begin
end

def auto_correct(corrector, node)

def auto_correct(corrector, node)
  if parentheses_at_the_end_of_multiline_call?(node)
    corrector.replace(args_begin(node), ' \\')
  else
    corrector.replace(args_begin(node), ' ')
  end
  corrector.remove(node.loc.end)
end

def call_as_argument_or_chain?(node)

def call_as_argument_or_chain?(node)
  node.parent &&
    (node.parent.send_type? && !assigned_before?(node.parent, node) ||
    node.parent.csend_type? || node.parent.super_type?)
end

def call_in_literals?(node)

def call_in_literals?(node)
  node.parent &&
    (node.parent.pair_type? ||
    node.parent.array_type? ||
    node.parent.range_type? ||
    splat?(node.parent) ||
    ternary_if?(node.parent))
end

def call_in_logical_operators?(node)

def call_in_logical_operators?(node)
  parent = node.parent&.block_type? ? node.parent.parent : node.parent
  parent &&
    (logical_operator?(parent) ||
    parent.send_type? &&
    parent.arguments.any? { |argument| logical_operator?(argument) })
end

def call_in_optional_arguments?(node)

def call_in_optional_arguments?(node)
  node.parent &&
    (node.parent.optarg_type? || node.parent.kwoptarg_type?)
end

def call_in_single_line_inheritance?(node)

def call_in_single_line_inheritance?(node)
  node.parent&.class_type? && node.parent&.single_line?
end

def call_with_ambiguous_arguments?(node)

def call_with_ambiguous_arguments?(node)
  call_with_braced_block?(node) ||
    call_as_argument_or_chain?(node) ||
    hash_literal_in_arguments?(node) ||
    node.descendants.any? do |n|
      ambigious_literal?(n) || logical_operator?(n) ||
        call_with_braced_block?(n)
    end
end

def call_with_braced_block?(node)

def call_with_braced_block?(node)
  (node.send_type? || node.super_type?) &&
    node.block_node && node.block_node.braces?
end

def hash_literal?(node)

def hash_literal?(node)
  node.hash_type? && node.braces?
end

def hash_literal_in_arguments?(node)

def hash_literal_in_arguments?(node)
  node.arguments.any? do |n|
    hash_literal?(n) ||
      n.send_type? && node.descendants.any? { |descendant| hash_literal?(descendant) }
  end
end

def inside_endless_method_def?(node)

def inside_endless_method_def?(node)
  # parens are required around arguments inside an endless method
  node.each_ancestor(:def).any?(&:endless?) && node.arguments.any?
end

def legitimate_call_with_parentheses?(node)

def legitimate_call_with_parentheses?(node)
  call_in_literals?(node) ||
    call_with_ambiguous_arguments?(node) ||
    call_in_logical_operators?(node) ||
    call_in_optional_arguments?(node) ||
    call_in_single_line_inheritance?(node) ||
    allowed_multiline_call_with_parentheses?(node) ||
    allowed_chained_call_with_parentheses?(node)
end

def logical_operator?(node)

def logical_operator?(node)
  (node.and_type? || node.or_type?) && node.logical_operator?
end

def offense_range(node)

def offense_range(node)
  node.loc.begin.join(node.loc.end)
end

def omit_parentheses(node)

def omit_parentheses(node)
  return unless node.parenthesized?
  return if inside_endless_method_def?(node)
  return if node.implicit_call?
  return if super_call_without_arguments?(node)
  return if allowed_camel_case_method_call?(node)
  return if legitimate_call_with_parentheses?(node)
  add_offense(offense_range(node), message: OMIT_MSG) do |corrector|
    auto_correct(corrector, node)
  end
end

def parentheses_at_the_end_of_multiline_call?(node)

def parentheses_at_the_end_of_multiline_call?(node)
  node.multiline? &&
    node.loc.begin.source_line
        .gsub(TRAILING_WHITESPACE_REGEX, '')
        .end_with?('(')
end

def regexp_slash_literal?(node)

def regexp_slash_literal?(node)
  node.regexp_type? && node.loc.begin.source == '/'
end

def splat?(node)

def splat?(node)
  node.splat_type? || node.kwsplat_type? || node.block_pass_type?
end

def super_call_without_arguments?(node)

def super_call_without_arguments?(node)
  node.super_type? && node.arguments.none?
end

def ternary_if?(node)

def ternary_if?(node)
  node.if_type? && node.ternary?
end

def unary_literal?(node)

def unary_literal?(node)
  node.numeric_type? && node.sign? ||
    node.parent&.send_type? && node.parent&.unary_operation?
end