mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Source#content -> Source#code, Source::Error#pos -> Source::Error#location
This commit is contained in:
parent
9036a7ca71
commit
e718c90f16
39 changed files with 91 additions and 90 deletions
|
@ -84,7 +84,7 @@ struct DebuggerStatement < Rule
|
||||||
# to remove a debugger statement.
|
# to remove a debugger statement.
|
||||||
return unless node.name == "debugger" && node.args.empty? && node.obj.nil?
|
return unless node.name == "debugger" && node.args.empty? && node.obj.nil?
|
||||||
|
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Possible forgotten debugger statement detected"
|
"Possible forgotten debugger statement detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,7 @@ module Ameba::Formatter
|
||||||
|
|
||||||
it "writes invalid source" do
|
it "writes invalid source" do
|
||||||
s = Source.new ""
|
s = Source.new ""
|
||||||
s.error DummyRule.new, 3, "message"
|
s.error DummyRule.new, nil, "message"
|
||||||
subject.source_finished s
|
subject.source_finished s
|
||||||
output.to_s.should contain "F"
|
output.to_s.should contain "F"
|
||||||
end
|
end
|
||||||
|
|
|
@ -63,12 +63,12 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
source = Source.new "a != true"
|
source = Source.new "a != true", "source.cr"
|
||||||
subject.catch(source)
|
subject.catch(source)
|
||||||
|
|
||||||
error = source.errors.first
|
error = source.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 1
|
error.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Comparison to a boolean is pointless"
|
error.message.should eq "Comparison to a boolean is pointless"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -100,12 +100,12 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
source = Source.new "true != a"
|
source = Source.new "true != a", "source.cr"
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
|
|
||||||
error = source.errors.first
|
error = source.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 1
|
error.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Comparison to a boolean is pointless"
|
error.message.should eq "Comparison to a boolean is pointless"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,9 +3,9 @@ require "../../spec_helper"
|
||||||
module Ameba
|
module Ameba
|
||||||
subject = Rules::ConstantNames.new
|
subject = Rules::ConstantNames.new
|
||||||
|
|
||||||
private def it_reports_constant(content, expected)
|
private def it_reports_constant(code, expected)
|
||||||
it "reports constant name #{expected}" do
|
it "reports constant name #{expected}" do
|
||||||
s = Source.new content
|
s = Source.new code
|
||||||
Rules::ConstantNames.new.catch(s).should_not be_valid
|
Rules::ConstantNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.errors.first.message.should contain expected
|
||||||
end
|
end
|
||||||
|
@ -38,11 +38,11 @@ module Ameba
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
s = Source.new %(
|
s = Source.new %(
|
||||||
Const = 1
|
Const = 1
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
error.message.should eq(
|
||||||
"Constant name should be screaming-cased: CONST, not Const"
|
"Constant name should be screaming-cased: CONST, not Const"
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,12 +32,12 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
s = Source.new "debugger"
|
s = Source.new "debugger", "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 1
|
error.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Possible forgotten debugger statement detected"
|
error.message.should eq "Possible forgotten debugger statement detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -70,15 +70,15 @@ module Ameba
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, location and message" do
|
||||||
s = Source.new %(
|
s = Source.new %(
|
||||||
if ()
|
if ()
|
||||||
end
|
end
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:12"
|
||||||
error.message.should eq "Avoid empty expression '()'"
|
error.message.should eq "Avoid empty expression '()'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -107,11 +107,11 @@ module Ameba
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
s = Source.new %q(
|
s = Source.new %q(
|
||||||
1200000
|
1200000
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:10"
|
||||||
error.message.should match /1_200_000/
|
error.message.should match /1_200_000/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,13 +21,13 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
source = Source.new long_line
|
source = Source.new long_line, "source.cr"
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
|
|
||||||
error = source.errors.first
|
error = source.errors.first
|
||||||
error.rule.should eq subject
|
error.rule.should eq subject
|
||||||
error.pos.should eq 1
|
error.location.to_s.should eq "source.cr:1:81"
|
||||||
error.message.should eq "Line too long (81 symbols)"
|
error.message.should eq "Line too long"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,13 +59,13 @@ module Ameba::Rules
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
s = Source.new %(
|
s = Source.new %(
|
||||||
puts "hello" if true
|
puts "hello" if true
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
s.errors.size.should eq 1
|
s.errors.size.should eq 1
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq "Literal value found in conditional"
|
error.message.should eq "Literal value found in conditional"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,12 +29,12 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
s = Source.new %q("#{4}")
|
s = Source.new %q("#{4}"), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 1
|
error.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Literal value found in interpolation"
|
error.message.should eq "Literal value found in interpolation"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,9 +3,9 @@ require "../../spec_helper"
|
||||||
module Ameba
|
module Ameba
|
||||||
subject = Rules::MethodNames.new
|
subject = Rules::MethodNames.new
|
||||||
|
|
||||||
private def it_reports_method_name(content, expected)
|
private def it_reports_method_name(code, expected)
|
||||||
it "reports method name #{expected}" do
|
it "reports method name #{expected}" do
|
||||||
s = Source.new content
|
s = Source.new code
|
||||||
Rules::MethodNames.new.catch(s).should_not be_valid
|
Rules::MethodNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.errors.first.message.should contain expected
|
||||||
end
|
end
|
||||||
|
@ -42,11 +42,11 @@ module Ameba
|
||||||
s = Source.new %(
|
s = Source.new %(
|
||||||
def bad_Name
|
def bad_Name
|
||||||
end
|
end
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
error.message.should eq(
|
||||||
"Method name should be underscore-cased: bad_name, not bad_Name"
|
"Method name should be underscore-cased: bad_name, not bad_Name"
|
||||||
)
|
)
|
||||||
|
|
|
@ -56,12 +56,12 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
s = Source.new ":nok unless !s.empty?"
|
s = Source.new ":nok unless !s.empty?", "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 1
|
error.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Avoid negated conditions in unless blocks"
|
error.message.should eq "Avoid negated conditions in unless blocks"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,12 +32,12 @@ module Ameba::Rules
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 3
|
error.location.to_s.should eq "source.cr:3:11"
|
||||||
error.message.should eq(
|
error.message.should eq(
|
||||||
"Favour method name 'picture?' over 'has_picture?'")
|
"Favour method name 'picture?' over 'has_picture?'")
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,12 +25,12 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
source = Source.new "a = 1\n\n "
|
source = Source.new "a = 1\n\n ", "source.cr"
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
|
|
||||||
error = source.errors.first
|
error = source.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 3
|
error.location.to_s.should eq "source.cr:3:1"
|
||||||
error.message.should eq "Blank lines detected at the end of the file"
|
error.message.should eq "Blank lines detected at the end of the file"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,12 +15,12 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
source = Source.new "a = 1\n b = 2 "
|
source = Source.new "a = 1\n b = 2 ", "source.cr"
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
|
|
||||||
error = source.errors.first
|
error = source.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:7"
|
||||||
error.message.should eq "Trailing whitespace detected"
|
error.message.should eq "Trailing whitespace detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,9 +3,9 @@ require "../../spec_helper"
|
||||||
module Ameba
|
module Ameba
|
||||||
subject = Rules::TypeNames.new
|
subject = Rules::TypeNames.new
|
||||||
|
|
||||||
private def it_reports_name(content, expected)
|
private def it_reports_name(code, expected)
|
||||||
it "reports type name #{expected}" do
|
it "reports type name #{expected}" do
|
||||||
s = Source.new content
|
s = Source.new code
|
||||||
Rules::TypeNames.new.catch(s).should_not be_valid
|
Rules::TypeNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.errors.first.message.should contain expected
|
||||||
end
|
end
|
||||||
|
@ -47,11 +47,11 @@ module Ameba
|
||||||
s = Source.new %(
|
s = Source.new %(
|
||||||
class My_class
|
class My_class
|
||||||
end
|
end
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
error.message.should eq(
|
||||||
"Type name should be camelcased: MyClass, but it was My_class"
|
"Type name should be camelcased: MyClass, but it was My_class"
|
||||||
)
|
)
|
||||||
|
|
|
@ -31,13 +31,13 @@ module Ameba::Rules
|
||||||
else
|
else
|
||||||
:two
|
:two
|
||||||
end
|
end
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.should_not be_nil
|
error.should_not be_nil
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq "Favour if over unless with else"
|
error.message.should eq "Favour if over unless with else"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,9 +3,9 @@ require "../../spec_helper"
|
||||||
module Ameba
|
module Ameba
|
||||||
subject = Rules::VariableNames.new
|
subject = Rules::VariableNames.new
|
||||||
|
|
||||||
private def it_reports_var_name(content, expected)
|
private def it_reports_var_name(code, expected)
|
||||||
it "reports method name #{expected}" do
|
it "reports method name #{expected}" do
|
||||||
s = Source.new content
|
s = Source.new code
|
||||||
Rules::VariableNames.new.catch(s).should_not be_valid
|
Rules::VariableNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.errors.first.message.should contain expected
|
||||||
end
|
end
|
||||||
|
@ -48,11 +48,11 @@ module Ameba
|
||||||
it "reports rule, pos and message" do
|
it "reports rule, pos and message" do
|
||||||
s = Source.new %(
|
s = Source.new %(
|
||||||
badName = "Yeah"
|
badName = "Yeah"
|
||||||
)
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
error = s.errors.first
|
||||||
error.rule.should_not be_nil
|
error.rule.should_not be_nil
|
||||||
error.pos.should eq 2
|
error.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
error.message.should eq(
|
||||||
"Var name should be underscore-cased: bad_name, not badName"
|
"Var name should be underscore-cased: bad_name, not badName"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,22 +3,24 @@ require "../spec_helper"
|
||||||
module Ameba
|
module Ameba
|
||||||
describe Source do
|
describe Source do
|
||||||
describe ".new" do
|
describe ".new" do
|
||||||
it "allows to create a source by content and path" do
|
it "allows to create a source by code and path" do
|
||||||
s = Source.new("content", "path")
|
s = Source.new("code", "path")
|
||||||
s.path.should eq "path"
|
s.path.should eq "path"
|
||||||
s.content.should eq "content"
|
s.code.should eq "code"
|
||||||
s.lines.should eq ["content"]
|
s.lines.should eq ["code"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#error" do
|
describe "#error" do
|
||||||
it "adds and error" do
|
it "adds and error" do
|
||||||
s = Source.new ""
|
s = Source.new "", "source.cr"
|
||||||
s.error(DummyRule.new, 23, "Error!")
|
s.error(DummyRule.new, s.location(23, 2), "Error!")
|
||||||
s.errors.size.should eq 1
|
s.should_not be_valid
|
||||||
s.errors.first.rule.should_not be_nil
|
|
||||||
s.errors.first.pos.should eq 23
|
error = s.errors.first
|
||||||
s.errors.first.message.should eq "Error!"
|
error.rule.should_not be_nil
|
||||||
|
error.location.to_s.should eq "source.cr:23:2"
|
||||||
|
error.message.should eq "Error!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,7 +16,7 @@ module Ameba
|
||||||
String.build do |str|
|
String.build do |str|
|
||||||
str << "Source expected to be valid, but there are errors:\n\n"
|
str << "Source expected to be valid, but there are errors:\n\n"
|
||||||
source.errors.each do |e|
|
source.errors.each do |e|
|
||||||
str << " * #{e.rule.name}:#{e.pos} #{e.message}\n"
|
str << " * #{e.rule.name}: #{e.message}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,7 @@ module Ameba::Formatter
|
||||||
|
|
||||||
failed_sources.each do |source|
|
failed_sources.each do |source|
|
||||||
source.errors.each do |error|
|
source.errors.each do |error|
|
||||||
output << "#{source.path}:#{error.pos}\n".colorize(:cyan)
|
output << "#{error.location}\n".colorize(:cyan)
|
||||||
output << "#{error.rule.name}: #{error.message}\n\n".colorize(:red)
|
output << "#{error.rule.name}: #{error.message}\n\n".colorize(:red)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,8 +22,7 @@ module Ameba::Rules
|
||||||
node.args.first?.try &.is_a?(Crystal::BoolLiteral) ||
|
node.args.first?.try &.is_a?(Crystal::BoolLiteral) ||
|
||||||
node.obj.is_a?(Crystal::BoolLiteral)
|
node.obj.is_a?(Crystal::BoolLiteral)
|
||||||
)
|
)
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location, "Comparison to a boolean is pointless"
|
||||||
"Comparison to a boolean is pointless"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,7 @@ module Ameba::Rules
|
||||||
name = target.names.first
|
name = target.names.first
|
||||||
return if (expected = name.upcase) == name
|
return if (expected = name.upcase) == name
|
||||||
|
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Constant name should be screaming-cased: #{expected}, not #{name}"
|
"Constant name should be screaming-cased: #{expected}, not #{name}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,7 @@ module Ameba::Rules
|
||||||
node.args.empty? &&
|
node.args.empty? &&
|
||||||
node.obj.nil?
|
node.obj.nil?
|
||||||
|
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Possible forgotten debugger statement detected"
|
"Possible forgotten debugger statement detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,8 +33,7 @@ module Ameba::Rules
|
||||||
|
|
||||||
return if exp.nil? || exp == "nil"
|
return if exp.nil? || exp == "nil"
|
||||||
|
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location, "Avoid empty expression '#{exp}'"
|
||||||
"Avoid empty expression '#{exp}'"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,7 @@ module Ameba::Rules
|
||||||
next unless token.type == :NUMBER && decimal?(token.raw)
|
next unless token.type == :NUMBER && decimal?(token.raw)
|
||||||
|
|
||||||
if (expected = underscored token.raw) != token.raw
|
if (expected = underscored token.raw) != token.raw
|
||||||
source.error self, token.line_number,
|
source.error self, token.location,
|
||||||
"Large numbers should be written with underscores: #{expected}"
|
"Large numbers should be written with underscores: #{expected}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,8 +5,9 @@ module Ameba::Rules
|
||||||
def test(source)
|
def test(source)
|
||||||
source.lines.each_with_index do |line, index|
|
source.lines.each_with_index do |line, index|
|
||||||
next unless line.size > 80
|
next unless line.size > 80
|
||||||
source.error self, index + 1,
|
|
||||||
"Line too long (#{line.size} symbols)"
|
source.error self, source.location(index + 1, line.size),
|
||||||
|
"Line too long"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,8 +22,7 @@ module Ameba::Rules
|
||||||
|
|
||||||
def check_node(source, node)
|
def check_node(source, node)
|
||||||
return unless literal?(node.cond)
|
return unless literal?(node.cond)
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location, "Literal value found in conditional"
|
||||||
"Literal value found in conditional"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(source, node : Crystal::If)
|
def test(source, node : Crystal::If)
|
||||||
|
|
|
@ -19,8 +19,7 @@ module Ameba::Rules
|
||||||
def test(source, node : Crystal::StringInterpolation)
|
def test(source, node : Crystal::StringInterpolation)
|
||||||
found = node.expressions.any? { |e| !string_literal?(e) && literal?(e) }
|
found = node.expressions.any? { |e| !string_literal?(e) && literal?(e) }
|
||||||
return unless found
|
return unless found
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location, "Literal value found in interpolation"
|
||||||
"Literal value found in interpolation"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,7 +38,7 @@ module Ameba::Rules
|
||||||
def test(source, node : Crystal::Def)
|
def test(source, node : Crystal::Def)
|
||||||
return if (expected = node.name.underscore) == node.name
|
return if (expected = node.name.underscore) == node.name
|
||||||
|
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Method name should be underscore-cased: #{expected}, not #{node.name}"
|
"Method name should be underscore-cased: #{expected}, not #{node.name}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ module Ameba::Rules
|
||||||
|
|
||||||
def test(source, node : Crystal::Unless)
|
def test(source, node : Crystal::Unless)
|
||||||
return unless negated_condition? node.cond
|
return unless negated_condition? node.cond
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Avoid negated conditions in unless blocks"
|
"Avoid negated conditions in unless blocks"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Ameba::Rules
|
||||||
|
|
||||||
def test(source, node : Crystal::Def)
|
def test(source, node : Crystal::Def)
|
||||||
if node.name =~ /(is|has)_(\w+)\?/
|
if node.name =~ /(is|has)_(\w+)\?/
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Favour method name '#{$2}?' over '#{node.name}'"
|
"Favour method name '#{$2}?' over '#{node.name}'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ module Ameba::Rules
|
||||||
struct TrailingBlankLines < Rule
|
struct TrailingBlankLines < Rule
|
||||||
def test(source)
|
def test(source)
|
||||||
if source.lines.size > 1 && source.lines[-2, 2].join.strip.empty?
|
if source.lines.size > 1 && source.lines[-2, 2].join.strip.empty?
|
||||||
source.error self, source.lines.size,
|
source.error self, source.location(source.lines.size, 1),
|
||||||
"Blank lines detected at the end of the file"
|
"Blank lines detected at the end of the file"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Ameba::Rules
|
||||||
def test(source)
|
def test(source)
|
||||||
source.lines.each_with_index do |line, index|
|
source.lines.each_with_index do |line, index|
|
||||||
next unless line =~ /\s$/
|
next unless line =~ /\s$/
|
||||||
source.error self, index + 1,
|
source.error self, source.location(index + 1, line.size),
|
||||||
"Trailing whitespace detected"
|
"Trailing whitespace detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -55,7 +55,7 @@ module Ameba::Rules
|
||||||
expected = name.camelcase
|
expected = name.camelcase
|
||||||
return if expected == name
|
return if expected == name
|
||||||
|
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Type name should be camelcased: #{expected}, but it was #{name}"
|
"Type name should be camelcased: #{expected}, but it was #{name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,8 @@ module Ameba::Rules
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(source, node : Crystal::Unless)
|
def test(source, node : Crystal::Unless)
|
||||||
unless node.else.is_a?(Crystal::Nop)
|
return if node.else.nop?
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location, "Favour if over unless with else"
|
||||||
"Favour if over unless with else"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,7 +32,7 @@ module Ameba::Rules
|
||||||
private def check_node(source, node)
|
private def check_node(source, node)
|
||||||
return if (expected = node.name.underscore) == node.name
|
return if (expected = node.name.underscore) == node.name
|
||||||
|
|
||||||
source.error self, node.location.try &.line_number,
|
source.error self, node.location,
|
||||||
"Var name should be underscore-cased: #{expected}, not #{node.name}"
|
"Var name should be underscore-cased: #{expected}, not #{node.name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,20 +8,20 @@ module Ameba
|
||||||
# position of the error and a message.
|
# position of the error and a message.
|
||||||
record Error,
|
record Error,
|
||||||
rule : Rule,
|
rule : Rule,
|
||||||
pos : Int32?,
|
location : Crystal::Location?,
|
||||||
message : String
|
message : String
|
||||||
|
|
||||||
getter lines : Array(String)?
|
getter lines : Array(String)?
|
||||||
getter errors = [] of Error
|
getter errors = [] of Error
|
||||||
getter path : String?
|
getter path : String?
|
||||||
getter content : String
|
getter code : String
|
||||||
getter ast : Crystal::ASTNode?
|
getter ast : Crystal::ASTNode?
|
||||||
|
|
||||||
def initialize(@content : String, @path = nil)
|
def initialize(@code : String, @path = nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def error(rule : Rule, line_number : Int32?, message : String)
|
def error(rule : Rule, location, message : String)
|
||||||
errors << Error.new rule, line_number, message
|
errors << Error.new rule, location, message
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid?
|
def valid?
|
||||||
|
@ -29,14 +29,18 @@ module Ameba
|
||||||
end
|
end
|
||||||
|
|
||||||
def lines
|
def lines
|
||||||
@lines ||= @content.split("\n")
|
@lines ||= @code.split("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
def ast
|
def ast
|
||||||
@ast ||=
|
@ast ||=
|
||||||
Crystal::Parser.new(content)
|
Crystal::Parser.new(code)
|
||||||
.tap { |parser| parser.filename = @path }
|
.tap { |parser| parser.filename = @path }
|
||||||
.parse
|
.parse
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def location(l, c)
|
||||||
|
Crystal::Location.new path, l, c
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ require "compiler/crystal/syntax/*"
|
||||||
module Ameba
|
module Ameba
|
||||||
class Tokenizer
|
class Tokenizer
|
||||||
def initialize(source)
|
def initialize(source)
|
||||||
@lexer = Crystal::Lexer.new source.content
|
@lexer = Crystal::Lexer.new source.code
|
||||||
@lexer.count_whitespace = true
|
@lexer.count_whitespace = true
|
||||||
@lexer.comments_enabled = true
|
@lexer.comments_enabled = true
|
||||||
@lexer.wants_raw = true
|
@lexer.wants_raw = true
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue