diff --git a/spec/ameba/rule/lint/literal_in_condition_spec.cr b/spec/ameba/rule/lint/literal_in_condition_spec.cr index 120a840c..8150ad2b 100644 --- a/spec/ameba/rule/lint/literal_in_condition_spec.cr +++ b/spec/ameba/rule/lint/literal_in_condition_spec.cr @@ -44,16 +44,122 @@ module Ameba::Rule::Lint subject.catch(s).should_not be_valid end - it "fails if there is a predicate in case conditional" do - s = Source.new %( - case [1, 2, 3] - when :array - :ok - when :not_array - :also_ok - end - ) - subject.catch(s).should_not be_valid + describe "range" do + it "reports range with literals" do + s = Source.new %( + case 1..2 + end + ) + subject.catch(s).should_not be_valid + end + + it "doesn't report range with non-literals" do + s = Source.new %( + case (1..a) + end + ) + subject.catch(s).should be_valid + end + end + + describe "array" do + it "reports array with literals" do + s = Source.new %( + case [1, 2, 3] + when :array + :ok + when :not_array + :also_ok + end + ) + subject.catch(s).should_not be_valid + end + + it "doesn't report array with non-literals" do + s = Source.new %( + a, b = 1, 2 + case [1, 2, a] + when :array + :ok + when :not_array + :also_ok + end + ) + subject.catch(s).should be_valid + end + end + + describe "hash" do + it "reports hash with literals" do + s = Source.new %( + case { "name" => 1, 33 => 'b' } + when :hash + :ok + end + ) + subject.catch(s).should_not be_valid + end + + it "doesn't report hash with non-literals in keys" do + s = Source.new %( + case { a => 1, 33 => 'b' } + when :hash + :ok + end + ) + subject.catch(s).should be_valid + end + + it "doesn't report hash with non-literals in values" do + s = Source.new %( + case { "name" => a, 33 => 'b' } + when :hash + :ok + end + ) + subject.catch(s).should be_valid + end + end + + describe "tuple" do + it "reports tuple with literals" do + s = Source.new %( + case {1, false} + when {1, _} + :ok + end + ) + subject.catch(s).should_not be_valid + end + + it "doesn't report tuple with non-literals" do + s = Source.new %( + a, b = 1, 2 + case {1, b} + when {1, 2} + :ok + end + ) + subject.catch(s).should be_valid + end + end + + describe "named tuple" do + it "reports named tuple with literals" do + s = Source.new %( + case { name: 1, foo: :bar} + end + ) + subject.catch(s).should_not be_valid + end + + it "doesn't report named tuple with non-literals" do + s = Source.new %( + case { name: a, foo: :bar} + end + ) + subject.catch(s).should be_valid + end end it "reports rule, pos and message" do diff --git a/src/ameba/ast/util.cr b/src/ameba/ast/util.cr index b00b3a09..ff97006b 100644 --- a/src/ameba/ast/util.cr +++ b/src/ameba/ast/util.cr @@ -2,7 +2,29 @@ module Ameba::AST::Util # Returns true if current `node` is a literal, false otherwise. def literal?(node) - node.try &.class.name.ends_with? "Literal" + case node + when Crystal::NilLiteral, + Crystal::BoolLiteral, + Crystal::NumberLiteral, + Crystal::CharLiteral, + Crystal::StringLiteral, + Crystal::SymbolLiteral, + Crystal::RegexLiteral, + Crystal::ProcLiteral, + Crystal::MacroLiteral + true + when Crystal::RangeLiteral + literal?(node.from) && literal?(node.to) + when Crystal::ArrayLiteral, + Crystal::TupleLiteral + node.elements.all? { |el| literal?(el) } + when Crystal::HashLiteral + node.entries.all? { |entry| literal?(entry.key) && literal?(entry.value) } + when Crystal::NamedTupleLiteral + node.entries.all? { |entry| literal?(entry.value) } + else + false + end end # Returns true if current `node` is a string literal, false otherwise.