Skip to content

Commit

Permalink
Merge pull request #434 from crystal-ameba/misc-refactors
Browse files Browse the repository at this point in the history
v1.6.1
  • Loading branch information
Sija authored Jan 9, 2024
2 parents 452a7a8 + ce3f2b7 commit b6bd74e
Show file tree
Hide file tree
Showing 18 changed files with 101 additions and 89 deletions.
2 changes: 1 addition & 1 deletion shard.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: ameba
version: 1.6.0
version: 1.6.1

authors:
- Vitalii Elenhaupt <velenhaupt@gmail.com>
Expand Down
28 changes: 17 additions & 11 deletions spec/ameba/ast/scope_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,15 @@ module Ameba::AST
end
end
CRYSTAL
scope = Scope.new nodes.def_nodes.first

var_node = nodes.var_nodes.first
scope.add_variable var_node

scope = Scope.new nodes.def_nodes.first
scope.add_variable(var_node)
scope.inner_scopes << Scope.new(nodes.block_nodes.first, scope)

variable = Variable.new(var_node, scope)
variable.reference nodes.var_nodes.first, scope.inner_scopes.first
variable.reference(nodes.var_nodes.first, scope.inner_scopes.first)

scope.references?(variable).should be_true
end
Expand All @@ -77,13 +79,15 @@ module Ameba::AST
end
end
CRYSTAL
scope = Scope.new nodes.def_nodes.first

var_node = nodes.var_nodes.first
scope.add_variable var_node

scope = Scope.new nodes.def_nodes.first
scope.add_variable(var_node)
scope.inner_scopes << Scope.new(nodes.block_nodes.first, scope)

variable = Variable.new(var_node, scope)
variable.reference nodes.var_nodes.first, scope.inner_scopes.first
variable.reference(nodes.var_nodes.first, scope.inner_scopes.first)

scope.references?(variable, check_inner_scopes: false).should be_false
end
Expand All @@ -98,9 +102,11 @@ module Ameba::AST
end
end
CRYSTAL
scope = Scope.new nodes.def_nodes.first

var_node = nodes.var_nodes.first
scope.add_variable var_node

scope = Scope.new nodes.def_nodes.first
scope.add_variable(var_node)
scope.inner_scopes << Scope.new(nodes.block_nodes.first, scope)

variable = Variable.new(var_node, scope)
Expand All @@ -120,7 +126,7 @@ module Ameba::AST
describe "#find_variable" do
it "returns the variable in the scope by name" do
scope = Scope.new as_node("foo = 1")
scope.add_variable Crystal::Var.new "foo"
scope.add_variable(Crystal::Var.new "foo")
scope.find_variable("foo").should_not be_nil
end

Expand All @@ -133,15 +139,15 @@ module Ameba::AST
describe "#assign_variable" do
it "creates a new assignment" do
scope = Scope.new as_node("foo = 1")
scope.add_variable Crystal::Var.new "foo"
scope.add_variable(Crystal::Var.new "foo")
scope.assign_variable("foo", Crystal::Var.new "foo")
var = scope.find_variable("foo").should_not be_nil
var.assignments.size.should eq 1
end

it "does not create the assignment if variable is wrong" do
scope = Scope.new as_node("foo = 1")
scope.add_variable Crystal::Var.new "foo"
scope.add_variable(Crystal::Var.new "foo")
scope.assign_variable("bar", Crystal::Var.new "bar")
var = scope.find_variable("foo").should_not be_nil
var.assignments.size.should eq 0
Expand Down
13 changes: 9 additions & 4 deletions spec/ameba/ast/variabling/variable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,16 @@ module Ameba::AST
3.times { |i| a = a + i }
end
CRYSTAL
scope = Scope.new nodes.def_nodes.first

var_node = nodes.var_nodes.first
scope.add_variable var_node

scope = Scope.new(nodes.def_nodes.first)
scope.add_variable(var_node)
scope.inner_scopes << Scope.new(nodes.block_nodes.first, scope)

variable = Variable.new(var_node, scope)
variable.reference nodes.var_nodes.last, scope.inner_scopes.last
variable.reference(nodes.var_nodes.last, scope.inner_scopes.last)

variable.captured_by_block?.should be_truthy
end

Expand All @@ -101,8 +104,10 @@ module Ameba::AST
a = 1
end
CRYSTAL
scope.add_variable Crystal::Var.new "a"

scope.add_variable(Crystal::Var.new "a")
variable = scope.variables.first

variable.captured_by_block?.should be_falsey
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/ameba/config_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ module Ameba
end

it "raises when custom config file doesn't exist" do
expect_raises(Exception, "Unable to load config file: Config file does not exist foo.yml") do
expect_raises(Exception, "Unable to load config file: Config file does not exist") do
Config.load "foo.yml"
end
end
Expand Down
2 changes: 2 additions & 0 deletions spec/ameba/rule/lint/literals_comparison_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ module Ameba::Rule::Lint
["foo"] === [foo]
"foo" == foo
"foo" != foo
"foo" == FOO
FOO == "foo"
foo == "foo"
foo != "foo"
CRYSTAL
Expand Down
5 changes: 2 additions & 3 deletions src/ameba/ast/scope.cr
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ module Ameba::AST
# The actual AST node that represents a current scope.
getter node : Crystal::ASTNode

delegate to_s, to: node
delegate location, to: node
delegate end_location, to: node
delegate location, end_location, to_s,
to: @node

def_equals_and_hash node, location

Expand Down
5 changes: 2 additions & 3 deletions src/ameba/ast/variabling/argument.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ module Ameba::AST
# Variable of this argument (may be the same node)
getter variable : Variable

delegate location, to: @node
delegate end_location, to: @node
delegate to_s, to: @node
delegate location, end_location, to_s,
to: @node

# Creates a new argument.
#
Expand Down
5 changes: 2 additions & 3 deletions src/ameba/ast/variabling/assignment.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ module Ameba::AST
# A scope assignment belongs to
getter scope : Scope

delegate to_s, to: @node
delegate location, to: @node
delegate end_location, to: @node
delegate location, end_location, to_s,
to: @node

# Creates a new assignment.
#
Expand Down
6 changes: 2 additions & 4 deletions src/ameba/ast/variabling/ivariable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ module Ameba::AST
class InstanceVariable
getter node : Crystal::InstanceVar

delegate location, to: @node
delegate end_location, to: @node
delegate name, to: @node
delegate to_s, to: @node
delegate location, end_location, name, to_s,
to: @node

def initialize(@node)
end
Expand Down
5 changes: 2 additions & 3 deletions src/ameba/ast/variabling/type_dec_variable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ module Ameba::AST
class TypeDecVariable
getter node : Crystal::TypeDeclaration

delegate location, to: @node
delegate end_location, to: @node
delegate to_s, to: @node
delegate location, end_location, to_s,
to: @node

def initialize(@node)
end
Expand Down
19 changes: 11 additions & 8 deletions src/ameba/ast/variabling/variable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ module Ameba::AST
# Node of the first assignment which can be available before any reference.
getter assign_before_reference : Crystal::ASTNode?

delegate location, to: @node
delegate end_location, to: @node
delegate name, to: @node
delegate to_s, to: @node
delegate location, end_location, name, to_s,
to: @node

# Creates a new variable(in the scope).
#
Expand Down Expand Up @@ -54,7 +52,7 @@ module Ameba::AST
#
# ```
# variable = Variable.new(node, scope)
# variable.reference(var_node)
# variable.reference(var_node, some_scope)
# variable.referenced? # => true
# ```
def referenced?
Expand All @@ -74,6 +72,11 @@ module Ameba::AST
end
end

# :ditto:
def reference(scope : Scope)
reference(node, scope)
end

# Reference variable's assignments.
#
# ```
Expand Down Expand Up @@ -208,9 +211,9 @@ module Ameba::AST
return if references.size > assignments.size
return if assignments.any?(&.op_assign?)

@assign_before_reference = assignments.find { |ass|
!ass.in_branch?
}.try &.node
@assign_before_reference = assignments
.find(&.in_branch?.!)
.try(&.node)
end
end
end
8 changes: 3 additions & 5 deletions src/ameba/ast/visitors/scope_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,15 @@ module Ameba::AST

# :nodoc:
def visit(node : Crystal::Var)
variable = @current_scope.find_variable node.name
variable = @current_scope.find_variable(node.name)

case
when @current_scope.arg?(node) # node is an argument
@current_scope.add_argument(node)
when variable.nil? && @current_assign # node is a variable
@current_scope.add_variable(node)
when variable # node is a reference
reference = variable.reference node, @current_scope
reference = variable.reference(node, @current_scope)
if @current_assign.is_a?(Crystal::OpAssign) || !reference.target_of?(@current_assign)
variable.reference_assignments!
end
Expand All @@ -178,9 +178,7 @@ module Ameba::AST
when scope.type_definition? && accessor_macro?(node) then return false
when scope.def? && special_node?(node)
scope.arguments.each do |arg|
variable = arg.variable

ref = variable.reference(variable.node, scope)
ref = arg.variable.reference(scope)
ref.explicit = false
end
end
Expand Down
9 changes: 5 additions & 4 deletions src/ameba/config.cr
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ class Ameba::Config
@excluded = load_array_section(config, "Excluded")
@globs = load_array_section(config, "Globs", DEFAULT_GLOBS)

return unless formatter_name = load_formatter_name(config)
self.formatter = formatter_name
if formatter_name = load_formatter_name(config)
self.formatter = formatter_name
end
end

# Loads YAML configuration file by `path`.
Expand All @@ -120,8 +121,8 @@ class Ameba::Config

protected def self.read_config(path = nil)
if path
raise ArgumentError.new("Config file does not exist #{path}") unless File.exists?(path)
return File.read(path)
return File.read(path) if File.exists?(path)
raise "Config file does not exist"
end
each_config_path do |config_path|
return File.read(config_path) if File.exists?(config_path)
Expand Down
6 changes: 3 additions & 3 deletions src/ameba/formatter/base_formatter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ module Ameba::Formatter
# A list of sources to inspect is passed as an argument.
def started(sources); end

# Callback that indicates when source inspection is finished.
# Callback that indicates when source inspection is started.
# A corresponding source is passed as an argument.
def source_finished(source : Source); end
def source_started(source : Source); end

# Callback that indicates when source inspection is finished.
# A corresponding source is passed as an argument.
def source_started(source : Source); end
def source_finished(source : Source); end

# Callback that indicates when inspection is finished.
# A list of inspected sources is passed as an argument.
Expand Down
33 changes: 19 additions & 14 deletions src/ameba/formatter/todo_formatter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,21 @@ module Ameba::Formatter
end

private def generate_todo_config(issues)
file = File.new(@config_path, mode: "w")
file << header
rule_issues_map(issues).each do |rule, rule_issues|
file << "\n# Problems found: #{rule_issues.size}"
file << "\n# Run `ameba --only #{rule.name}` for details"
file << rule_todo(rule, rule_issues).gsub("---", "")
File.open(@config_path, mode: "w") do |file|
file << header

rule_issues_map(issues).each do |rule, rule_issues|
rule_todo = rule_todo(rule, rule_issues)
rule_todo =
{rule_todo.name => rule_todo}
.to_yaml.gsub("---", "")

file << "\n# Problems found: #{rule_issues.size}"
file << "\n# Run `ameba --only #{rule.name}` for details"
file << rule_todo
end
file
end
file
ensure
file.close if file
end

private def rule_issues_map(issues)
Expand All @@ -60,11 +65,11 @@ module Ameba::Formatter
end

private def rule_todo(rule, issues)
rule.excluded = issues
.compact_map(&.location.try &.filename.try &.to_s)
.uniq!

{rule.name => rule}.to_yaml
rule.dup.tap do |rule_todo|
rule_todo.excluded = issues
.compact_map(&.location.try &.filename.try &.to_s)
.uniq!
end
end
end
end
5 changes: 3 additions & 2 deletions src/ameba/rule/base.cr
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ module Ameba::Rule
# This method is designed to test the source passed in. If source has issues
# that are tested by this rule, it should add an issue.
#
# Be default it uses a node visitor to traverse all the nodes in the source.
# By default it uses a node visitor to traverse all the nodes in the source.
#
# NOTE: Must be overridden for other type of rules.
def test(source : Source)
AST::NodeVisitor.new self, source
end

# NOTE: Can't be abstract
def test(source : Source, node : Crystal::ASTNode, *opts)
# can't be abstract
end

# A convenient addition to `#test` method that does the same
Expand Down
2 changes: 1 addition & 1 deletion src/ameba/rule/naming/block_parameter_name.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module Ameba::Rule::Naming
end

private def valid_name?(name)
return true if name.blank? # happens with compound names like `(arg1, arg2)`
return true if name.blank? # TODO: handle unpacked variables
return true if name.in?(allowed_names)

return false if name.in?(forbidden_names)
Expand Down
Loading

0 comments on commit b6bd74e

Please sign in to comment.