Skip to content

Commit

Permalink
Add Lint/LogicalWithoutParenthesis (crystal-ameba#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
nobodywasishere committed Nov 23, 2024
1 parent 51cb88e commit ba5fb8e
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
44 changes: 44 additions & 0 deletions spec/ameba/rule/lint/logical_without_paren_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require "../../../spec_helper"

module Ameba::Rule::Lint
describe LogicalWithoutParenthesis do
subject = LogicalWithoutParenthesis.new

it "passes if logical operator in call args has parenthesis" do
expect_no_issues subject, <<-CRYSTAL
if foo.includes?("bar" || foo.includes? "batz")
puts "this code is bug-free"
end
if foo.includes?("bar") || foo.includes?("batz")
puts "this code is bug-free"
end
form.add("query", "val_1" || "val_2")
form.add "query", ("val_1" || "val_2")
CRYSTAL
end

it "passes if logical operator in assignment call" do
expect_no_issues subject, <<-CRYSTAL
hello.there = "world" || method.call
CRYSTAL
end

it "passes if logical operator in square bracket call" do
expect_no_issues subject, <<-CRYSTAL
hello["world" || :thing]
this.is[1 || method.call]
CRYSTAL
end

it "fails if logical operator in call args doesn't have parenthesis" do
expect_issue subject, <<-CRYSTAL
if foo.includes? "bar" || foo.includes? "batz"
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Logical operator in method args without parenthesis is not allowed
puts "this code is not bug-free"
end
CRYSTAL
end
end
end
51 changes: 51 additions & 0 deletions src/ameba/rule/lint/logical_without_paren.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module Ameba::Rule::Lint
# A rule that disallows logical operators in method args without parenthesis.
#
# For example, this is considered invalid:
#
# ```
# if a.includes? "b" && c.includes? "c"
# end
#
# form.add "query", "val_1" || "val_2"
# ```
#
# And need to be written as:
#
# ```
# if a.includes?("b") && c.includes?("c")
# end
#
# form.add("query", "val_1" || "val_2")
# # OR
# form.add "query", ("val_1" || "val_2")
# ```
#
# YAML configuration example:
#
# ```
# Lint/LogicalWithoutParenthesis:
# Enabled: true
# ```
class LogicalWithoutParenthesis < Base
properties do
description "Disallows logical operators in method args without parenthesis"
end

MSG = "Logical operator in method args without parenthesis is not allowed"

def test(source, node : Crystal::Call)
return if node.args.size == 0 ||
node.has_parentheses? ||
node.name.ends_with?("=") ||
node.name.in?(["[]?", "[]"])

node.args.each do |arg|
case arg
when Crystal::BinaryOp
issue_for arg, MSG
end
end
end
end
end

0 comments on commit ba5fb8e

Please sign in to comment.