mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Rename Error to Issue
This commit is contained in:
parent
e1b51f62a5
commit
f8d14d4222
81 changed files with 475 additions and 384 deletions
|
@ -16,8 +16,8 @@ module Ameba::Formatter
|
||||||
|
|
||||||
path = "source.cr"
|
path = "source.cr"
|
||||||
s = Source.new("", path).tap do |source|
|
s = Source.new("", path).tap do |source|
|
||||||
source.error(ErrorRule.new, 1, 2, "ErrorRule", :disabled)
|
source.add_issue(ErrorRule.new, {1, 2}, message: "ErrorRule", status: :disabled)
|
||||||
source.error(NamedRule.new, 2, 2, "NamedRule", :disabled)
|
source.add_issue(NamedRule.new, location: {2, 2}, message: "NamedRule", status: :disabled)
|
||||||
end
|
end
|
||||||
subject.finished [s]
|
subject.finished [s]
|
||||||
log = output.to_s
|
log = output.to_s
|
||||||
|
@ -30,8 +30,9 @@ module Ameba::Formatter
|
||||||
|
|
||||||
it "does not write not-disabled rules" do
|
it "does not write not-disabled rules" do
|
||||||
s = Source.new("", "source.cr").tap do |source|
|
s = Source.new("", "source.cr").tap do |source|
|
||||||
source.error(ErrorRule.new, 1, 2, "ErrorRule")
|
source.add_issue(ErrorRule.new, {1, 2}, "ErrorRule")
|
||||||
source.error(NamedRule.new, 2, 2, "NamedRule", :disabled)
|
source.add_issue(NamedRule.new, location: {2, 2},
|
||||||
|
message: "NamedRule", status: :disabled)
|
||||||
end
|
end
|
||||||
subject.finished [s]
|
subject.finished [s]
|
||||||
output.to_s.should_not contain ErrorRule.name
|
output.to_s.should_not contain ErrorRule.name
|
||||||
|
|
|
@ -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, nil, "message"
|
s.add_issue DummyRule.new, Crystal::Nop.new, "message"
|
||||||
subject.source_finished s
|
subject.source_finished s
|
||||||
output.to_s.should contain "F"
|
output.to_s.should contain "F"
|
||||||
end
|
end
|
||||||
|
@ -37,11 +37,11 @@ module Ameba::Formatter
|
||||||
output.to_s.should contain "Finished in"
|
output.to_s.should contain "Finished in"
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when errors found" do
|
context "when issues found" do
|
||||||
it "writes each error" do
|
it "writes each issue" do
|
||||||
s = Source.new("").tap do |source|
|
s = Source.new("").tap do |source|
|
||||||
source.error(DummyRule.new, 1, 1, "DummyRuleError")
|
source.add_issue(DummyRule.new, {1, 1}, "DummyRuleError")
|
||||||
source.error(NamedRule.new, 1, 2, "NamedRuleError")
|
source.add_issue(NamedRule.new, {1, 2}, "NamedRuleError")
|
||||||
end
|
end
|
||||||
subject.finished [s]
|
subject.finished [s]
|
||||||
log = output.to_s
|
log = output.to_s
|
||||||
|
@ -50,9 +50,10 @@ module Ameba::Formatter
|
||||||
log.should contain "NamedRuleError"
|
log.should contain "NamedRuleError"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not write disabled errors" do
|
it "does not write disabled issues" do
|
||||||
s = Source.new ""
|
s = Source.new ""
|
||||||
s.error(DummyRule.new, 1, 1, "DummyRuleError", :disabled)
|
s.add_issue(DummyRule.new, location: {1, 1},
|
||||||
|
message: "DummyRuleError", status: :disabled)
|
||||||
subject.finished [s]
|
subject.finished [s]
|
||||||
output.to_s.should contain "1 inspected, 0 failures."
|
output.to_s.should contain "1 inspected, 0 failures."
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,9 +16,9 @@ module Ameba::Formatter
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when problems found" do
|
context "when problems found" do
|
||||||
it "reports an error" do
|
it "reports an issue" do
|
||||||
s = Source.new "a = 1", "source.cr"
|
s = Source.new "a = 1", "source.cr"
|
||||||
s.error DummyRule.new, 1, 2, "message"
|
s.add_issue DummyRule.new, {1, 2}, "message"
|
||||||
subject = flycheck
|
subject = flycheck
|
||||||
subject.source_finished s
|
subject.source_finished s
|
||||||
subject.output.to_s.should eq(
|
subject.output.to_s.should eq(
|
||||||
|
@ -28,7 +28,7 @@ module Ameba::Formatter
|
||||||
|
|
||||||
it "properly reports multi-line message" do
|
it "properly reports multi-line message" do
|
||||||
s = Source.new "a = 1", "source.cr"
|
s = Source.new "a = 1", "source.cr"
|
||||||
s.error DummyRule.new, 1, 2, "multi\nline"
|
s.add_issue DummyRule.new, {1, 2}, "multi\nline"
|
||||||
subject = flycheck
|
subject = flycheck
|
||||||
subject.source_finished s
|
subject.source_finished s
|
||||||
subject.output.to_s.should eq(
|
subject.output.to_s.should eq(
|
||||||
|
@ -38,7 +38,7 @@ module Ameba::Formatter
|
||||||
|
|
||||||
it "reports nothing if location was not set" do
|
it "reports nothing if location was not set" do
|
||||||
s = Source.new "a = 1", "source.cr"
|
s = Source.new "a = 1", "source.cr"
|
||||||
s.error DummyRule.new, nil, "message"
|
s.add_issue DummyRule.new, Crystal::Nop.new, "message"
|
||||||
subject = flycheck
|
subject = flycheck
|
||||||
subject.source_finished s
|
subject.source_finished s
|
||||||
subject.output.to_s.should eq ""
|
subject.output.to_s.should eq ""
|
||||||
|
|
|
@ -31,26 +31,26 @@ module Ameba
|
||||||
|
|
||||||
it "shows rule name" do
|
it "shows rule name" do
|
||||||
s = Source.new ""
|
s = Source.new ""
|
||||||
s.error DummyRule.new, 1, 2, "message1"
|
s.add_issue DummyRule.new, {1, 2}, "message1"
|
||||||
|
|
||||||
result = get_result [s]
|
result = get_result [s]
|
||||||
result["sources"][0]["errors"][0]["rule_name"].should eq DummyRule.name
|
result["sources"][0]["issues"][0]["rule_name"].should eq DummyRule.name
|
||||||
end
|
end
|
||||||
|
|
||||||
it "shows a message" do
|
it "shows a message" do
|
||||||
s = Source.new ""
|
s = Source.new ""
|
||||||
s.error DummyRule.new, 1, 2, "message"
|
s.add_issue DummyRule.new, {1, 2}, "message"
|
||||||
|
|
||||||
result = get_result [s]
|
result = get_result [s]
|
||||||
result["sources"][0]["errors"][0]["message"].should eq "message"
|
result["sources"][0]["issues"][0]["message"].should eq "message"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "shows error location" do
|
it "shows issue location" do
|
||||||
s = Source.new ""
|
s = Source.new ""
|
||||||
s.error DummyRule.new, 1, 2, "message"
|
s.add_issue DummyRule.new, {1, 2}, "message"
|
||||||
|
|
||||||
result = get_result [s]
|
result = get_result [s]
|
||||||
location = result["sources"][0]["errors"][0]["location"]
|
location = result["sources"][0]["issues"][0]["location"]
|
||||||
location["line"].should eq 1
|
location["line"].should eq 1
|
||||||
location["column"].should eq 2
|
location["column"].should eq 2
|
||||||
end
|
end
|
||||||
|
@ -62,16 +62,16 @@ module Ameba
|
||||||
result["summary"]["target_sources_count"].should eq 2
|
result["summary"]["target_sources_count"].should eq 2
|
||||||
end
|
end
|
||||||
|
|
||||||
it "shows errors count" do
|
it "shows issues count" do
|
||||||
s1 = Source.new ""
|
s1 = Source.new ""
|
||||||
s1.error DummyRule.new, 1, 2, "message1"
|
s1.add_issue DummyRule.new, {1, 2}, "message1"
|
||||||
s1.error DummyRule.new, 1, 2, "message2"
|
s1.add_issue DummyRule.new, {1, 2}, "message2"
|
||||||
|
|
||||||
s2 = Source.new ""
|
s2 = Source.new ""
|
||||||
s2.error DummyRule.new, 1, 2, "message3"
|
s2.add_issue DummyRule.new, {1, 2}, "message3"
|
||||||
|
|
||||||
result = get_result [s1, s2]
|
result = get_result [s1, s2]
|
||||||
result["summary"]["errors_count"].should eq 3
|
result["summary"]["issues_count"].should eq 3
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Ameba
|
||||||
formatter = Formatter::TODOFormatter.new IO::Memory.new, file
|
formatter = Formatter::TODOFormatter.new IO::Memory.new, file
|
||||||
|
|
||||||
s = Source.new "a = 1", "source.cr"
|
s = Source.new "a = 1", "source.cr"
|
||||||
s.error DummyRule.new, 1, 2, "message"
|
s.add_issue DummyRule.new, {1, 2}, "message"
|
||||||
|
|
||||||
formatter.finished [s]
|
formatter.finished [s]
|
||||||
file.to_s
|
file.to_s
|
||||||
|
@ -57,7 +57,7 @@ module Ameba
|
||||||
formatter = Formatter::TODOFormatter.new IO::Memory.new, file
|
formatter = Formatter::TODOFormatter.new IO::Memory.new, file
|
||||||
|
|
||||||
s = Source.new "def invalid_syntax"
|
s = Source.new "def invalid_syntax"
|
||||||
s.error Rule::Syntax.new, 1, 2, "message"
|
s.add_issue Rule::Syntax.new, {1, 2}, "message"
|
||||||
|
|
||||||
formatter.finished [s]
|
formatter.finished [s]
|
||||||
content = file.to_s
|
content = file.to_s
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Ameba
|
||||||
# ameba:disable #{NamedRule.name}
|
# ameba:disable #{NamedRule.name}
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "Error!")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "Error!")
|
||||||
s.should be_valid
|
s.should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ module Ameba
|
||||||
s = Source.new %Q(
|
s = Source.new %Q(
|
||||||
Time.epoch(1483859302) # ameba:disable #{NamedRule.name}
|
Time.epoch(1483859302) # ameba:disable #{NamedRule.name}
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 2, 12, "Error!")
|
s.add_issue(NamedRule.new, location: {2, 12}, message: "Error!")
|
||||||
s.should be_valid
|
s.should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ module Ameba
|
||||||
# ameba:disable WrongName
|
# ameba:disable WrongName
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "Error!")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "Error!")
|
||||||
s.should_not be_valid
|
s.should_not be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ module Ameba
|
||||||
# ameba:disable SomeRule LargeNumbers #{NamedRule.name} SomeOtherRule
|
# ameba:disable SomeRule LargeNumbers #{NamedRule.name} SomeOtherRule
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "")
|
||||||
s.should be_valid
|
s.should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ module Ameba
|
||||||
# ameba:disable SomeRule, LargeNumbers, #{NamedRule.name}, SomeOtherRule
|
# ameba:disable SomeRule, LargeNumbers, #{NamedRule.name}, SomeOtherRule
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "")
|
||||||
s.should be_valid
|
s.should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ module Ameba
|
||||||
# ameba:disable SomeRule, SomeOtherRule LargeNumbers
|
# ameba:disable SomeRule, SomeOtherRule LargeNumbers
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "")
|
||||||
s.should_not be_valid
|
s.should_not be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ module Ameba
|
||||||
#
|
#
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 4, 12, "")
|
s.add_issue(NamedRule.new, location: {4, 12}, message: "")
|
||||||
s.should_not be_valid
|
s.should_not be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ module Ameba
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "")
|
||||||
s.should_not be_valid
|
s.should_not be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ module Ameba
|
||||||
"ameba:disable #{NamedRule.name}"
|
"ameba:disable #{NamedRule.name}"
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "")
|
||||||
s.should_not be_valid
|
s.should_not be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ module Ameba
|
||||||
# # ameba:disable #{NamedRule.name}
|
# # ameba:disable #{NamedRule.name}
|
||||||
Time.epoch(1483859302)
|
Time.epoch(1483859302)
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 3, 12, "")
|
s.add_issue(NamedRule.new, location: {3, 12}, message: "")
|
||||||
s.should_not be_valid
|
s.should_not be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ module Ameba
|
||||||
s = Source.new %Q(
|
s = Source.new %Q(
|
||||||
a = 1 # Disable it: # ameba:disable #{NamedRule.name}
|
a = 1 # Disable it: # ameba:disable #{NamedRule.name}
|
||||||
)
|
)
|
||||||
s.error(NamedRule.new, 2, 12, "")
|
s.add_issue(NamedRule.new, location: {2, 12}, message: "")
|
||||||
s.should_not be_valid
|
s.should_not be_valid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
50
spec/ameba/issue_spec.cr
Normal file
50
spec/ameba/issue_spec.cr
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
require "../spec_helper"
|
||||||
|
|
||||||
|
module Ameba
|
||||||
|
describe Issue do
|
||||||
|
it "accepts rule and message" do
|
||||||
|
issue = Issue.new rule: DummyRule.new,
|
||||||
|
location: nil,
|
||||||
|
end_location: nil,
|
||||||
|
message: "Blah",
|
||||||
|
status: nil
|
||||||
|
|
||||||
|
issue.rule.should_not be_nil
|
||||||
|
issue.message.should eq "Blah"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts location" do
|
||||||
|
location = Crystal::Location.new("path", 3, 2)
|
||||||
|
issue = Issue.new rule: DummyRule.new,
|
||||||
|
location: location,
|
||||||
|
end_location: nil,
|
||||||
|
message: "Blah",
|
||||||
|
status: nil
|
||||||
|
|
||||||
|
issue.location.to_s.should eq location.to_s
|
||||||
|
issue.end_location.should eq nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts end_location" do
|
||||||
|
location = Crystal::Location.new("path", 3, 2)
|
||||||
|
issue = Issue.new rule: DummyRule.new,
|
||||||
|
location: nil,
|
||||||
|
end_location: location,
|
||||||
|
message: "Blah",
|
||||||
|
status: nil
|
||||||
|
|
||||||
|
issue.location.should eq nil
|
||||||
|
issue.end_location.to_s.should eq location.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts status" do
|
||||||
|
issue = Issue.new rule: DummyRule.new,
|
||||||
|
location: nil,
|
||||||
|
end_location: nil,
|
||||||
|
message: "",
|
||||||
|
status: :enabled
|
||||||
|
|
||||||
|
issue.status.should eq :enabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
40
spec/ameba/reportable_spec.cr
Normal file
40
spec/ameba/reportable_spec.cr
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
require "../spec_helper"
|
||||||
|
|
||||||
|
module Ameba
|
||||||
|
describe Reportable do
|
||||||
|
describe "#add_issue" do
|
||||||
|
it "adds a new issue for node" do
|
||||||
|
s = Source.new "", "source.cr"
|
||||||
|
s.add_issue(DummyRule.new, Crystal::Nop.new, "Error!")
|
||||||
|
|
||||||
|
issue = s.issues.first
|
||||||
|
issue.rule.should_not be_nil
|
||||||
|
issue.location.to_s.should eq ""
|
||||||
|
issue.message.should eq "Error!"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds a new issue by line and column number" do
|
||||||
|
s = Source.new "", "source.cr"
|
||||||
|
s.add_issue(DummyRule.new, {23, 2}, "Error!")
|
||||||
|
|
||||||
|
issue = s.issues.first
|
||||||
|
issue.rule.should_not be_nil
|
||||||
|
issue.location.to_s.should eq "source.cr:23:2"
|
||||||
|
issue.message.should eq "Error!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#valid?" do
|
||||||
|
it "returns true if no issues added" do
|
||||||
|
s = Source.new "", "source.cr"
|
||||||
|
s.should be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false if there are issues added" do
|
||||||
|
s = Source.new "", "source.cr"
|
||||||
|
s.add_issue DummyRule.new, {22, 2}, "ERROR!"
|
||||||
|
s.should_not be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -66,10 +66,10 @@ module Ameba::Rule
|
||||||
source = Source.new "a != true", "source.cr"
|
source = Source.new "a != true", "source.cr"
|
||||||
subject.catch(source)
|
subject.catch(source)
|
||||||
|
|
||||||
error = source.errors.first
|
issue = source.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:1:1"
|
issue.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Comparison to a boolean is pointless"
|
issue.message.should eq "Comparison to a boolean is pointless"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -103,10 +103,10 @@ module Ameba::Rule
|
||||||
source = Source.new "true != a", "source.cr"
|
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
|
issue = source.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:1:1"
|
issue.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Comparison to a boolean is pointless"
|
issue.message.should eq "Comparison to a boolean is pointless"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Ameba
|
||||||
it "reports constant name #{expected}" do
|
it "reports constant name #{expected}" do
|
||||||
s = Source.new code
|
s = Source.new code
|
||||||
Rule::ConstantNames.new.catch(s).should_not be_valid
|
Rule::ConstantNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.issues.first.message.should contain expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,10 +40,10 @@ module Ameba
|
||||||
Const = 1
|
Const = 1
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
issue.message.should eq(
|
||||||
"Constant name should be screaming-cased: CONST, not Const"
|
"Constant name should be screaming-cased: CONST, not Const"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,10 +35,10 @@ module Ameba::Rule
|
||||||
s = Source.new "debugger", "source.cr"
|
s = Source.new "debugger", "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:1:1"
|
issue.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Possible forgotten debugger statement detected"
|
issue.message.should eq "Possible forgotten debugger statement detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -58,11 +58,11 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
|
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:3:11"
|
issue.location.to_s.should eq "source.cr:3:11"
|
||||||
error.message.should eq "Empty `ensure` block detected"
|
issue.message.should eq "Empty `ensure` block detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -101,10 +101,10 @@ module Ameba
|
||||||
end
|
end
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:12"
|
issue.location.to_s.should eq "source.cr:2:12"
|
||||||
error.message.should eq "Avoid empty expressions"
|
issue.message.should eq "Avoid empty expressions"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,10 +32,10 @@ module Ameba::Rule
|
||||||
h = {"a" => 1, "a" => 2}
|
h = {"a" => 1, "a" => 2}
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:13"
|
issue.location.to_s.should eq "source.cr:2:13"
|
||||||
error.message.should eq %(Duplicated keys in hash literal: "a")
|
issue.message.should eq %(Duplicated keys in hash literal: "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports multiple duplicated keys" do
|
it "reports multiple duplicated keys" do
|
||||||
|
@ -43,8 +43,8 @@ module Ameba::Rule
|
||||||
h = {"key1" => 1, "key1" => 2, "key2" => 3, "key2" => 4}
|
h = {"key1" => 1, "key1" => 2, "key2" => 3, "key2" => 4}
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.message.should eq %(Duplicated keys in hash literal: "key1", "key2")
|
issue.message.should eq %(Duplicated keys in hash literal: "key1", "key2")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Ameba
|
||||||
it "transforms large number #{number}" do
|
it "transforms large number #{number}" do
|
||||||
s = Source.new number
|
s = Source.new number
|
||||||
Rule::LargeNumbers.new.catch(s).should_not be_valid
|
Rule::LargeNumbers.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.issues.first.message.should contain expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -115,10 +115,10 @@ module Ameba
|
||||||
1200000
|
1200000
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:10"
|
issue.location.to_s.should eq "source.cr:2:10"
|
||||||
error.message.should match /1_200_000/
|
issue.message.should match /1_200_000/
|
||||||
end
|
end
|
||||||
|
|
||||||
context "properties" do
|
context "properties" do
|
||||||
|
|
|
@ -24,10 +24,10 @@ module Ameba::Rule
|
||||||
source = Source.new long_line, "source.cr"
|
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
|
issue = source.issues.first
|
||||||
error.rule.should eq subject
|
issue.rule.should eq subject
|
||||||
error.location.to_s.should eq "source.cr:1:81"
|
issue.location.to_s.should eq "source.cr:1:81"
|
||||||
error.message.should eq "Line too long"
|
issue.message.should eq "Line too long"
|
||||||
end
|
end
|
||||||
|
|
||||||
context "properties" do
|
context "properties" do
|
||||||
|
|
|
@ -62,11 +62,11 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
s.errors.size.should eq 1
|
s.issues.size.should eq 1
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq "Literal value found in conditional"
|
issue.message.should eq "Literal value found in conditional"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,10 +32,10 @@ module Ameba::Rule
|
||||||
s = Source.new %q("#{4}"), "source.cr"
|
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
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:1:1"
|
issue.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Literal value found in interpolation"
|
issue.message.should eq "Literal value found in interpolation"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Ameba
|
||||||
it "reports method name #{expected}" do
|
it "reports method name #{expected}" do
|
||||||
s = Source.new code
|
s = Source.new code
|
||||||
Rule::MethodNames.new.catch(s).should_not be_valid
|
Rule::MethodNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.issues.first.message.should contain expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -44,10 +44,10 @@ module Ameba
|
||||||
end
|
end
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
issue.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"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,10 +59,10 @@ module Ameba::Rule
|
||||||
s = Source.new ":nok unless !s.empty?", "source.cr"
|
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
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:1:1"
|
issue.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "Avoid negated conditions in unless blocks"
|
issue.message.should eq "Avoid negated conditions in unless blocks"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,10 +44,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
|
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
issue.message.should eq(
|
||||||
"Symbols `,:` may be unwanted in %i array literals"
|
"Symbols `,:` may be unwanted in %i array literals"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -58,10 +58,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
|
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
issue.message.should eq(
|
||||||
"Symbols `,\"` may be unwanted in %w array literals"
|
"Symbols `,\"` may be unwanted in %w array literals"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,10 +38,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:3:11"
|
issue.location.to_s.should eq "source.cr:3:11"
|
||||||
error.message.should eq(
|
issue.message.should eq(
|
||||||
"Favour method name 'picture?' over 'has_picture?'")
|
"Favour method name 'picture?' over 'has_picture?'")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,11 @@ module Ameba::Rule
|
||||||
it "reports rule, location and a message" do
|
it "reports rule, location and a message" do
|
||||||
s = Source.new "rand(1)", "source.cr"
|
s = Source.new "rand(1)", "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
|
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:1:1"
|
issue.location.to_s.should eq "source.cr:1:1"
|
||||||
error.message.should eq "rand(1) always returns 0"
|
issue.message.should eq "rand(1) always returns 0"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -204,10 +204,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq "Redundant `begin` block detected"
|
issue.message.should eq "Redundant `begin` block detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -156,10 +156,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:3:11"
|
issue.location.to_s.should eq "source.cr:3:11"
|
||||||
error.message.should eq "Argument `bar` is assigned before it is used"
|
issue.message.should eq "Argument `bar` is assigned before it is used"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ require "../../spec_helper"
|
||||||
private def check_shadowed(source, exceptions)
|
private def check_shadowed(source, exceptions)
|
||||||
s = Ameba::Source.new source
|
s = Ameba::Source.new source
|
||||||
Ameba::Rule::ShadowedException.new.catch(s).should_not be_valid
|
Ameba::Rule::ShadowedException.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain exceptions.join(", ")
|
s.issues.first.message.should contain exceptions.join(", ")
|
||||||
end
|
end
|
||||||
|
|
||||||
module Ameba::Rule
|
module Ameba::Rule
|
||||||
|
@ -163,11 +163,11 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
|
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:3:11"
|
issue.location.to_s.should eq "source.cr:3:11"
|
||||||
error.message.should eq(
|
issue.message.should eq(
|
||||||
"Exception handler has shadowed exceptions: IndexError"
|
"Exception handler has shadowed exceptions: IndexError"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,7 +68,7 @@ module Ameba::Rule
|
||||||
)
|
)
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
|
|
||||||
source.errors.size.should eq 2
|
source.issues.size.should eq 2
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports if a splat block argument shadows local var" do
|
it "reports if a splat block argument shadows local var" do
|
||||||
|
@ -89,7 +89,7 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
source.errors.first.message.should eq "Shadowing outer local variable `block`"
|
source.issues.first.message.should eq "Shadowing outer local variable `block`"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports if there are multiple args and one shadows local var" do
|
it "reports if there are multiple args and one shadows local var" do
|
||||||
|
@ -100,7 +100,7 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
source.errors.first.message.should eq "Shadowing outer local variable `foo`"
|
source.issues.first.message.should eq "Shadowing outer local variable `foo`"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't report if an outer var is reassigned in a block" do
|
it "doesn't report if an outer var is reassigned in a block" do
|
||||||
|
@ -131,10 +131,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
|
|
||||||
error = source.errors.first
|
issue = source.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:3:20"
|
issue.location.to_s.should eq "source.cr:3:20"
|
||||||
error.message.should eq "Shadowing outer local variable `foo`"
|
issue.message.should eq "Shadowing outer local variable `foo`"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,11 +27,11 @@ module Ameba::Rule
|
||||||
it "reports rule, location and message" do
|
it "reports rule, location and message" do
|
||||||
s = Source.new "def hello end", "source.cr"
|
s = Source.new "def hello end", "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
|
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:1:11"
|
issue.location.to_s.should eq "source.cr:1:11"
|
||||||
error.message.should eq "unexpected token: end (expected ';' or newline)"
|
issue.message.should eq "unexpected token: end (expected ';' or newline)"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,10 +28,10 @@ module Ameba::Rule
|
||||||
source = Source.new "a = 1\n\n ", "source.cr"
|
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
|
issue = source.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:3:1"
|
issue.location.to_s.should eq "source.cr:3:1"
|
||||||
error.message.should eq "Blank lines detected at the end of the file"
|
issue.message.should eq "Blank lines detected at the end of the file"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,10 +18,10 @@ module Ameba::Rule
|
||||||
source = Source.new "a = 1\n b = 2 ", "source.cr"
|
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
|
issue = source.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:7"
|
issue.location.to_s.should eq "source.cr:2:7"
|
||||||
error.message.should eq "Trailing whitespace detected"
|
issue.message.should eq "Trailing whitespace detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Ameba
|
||||||
it "reports type name #{expected}" do
|
it "reports type name #{expected}" do
|
||||||
s = Source.new code
|
s = Source.new code
|
||||||
Rule::TypeNames.new.catch(s).should_not be_valid
|
Rule::TypeNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.issues.first.message.should contain expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,10 +49,10 @@ module Ameba
|
||||||
end
|
end
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
issue.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"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,11 +34,11 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.should_not be_nil
|
issue.should_not be_nil
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq "Favour if over unless with else"
|
issue.message.should eq "Favour if over unless with else"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,8 @@ module Ameba::Rule
|
||||||
# ameba:disable #{NamedRule.name}
|
# ameba:disable #{NamedRule.name}
|
||||||
a = 1
|
a = 1
|
||||||
)
|
)
|
||||||
s.error NamedRule.new, 3, 9, "Useless assignment", :disabled
|
s.add_issue NamedRule.new, location: {3, 9},
|
||||||
|
message: "Useless assignment", status: :disabled
|
||||||
subject.catch(s).should be_valid
|
subject.catch(s).should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +32,8 @@ module Ameba::Rule
|
||||||
s = Source.new %Q(
|
s = Source.new %Q(
|
||||||
a = 1 # ameba:disable #{NamedRule.name}
|
a = 1 # ameba:disable #{NamedRule.name}
|
||||||
)
|
)
|
||||||
s.error NamedRule.new, 2, 1, "Alarm!", :disabled
|
s.add_issue NamedRule.new, location: {2, 1},
|
||||||
|
message: "Alarm!", status: :disabled
|
||||||
subject.catch(s).should be_valid
|
subject.catch(s).should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,7 +42,8 @@ module Ameba::Rule
|
||||||
# # ameba:disable #{NamedRule.name}
|
# # ameba:disable #{NamedRule.name}
|
||||||
a = 1
|
a = 1
|
||||||
)
|
)
|
||||||
s.error NamedRule.new, 3, 1, "Alarm!", :disabled
|
s.add_issue NamedRule.new, location: {3, 1},
|
||||||
|
message: "Alarm!", status: :disabled
|
||||||
subject.catch(s).should be_valid
|
subject.catch(s).should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,7 +53,7 @@ module Ameba::Rule
|
||||||
a = 1
|
a = 1
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should eq(
|
s.issues.first.message.should eq(
|
||||||
"Unnecessary disabling of #{NamedRule.name}"
|
"Unnecessary disabling of #{NamedRule.name}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -58,7 +61,7 @@ module Ameba::Rule
|
||||||
it "fails if there is inline unneeded directive" do
|
it "fails if there is inline unneeded directive" do
|
||||||
s = Source.new %Q(a = 1 # ameba:disable #{NamedRule.name})
|
s = Source.new %Q(a = 1 # ameba:disable #{NamedRule.name})
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should eq(
|
s.issues.first.message.should eq(
|
||||||
"Unnecessary disabling of #{NamedRule.name}"
|
"Unnecessary disabling of #{NamedRule.name}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -69,9 +72,9 @@ module Ameba::Rule
|
||||||
a = 1 # ameba:disable Rule3
|
a = 1 # ameba:disable Rule3
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 2
|
s.issues.size.should eq 2
|
||||||
s.errors.first.message.should contain "Rule1, Rule2"
|
s.issues.first.message.should contain "Rule1, Rule2"
|
||||||
s.errors.last.message.should contain "Rule3"
|
s.issues.last.message.should contain "Rule3"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fails if there is disabled UnneededDisableDirective" do
|
it "fails if there is disabled UnneededDisableDirective" do
|
||||||
|
@ -79,20 +82,21 @@ module Ameba::Rule
|
||||||
# ameba:disable #{UnneededDisableDirective.rule_name}
|
# ameba:disable #{UnneededDisableDirective.rule_name}
|
||||||
a = 1
|
a = 1
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
s.error UnneededDisableDirective.new, 3, 1, "Alarm!", :disabled
|
s.add_issue UnneededDisableDirective.new, location: {3, 1},
|
||||||
|
message: "Alarm!", status: :disabled
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports error, location and message" do
|
it "reports issue, location and message" do
|
||||||
s = Source.new %Q(
|
s = Source.new %Q(
|
||||||
# ameba:disable Rule1, Rule2
|
# ameba:disable Rule1, Rule2
|
||||||
a = 1
|
a = 1
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq "Unnecessary disabling of Rule1, Rule2"
|
issue.message.should eq "Unnecessary disabling of Rule1, Rule2"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should eq "Unused argument `c`. If it's necessary, use `_c` " \
|
s.issues.first.message.should eq "Unused argument `c`. If it's necessary, use `_c` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should eq "Unused argument `i`. If it's necessary, use `_` " \
|
s.issues.first.message.should eq "Unused argument `i`. If it's necessary, use `_` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
s.issues.first.message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -60,11 +60,11 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors[0].message.should eq "Unused argument `a`. If it's necessary, use `_a` " \
|
s.issues[0].message.should eq "Unused argument `a`. If it's necessary, use `_a` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
s.errors[1].message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
s.issues[1].message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
s.errors[2].message.should eq "Unused argument `c`. If it's necessary, use `_c` " \
|
s.issues[2].message.should eq "Unused argument `c`. If it's necessary, use `_c` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
s.issues.first.message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -174,11 +174,11 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.message.should eq "Unused argument `a`. If it's necessary, use `_a` " \
|
issue.message.should eq "Unused argument `a`. If it's necessary, use `_a` " \
|
||||||
"as an argument name to indicate that it won't be used."
|
"as an argument name to indicate that it won't be used."
|
||||||
error.location.to_s.should eq "source.cr:2:22"
|
issue.location.to_s.should eq "source.cr:2:22"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -75,10 +75,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:3:11"
|
issue.location.to_s.should eq "source.cr:3:11"
|
||||||
error.message.should eq "Useless assignment to variable `a`"
|
issue.message.should eq "Useless assignment to variable `a`"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not report useless assignment of instance var" do
|
it "does not report useless assignment of instance var" do
|
||||||
|
@ -137,7 +137,7 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.first.location.to_s.should eq ":3:11"
|
s.issues.first.location.to_s.should eq ":3:11"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports if variable reassigned and not used" do
|
it "reports if variable reassigned and not used" do
|
||||||
|
@ -314,10 +314,10 @@ module Ameba::Rule
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.last
|
issue = s.issues.last
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:5:13"
|
issue.location.to_s.should eq "source.cr:5:13"
|
||||||
error.message.should eq "Useless assignment to variable `a`"
|
issue.message.should eq "Useless assignment to variable `a`"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -340,9 +340,9 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.location.to_s.should eq ":3:16"
|
issue.location.to_s.should eq ":3:16"
|
||||||
error.message.should eq "Useless assignment to variable `b`"
|
issue.message.should eq "Useless assignment to variable `b`"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports if both assigns are reassigned and useless" do
|
it "reports if both assigns are reassigned and useless" do
|
||||||
|
@ -363,13 +363,13 @@ module Ameba::Rule
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
|
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.location.to_s.should eq ":3:13"
|
issue.location.to_s.should eq ":3:13"
|
||||||
error.message.should eq "Useless assignment to variable `a`"
|
issue.message.should eq "Useless assignment to variable `a`"
|
||||||
|
|
||||||
error = s.errors.last
|
issue = s.issues.last
|
||||||
error.location.to_s.should eq ":3:16"
|
issue.location.to_s.should eq ":3:16"
|
||||||
error.message.should eq "Useless assignment to variable `b`"
|
issue.message.should eq "Useless assignment to variable `b`"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -380,9 +380,9 @@ module Ameba::Rule
|
||||||
a = 2
|
a = 2
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 2
|
s.issues.size.should eq 2
|
||||||
s.errors.first.location.to_s.should eq ":2:11"
|
s.issues.first.location.to_s.should eq ":2:11"
|
||||||
s.errors.last.location.to_s.should eq ":3:11"
|
s.issues.last.location.to_s.should eq ":3:11"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't report if assignments are referenced" do
|
it "doesn't report if assignments are referenced" do
|
||||||
|
@ -476,8 +476,8 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 1
|
s.issues.size.should eq 1
|
||||||
s.errors.first.location.to_s.should eq ":5:17"
|
s.issues.first.location.to_s.should eq ":5:17"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not report of assignments are referenced in all branches" do
|
it "does not report of assignments are referenced in all branches" do
|
||||||
|
@ -545,8 +545,8 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 1
|
s.issues.size.should eq 1
|
||||||
s.errors.first.location.to_s.should eq ":5:17"
|
s.issues.first.location.to_s.should eq ":5:17"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -578,9 +578,9 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 2
|
s.issues.size.should eq 2
|
||||||
s.errors.first.location.to_s.should eq ":5:17"
|
s.issues.first.location.to_s.should eq ":5:17"
|
||||||
s.errors.last.location.to_s.should eq ":7:17"
|
s.issues.last.location.to_s.should eq ":7:17"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't report if assignment is referenced in cond" do
|
it "doesn't report if assignment is referenced in cond" do
|
||||||
|
@ -615,8 +615,8 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 1
|
s.issues.size.should eq 1
|
||||||
s.errors.first.location.to_s.should eq ":3:27"
|
s.issues.first.location.to_s.should eq ":3:27"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -642,8 +642,8 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 1
|
s.issues.size.should eq 1
|
||||||
s.errors.first.location.to_s.should eq ":4:17"
|
s.issues.first.location.to_s.should eq ":4:17"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not report if assignment is referenced in a loop" do
|
it "does not report if assignment is referenced in a loop" do
|
||||||
|
@ -737,8 +737,8 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 1
|
s.issues.size.should eq 1
|
||||||
s.errors.first.location.to_s.should eq ":4:17"
|
s.issues.first.location.to_s.should eq ":4:17"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -785,8 +785,8 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
s.errors.size.should eq 1
|
s.issues.size.should eq 1
|
||||||
s.errors.first.location.to_s.should eq ":4:15"
|
s.issues.first.location.to_s.should eq ":4:15"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,10 +36,10 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:6:23"
|
issue.location.to_s.should eq "source.cr:6:23"
|
||||||
error.message.should eq "Useless condition in when detected"
|
issue.message.should eq "Useless condition in when detected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Ameba
|
||||||
it "reports method name #{expected}" do
|
it "reports method name #{expected}" do
|
||||||
s = Source.new code
|
s = Source.new code
|
||||||
Rule::VariableNames.new.catch(s).should_not be_valid
|
Rule::VariableNames.new.catch(s).should_not be_valid
|
||||||
s.errors.first.message.should contain expected
|
s.issues.first.message.should contain expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,10 +50,10 @@ module Ameba
|
||||||
badName = "Yeah"
|
badName = "Yeah"
|
||||||
), "source.cr"
|
), "source.cr"
|
||||||
subject.catch(s).should_not be_valid
|
subject.catch(s).should_not be_valid
|
||||||
error = s.errors.first
|
issue = s.issues.first
|
||||||
error.rule.should_not be_nil
|
issue.rule.should_not be_nil
|
||||||
error.location.to_s.should eq "source.cr:2:9"
|
issue.location.to_s.should eq "source.cr:2:9"
|
||||||
error.message.should eq(
|
issue.message.should eq(
|
||||||
"Var name should be underscore-cased: bad_name, not badName"
|
"Var name should be underscore-cased: bad_name, not badName"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,9 +34,9 @@ module Ameba::Rule
|
||||||
source = Source.new invalid_source, "source.cr"
|
source = Source.new invalid_source, "source.cr"
|
||||||
subject.catch(source).should_not be_valid
|
subject.catch(source).should_not be_valid
|
||||||
|
|
||||||
error = source.errors.first
|
issue = source.issues.first
|
||||||
error.location.to_s.should eq "source.cr:2:1"
|
issue.location.to_s.should eq "source.cr:2:1"
|
||||||
error.message.should eq "While statement using true literal as condition"
|
issue.message.should eq "While statement using true literal as condition"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,7 +59,7 @@ module Ameba
|
||||||
|
|
||||||
Runner.new(rules, [source], formatter).run
|
Runner.new(rules, [source], formatter).run
|
||||||
source.should_not be_valid
|
source.should_not be_valid
|
||||||
source.errors.first.rule.name.should eq Rule::Syntax.rule_name
|
source.issues.first.rule.name.should eq Rule::Syntax.rule_name
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not run other rules" do
|
it "does not run other rules" do
|
||||||
|
@ -72,12 +72,12 @@ module Ameba
|
||||||
|
|
||||||
Runner.new(rules, [source], formatter).run
|
Runner.new(rules, [source], formatter).run
|
||||||
source.should_not be_valid
|
source.should_not be_valid
|
||||||
source.errors.size.should eq 1
|
source.issues.size.should eq 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "unneeded disables" do
|
context "unneeded disables" do
|
||||||
it "reports an error if such disable exists" do
|
it "reports an issue if such disable exists" do
|
||||||
rules = [Rule::UnneededDisableDirective.new] of Rule::Base
|
rules = [Rule::UnneededDisableDirective.new] of Rule::Base
|
||||||
source = Source.new %(
|
source = Source.new %(
|
||||||
a = 1 # ameba:disable LineLength
|
a = 1 # ameba:disable LineLength
|
||||||
|
@ -85,7 +85,7 @@ module Ameba
|
||||||
|
|
||||||
Runner.new(rules, [source], formatter).run
|
Runner.new(rules, [source], formatter).run
|
||||||
source.should_not be_valid
|
source.should_not be_valid
|
||||||
source.errors.first.rule.name.should eq Rule::UnneededDisableDirective.rule_name
|
source.issues.first.rule.name.should eq Rule::UnneededDisableDirective.rule_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,19 +11,6 @@ module Ameba
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#error" do
|
|
||||||
it "adds and error" do
|
|
||||||
s = Source.new "", "source.cr"
|
|
||||||
s.error(DummyRule.new, 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
|
|
||||||
|
|
||||||
describe "#fullpath" do
|
describe "#fullpath" do
|
||||||
it "returns a relative path of the source" do
|
it "returns a relative path of the source" do
|
||||||
s = Source.new "", "./source_spec.cr"
|
s = Source.new "", "./source_spec.cr"
|
||||||
|
|
|
@ -26,7 +26,7 @@ module Ameba
|
||||||
|
|
||||||
struct ErrorRule < Rule::Base
|
struct ErrorRule < Rule::Base
|
||||||
def test(source)
|
def test(source)
|
||||||
source.error self, 1, 1, "This rule always adds an error"
|
issue_for({1, 1}, "This rule always adds an error")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,8 +71,8 @@ module Ameba
|
||||||
|
|
||||||
def failure_message(source)
|
def failure_message(source)
|
||||||
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 issues: \n\n"
|
||||||
source.errors.reject(&.disabled?).each do |e|
|
source.issues.reject(&.disabled?).each do |e|
|
||||||
str << " * #{e.rule.name}: #{e.message}\n"
|
str << " * #{e.rule.name}: #{e.message}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Ameba::Formatter
|
||||||
output << "Disabled rules using inline directives: \n\n"
|
output << "Disabled rules using inline directives: \n\n"
|
||||||
|
|
||||||
sources.each do |source|
|
sources.each do |source|
|
||||||
source.errors.select(&.disabled?).each do |e|
|
source.issues.select(&.disabled?).each do |e|
|
||||||
if loc = e.location
|
if loc = e.location
|
||||||
output << "#{source.path}:#{loc.line_number}".colorize(:cyan)
|
output << "#{source.path}:#{loc.line_number}".colorize(:cyan)
|
||||||
output << " #{e.rule.name}\n"
|
output << " #{e.rule.name}\n"
|
||||||
|
|
|
@ -24,10 +24,10 @@ module Ameba::Formatter
|
||||||
failed_sources = sources.reject &.valid?
|
failed_sources = sources.reject &.valid?
|
||||||
|
|
||||||
failed_sources.each do |source|
|
failed_sources.each do |source|
|
||||||
source.errors.each do |error|
|
source.issues.each do |issue|
|
||||||
next if error.disabled?
|
next if issue.disabled?
|
||||||
output << "#{error.location}\n".colorize(:cyan)
|
output << "#{issue.location}\n".colorize(:cyan)
|
||||||
output << "#{error.rule.name}: #{error.message}\n\n".colorize(:red)
|
output << "#{issue.rule.name}: #{issue.message}\n\n".colorize(:red)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ module Ameba::Formatter
|
||||||
|
|
||||||
private def final_message(sources, failed_sources)
|
private def final_message(sources, failed_sources)
|
||||||
total = sources.size
|
total = sources.size
|
||||||
failures = failed_sources.map { |f| f.errors.size }.sum
|
failures = failed_sources.map { |f| f.issues.size }.sum
|
||||||
color = failures == 0 ? :green : :red
|
color = failures == 0 ? :green : :red
|
||||||
s = failures != 1 ? "s" : ""
|
s = failures != 1 ? "s" : ""
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module Ameba::Formatter
|
module Ameba::Formatter
|
||||||
class FlycheckFormatter < BaseFormatter
|
class FlycheckFormatter < BaseFormatter
|
||||||
def source_finished(source : Source)
|
def source_finished(source : Source)
|
||||||
source.errors.each do |e|
|
source.issues.each do |e|
|
||||||
next if e.disabled?
|
next if e.disabled?
|
||||||
if loc = e.location
|
if loc = e.location
|
||||||
output.printf "%s:%d:%d: %s: [%s] %s\n",
|
output.printf "%s:%d:%d: %s: [%s] %s\n",
|
||||||
|
|
|
@ -13,7 +13,7 @@ module Ameba::Formatter
|
||||||
# },
|
# },
|
||||||
# "sources": [
|
# "sources": [
|
||||||
# {
|
# {
|
||||||
# "errors": [
|
# "issues": [
|
||||||
# {
|
# {
|
||||||
# "location": {
|
# "location": {
|
||||||
# "column": 7,
|
# "column": 7,
|
||||||
|
@ -43,7 +43,7 @@ module Ameba::Formatter
|
||||||
# },
|
# },
|
||||||
# ],
|
# ],
|
||||||
# "summary": {
|
# "summary": {
|
||||||
# "errors_count": 3,
|
# "issues_count": 3,
|
||||||
# "target_sources_count": 1,
|
# "target_sources_count": 1,
|
||||||
# },
|
# },
|
||||||
# }
|
# }
|
||||||
|
@ -61,10 +61,10 @@ module Ameba::Formatter
|
||||||
def source_finished(source : Source)
|
def source_finished(source : Source)
|
||||||
json_source = AsJSON::Source.new source.path
|
json_source = AsJSON::Source.new source.path
|
||||||
|
|
||||||
source.errors.each do |e|
|
source.issues.each do |e|
|
||||||
next if e.disabled?
|
next if e.disabled?
|
||||||
json_source.errors << AsJSON::Error.new(e.rule.name, e.location, e.message)
|
json_source.issues << AsJSON::Issue.new(e.rule.name, e.location, e.message)
|
||||||
@result.summary.errors_count += 1
|
@result.summary.issues_count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@result.sources << json_source
|
@result.sources << json_source
|
||||||
|
@ -87,13 +87,13 @@ module Ameba::Formatter
|
||||||
|
|
||||||
record Source,
|
record Source,
|
||||||
path : String,
|
path : String,
|
||||||
errors = [] of Error do
|
issues = [] of Issue do
|
||||||
def to_json(json)
|
def to_json(json)
|
||||||
{path: path, errors: errors}.to_json(json)
|
{path: path, issues: issues}.to_json(json)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
record Error,
|
record Issue,
|
||||||
rule_name : String,
|
rule_name : String,
|
||||||
location : Crystal::Location?,
|
location : Crystal::Location?,
|
||||||
message : String do
|
message : String do
|
||||||
|
@ -120,12 +120,12 @@ module Ameba::Formatter
|
||||||
|
|
||||||
class Summary
|
class Summary
|
||||||
property target_sources_count = 0
|
property target_sources_count = 0
|
||||||
property errors_count = 0
|
property issues_count = 0
|
||||||
|
|
||||||
def to_json(json)
|
def to_json(json)
|
||||||
json.object do
|
json.object do
|
||||||
json.field :target_sources_count, target_sources_count
|
json.field :target_sources_count, target_sources_count
|
||||||
json.field :errors_count, errors_count
|
json.field :issues_count, issues_count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module Ameba::Formatter
|
module Ameba::Formatter
|
||||||
# A formatter that creates a todo config.
|
# A formatter that creates a todo config.
|
||||||
# Basically, it takes all errors reported and disables corresponding rules
|
# Basically, it takes all issues reported and disables corresponding rules
|
||||||
# or excludes failed sources from these rules.
|
# or excludes failed sources from these rules.
|
||||||
class TODOFormatter < DotFormatter
|
class TODOFormatter < DotFormatter
|
||||||
@io : IO::FileDescriptor | IO::Memory
|
@io : IO::FileDescriptor | IO::Memory
|
||||||
|
@ -10,30 +10,30 @@ module Ameba::Formatter
|
||||||
|
|
||||||
def finished(sources)
|
def finished(sources)
|
||||||
super
|
super
|
||||||
errors = sources.map(&.errors).flatten
|
issues = sources.map(&.issues).flatten
|
||||||
generate_todo_config errors if errors.any?
|
generate_todo_config issues if issues.any?
|
||||||
if (io = @io).is_a?(File)
|
if (io = @io).is_a?(File)
|
||||||
@output << "Created #{io.path}\n"
|
@output << "Created #{io.path}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def generate_todo_config(errors)
|
private def generate_todo_config(issues)
|
||||||
@io << header
|
@io << header
|
||||||
rule_errors_map(errors).each do |rule, rule_errors|
|
rule_issues_map(issues).each do |rule, rule_issues|
|
||||||
@io << "\n# Problems found: #{rule_errors.size}"
|
@io << "\n# Problems found: #{rule_issues.size}"
|
||||||
@io << "\n# Run `ameba --only #{rule.name}` for details"
|
@io << "\n# Run `ameba --only #{rule.name}` for details"
|
||||||
@io << rule_todo(rule, rule_errors).gsub("---", "")
|
@io << rule_todo(rule, rule_issues).gsub("---", "")
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
@io.flush
|
@io.flush
|
||||||
end
|
end
|
||||||
|
|
||||||
private def rule_errors_map(errors)
|
private def rule_issues_map(issues)
|
||||||
Hash(Rule::Base, Array(Source::Error)).new.tap do |h|
|
Hash(Rule::Base, Array(Issue)).new.tap do |h|
|
||||||
errors.each do |error|
|
issues.each do |issue|
|
||||||
next if error.disabled? || error.rule.is_a? Rule::Syntax
|
next if issue.disabled? || issue.rule.is_a? Rule::Syntax
|
||||||
h[error.rule] ||= Array(Source::Error).new
|
h[issue.rule] ||= Array(Issue).new
|
||||||
h[error.rule] << error
|
h[issue.rule] << issue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -48,9 +48,9 @@ module Ameba::Formatter
|
||||||
HEADER
|
HEADER
|
||||||
end
|
end
|
||||||
|
|
||||||
private def rule_todo(rule, errors)
|
private def rule_todo(rule, issues)
|
||||||
rule.excluded =
|
rule.excluded =
|
||||||
errors.map(&.location.try &.filename.try &.to_s)
|
issues.map(&.location.try &.filename.try &.to_s)
|
||||||
.compact
|
.compact
|
||||||
.uniq!
|
.uniq!
|
||||||
|
|
||||||
|
|
22
src/ameba/issue.cr
Normal file
22
src/ameba/issue.cr
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
module Ameba
|
||||||
|
# Represents an issue reported by Ameba.
|
||||||
|
record Issue,
|
||||||
|
# A rule that triggers this issue.
|
||||||
|
rule : Rule::Base,
|
||||||
|
|
||||||
|
# Location of the issue.
|
||||||
|
location : Crystal::Location?,
|
||||||
|
|
||||||
|
# End location of the issue.
|
||||||
|
end_location : Crystal::Location?,
|
||||||
|
|
||||||
|
# Issue message.
|
||||||
|
message : String,
|
||||||
|
|
||||||
|
# Issue status.
|
||||||
|
status : Symbol? do
|
||||||
|
def disabled?
|
||||||
|
status == :disabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
34
src/ameba/reportable.cr
Normal file
34
src/ameba/reportable.cr
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
module Ameba
|
||||||
|
# Represents a module used to report issues.
|
||||||
|
module Reportable
|
||||||
|
# List of reported issues.
|
||||||
|
getter issues = [] of Issue
|
||||||
|
|
||||||
|
# Adds a new issue to the list of issues.
|
||||||
|
def add_issue(rule, location, end_location, message, status = nil)
|
||||||
|
status ||= :disabled if location_disabled?(location, rule.name)
|
||||||
|
issues << Issue.new rule, location, end_location, message, status
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a new issue for AST *node*.
|
||||||
|
def add_issue(rule, node, message, **args)
|
||||||
|
add_issue rule, node.location, node.end_location, message, **args
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a new issue for Crystal *token*.
|
||||||
|
def add_issue(rule, token, message, **args)
|
||||||
|
add_issue rule, token.location, nil, message, **args
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a new issue for *location* defined by line and column numbers.
|
||||||
|
def add_issue(rule, location : Tuple(Int32, Int32), message, **args)
|
||||||
|
location = Crystal::Location.new path, *location
|
||||||
|
add_issue rule, location, nil, message, **args
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if the list of not disabled issues is empty, false otherwise.
|
||||||
|
def valid?
|
||||||
|
issues.reject(&.disabled?).empty?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -13,7 +13,7 @@ module Ameba::Rule
|
||||||
# struct MyRule < Ameba::Rule::Base
|
# struct MyRule < Ameba::Rule::Base
|
||||||
# def test(source)
|
# def test(source)
|
||||||
# if invalid?(source)
|
# if invalid?(source)
|
||||||
# source.error self, location, "Something wrong."
|
# issue_for line, column, "Something wrong."
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
|
@ -25,13 +25,13 @@ module Ameba::Rule
|
||||||
#
|
#
|
||||||
# Enforces rules to implement an abstract `#test` method which
|
# Enforces rules to implement an abstract `#test` method which
|
||||||
# is designed to test the source passed in. If source has issues
|
# is designed to test the source passed in. If source has issues
|
||||||
# that are tested by this rule, it should add an error.
|
# that are tested by this rule, it should add an issue.
|
||||||
#
|
#
|
||||||
abstract struct Base
|
abstract struct Base
|
||||||
include Config::RuleConfig
|
include Config::RuleConfig
|
||||||
|
|
||||||
# This method is designed to test the source passed in. If source has issues
|
# This method is designed to test the source passed in. If source has issues
|
||||||
# that are tested by this rule, it should add an error.
|
# that are tested by this rule, it should add an issue.
|
||||||
abstract def test(source : Source)
|
abstract def test(source : Source)
|
||||||
|
|
||||||
def test(source : Source, node : Crystal::ASTNode, *opts)
|
def test(source : Source, node : Crystal::ASTNode, *opts)
|
||||||
|
@ -91,6 +91,10 @@ module Ameba::Rule
|
||||||
SPECIAL.includes? name
|
SPECIAL.includes? name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
macro issue_for(*args)
|
||||||
|
source.add_issue self, {{*args}}
|
||||||
|
end
|
||||||
|
|
||||||
protected def self.rule_name
|
protected def self.rule_name
|
||||||
name.gsub("Ameba::Rule::", "")
|
name.gsub("Ameba::Rule::", "")
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,7 +39,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
return unless comparison? && to_boolean?
|
return unless comparison? && to_boolean?
|
||||||
|
|
||||||
source.error self, node.location, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,7 +38,7 @@ module Ameba::Rule
|
||||||
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, sprintf(MSG, expected, name)
|
issue_for node, MSG % {expected, name}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ module Ameba::Rule
|
||||||
node.args.empty? &&
|
node.args.empty? &&
|
||||||
node.obj.nil?
|
node.obj.nil?
|
||||||
|
|
||||||
source.error self, node.location, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,7 +47,7 @@ module Ameba::Rule
|
||||||
node_ensure = node.ensure
|
node_ensure = node.ensure
|
||||||
return if node_ensure.nil? || !node_ensure.nop?
|
return if node_ensure.nil? || !node_ensure.nop?
|
||||||
|
|
||||||
source.error self, node.location, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,12 +47,12 @@ module Ameba::Rule
|
||||||
|
|
||||||
return if exp.nil? || exp == "nil"
|
return if exp.nil? || exp == "nil"
|
||||||
|
|
||||||
source.error self, node.location, MSG % exp
|
issue_for node, MSG % exp
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(source, node : Crystal::Expressions)
|
def test(source, node : Crystal::Expressions)
|
||||||
if node.expressions.size == 1 && node.expressions.first.nop?
|
if node.expressions.size == 1 && node.expressions.first.nop?
|
||||||
source.error self, node.location, MSG_EXRS
|
issue_for node, MSG_EXRS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,7 +34,7 @@ module Ameba::Rule
|
||||||
def test(source, node : Crystal::HashLiteral)
|
def test(source, node : Crystal::HashLiteral)
|
||||||
return unless (keys = duplicated_keys(node.entries)).any?
|
return unless (keys = duplicated_keys(node.entries)).any?
|
||||||
|
|
||||||
source.error self, node.location, MSG % keys.join(", ")
|
issue_for node, MSG % keys.join(", ")
|
||||||
end
|
end
|
||||||
|
|
||||||
private def duplicated_keys(entries)
|
private def duplicated_keys(entries)
|
||||||
|
|
|
@ -42,7 +42,7 @@ module Ameba::Rule
|
||||||
parsed = parse_number token.raw
|
parsed = parse_number token.raw
|
||||||
|
|
||||||
if allowed?(*parsed) && (expected = underscored *parsed) != token.raw
|
if allowed?(*parsed) && (expected = underscored *parsed) != token.raw
|
||||||
source.error self, token.location, MSG % expected
|
issue_for token, MSG % expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,7 +22,7 @@ module Ameba::Rule
|
||||||
source.lines.each_with_index do |line, index|
|
source.lines.each_with_index do |line, index|
|
||||||
next unless line.size > max_length
|
next unless line.size > max_length
|
||||||
|
|
||||||
source.error self, index + 1, line.size, MSG
|
issue_for({index + 1, line.size}, MSG)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,7 +36,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
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, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(source, node : Crystal::If)
|
def test(source, node : Crystal::If)
|
||||||
|
|
|
@ -32,7 +32,7 @@ module Ameba::Rule
|
||||||
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, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -52,7 +52,7 @@ module Ameba::Rule
|
||||||
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, sprintf(MSG, expected, node.name)
|
issue_for node, MSG % {expected, node.name}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,7 +40,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
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, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
|
|
||||||
private def negated_condition?(node)
|
private def negated_condition?(node)
|
||||||
|
|
|
@ -34,21 +34,21 @@ module Ameba::Rule
|
||||||
MSG = "Symbols `%s` may be unwanted in %s array literals"
|
MSG = "Symbols `%s` may be unwanted in %s array literals"
|
||||||
|
|
||||||
def test(source)
|
def test(source)
|
||||||
error = start_token = nil
|
issue = start_token = nil
|
||||||
|
|
||||||
Tokenizer.new(source).run do |token|
|
Tokenizer.new(source).run do |token|
|
||||||
case token.type
|
case token.type
|
||||||
when :STRING_ARRAY_START, :SYMBOL_ARRAY_START
|
when :STRING_ARRAY_START, :SYMBOL_ARRAY_START
|
||||||
start_token = token.dup
|
start_token = token.dup
|
||||||
when :STRING
|
when :STRING
|
||||||
if start_token && error.nil?
|
if start_token && issue.nil?
|
||||||
error = array_entry_invalid?(token.value, start_token.not_nil!.raw)
|
issue = array_entry_invalid?(token.value, start_token.not_nil!.raw)
|
||||||
end
|
end
|
||||||
when :STRING_ARRAY_END, :SYMBOL_ARRAY_END
|
when :STRING_ARRAY_END, :SYMBOL_ARRAY_END
|
||||||
if error
|
if issue
|
||||||
source.error(self, start_token.try &.location, error.not_nil!)
|
issue_for start_token.not_nil!, issue.not_nil!
|
||||||
end
|
end
|
||||||
error = start_token = nil
|
issue = start_token = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -64,7 +64,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
private def check_array_entry(entry, symbols, literal)
|
private def check_array_entry(entry, symbols, literal)
|
||||||
return unless entry =~ /[#{symbols}]/
|
return unless entry =~ /[#{symbols}]/
|
||||||
sprintf(MSG, symbols, literal)
|
MSG % {symbols, literal}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,7 +45,7 @@ module Ameba::Rule
|
||||||
alternative = $2
|
alternative = $2
|
||||||
return unless alternative =~ /^[a-z][a-zA-Z_0-9]*$/
|
return unless alternative =~ /^[a-z][a-zA-Z_0-9]*$/
|
||||||
|
|
||||||
source.error self, node.location, sprintf(MSG, alternative, node.name)
|
issue_for node, MSG % {alternative, node.name}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,7 +42,7 @@ module Ameba::Rule
|
||||||
(value = arg.value) &&
|
(value = arg.value) &&
|
||||||
(value == "0" || value == "1")
|
(value == "0" || value == "1")
|
||||||
|
|
||||||
source.error self, node.location, MSG % node
|
issue_for node, MSG % node
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,7 +71,7 @@ module Ameba::Rule
|
||||||
def test(source, node : Crystal::Def)
|
def test(source, node : Crystal::Def)
|
||||||
return unless redundant_begin?(source, node)
|
return unless redundant_begin?(source, node)
|
||||||
|
|
||||||
source.error self, node.location, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
|
|
||||||
private def redundant_begin?(source, node)
|
private def redundant_begin?(source, node)
|
||||||
|
|
|
@ -51,7 +51,7 @@ module Ameba::Rule
|
||||||
scope.arguments.each do |arg|
|
scope.arguments.each do |arg|
|
||||||
next unless assign = arg.variable.assign_before_reference
|
next unless assign = arg.variable.assign_before_reference
|
||||||
|
|
||||||
source.error self, assign.location, MSG % arg.name
|
issue_for assign, MSG % arg.name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -49,7 +49,7 @@ module Ameba::Rule
|
||||||
return unless excs = node.rescues
|
return unless excs = node.rescues
|
||||||
|
|
||||||
if (excs = shadowed excs.map(&.types)).any?
|
if (excs = shadowed excs.map(&.types)).any?
|
||||||
source.error self, node.location, MSG % excs.join(", ")
|
issue_for node, MSG % excs.join(", ")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ module Ameba::Rule
|
||||||
private def find_shadowing(source, scope)
|
private def find_shadowing(source, scope)
|
||||||
scope.arguments.each do |arg|
|
scope.arguments.each do |arg|
|
||||||
if scope.outer_scope.try &.find_variable(arg.name)
|
if scope.outer_scope.try &.find_variable(arg.name)
|
||||||
source.error self, arg.location, MSG % arg.name
|
issue_for arg, MSG % arg.name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,7 @@ module Ameba::Rule
|
||||||
def test(source)
|
def test(source)
|
||||||
source.ast
|
source.ast
|
||||||
rescue e : Crystal::SyntaxException
|
rescue e : Crystal::SyntaxException
|
||||||
source.error self, e.line_number, e.column_number, e.message.to_s
|
issue_for({e.line_number, e.column_number}, e.message.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ module Ameba::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, 1, MSG
|
issue_for({source.lines.size, 1}, MSG)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,7 @@ module Ameba::Rule
|
||||||
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, line.size, MSG
|
issue_for({index + 1, line.size}, MSG)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,7 +68,7 @@ module Ameba::Rule
|
||||||
expected = name.camelcase
|
expected = name.camelcase
|
||||||
return if expected == name
|
return if expected == name
|
||||||
|
|
||||||
source.error self, node.location, sprintf(MSG, expected, name)
|
issue_for node, MSG % {expected, name}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(source, node : Crystal::ClassDef)
|
def test(source, node : Crystal::ClassDef)
|
||||||
|
|
|
@ -56,7 +56,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
def test(source, node : Crystal::Unless)
|
def test(source, node : Crystal::Unless)
|
||||||
return if node.else.nop?
|
return if node.else.nop?
|
||||||
source.error self, node.location, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,7 +32,7 @@ module Ameba::Rule
|
||||||
next unless names = unneeded_disables(source, directive, token.location)
|
next unless names = unneeded_disables(source, directive, token.location)
|
||||||
next unless names.any?
|
next unless names.any?
|
||||||
|
|
||||||
source.error self, token.location, MSG % names.join(", ")
|
issue_for token, MSG % names.join(", ")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,19 +40,19 @@ module Ameba::Rule
|
||||||
return unless directive[:action] == "disable"
|
return unless directive[:action] == "disable"
|
||||||
|
|
||||||
directive[:rules].reject do |rule_name|
|
directive[:rules].reject do |rule_name|
|
||||||
source.errors.any? do |error|
|
source.issues.any? do |issue|
|
||||||
error.rule.name == rule_name &&
|
issue.rule.name == rule_name &&
|
||||||
error.disabled? &&
|
issue.disabled? &&
|
||||||
error_at_location?(source, error, location)
|
issue_at_location?(source, issue, location)
|
||||||
end && rule_name != self.name
|
end && rule_name != self.name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def error_at_location?(source, error, location)
|
private def issue_at_location?(source, issue, location)
|
||||||
return false unless error_line_number = error.location.try(&.line_number)
|
return false unless issue_line_number = issue.location.try(&.line_number)
|
||||||
|
|
||||||
error_line_number == location.line_number ||
|
issue_line_number == location.line_number ||
|
||||||
((prev_line_number = error_line_number - 1) &&
|
((prev_line_number = issue_line_number - 1) &&
|
||||||
prev_line_number == location.line_number &&
|
prev_line_number == location.line_number &&
|
||||||
source.comment?(prev_line_number - 1))
|
source.comment?(prev_line_number - 1))
|
||||||
end
|
end
|
||||||
|
|
|
@ -58,7 +58,7 @@ module Ameba::Rule
|
||||||
next if argument.ignored? || scope.references?(argument.variable)
|
next if argument.ignored? || scope.references?(argument.variable)
|
||||||
|
|
||||||
name_suggestion = scope.node.is_a?(Crystal::Block) ? '_' : "_#{argument.name}"
|
name_suggestion = scope.node.is_a?(Crystal::Block) ? '_' : "_#{argument.name}"
|
||||||
source.error self, argument.location, MSG % {argument.name, name_suggestion}
|
issue_for argument, MSG % {argument.name, name_suggestion}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,7 +43,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
var.assignments.each do |assign|
|
var.assignments.each do |assign|
|
||||||
next if assign.referenced?
|
next if assign.referenced?
|
||||||
source.error self, assign.location, MSG % var.name
|
issue_for assign, MSG % var.name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,7 +48,7 @@ module Ameba::Rule
|
||||||
.map(&.to_s)
|
.map(&.to_s)
|
||||||
.none? { |c| c == cond_s }
|
.none? { |c| c == cond_s }
|
||||||
|
|
||||||
source.error self, cond.location, MSG
|
issue_for cond, MSG
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(source)
|
def test(source)
|
||||||
|
|
|
@ -45,7 +45,7 @@ module Ameba::Rule
|
||||||
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, sprintf(MSG, expected, node.name)
|
issue_for node, MSG % {expected, node.name}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(source, node : Crystal::Var)
|
def test(source, node : Crystal::Var)
|
||||||
|
|
|
@ -39,7 +39,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
def test(source, node : Crystal::While)
|
def test(source, node : Crystal::While)
|
||||||
return unless node.cond.true_literal?
|
return unless node.cond.true_literal?
|
||||||
source.error self, node.location, MSG
|
issue_for node, MSG
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -52,7 +52,7 @@ module Ameba
|
||||||
|
|
||||||
# Performs the inspection. Iterates through all sources and test it using
|
# Performs the inspection. Iterates through all sources and test it using
|
||||||
# list of rules. If a specific rule fails on a specific source, it adds
|
# list of rules. If a specific rule fails on a specific source, it adds
|
||||||
# an error to that source.
|
# an issue to that source.
|
||||||
#
|
#
|
||||||
# This action also notifies formatter when inspection is started/finished,
|
# This action also notifies formatter when inspection is started/finished,
|
||||||
# and when a specific source started/finished to be inspected.
|
# and when a specific source started/finished to be inspected.
|
||||||
|
|
|
@ -1,22 +1,9 @@
|
||||||
module Ameba
|
module Ameba
|
||||||
# An entity that represents a Crystal source file.
|
# An entity that represents a Crystal source file.
|
||||||
# Has path, lines of code and errors reported by rules.
|
# Has path, lines of code and issues reported by rules.
|
||||||
class Source
|
class Source
|
||||||
include InlineComments
|
include InlineComments
|
||||||
|
include Reportable
|
||||||
# Represents an error caught by Ameba.
|
|
||||||
#
|
|
||||||
# Each error has the rule that created this error,
|
|
||||||
# location of the issue, message and status.
|
|
||||||
record Error,
|
|
||||||
rule : Rule::Base,
|
|
||||||
location : Crystal::Location?,
|
|
||||||
message : String,
|
|
||||||
status : Symbol? do
|
|
||||||
def disabled?
|
|
||||||
status == :disabled
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Path to the source file.
|
# Path to the source file.
|
||||||
getter path : String
|
getter path : String
|
||||||
|
@ -24,9 +11,6 @@ module Ameba
|
||||||
# Crystal code (content of a source file).
|
# Crystal code (content of a source file).
|
||||||
getter code : String
|
getter code : String
|
||||||
|
|
||||||
# List of errors reported.
|
|
||||||
getter errors = [] of Error
|
|
||||||
|
|
||||||
@lines : Array(String)?
|
@lines : Array(String)?
|
||||||
@ast : Crystal::ASTNode?
|
@ast : Crystal::ASTNode?
|
||||||
@fullpath : String?
|
@fullpath : String?
|
||||||
|
@ -43,42 +27,6 @@ module Ameba
|
||||||
def initialize(@code : String, @path = "")
|
def initialize(@code : String, @path = "")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a new error to the list of errors.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# source.error rule, location, "Line too long"
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
def error(rule : Rule::Base, location, message : String, status = nil)
|
|
||||||
status ||= :disabled if location_disabled?(location, rule.name)
|
|
||||||
errors << Error.new rule, location, message, status
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a new error to the list of errors using line and column number.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# source.error rule, line_number, column_number, "Bad code"
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
def error(rule : Rule::Base, l, c, message : String, status = nil)
|
|
||||||
location = Crystal::Location.new path, l, c
|
|
||||||
error rule, location, message, status
|
|
||||||
end
|
|
||||||
|
|
||||||
# Indicates whether source is valid or not.
|
|
||||||
# Returns true if the list or errors empty, false otherwise.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# source = Ameba::Source.new code, path
|
|
||||||
# source.valid? # => true
|
|
||||||
# source.error rule, location, message
|
|
||||||
# source.valid? # => false
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
def valid?
|
|
||||||
errors.reject(&.disabled?).empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns lines of code splitted by new line character.
|
# Returns lines of code splitted by new line character.
|
||||||
# Since `code` is immutable and can't be changed, this
|
# Since `code` is immutable and can't be changed, this
|
||||||
# method caches lines in an instance variable, so calling
|
# method caches lines in an instance variable, so calling
|
||||||
|
|
Loading…
Reference in a new issue