Merge pull request #303 from crystal-ameba/Sija/lint-literal-assignments-in-expressions-rule

Add `Lint/LiteralAssignmentsInExpressions` rule
This commit is contained in:
Sijawusz Pur Rahnama 2022-11-17 14:19:17 +01:00 committed by GitHub
commit 496e8930e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 0 deletions

View File

@ -0,0 +1,47 @@
require "../../../spec_helper"
LITERAL_SAMPLES = {
nil, true, 42, 4.2, 'c', "foo", :foo, /foo/,
0..42, [1, 2, 3], {1, 2, 3},
{foo: :bar}, {:foo => :bar},
}
module Ameba::Rule::Lint
subject = LiteralAssignmentsInExpressions.new
describe LiteralAssignmentsInExpressions do
it "passes if the assignment value is not a literal" do
expect_no_issues subject, <<-CRYSTAL
if a = b
:ok
end
unless a = b.presence
:ok
end
:ok if a = b
:ok unless a = b
case {a, b}
when {0, 1} then :gt
when {1, 0} then :lt
end
CRYSTAL
end
{% for literal in LITERAL_SAMPLES %}
it %(reports if the assignment value is a {{ literal }} literal) do
expect_issue subject, <<-CRYSTAL, literal: {{ literal.stringify }}
raise "boo!" if foo = {{ literal }}
# ^{literal}^^^^^^ error: Detected assignment with a literal value in control expression
CRYSTAL
expect_issue subject, <<-CRYSTAL, literal: {{ literal.stringify }}
raise "boo!" unless foo = {{ literal }}
# ^{literal}^^^^^^ error: Detected assignment with a literal value in control expression
CRYSTAL
end
{% end %}
end
end

View File

@ -0,0 +1,43 @@
module Ameba::Rule::Lint
# A rule that disallows assignments with literal values
# in control expressions.
#
# For example, this is considered invalid:
#
# ```
# if foo = 42
# do_something
# end
# ```
#
# And most likely should be replaced by the following:
#
# ```
# if foo == 42
# do_something
# end
# ```
#
# YAML configuration example:
#
# ```
# Lint/LiteralAssignmentsInExpressions:
# Enabled: true
# ```
class LiteralAssignmentsInExpressions < Base
include AST::Util
properties do
description "Disallows assignments with literal values in control expressions"
end
MSG = "Detected assignment with a literal value in control expression"
def test(source, node : Crystal::If | Crystal::Unless | Crystal::Case | Crystal::While | Crystal::Until)
return unless (cond = node.cond).is_a?(Crystal::Assign)
return unless literal?(cond.value, include_paths: true)
issue_for cond, MSG
end
end
end