Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions spec/ameba/rule/lint/duplicate_method_signature_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
require "../../../spec_helper"

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

it "passes if there are no duplicate methods" do
expect_no_issues subject, <<-CRYSTAL
class Foo
def foo; end
def foo(&); end
def foo?; end
def foo!; end
def foo(
bar : Bar,
)
end
def foo(
baz : Baz,
)
end
end
CRYSTAL
end

it "passes if there are duplicate methods with `previous_def`" do
expect_no_issues subject, <<-CRYSTAL
class Foo
def foo
42
end

def foo
previous_def if rand >= 0.42
24
end
end
CRYSTAL
end

it "reports if there are duplicate methods without `previous_def`" do
expect_issue subject, <<-CRYSTAL
class Foo
def foo
42
end

def foo
# ^^^^^^^ error: Duplicate method signature detected
previous_definition if rand >= 0.42
24
end
end
CRYSTAL
end

it "reports if there are multiple duplicate methods" do
expect_issue subject, <<-CRYSTAL
class Foo
def foo; end
def bar; end
def foo; end
# ^^^^^^^^^^^^ error: Duplicate method signature detected
def foo; end
# ^^^^^^^^^^^^ error: Duplicate method signature detected
end
CRYSTAL
end

it "reports if there are duplicate methods (with block)" do
expect_issue subject, <<-CRYSTAL
class Foo
def foo(&); end
def bar(&); end
def foo(&); end
# ^^^^^^^^^^^^^^^ error: Duplicate method signature detected
end
CRYSTAL
end

it "reports if there are duplicate methods (with visibility modifier)" do
expect_issue subject, <<-CRYSTAL
class Foo
def foo; end
private def foo; end
# ^^^^^^^^^^^^ error: Duplicate method signature detected
protected def foo; end
# ^^^^^^^^^^^^ error: Duplicate method signature detected
end
CRYSTAL
end

it "reports if there are duplicate methods (with arguments)" do
expect_issue subject, <<-CRYSTAL
class Foo
def foo(a, b, c = 3, &); end
def foo(a, b, c = 3); end
def foo(a, b, c = 3); end
# ^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicate method signature detected
end
CRYSTAL
end

it "reports if there are duplicate methods with different bodies" do
expect_issue subject, <<-CRYSTAL
class Foo
def foo(a, b, c = 3)
puts :foo
end

def foo(a, b, c = 3)
# ^^^^^^^^^^^^^^^^^^^^ error: Duplicate method signature detected
puts :bar
end
end
CRYSTAL
end
end
end
66 changes: 66 additions & 0 deletions src/ameba/rule/lint/duplicate_method_signature.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
module Ameba::Rule::Lint
# Reports repeated class or module method signatures.
#
# Only methods of the same signature are considered duplicates,
# regardless of their bodies, except for ones including `previous_def`.
#
# ```
# class Foo
# def greet(name)
# puts "Hello #{name}!"
# end
#
# def greet(name) # duplicated method signature
# puts "¡Hola! #{name}"
# end
# end
# ```
#
# YAML configuration example:
#
# ```
# Lint/DuplicateMethodSignature:
# Enabled: true
# ```
class DuplicateMethodSignature < Base
properties do
since_version "1.7.0"
description "Reports repeated method signatures"
end

MSG = "Duplicate method signature detected"

def test(source)
AST::ScopeVisitor.new self, source
end

def test(source, node : Crystal::ClassDef | Crystal::ModuleDef, scope : AST::Scope)
found_defs = Set(String).new

each_def_node(node) do |def_node|
def_node_to_s = def_node.to_s

next if def_node_to_s.matches?(/\Wprevious_def\W/)
next if found_defs.add?(def_node_to_s.lines.first)

issue_for def_node, MSG
end
end

private def each_def_node(node, &)
case body = node.body
when Crystal::Def
yield body
when Crystal::VisibilityModifier
yield body.exp
when Crystal::Expressions
body.expressions.each do |exp|
case exp
when Crystal::Def then yield exp
when Crystal::VisibilityModifier then yield exp.exp
end
end
end
end
end
end
Loading