Merge pull request #137 from crystal-ameba/feat/redundant-string-coercion

New rule: Lint/RedundantStringCoercion
This commit is contained in:
Vitalii Elenhaupt 2020-03-26 23:55:23 +02:00 committed by GitHub
commit 9c6bc2a376
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 133 additions and 0 deletions

View file

@ -0,0 +1,90 @@
require "../../../spec_helper"
module Ameba::Rule::Lint
describe RedundantStringCoercion do
subject = RedundantStringCoercion.new
it "does not report if there is no redundant string coersion" do
s = Source.new %(
"Hello, #{name}"
)
subject.catch(s).should be_valid
end
it "reports if there is a redundant string coersion" do
s = Source.new %q(
"Hello, #{name.to_s}"
)
subject.catch(s).should_not be_valid
end
it "does not report if coersion is used in binary op" do
s = Source.new %q(
"Hello, #{3.to_s + 's'}"
)
subject.catch(s).should be_valid
end
it "reports if coercion is used with symbol literals" do
s = Source.new %q("Hello, #{:symbol.to_s}")
subject.catch(s).should_not be_valid
end
it "reports if coercion is used with number literals" do
s = Source.new %q("Hello, #{42.to_s}")
subject.catch(s).should_not be_valid
end
it "reports if coercion is used with boolean literals" do
s = Source.new %q("Hello, #{false.to_s}")
subject.catch(s).should_not be_valid
end
it "reports if coercion is used with char literals" do
s = Source.new %q("Hello, #{'t'.to_s}")
subject.catch(s).should_not be_valid
end
it "reports redundant coercion in regex" do
s = Source.new %q(
/\w #{name.to_s}/
)
subject.catch(s).should_not be_valid
end
it "doesn't report if Object#to_s is called with arguments" do
s = Source.new %q(
/\w #{name.to_s(io)}/
)
subject.catch(s).should be_valid
end
it "doesn't report if Object#to_s is called without receiver" do
s = Source.new %q(
/\w #{to_s}/
)
subject.catch(s).should be_valid
end
it "reports rule, location and message" do
s = Source.new %q(
"Hello, #{name1.to_s}"
"Hello, #{name2.to_s}"
), "source.cr"
subject.catch(s).should_not be_valid
s.issues.size.should eq 2
issue = s.issues[0]
issue.rule.should_not be_nil
issue.location.to_s.should eq "source.cr:1:17"
issue.end_location.to_s.should eq "source.cr:1:20"
issue.message.should eq RedundantStringCoercion::MSG
issue = s.issues[1]
issue.rule.should_not be_nil
issue.location.to_s.should eq "source.cr:2:17"
issue.end_location.to_s.should eq "source.cr:2:20"
issue.message.should eq RedundantStringCoercion::MSG
end
end
end

View file

@ -0,0 +1,43 @@
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/RedundantStringCoersion
# Enabled: true
# ```
#
struct RedundantStringCoercion < Base
include AST::Util
properties do
description "Disallows redundant string conversions in interpolation"
end
MSG = "Redundant use of `Object#to_s` in interpolation"
def test(source, node : Crystal::StringInterpolation)
string_coercion_nodes(node).each { |n| issue_for n.name_location, n.end_location, MSG }
end
private def string_coercion_nodes(node)
node.expressions.select do |e|
e.is_a?(Crystal::Call) && e.name == "to_s" && e.args.size.zero? && e.obj
end
end
end
end