Skip to content

Further refinements #317

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 14 commits into from
Dec 11, 2022
Merged
43 changes: 21 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@

- [About](#about)
- [Usage](#usage)
* [Watch a tutorial](#watch-a-tutorial)
* [Autocorrection](#autocorrection)
* [Explain issues](#explain-issues)
* [Run in parallel](#run-in-parallel)
- [Watch a tutorial](#watch-a-tutorial)
- [Autocorrection](#autocorrection)
- [Explain issues](#explain-issues)
- [Run in parallel](#run-in-parallel)
- [Installation](#installation)
* [As a project dependency:](#as-a-project-dependency)
* [OS X](#os-x)
* [Docker](#docker)
* [From sources](#from-sources)
- [As a project dependency:](#as-a-project-dependency)
- [OS X](#os-x)
- [Docker](#docker)
- [From sources](#from-sources)
- [Configuration](#configuration)
* [Sources](#sources)
* [Rules](#rules)
* [Inline disabling](#inline-disabling)
- [Editors & integrations](#editors--integrations)
- [Credits & inspirations](#credits--inspirations)
- [Sources](#sources)
- [Rules](#rules)
- [Inline disabling](#inline-disabling)
- [Editors \& integrations](#editors--integrations)
- [Credits \& inspirations](#credits--inspirations)
- [Contributors](#contributors)

## About
Expand Down Expand Up @@ -201,8 +201,8 @@ In this example we define default globs and exclude `src/compiler` folder:

``` yaml
Globs:
- **/*.cr
- !lib
- "**/*.cr"
- "!lib"

Excluded:
- src/compiler
Expand Down Expand Up @@ -245,18 +245,17 @@ One or more rules or one or more group of rules can be disabled using inline dir
time = Time.epoch(1483859302)

time = Time.epoch(1483859302) # ameba:disable Style/LargeNumbers, Lint/UselessAssign

time = Time.epoch(1483859302) # ameba:disable Style, Lint
```

## Editors & integrations

* Vim: [vim-crystal](https://github.com/rhysd/vim-crystal), [Ale](https://github.com/w0rp/ale)
* Emacs: [ameba.el](https://github.com/crystal-ameba/ameba.el)
* Sublime Text: [Sublime Linter Ameba](https://github.com/epergo/SublimeLinter-contrib-ameba)
* VSCode: [vscode-crystal-ameba](https://github.com/crystal-ameba/vscode-crystal-ameba)
* Codacy: [codacy-ameba](https://github.com/codacy/codacy-ameba)
* GitHub Actions: [github-action](https://github.com/crystal-ameba/github-action)
- Vim: [vim-crystal](https://github.com/rhysd/vim-crystal), [Ale](https://github.com/w0rp/ale)
- Emacs: [ameba.el](https://github.com/crystal-ameba/ameba.el)
- Sublime Text: [Sublime Linter Ameba](https://github.com/epergo/SublimeLinter-contrib-ameba)
- VSCode: [vscode-crystal-ameba](https://github.com/crystal-ameba/vscode-crystal-ameba)
- Codacy: [codacy-ameba](https://github.com/codacy/codacy-ameba)
- GitHub Actions: [github-action](https://github.com/crystal-ameba/github-action)

## Credits & inspirations

Expand Down
16 changes: 8 additions & 8 deletions spec/ameba/formatter/util_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module Ameba::Formatter

describe "#context" do
it "returns correct pre/post context lines" do
source = Source.new <<-EOF
source = Source.new <<-CRYSTAL
# pre:1
# pre:2
# pre:3
Expand All @@ -51,7 +51,7 @@ module Ameba::Formatter
# post:3
# post:4
# post:5
EOF
CRYSTAL

subject.context(source.lines, lineno: 6, context_lines: 3)
.should eq({<<-PRE.lines, <<-POST.lines
Expand All @@ -69,24 +69,24 @@ module Ameba::Formatter

describe "#affected_code" do
it "returns nil if there is no such a line number" do
code = <<-EOF
code = <<-CRYSTAL
a = 1
EOF
CRYSTAL
location = Crystal::Location.new("filename", 2, 1)
subject.affected_code(code, location).should be_nil
end

it "returns correct line if it is found" do
code = <<-EOF
code = <<-CRYSTAL
a = 1
EOF
CRYSTAL
location = Crystal::Location.new("filename", 1, 1)
subject.deansify(subject.affected_code(code, location))
.should eq "> a = 1\n ^\n"
end

it "returns correct line if it is found" do
code = <<-EOF
code = <<-CRYSTAL
# pre:1
# pre:2
# pre:3
Expand All @@ -98,7 +98,7 @@ module Ameba::Formatter
# post:3
# post:4
# post:5
EOF
CRYSTAL

location = Crystal::Location.new("filename", 6, 1)
subject.deansify(subject.affected_code(code, location, context_lines: 3))
Expand Down
16 changes: 6 additions & 10 deletions spec/ameba/rule/lint/literals_comparison_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,20 @@ module Ameba::Rule::Lint
CRYSTAL
end

it "reports if there is a static path comparison evaluating to false" do
expect_issue subject, <<-CRYSTAL
String == Nil
# ^^^^^^^^^^^ error: Comparison always evaluates to false
CRYSTAL
end

context "macro" do
pending "reports in macro scope" do
it "reports in macro scope" do
expect_issue subject, <<-CRYSTAL
{{ "foo" == "foo" }}
# ^^^^^^^^^^^^^^ error: Comparison always evaluates to true
CRYSTAL
end

it "passes for free variables comparisons in macro scope" do
it "passes for valid cases" do
expect_no_issues subject, <<-CRYSTAL
{{ T == Nil }}
{{ "foo" == foo }}
{{ "foo" != foo }}
{% foo == "foo" %}
{% foo != "foo" %}
CRYSTAL
end
end
Expand Down
7 changes: 7 additions & 0 deletions spec/ameba/rule/lint/not_nil_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ module Ameba::Rule::Lint
CRYSTAL
end

it "reports if there is a `not_nil!` call in the middle of the call-chain" do
expect_issue subject, <<-CRYSTAL
(1..3).first?.not_nil!.to_s
# ^^^^^^^^ error: Avoid using `not_nil!`
CRYSTAL
end

context "macro" do
it "doesn't report in macro scope" do
expect_no_issues subject, <<-CRYSTAL
Expand Down
4 changes: 2 additions & 2 deletions spec/ameba/rule/metrics/cyclomatic_complexity_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ require "../../../spec_helper"

module Ameba::Rule::Metrics
subject = CyclomaticComplexity.new
complex_method = <<-CODE
complex_method = <<-CRYSTAL
def hello(a, b, c)
if a && b && c
begin
Expand All @@ -15,7 +15,7 @@ module Ameba::Rule::Metrics
end
end
end
CODE
CRYSTAL

describe CyclomaticComplexity do
it "passes for empty methods" do
Expand Down
12 changes: 10 additions & 2 deletions spec/ameba/rule/style/is_a_nil_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,25 @@ module Ameba::Rule::Style
end

it "reports if there is a call to is_a?(Nil) without receiver" do
expect_issue subject, <<-CRYSTAL
source = expect_issue subject, <<-CRYSTAL
a = is_a?(Nil)
# ^^^ error: Use `nil?` instead of `is_a?(Nil)`
CRYSTAL

expect_correction source, <<-CRYSTAL
a = self.nil?
CRYSTAL
end

it "reports if there is a call to is_a?(Nil) with receiver" do
expect_issue subject, <<-CRYSTAL
source = expect_issue subject, <<-CRYSTAL
a.is_a?(Nil)
# ^^^ error: Use `nil?` instead of `is_a?(Nil)`
CRYSTAL

expect_correction source, <<-CRYSTAL
a.nil?
CRYSTAL
end

it "reports rule, location and message" do
Expand Down
2 changes: 1 addition & 1 deletion src/ameba/ast/branch.cr
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module Ameba::AST
def initialize(@node, @parent)
end

# Returns true if current branch is in a loop, false - otherwise.
# Returns `true` if current branch is in a loop, `false` - otherwise.
# For example, this branch is in a loop:
#
# ```
Expand Down
3 changes: 2 additions & 1 deletion src/ameba/ast/branchable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ module Ameba::AST
def initialize(@node, @parent = nil)
end

# Returns true if this node or one of the parent branchables is a loop, false otherwise.
# Returns `true` if this node or one of the parent branchables is a loop,
# `false` otherwise.
def loop?
loop?(node) || !!parent.try(&.loop?)
end
Expand Down
4 changes: 2 additions & 2 deletions src/ameba/ast/scope.cr
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ module Ameba::AST
node.is_a?(Crystal::CStructOrUnionDef)
end

# Returns true if current scope (or any of inner scopes) references variable,
# Returns `true` if current scope (or any of inner scopes) references variable,
# `false` otherwise.
def references?(variable : Variable, check_inner_scopes = true)
variable.references.any? do |reference|
Expand All @@ -153,7 +153,7 @@ module Ameba::AST
outer_scope.nil?
end

# Returns true if var is an argument in current scope, `false` otherwise.
# Returns `true` if var is an argument in current scope, `false` otherwise.
def arg?(var)
case current_node = node
when Crystal::Def
Expand Down
30 changes: 14 additions & 16 deletions src/ameba/ast/util.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Ameba::AST::Util
#
# 1. is *node* a literal?
# 2. can *node* be proven static?
protected def literal_kind?(node, include_paths = false) : {Bool, Bool}
protected def literal_kind?(node) : {Bool, Bool}
case node
when Crystal::NilLiteral,
Crystal::BoolLiteral,
Expand All @@ -17,44 +17,42 @@ module Ameba::AST::Util
Crystal::MacroLiteral
{true, true}
when Crystal::RangeLiteral
{true, static_literal?(node.from, include_paths) &&
static_literal?(node.to, include_paths)}
{true, static_literal?(node.from) &&
static_literal?(node.to)}
when Crystal::ArrayLiteral,
Crystal::TupleLiteral
{true, node.elements.all? do |el|
static_literal?(el, include_paths)
static_literal?(el)
end}
when Crystal::HashLiteral
{true, node.entries.all? do |entry|
static_literal?(entry.key, include_paths) &&
static_literal?(entry.value, include_paths)
static_literal?(entry.key) &&
static_literal?(entry.value)
end}
when Crystal::NamedTupleLiteral
{true, node.entries.all? do |entry|
static_literal?(entry.value, include_paths)
static_literal?(entry.value)
end}
when Crystal::Path
{include_paths, true}
else
{false, false}
end
end

# Returns `true` if current `node` is a static literal, `false` otherwise.
def static_literal?(node, include_paths = false) : Bool
is_literal, is_static = literal_kind?(node, include_paths)
def static_literal?(node) : Bool
is_literal, is_static = literal_kind?(node)
is_literal && is_static
end

# Returns `true` if current `node` is a dynamic literal, `false` otherwise.
def dynamic_literal?(node, include_paths = false) : Bool
is_literal, is_static = literal_kind?(node, include_paths)
def dynamic_literal?(node) : Bool
is_literal, is_static = literal_kind?(node)
is_literal && !is_static
end

# Returns `true` if current `node` is a literal, `false` otherwise.
def literal?(node, include_paths = false) : Bool
is_literal, _ = literal_kind?(node, include_paths)
def literal?(node) : Bool
is_literal, _ = literal_kind?(node)
is_literal
end

Expand Down Expand Up @@ -93,8 +91,8 @@ module Ameba::AST::Util
end

return if last_line.size < end_column + 1
node_lines[-1] = last_line.sub(end_column + 1...last_line.size, "")

node_lines[-1] = last_line.sub(end_column + 1...last_line.size, "")
node_lines.join('\n')
end

Expand Down
2 changes: 1 addition & 1 deletion src/ameba/ast/variabling/argument.cr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module Ameba::AST
def initialize(@node, @variable)
end

# Returns true if the name starts with '_', false if not.
# Returns `true` if the name starts with '_', `false` if not.
def ignored?
name.starts_with? '_'
end
Expand Down
4 changes: 2 additions & 2 deletions src/ameba/ast/variabling/assignment.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module Ameba::AST
@variable.referenced? && [email protected](&.in_loop?)
end

# Returns true if this assignment is an op assign, false if not.
# Returns `true` if this assignment is an op assign, `false` if not.
# For example, this is an op assign:
#
# ```
Expand All @@ -51,7 +51,7 @@ module Ameba::AST
node.is_a?(Crystal::OpAssign)
end

# Returns true if this assignment is in a branch, false if not.
# Returns `true` if this assignment is in a branch, `false` if not.
# For example, this assignment is in a branch:
#
# ```
Expand Down
2 changes: 1 addition & 1 deletion src/ameba/ast/variabling/variable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ module Ameba::AST
node.accept self
end

# @[AlwaysInline]
@[AlwaysInline]
private def includes_reference?(val)
val.to_s.includes?(@reference)
end
Expand Down
2 changes: 1 addition & 1 deletion src/ameba/ast/visitors/base_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module Ameba::AST
end

# A main visit method that accepts `Crystal::ASTNode`.
# Returns true meaning all child nodes will be traversed.
# Returns `true`, meaning all child nodes will be traversed.
def visit(node : Crystal::ASTNode)
true
end
Expand Down
2 changes: 1 addition & 1 deletion src/ameba/config.cr
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Ameba::Config
# ```
property excluded : Array(String)

# Returns true if correctable issues should be autocorrected.
# Returns `true` if correctable issues should be autocorrected.
property? autocorrect = false

@rule_groups : Hash(String, Array(Rule::Base))
Expand Down
Loading