Skip to content

Commit

Permalink
Merge pull request #303 from crystal-ameba/Sija/lint-literal-assignme…
Browse files Browse the repository at this point in the history
…nts-in-expressions-rule

Add `Lint/LiteralAssignmentsInExpressions` rule
  • Loading branch information
Sija committed Nov 17, 2022
2 parents 2430717 + 5c08b64 commit 496e893
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
47 changes: 47 additions & 0 deletions spec/ameba/rule/lint/literal_assignments_in_expressions_spec.cr
Original file line number Diff line number Diff line change
@@ -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
43 changes: 43 additions & 0 deletions src/ameba/rule/lint/literal_assignments_in_expressions.cr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 496e893

Please sign in to comment.