module Ameba::Rule::Lint
  # A rule that disallows string conversion in string interpolation,
  # which is redundant.
  #
  # For example, this is considered invalid:
  #
  # ```
  # "Hello, #{name.to_s}"
  # ```
  #
  # And this is valid:
  #
  # ```
  # "Hello, #{name}"
  # ```
  #
  # YAML configuration example:
  #
  # ```
  # Lint/RedundantStringCoercion:
  #   Enabled: true
  # ```
  class RedundantStringCoercion < Base
    include AST::Util

    properties do
      since_version "0.12.0"
      description "Disallows redundant string conversions in interpolation"
    end

    MSG = "Redundant use of `Object#to_s` in interpolation"

    def test(source, node : Crystal::StringInterpolation)
      each_string_coercion_node(node) do |expr|
        begin_location = name_location(expr)
        end_location = expr.end_location

        if begin_location && end_location
          issue_for(begin_location, end_location, MSG) do |corrector|
            corrector.remove(
              begin_location.adjust(column_number: -1),
              end_location,
            )
          end
        else
          issue_for(begin_location, end_location, MSG)
        end
      end
    end

    private def each_string_coercion_node(node, &)
      node.expressions.each do |exp|
        yield exp if exp.is_a?(Crystal::Call) &&
                     exp.name == "to_s" &&
                     exp.obj &&
                     !has_arguments?(exp)
      end
    end
  end
end
