Fix the edge case re: free var comparison

This commit is contained in:
Sijawusz Pur Rahnama 2022-11-13 00:24:58 +01:00
parent 35ff16206c
commit 5491d31b5f
2 changed files with 24 additions and 0 deletions

View file

@ -41,6 +41,13 @@ module Ameba::Rule::Lint
CRYSTAL CRYSTAL
end end
pending "reports if there is a static path comparison evaluating to false" do
expect_issue subject, <<-CRYSTAL
String == Nil
# ^^^^^^^^^^^ error: Comparison always evaluates to false
CRYSTAL
end
context "macro" do context "macro" do
it "reports in macro scope" do it "reports in macro scope" do
expect_issue subject, <<-CRYSTAL expect_issue subject, <<-CRYSTAL
@ -48,6 +55,12 @@ module Ameba::Rule::Lint
# ^^^^^^^^^^^^^^ error: Comparison always evaluates to true # ^^^^^^^^^^^^^^ error: Comparison always evaluates to true
CRYSTAL CRYSTAL
end end
it "passes for free variables comparisons in macro scope" do
expect_no_issues subject, <<-CRYSTAL
{{ T == Nil }}
CRYSTAL
end
end end
it "reports rule, pos and message" do it "reports rule, pos and message" do

View file

@ -59,6 +59,17 @@ module Ameba::Rule::Lint
return unless obj.class.in?(LITERAL_TYPES) && return unless obj.class.in?(LITERAL_TYPES) &&
arg.class.in?(LITERAL_TYPES) arg.class.in?(LITERAL_TYPES)
# Edge-case: `{{ T == Nil }}`
#
# Current implementation works for any single name path comparisons:
# `String == Nil`, regardless of the free variable being present.
#
# Ideally we should only check whether either of the sides
# is a free var
if obj.is_a?(Crystal::Path) && arg.is_a?(Crystal::Path)
return if obj.single_name? && arg.single_name? && (obj != arg)
end
is_dynamic = obj.class.in?(DYNAMIC_LITERAL_TYPES) || is_dynamic = obj.class.in?(DYNAMIC_LITERAL_TYPES) ||
arg.class.in?(DYNAMIC_LITERAL_TYPES) arg.class.in?(DYNAMIC_LITERAL_TYPES)