Skip to content

Commit

Permalink
Merge pull request #422 from crystal-ameba/refactor-adding-issues-wit…
Browse files Browse the repository at this point in the history
…h-name-location

Make it easier to add issues for nodes with name location preference
  • Loading branch information
Sija committed Nov 13, 2023
2 parents 6caf24a + 0a2609c commit 0b225da
Show file tree
Hide file tree
Showing 24 changed files with 68 additions and 92 deletions.
18 changes: 14 additions & 4 deletions src/ameba/reportable.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
require "./ast/util"

module Ameba
# Represents a module used to report issues.
module Reportable
include AST::Util

# List of reported issues.
getter issues = [] of Issue

Expand Down Expand Up @@ -30,13 +34,19 @@ module Ameba
end

# Adds a new issue for Crystal AST *node*.
def add_issue(rule, node : Crystal::ASTNode, message, status : Issue::Status? = nil, block : (Source::Corrector ->)? = nil) : Issue
add_issue rule, node.location, node.end_location, message, status, block
def add_issue(rule, node : Crystal::ASTNode, message, status : Issue::Status? = nil, block : (Source::Corrector ->)? = nil, *, prefer_name_location = false) : Issue
location = name_location(node) if prefer_name_location
location ||= node.location

end_location = name_end_location(node) if prefer_name_location
end_location ||= node.end_location

add_issue rule, location, end_location, message, status, block
end

# :ditto:
def add_issue(rule, node : Crystal::ASTNode, message, status : Issue::Status? = nil, &block : Source::Corrector ->) : Issue
add_issue rule, node, message, status, block
def add_issue(rule, node : Crystal::ASTNode, message, status : Issue::Status? = nil, *, prefer_name_location = false, &block : Source::Corrector ->) : Issue
add_issue rule, node, message, status, block, prefer_name_location: prefer_name_location
end

# Adds a new issue for Crystal *token*.
Expand Down
7 changes: 1 addition & 6 deletions src/ameba/rule/lint/missing_block_argument.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ module Ameba::Rule::Lint
# Enabled: true
# ```
class MissingBlockArgument < Base
include AST::Util

properties do
description "Disallows yielding method definitions without block argument"
end
Expand All @@ -36,10 +34,7 @@ module Ameba::Rule::Lint
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
issue_for node, MSG, prefer_name_location: true
end
end
end
7 changes: 1 addition & 6 deletions src/ameba/rule/lint/not_nil.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ module Ameba::Rule::Lint
# Enabled: true
# ```
class NotNil < Base
include AST::Util

properties do
description "Identifies usage of `not_nil!` calls"
end
Expand All @@ -42,10 +40,7 @@ module Ameba::Rule::Lint
return unless node.name == "not_nil!"
return unless node.obj && node.args.empty?

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

issue_for name_location, end_location, MSG
issue_for node, MSG, prefer_name_location: true
end
end
end
2 changes: 1 addition & 1 deletion src/ameba/rule/lint/not_nil_after_no_bang.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module Ameba::Rule::Lint
return unless (obj = node.obj).is_a?(Crystal::Call)
return unless obj.name.in?(obj.block ? BLOCK_CALL_NAMES : CALL_NAMES)

return unless name_location = obj.name_location
return unless name_location = name_location(obj)
return unless name_location_end = name_end_location(obj)
return unless end_location = name_end_location(node)

Expand Down
2 changes: 1 addition & 1 deletion src/ameba/rule/lint/redundant_string_coercion.cr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module Ameba::Rule::Lint

def test(source, node : Crystal::StringInterpolation)
string_coercion_nodes(node).each do |expr|
issue_for expr.name_location, expr.end_location, MSG
issue_for name_location(expr), expr.end_location, MSG
end
end

Expand Down
2 changes: 1 addition & 1 deletion src/ameba/rule/lint/redundant_with_index.cr
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ module Ameba::Rule::Lint
end

private def report(source, node, msg)
issue_for node.name_location, node.name_end_location, msg
issue_for node, msg, prefer_name_location: true
end
end
end
2 changes: 1 addition & 1 deletion src/ameba/rule/lint/redundant_with_object.cr
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module Ameba::Rule::Lint
!(block = node.block) ||
with_index_arg?(block)

issue_for node.name_location, node.name_end_location, MSG
issue_for node, MSG, prefer_name_location: true
end

private def with_index_arg?(block : Crystal::Block)
Expand Down
7 changes: 1 addition & 6 deletions src/ameba/rule/metrics/cyclomatic_complexity.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ module Ameba::Rule::Metrics
# MaxComplexity: 10
# ```
class CyclomaticComplexity < Base
include AST::Util

properties do
description "Disallows methods with a cyclomatic complexity higher than `MaxComplexity`"
max_complexity 10
Expand All @@ -22,10 +20,7 @@ module Ameba::Rule::Metrics
complexity = AST::CountingVisitor.new(node).count
return unless complexity > max_complexity

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

issue_for location, end_location, MSG % {complexity, max_complexity}
issue_for node, MSG % {complexity, max_complexity}, prefer_name_location: true
end
end
end
17 changes: 2 additions & 15 deletions src/ameba/rule/naming/accessor_method_name.cr
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ module Ameba::Rule::Naming
# Enabled: true
# ```
class AccessorMethodName < Base
include AST::Util

properties do
description "Makes sure that accessor methods are named properly"
end
Expand Down Expand Up @@ -66,24 +64,13 @@ module Ameba::Rule::Naming
end

private def check_issue(source, node : Crystal::Def)
location = name_location(node)
end_location = name_end_location(node)

case node.name
when /^get_([a-z]\w*)$/
return unless node.args.empty?
if location && end_location
issue_for location, end_location, MSG % {$1, node.name}
else
issue_for node, MSG % {$1, node.name}
end
issue_for node, MSG % {$1, node.name}, prefer_name_location: true
when /^set_([a-z]\w*)$/
return unless node.args.size == 1
if location && end_location
issue_for location, end_location, MSG % {"#{$1}=", node.name}
else
issue_for node, MSG % {"#{$1}=", node.name}
end
issue_for node, MSG % {"#{$1}=", node.name}, prefer_name_location: true
end
end
end
Expand Down
23 changes: 5 additions & 18 deletions src/ameba/rule/naming/ascii_identifiers.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ module Ameba::Rule::Naming
# Enabled: true
# ```
class AsciiIdentifiers < Base
include AST::Util

properties do
description "Disallows non-ascii characters in identifiers"
end
Expand All @@ -43,38 +41,27 @@ module Ameba::Rule::Naming
end

def test(source, node : Crystal::Def)
check_issue_with_location(source, node)
check_issue(source, node, prefer_name_location: true)

node.args.each do |arg|
check_issue_with_location(source, arg)
check_issue(source, arg, prefer_name_location: true)
end
end

def test(source, node : Crystal::ClassVar | Crystal::InstanceVar | Crystal::Var | Crystal::Alias)
check_issue_with_location(source, node)
check_issue(source, node, prefer_name_location: true)
end

def test(source, node : Crystal::ClassDef | Crystal::ModuleDef | Crystal::EnumDef | Crystal::LibDef)
check_issue(source, node.name, node.name)
end

private def check_issue_with_location(source, node)
location = name_location(node)
end_location = name_end_location(node)

if location && end_location
check_issue(source, location, end_location, node.name)
else
check_issue(source, node, node.name)
end
end

private def check_issue(source, location, end_location, name)
issue_for location, end_location, MSG unless name.to_s.ascii_only?
end

private def check_issue(source, node, name)
issue_for node, MSG unless name.to_s.ascii_only?
private def check_issue(source, node, name = node.name, *, prefer_name_location = false)
issue_for node, MSG, prefer_name_location: prefer_name_location unless name.to_s.ascii_only?
end
end
end
4 changes: 2 additions & 2 deletions src/ameba/rule/naming/block_parameter_name.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ module Ameba::Rule::Naming
# Enabled: true
# MinNameLength: 3
# AllowNamesEndingInNumbers: true
# AllowedNames: [_, e, i, j, k, v, x, y, ex, io, ws, tx, id, k1, k2, v1, v2]
# AllowedNames: [_, e, i, j, k, v, x, y, ex, io, ws, op, tx, id, ip, k1, k2, v1, v2]
# ForbiddenNames: []
# ```
class BlockParameterName < Base
properties do
description "Disallows non-descriptive block parameter names"
min_name_length 3
allow_names_ending_in_numbers true
allowed_names %w[_ e i j k v x y ex io ws tx id k1 k2 v1 v2]
allowed_names %w[_ e i j k v x y ex io ws op tx id ip k1 k2 v1 v2]
forbidden_names %w[]
end

Expand Down
7 changes: 1 addition & 6 deletions src/ameba/rule/naming/method_names.cr
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ module Ameba::Rule::Naming
# Enabled: true
# ```
class MethodNames < Base
include AST::Util

properties do
description "Enforces method names to be in underscored case"
end
Expand All @@ -49,10 +47,7 @@ module Ameba::Rule::Naming
def test(source, node : Crystal::Def)
return if (expected = node.name.underscore) == node.name

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

issue_for location, end_location, MSG % {expected, node.name}
issue_for node, MSG % {expected, node.name}, prefer_name_location: true
end
end
end
4 changes: 3 additions & 1 deletion src/ameba/rule/performance/any_after_filter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ module Ameba::Rule::Performance
# - reject
# ```
class AnyAfterFilter < Base
include AST::Util

properties do
description "Identifies usage of `any?` calls that follow filters"
filter_names %w(select reject)
Expand All @@ -39,7 +41,7 @@ module Ameba::Rule::Performance
return unless obj.is_a?(Crystal::Call) && obj.block && node.block.nil?
return unless obj.name.in?(filter_names)

issue_for obj.name_location, node.name_end_location, MSG % obj.name
issue_for name_location(obj), name_end_location(node), MSG % obj.name
end
end
end
7 changes: 1 addition & 6 deletions src/ameba/rule/performance/any_instead_of_empty.cr
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ module Ameba::Rule::Performance
# Enabled: true
# ```
class AnyInsteadOfEmpty < Base
include AST::Util

properties do
description "Identifies usage of arg-less `any?` calls"
end
Expand All @@ -41,10 +39,7 @@ module Ameba::Rule::Performance
return unless node.block.nil? && node.args.empty?
return unless node.obj

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

issue_for name_location, end_location, MSG
issue_for node, MSG, prefer_name_location: true
end
end
end
11 changes: 6 additions & 5 deletions src/ameba/rule/performance/chained_call_with_no_bang.cr
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ module Ameba::Rule::Performance
return unless node.name.in?(call_names)
return unless obj.name.in?(call_names) || obj.name.in?(ALLOCATING_METHOD_NAMES)

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

issue_for location, end_location, MSG % {node.name, obj.name} do |corrector|
corrector.insert_after(end_location, '!')
if end_location = name_end_location(node)
issue_for node, MSG % {node.name, obj.name}, prefer_name_location: true do |corrector|
corrector.insert_after(end_location, '!')
end
else
issue_for node, MSG % {node.name, obj.name}, prefer_name_location: true
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion src/ameba/rule/performance/compact_after_map.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ module Ameba::Rule::Performance
# Enabled: true
# ```
class CompactAfterMap < Base
include AST::Util

properties do
description "Identifies usage of `compact` calls that follow `map`"
end
Expand All @@ -37,7 +39,7 @@ module Ameba::Rule::Performance
return unless obj.is_a?(Crystal::Call) && obj.block
return unless obj.name == "map"

issue_for obj.name_location, node.name_end_location, MSG
issue_for name_location(obj), name_end_location(node), MSG
end
end
end
2 changes: 1 addition & 1 deletion src/ameba/rule/performance/excessive_allocations.cr
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ module Ameba::Rule::Performance
return unless obj.args.empty? && obj.block.nil?
return unless method = call_names[obj.name]?

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

msg = MSG % {method, obj.name}
Expand Down
4 changes: 3 additions & 1 deletion src/ameba/rule/performance/first_last_after_filter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ module Ameba::Rule::Performance
# - select
# ```
class FirstLastAfterFilter < Base
include AST::Util

properties do
description "Identifies usage of `first/last/first?/last?` calls that follow filters"
filter_names %w(select)
Expand All @@ -47,7 +49,7 @@ module Ameba::Rule::Performance

message = node.name.includes?(CALL_NAMES.first) ? MSG : MSG_REVERSE

issue_for obj.name_location, node.name_end_location,
issue_for name_location(obj), name_end_location(node),
message % {obj.name, node.name}
end
end
Expand Down
4 changes: 3 additions & 1 deletion src/ameba/rule/performance/flatten_after_map.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ module Ameba::Rule::Performance
# Enabled: true
# ```
class FlattenAfterMap < Base
include AST::Util

properties do
description "Identifies usage of `flatten` calls that follow `map`"
end
Expand All @@ -37,7 +39,7 @@ module Ameba::Rule::Performance
return unless obj.is_a?(Crystal::Call) && obj.block
return unless obj.name == "map"

issue_for obj.name_location, node.name_end_location, MSG
issue_for name_location(obj), name_end_location(node), MSG
end
end
end
4 changes: 3 additions & 1 deletion src/ameba/rule/performance/map_instead_of_block.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ module Ameba::Rule::Performance
# Enabled: true
# ```
class MapInsteadOfBlock < Base
include AST::Util

properties do
description "Identifies usage of `sum/product` calls that follow `map`"
end
Expand All @@ -40,7 +42,7 @@ module Ameba::Rule::Performance
return unless obj.is_a?(Crystal::Call) && obj.block
return unless obj.name == MAP_NAME

issue_for obj.name_location, node.name_end_location,
issue_for name_location(obj), name_end_location(node),
MSG % {node.name, node.name}
end
end
Expand Down
Loading

0 comments on commit 0b225da

Please sign in to comment.