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