Skip to content

Add Lint/MissingBlockArgument rule #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 20, 2022
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
2 changes: 1 addition & 1 deletion spec/ameba/formatter/todo_formatter_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ require "../../spec_helper"
require "file_utils"

module Ameba
private def with_formatter
private def with_formatter(&)
io = IO::Memory.new
formatter = Formatter::TODOFormatter.new(io)

Expand Down
42 changes: 42 additions & 0 deletions spec/ameba/rule/lint/missing_block_argument_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require "../../../spec_helper"

module Ameba::Rule::Lint
subject = MissingBlockArgument.new

describe MissingBlockArgument do
it "passes if the block argument is defined" do
expect_no_issues subject, <<-CRYSTAL
def foo(&)
yield 42
end

def bar(&block)
yield 24
end

def baz(a, b, c, &block)
yield a, b, c
end
CRYSTAL
end

it "reports if the block argument is missing" do
expect_issue subject, <<-CRYSTAL
def foo
# ^^^ error: Missing anonymous block argument. Use `&` as an argument name to indicate yielding method.
yield 42
end

def bar
# ^^^ error: Missing anonymous block argument. Use `&` as an argument name to indicate yielding method.
yield 24
end

def baz(a, b, c)
# ^^^ error: Missing anonymous block argument. Use `&` as an argument name to indicate yielding method.
yield a, b, c
end
CRYSTAL
end
end
end
49 changes: 49 additions & 0 deletions src/ameba/rule/lint/missing_block_argument.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module Ameba::Rule::Lint
# A rule that disallows yielding method definitions without block argument.
#
# For example, this is considered invalid:
#
# ```
# def foo
# yield 42
# end
# ```
#
# And has to be written as the following:
#
# ```
# def foo(&)
# yield 42
# end
# ```
#
# YAML configuration example:
#
# ```
# Lint/MissingBlockArgument:
# Enabled: true
# ```
class MissingBlockArgument < Base
include AST::Util

properties do
description "Disallows yielding method definitions without block argument"
end

MSG = "Missing anonymous block argument. Use `&` as an argument " \
"name to indicate yielding method."

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

def test(source, node : Crystal::Def, scope : AST::Scope)
return if !scope.yields? || node.block_arg

return unless location = node.name_location
end_location = name_end_location(node)

issue_for location, end_location, MSG
end
end
end
2 changes: 1 addition & 1 deletion src/ameba/runner.cr
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ module Ameba

private MAX_ITERATIONS = 200

private def loop_unless_infinite(source, corrected_issues)
private def loop_unless_infinite(source, corrected_issues, &)
# Keep track of the state of the source. If a rule modifies the source
# and another rule undoes it producing identical source we have an
# infinite loop.
Expand Down
2 changes: 1 addition & 1 deletion src/ameba/source/rewriter/action.cr
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class Ameba::Source::Rewriter
end

# Similar to `@children.bsearch_index || size` except allows for a starting point
protected def bsearch_child_index(from = 0)
protected def bsearch_child_index(from = 0, &)
size = @children.size
(from...size).bsearch { |i| yield @children[i] } || size
end
Expand Down