Skip to content

Add ameba #15875

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

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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
198 changes: 198 additions & 0 deletions .ameba.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# This configuration file was generated by `ameba --gen-config`
# on 2025-06-02 13:57:07 UTC using Ameba version 1.7.0-dev.
# The point is for the user to remove these configuration records
# one by one as the reported problems are removed from the code base.
#
# For more details on any individual rule, run `ameba --only RuleName`.

# Indicators for comment annotations:
#
# * `Disabled`: The rule is disabled because it does not seem useful for this repo (or in general).
# * `BUG`: A bug in ameba prevents using this rule either entirely or for specific files.
# * `FIXME`: The rule seems useful, but requires some effort to resolve. That's deferred for later.
# * `TODO`: The rule might be useful, but we need to investigate whether we want to use it or not.

Version: "1.7.0-dev"

# Documentation
# =========================

# Disabled: What's the point in alerting about existing TODOs in code?
Documentation/DocumentationAdmonition:
Enabled: false

# Lint
# =========================

Lint/DebugCalls:
Excluded:
# Samples may legitimately use DebugCalls
- samples/**/*
# Explicit tests
- spec/std/pp_spec.cr

Lint/DebuggerStatement:
Excluded:
# Explicit tests
- spec/debug/**/*

# Disabled: `else nil` can be useful to explicitly show the consequence of the else branch
Lint/ElseNil:
Enabled: false

Lint/LiteralInCondition:
Excluded:
# Samples may legitimately use literals in conditions
- samples/**/*

Lint/LiteralInInterpolation:
Excluded:
- spec/std/random_spec.cr # BUG: https://github.com/crystal-ameba/ameba/issues/611

Lint/LiteralsComparison:
Excluded:
# Explicit tests for case equality on tuple literals
- spec/std/tuple_spec.cr

# TODO: Investigate if some `not_nil!` calls can be avoided.
Lint/NotNil:
Enabled: false

Lint/RandZero:
Excluded:
# Explicit tests
- spec/std/random_spec.cr

# FIXME: Resolve shadowing.
Lint/ShadowingOuterLocalVar:
Enabled: false

# TODO: Investigate file names and move to data directories.
Lint/SpecFilename:
Enabled: false

# BUG: https://github.com/crystal-ameba/ameba/issues/612
Lint/TopLevelOperatorDefinition:
Enabled: false

# Disabled: We're running typos explicitly in CI, no need for this rule.
Lint/Typos:
Enabled: false

# Disabled: We have an explicit CI job for `typos`. No reason to run it through
# ameba.
Lint/Typos:
Enabled: false

# TODO: Investigate unused arguments.
Lint/UnusedArgument:
Enabled: false

# TODO: Investigate unused block arguments.
Lint/UnusedBlockArgument:
Enabled: false

# FIXME: Investigate useless assigns.
Lint/UselessAssign:
Enabled: false

# Metrics
# =========================

# Disabled: Lot's of violations. Complexity is very individual.
Metrics/CyclomaticComplexity:
Enabled: false

# Naming
# =========================
# All disabled. There are many violations and some of the rules are questionable.
# TODO: Consider enabling some of these rules.

Naming/AccessorMethodName:
Enabled: false

Naming/BinaryOperatorParameterName:
Enabled: false

Naming/BlockParameterName:
Enabled: false

# Disabled: All violations follow the spelling of identifiers in upstream
# projects, e.g. for lib bindings.
Naming/ConstantNames:
Enabled: false

Naming/MethodNames:
Enabled: false

Naming/PredicateName:
Enabled: false

Naming/QueryBoolMethods:
Enabled: false

Naming/RescuedExceptionsVariableName:
Enabled: false

Naming/TypeNames:
Enabled: false

Naming/VariableNames:
Enabled: false

# Performance
# =========================

Performance/AnyInsteadOfEmpty:
Excluded:
# These specs explicitly test `#any?` implementations
- spec/std/bit_array_spec.cr
- spec/std/enumerable_spec.cr
- spec/std/hash_spec.cr

# Style
# =========================
# All disabled. There are many violations and some of the rules are questionable.
# TODO: Consider enabling some of these rules.

Style/HeredocEscape:
Enabled: false

Style/HeredocIndent:
Enabled: false

Style/MultilineCurlyBlock:
Enabled: false

# Disabled: This rule seems too strict when any negation inside a complex condition is
# considered a violation. Not sure if this is expected behaviour.
Style/NegatedConditionsInUnless:
Enabled: false

# BUG: https://github.com/crystal-ameba/ameba/issues/614
Style/ParenthesesAroundCondition:
Enabled: false

Style/PercentLiteralDelimiters:
Enabled: false

Style/RedundantBegin:
Enabled: false

Style/RedundantNext:
Enabled: false

Style/RedundantReturn:
Enabled: false

Style/RedundantSelf:
Enabled: false

Style/UnlessElse:
Enabled: false

Style/VerboseBlock:
Enabled: false

Style/WhileTrue:
Enabled: false
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
root = true

[*.cr]
[*.{cr,ecr}]
charset = utf-8
end_of_line = lf
insert_final_newline = true
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,12 @@ jobs:

- name: Check Format
run: bin/ci format

lint_ameba:
runs-on: ubuntu-latest
container: ghcr.io/crystal-ameba/ameba:sha-d861f4ed0f904e0ecdad11c26f98e968f7d95afa # 1.7.0-dev
steps:
- name: Download Crystal source
uses: actions/checkout@v4

- run: ameba
2 changes: 1 addition & 1 deletion scripts/generate_windows_zone_names.cr
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ windows_zone_names_items = entries.compact_map do |tzdata_name, territory, windo

{windows_name, zone1.name, zone2.name, location.name}
rescue err : Time::Location::InvalidLocationNameError
pp err
puts err
nil
end

Expand Down
2 changes: 1 addition & 1 deletion spec/llvm-ir/pass-closure-to-c-debug-loc.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ lib Foo
end

def raise(msg)
while true
while true # ameba:disable Lint/EmptyLoop
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/std/data/test_template3.ecr
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<%- 2.times do |i| %><%= i %><% end -%>
<%- 2.times do |i| %><%= i %><% end -%>
2 changes: 1 addition & 1 deletion spec/std/data/test_template4.ecr
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
hi
<%- 2.times do |i| %><%= i %><% end -%>
<%- 2.times do |i| %><%= i %><% end -%>
2 changes: 1 addition & 1 deletion spec/std/data/test_template6.ecr
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<%= "string with -%" %>
<%= "string with -%" %>
2 changes: 1 addition & 1 deletion spec/std/data/test_template7.ecr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Greetings, <%%= @name %>!
<%-% else -%>
Greetings!
<%-% end -%>
<%-% end -%>
3 changes: 2 additions & 1 deletion spec/std/ecr/ecr_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe "ECR" do
it "does with -% inside string" do
io = IO::Memory.new
ECR.embed "#{__DIR__}/../data/test_template6.ecr", io
io.to_s.should eq("string with -%")
io.to_s.should eq("string with -%\n")
end

it "does with <%% %>" do
Expand All @@ -74,6 +74,7 @@ describe "ECR" do
<%- else -%>
Greetings!
<%- end -%>

ECR
end

Expand Down
4 changes: 2 additions & 2 deletions spec/std/iterator_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ describe Iterator do

describe "uniq" do
it "without block" do
iter = (1..8).each.map { |x| x % 3 }.uniq
iter = (1..8).each.map { |x| x % 3 }.uniq # ameba:disable Performance/ChainedCallWithNoBang
iter.next.should eq(1)
iter.next.should eq(2)
iter.next.should eq(0)
Expand Down Expand Up @@ -806,7 +806,7 @@ describe Iterator do
end

it "flattens nested struct iterators with internal state being value types" do
iter = (1..2).each.map { |i| StructIter.new(10 * i + 1, 10 * i + 3) }.flatten
iter = (1..2).each.map { |i| StructIter.new(10 * i + 1, 10 * i + 3) }.flatten # ameba:disable Performance/FlattenAfterMap

iter.next.should eq(11)
iter.next.should eq(12)
Expand Down
4 changes: 2 additions & 2 deletions src/comparable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ module Comparable(T)
def ==(other : T)
if self.is_a?(Reference)
# Need to do two different comparisons because the compiler doesn't yet
# restrict something like `other.is_a?(Reference) || other.is_a?(Nil)`.
# restrict something like `other.is_a?(Reference) || other.nil?`.
# See #2461
return true if other.is_a?(Reference) && self.same?(other)
return true if other.is_a?(Nil) && self.same?(other)
return true if other.nil? && self.same?(other)
end

cmp = self <=> other
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/crystal/interpreter/compiler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,8 @@ class Crystal::Repl::Compiler < Crystal::Visitor
end

private def dispatch_class_var(owner : Type, metaclass : Bool, node : ASTNode, &)
types = owner.all_subclasses.select { |t| t.is_a?(ClassVarContainer) }
types = [] of Crystal::Type
owner.all_subclasses.each { |t| types << t if t.is_a?(ClassVarContainer) }
types.push(owner)
types.sort_by! { |type| -type.depth }

Expand Down
8 changes: 4 additions & 4 deletions src/kernel.cr
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ end
# See also: `Object#inspect(io)`.
def p(*objects)
objects.each do |obj|
p obj
p obj # ameba:disable Lint/DebugCalls
end
objects
end
Expand All @@ -482,7 +482,7 @@ end
#
# See `Object#inspect(io)`
def p(**objects)
p(objects) unless objects.empty?
p(objects) unless objects.empty? # ameba:disable Lint/DebugCalls
end

# Pretty prints *object* to `STDOUT` followed
Expand All @@ -501,7 +501,7 @@ end
# See also: `Object#pretty_print(pp)`.
def pp(*objects)
objects.each do |obj|
pp obj
pp obj # ameba:disable Lint/DebugCalls
end
objects
end
Expand All @@ -515,7 +515,7 @@ end
#
# See `Object#pretty_print(pp)`
def pp(**objects)
pp(objects) unless objects.empty?
pp(objects) unless objects.empty? # ameba:disable Lint/DebugCalls
end

# Registers the given `Proc` for execution when the program exits regularly.
Expand Down
Loading