New rule: literal in the interpolation

This commit is contained in:
Vitalii Elenhaupt 2017-11-01 14:18:28 +02:00
parent 6a81a648e3
commit 64ccc7448c
No known key found for this signature in database
GPG key ID: 7558EF3A4056C706
5 changed files with 86 additions and 0 deletions

View file

@ -35,5 +35,15 @@ module Ameba::AST
subject.literal?(Crystal::Nop).should be_false
end
end
describe "#string_literal?" do
it "returns true if node is a string literal" do
subject.string_literal?(Crystal::StringLiteral.new "").should be_true
end
it "returns false if node is not a string literal" do
subject.string_literal?(Crystal::Nop.new).should be_false
end
end
end
end

View file

@ -0,0 +1,41 @@
require "../../spec_helper"
module Ameba::Rules
subject = LiteralInInterpolation.new
describe LiteralInInterpolation do
it "passes with good interpolation examples" do
s = Source.new %q(
name = "Ary"
"Hello, #{name}"
"#{name}"
"Name size: #{name.size}"
)
subject.catch(s).valid?.should be_true
end
it "fails if there is useless interpolation" do
[
%q("#{:Ary}"),
%q("#{[1, 2, 3]}"),
%q("#{true}"),
%q("#{false}"),
%q("here are #{4} cats"),
].each do |str|
subject.catch(Source.new str).valid?.should be_false
end
end
it "reports rule, pos and message" do
s = Source.new %q("#{4}")
subject.catch(s).valid?.should be_false
error = s.errors.first
error.rule.should_not be_nil
error.pos.should eq 1
error.message.should eq "Literal value found in interpolation"
end
end
end

View file

@ -5,6 +5,7 @@ module Ameba::AST
Call,
Case,
If,
StringInterpolation,
Unless,
]

View file

@ -2,4 +2,8 @@ module Ameba::AST::Util
def literal?(node)
node.try &.class.name.ends_with? "Literal"
end
def string_literal?(node)
node.is_a? Crystal::StringLiteral
end
end

View file

@ -0,0 +1,30 @@
module Ameba::Rules
# A rule that disallows useless string interpolations
# that contain a literal value instead of a variable or function.
#
# For example:
#
# ```
# "Hello, #{:Ary}"
# "The are #{4} cats"
# ```
#
struct LiteralInInterpolation < Rule
include AST::Util
def test(source)
AST::StringInterpolationVisitor.new self, source
end
def test(source, node : Crystal::StringInterpolation)
has_literal = node.expressions.any? do |e|
!string_literal?(e) && literal?(e)
end
return unless has_literal
source.error self, node.location.try &.line_number,
"Literal value found in interpolation"
end
end
end