diff --git a/spec/cache_spec.lua b/spec/cache_spec.lua
index cf8a9b31..4a1e329f 100644
--- a/spec/cache_spec.lua
+++ b/spec/cache_spec.lua
@@ -68,7 +68,7 @@ describe("cache", function()
end)
it("handles error result", function()
- assert.same('return {2,4,10,"message"}', cache.serialize({error = "syntax", line = 2, column = 4, offset = 10, msg = "message"}))
+ assert.same('return {{"011",[3]=2,[4]=4,[24]="message"}}', cache.serialize({{code = "011", line = 2, column = 4, msg = "message"}}))
end)
end)
@@ -159,7 +159,7 @@ return {{"111"},{"122"}}
cache.update(tmpname,
{"foo", "bar"},
{1, 2},
- {{{code="111"}}, {error = "syntax", line = 2, column = 4, offset = 10, msg = "message"}})
+ {{{code="111"}}, {{code = "011", line = 2, column = 4, msg = "message"}}})
end)
after_each(function()
@@ -173,7 +173,7 @@ return {{"111"},{"122"}}
it("loads cached results", function()
assert.same({
foo = {{code="111"}},
- bar = {error = "syntax", line = 2, column = 4, offset = 10, msg = "message"}
+ bar = {{code = "011", line = 2, column = 4, msg = "message"}}
}, cache.load(tmpname, {"foo", "bar"}, {1, 2}))
end)
@@ -183,7 +183,7 @@ return {{"111"},{"122"}}
it("does not load outdated results", function()
assert.same(
- {bar = {error = "syntax", line = 2, column = 4, offset = 10, msg = "message"}},
+ {bar = {{code = "011", line = 2, column = 4, msg = "message"}}},
cache.load(tmpname, {"foo", "bar", "baz"}, {2, 2}))
end)
end)
diff --git a/spec/cli_spec.lua b/spec/cli_spec.lua
index 134a5bf5..4ae31c08 100644
--- a/spec/cli_spec.lua
+++ b/spec/cli_spec.lua
@@ -59,7 +59,7 @@ Total: 0 warnings / 0 errors in 1 file
it("works for incorrect files", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -74,13 +74,13 @@ Total: 5 warnings / 0 errors in 1 file
it("works for incorrect patterns in options", function()
assert.equal([[
-Fatal error: Invalid pattern '^%1foo$'
+Critical error: Invalid pattern '^%1foo$'
]], get_output "spec/samples/bad_code.lua --ignore %1foo --no-config")
end)
it("checks stdin when given -", function()
assert.equal([[
-Checking stdin Failure
+Checking stdin 5 warnings
stdin:3:16: unused function helper
stdin:3:23: unused variable length argument
@@ -95,7 +95,7 @@ Total: 5 warnings / 0 errors in 1 file
it("colors output", function()
assert.equal([[
Checking spec/samples/good_code.lua ###OK#
-Checking spec/samples/bad_code.lua ###Failure#
+Checking spec/samples/bad_code.lua ###5 warnings#
spec/samples/bad_code.lua:3:16: unused function ##helper#
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -110,7 +110,7 @@ Total: ###5# warnings / ###0# errors in 2 files
it("does not color output with --no-color", function()
assert.equal([[
Checking spec/samples/good_code.lua OK
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function 'helper'
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -123,7 +123,7 @@ Total: 5 warnings / 0 errors in 2 files
end)
it("suppresses OK output with -q", function()
- assert.equal([[Checking spec/samples/bad_code.lua Failure
+ assert.equal([[Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -131,7 +131,7 @@ Total: 5 warnings / 0 errors in 2 files
spec/samples/bad_code.lua:8:10: variable opt was previously defined as an argument on line 7
spec/samples/bad_code.lua:9:11: accessing undefined variable hepler
-Checking spec/samples/unused_code.lua Failure
+Checking spec/samples/unused_code.lua 9 warnings
spec/samples/unused_code.lua:3:18: unused argument baz
spec/samples/unused_code.lua:4:8: unused loop variable i
@@ -151,8 +151,8 @@ Total: 0 warnings / 0 errors in 1 file
end)
it("suppresses warnings output with -qq", function()
- assert.equal([[Checking spec/samples/bad_code.lua Failure
-Checking spec/samples/unused_code.lua Failure
+ assert.equal([[Checking spec/samples/bad_code.lua 5 warnings
+Checking spec/samples/unused_code.lua 9 warnings
Total: 14 warnings / 0 errors in 3 files
]], get_output "-qq spec/samples/*d_code.lua --no-config")
@@ -165,7 +165,7 @@ Total: 14 warnings / 0 errors in 3 files
it("allows to ignore some types of warnings", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 3 warnings
spec/samples/bad_code.lua:7:10: setting non-standard global variable embrace
spec/samples/bad_code.lua:8:10: variable opt was previously defined as an argument on line 7
@@ -174,7 +174,7 @@ Checking spec/samples/bad_code.lua Failure
Total: 3 warnings / 0 errors in 1 file
]], get_output "-u spec/samples/bad_code.lua --no-config")
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 3 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -183,7 +183,7 @@ Checking spec/samples/bad_code.lua Failure
Total: 3 warnings / 0 errors in 1 file
]], get_output "-g spec/samples/bad_code.lua --no-config")
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 4 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -196,7 +196,7 @@ Total: 4 warnings / 0 errors in 1 file
it("allows to define additional globals", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 4 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -209,7 +209,7 @@ Total: 4 warnings / 0 errors in 1 file
it("allows to set standard globals", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 6 warnings
spec/samples/bad_code.lua:1:1: accessing undefined variable package
spec/samples/bad_code.lua:3:16: unused function helper
@@ -221,7 +221,7 @@ Checking spec/samples/bad_code.lua Failure
Total: 6 warnings / 0 errors in 1 file
]], get_output "--std none spec/samples/bad_code.lua --no-config")
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -235,7 +235,7 @@ Total: 5 warnings / 0 errors in 1 file
it("allows to ignore some variables", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 3 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -247,7 +247,7 @@ Total: 3 warnings / 0 errors in 1 file
it("allows to only watch some variables", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 1 warning
spec/samples/bad_code.lua:3:16: unused function helper
@@ -257,7 +257,7 @@ Total: 1 warning / 0 errors in 1 file
it("recognizes different types of variables", function()
assert.equal([[
-Checking spec/samples/unused_code.lua Failure
+Checking spec/samples/unused_code.lua 9 warnings
spec/samples/unused_code.lua:3:18: unused argument baz
spec/samples/unused_code.lua:4:8: unused loop variable i
@@ -275,7 +275,7 @@ Total: 9 warnings / 0 errors in 1 file
it("allows to ignore unused arguments", function()
assert.equal([[
-Checking spec/samples/unused_code.lua Failure
+Checking spec/samples/unused_code.lua 4 warnings
spec/samples/unused_code.lua:5:13: unused variable q
spec/samples/unused_code.lua:13:7: value assigned to variable x is unused
@@ -288,7 +288,7 @@ Total: 4 warnings / 0 errors in 1 file
it("allows to ignore unused secondary values and variables", function()
assert.equal([[
-Checking spec/samples/unused_secondaries.lua Failure
+Checking spec/samples/unused_secondaries.lua 4 warnings
spec/samples/unused_secondaries.lua:3:7: unused variable a
spec/samples/unused_secondaries.lua:6:7: unused variable x
@@ -299,7 +299,7 @@ Total: 4 warnings / 0 errors in 1 file
]], get_output "spec/samples/unused_secondaries.lua --no-config")
assert.equal([[
-Checking spec/samples/unused_secondaries.lua Failure
+Checking spec/samples/unused_secondaries.lua 1 warning
spec/samples/unused_secondaries.lua:6:7: unused variable x
@@ -309,7 +309,7 @@ Total: 1 warning / 0 errors in 1 file
it("allows to ignore warnings related to implicit self", function()
assert.equal([[
-Checking spec/samples/redefined.lua Failure
+Checking spec/samples/redefined.lua 5 warnings
spec/samples/redefined.lua:4:10: shadowing upvalue a on line 1
spec/samples/redefined.lua:4:13: variable self is never set
@@ -323,20 +323,20 @@ Total: 5 warnings / 0 errors in 1 file
it("handles errors gracefully", function()
assert.equal([[
-Checking spec/samples/python_code.lua Syntax error
+Checking spec/samples/python_code.lua 1 error
spec/samples/python_code.lua:1:6: expected '=' near '__future__'
Checking spec/samples/absent_code.lua I/O error
-Total: 0 warnings / 2 errors in 2 files
+Total: 0 warnings / 1 error in 1 file, couldn't check 1 file
]], get_output "spec/samples/python_code.lua spec/samples/absent_code.lua --no-config")
assert.equal(2, get_exitcode "spec/samples/python_code.lua spec/samples/absent_code.lua --no-config")
end)
it("expands rockspecs", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -354,13 +354,13 @@ Total: 5 warnings / 0 errors in 2 files
assert.equal([[
Checking spec/samples/bad.rockspec Syntax error
-Total: 0 warnings / 1 error in 1 file
+Total: 0 warnings / 0 errors in 0 files, couldn't check 1 file
]], get_output "spec/samples/bad.rockspec --no-config")
end)
it("allows ignoring defined globals", function()
assert.equal([[
-Checking spec/samples/defined.lua Failure
+Checking spec/samples/defined.lua 1 warning
spec/samples/defined.lua:4:4: accessing undefined variable baz
@@ -371,7 +371,7 @@ Total: 1 warning / 0 errors in 2 files
assert.equal([[
Checking spec/samples/defined2.lua OK
-Checking spec/samples/defined.lua Failure
+Checking spec/samples/defined.lua 1 warning
spec/samples/defined.lua:4:4: accessing undefined variable baz
@@ -381,7 +381,7 @@ Total: 1 warning / 0 errors in 2 files
it("allows restricting scope of defined globals to the file with their definition", function()
assert.equal([[
-Checking spec/samples/defined2.lua Failure
+Checking spec/samples/defined2.lua 1 warning
spec/samples/defined2.lua:1:1: accessing undefined variable foo
@@ -393,7 +393,7 @@ Total: 1 warning / 0 errors in 2 files
it("allows ignoring globals defined in top level scope", function()
assert.equal([[
-Checking spec/samples/defined4.lua Failure
+Checking spec/samples/defined4.lua 2 warnings
spec/samples/defined4.lua:1:10: unused global variable foo
spec/samples/defined4.lua:3:4: setting non-standard global variable bar
@@ -404,7 +404,7 @@ Total: 2 warnings / 0 errors in 1 file
it("detects unused defined globals", function()
assert.equal([[
-Checking spec/samples/defined3.lua Failure
+Checking spec/samples/defined3.lua 3 warnings
spec/samples/defined3.lua:1:1: unused global variable foo
spec/samples/defined3.lua:2:1: unused global variable foo
@@ -414,7 +414,7 @@ Total: 3 warnings / 0 errors in 1 file
]], get_output "spec/samples/defined3.lua -d --no-config")
assert.equal([[
-Checking spec/samples/defined3.lua Failure
+Checking spec/samples/defined3.lua 1 warning
spec/samples/defined3.lua:3:1: unused global variable bar
@@ -432,7 +432,7 @@ Total: 0 warnings / 0 errors in 1 file
]], get_output "spec/samples/defined3.lua -gd --no-config")
assert.equal([[
-Checking spec/samples/defined3.lua Failure
+Checking spec/samples/defined3.lua 1 warning
spec/samples/defined3.lua:3:1: unused global variable bar
@@ -459,7 +459,7 @@ Total: 0 warnings / 0 errors in 2 files
it("detects flow issues", function()
assert.equal([[
-Checking spec/samples/bad_flow.lua Failure
+Checking spec/samples/bad_flow.lua 6 warnings
spec/samples/bad_flow.lua:1:28: empty if branch
spec/samples/bad_flow.lua:6:4: empty do..end block
@@ -474,7 +474,7 @@ Total: 6 warnings / 0 errors in 1 file
it("detects redefinitions", function()
assert.equal([[
-Checking spec/samples/redefined.lua Failure
+Checking spec/samples/redefined.lua 6 warnings
spec/samples/redefined.lua:3:11: unused argument self
spec/samples/redefined.lua:4:10: shadowing upvalue a on line 1
@@ -489,7 +489,7 @@ Total: 6 warnings / 0 errors in 1 file
it("detects issues related to read-only globals", function()
assert.equal([[
-Checking spec/samples/read_globals.lua Failure
+Checking spec/samples/read_globals.lua 5 warnings
spec/samples/read_globals.lua:1:1: setting read-only global variable string
spec/samples/read_globals.lua:2:1: mutating read-only global variable table
@@ -503,7 +503,7 @@ Total: 5 warnings / 0 errors in 1 file
it("allows showing warning codes", function()
assert.equal([[
-Checking spec/samples/read_globals.lua Failure
+Checking spec/samples/read_globals.lua 5 warnings
spec/samples/read_globals.lua:1:1: (W121) setting read-only global variable string
spec/samples/read_globals.lua:2:1: (W122) mutating read-only global variable table
@@ -517,7 +517,7 @@ Total: 5 warnings / 0 errors in 1 file
it("applies inline options", function()
assert.equal([[
-Checking spec/samples/inline_options.lua Failure
+Checking spec/samples/inline_options.lua 8 warnings / 2 errors
spec/samples/inline_options.lua:6:16: unused function f
spec/samples/inline_options.lua:12:4: accessing undefined variable qu
@@ -525,16 +525,16 @@ Checking spec/samples/inline_options.lua Failure
spec/samples/inline_options.lua:24:10: unused variable g
spec/samples/inline_options.lua:26:7: unused variable f
spec/samples/inline_options.lua:26:10: unused variable g
- spec/samples/inline_options.lua:28:1: unpaired inline option
- spec/samples/inline_options.lua:30:4: unpaired inline option
+ spec/samples/inline_options.lua:28:1: unpaired push directive
+ spec/samples/inline_options.lua:30:4: unpaired pop directive
spec/samples/inline_options.lua:36:1: empty do..end block
spec/samples/inline_options.lua:37:10: empty if branch
-Total: 10 warnings / 0 errors in 1 file
+Total: 8 warnings / 2 errors in 1 file
]], get_output "spec/samples/inline_options.lua --std=none --no-config")
assert.equal([[
-Checking spec/samples/inline_options.lua Failure
+Checking spec/samples/inline_options.lua 7 warnings / 2 errors
spec/samples/inline_options.lua:6:16: unused function f
spec/samples/inline_options.lua:12:4: accessing undefined variable qu
@@ -542,15 +542,15 @@ Checking spec/samples/inline_options.lua Failure
spec/samples/inline_options.lua:24:10: unused variable g
spec/samples/inline_options.lua:26:7: unused variable f
spec/samples/inline_options.lua:26:10: unused variable g
- spec/samples/inline_options.lua:28:1: unpaired inline option
- spec/samples/inline_options.lua:30:4: unpaired inline option
+ spec/samples/inline_options.lua:28:1: unpaired push directive
+ spec/samples/inline_options.lua:30:4: unpaired pop directive
spec/samples/inline_options.lua:36:1: empty do..end block
-Total: 9 warnings / 0 errors in 1 file
+Total: 7 warnings / 2 errors in 1 file
]], get_output "spec/samples/inline_options.lua --std=none --ignore=542 --no-config")
assert.equal([[
-Checking spec/samples/global_inline_options.lua Failure
+Checking spec/samples/global_inline_options.lua 3 warnings
spec/samples/global_inline_options.lua:6:10: unused global variable f
spec/samples/global_inline_options.lua:7:4: setting non-standard global variable baz
@@ -560,7 +560,7 @@ Total: 3 warnings / 0 errors in 1 file
]], get_output "spec/samples/global_inline_options.lua --std=lua52 --no-config")
assert.equal([[
-Checking spec/samples/read_globals_inline_options.lua Failure
+Checking spec/samples/read_globals_inline_options.lua 5 warnings
spec/samples/read_globals_inline_options.lua:2:10: accessing undefined variable baz
spec/samples/read_globals_inline_options.lua:3:1: setting read-only global variable foo
@@ -572,7 +572,7 @@ Total: 5 warnings / 0 errors in 1 file
]], get_output "spec/samples/read_globals_inline_options.lua --std=lua52 --no-config")
assert.equal([[
-Checking spec/samples/read_globals_inline_options.lua Failure
+Checking spec/samples/read_globals_inline_options.lua 1 warning
spec/samples/read_globals_inline_options.lua:3:16: mutating read-only global variable baz
@@ -582,7 +582,7 @@ Total: 1 warning / 0 errors in 1 file
it("inline options can use extended stds", function()
assert.equal([[
-Checking spec/samples/custom_std_inline_options.lua Failure
+Checking spec/samples/custom_std_inline_options.lua 2 warnings
spec/samples/custom_std_inline_options.lua:3:1: accessing undefined variable tostring
spec/samples/custom_std_inline_options.lua:6:25: accessing undefined variable it
@@ -593,7 +593,7 @@ Total: 2 warnings / 0 errors in 1 file
it("inline options can be disabled", function()
assert.equal([[
-Checking spec/samples/inline_options.lua Failure
+Checking spec/samples/inline_options.lua 26 warnings
spec/samples/inline_options.lua:3:1: accessing undefined variable foo
spec/samples/inline_options.lua:4:1: accessing undefined variable bar
@@ -640,7 +640,7 @@ Total: 26 warnings / 0 errors in 1 file
it("caches results", function()
assert.equal([[
Checking spec/samples/good_code.lua OK
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -648,7 +648,7 @@ Checking spec/samples/bad_code.lua Failure
spec/samples/bad_code.lua:8:10: variable opt was previously defined as an argument on line 7
spec/samples/bad_code.lua:9:11: accessing undefined variable hepler
-Checking spec/samples/python_code.lua Syntax error
+Checking spec/samples/python_code.lua 1 error
spec/samples/python_code.lua:1:6: expected '=' near '__future__'
@@ -665,7 +665,7 @@ spec/samples/bad_code.lua
local A="113";return {{A,"package",1,1},{"211","helper",3,16,%[9%]=true},{"212","...",3,23},{"111","embrace",7,10,%[11%]=true},{"412","opt",8,10,7,18},{A,"hepler",9,11}}
spec/samples/python_code.lua
(%d+)
-return {1,6,6,"expected '=' near '__future__'"}
+return {{"011",%[3%]=1,%[4%]=6,%[24%]="expected '=' near '__future__'"}}
]])
assert.string(good_mtime)
assert.string(bad_mtime)
@@ -673,7 +673,7 @@ return {1,6,6,"expected '=' near '__future__'"}
assert.equal([[
Checking spec/samples/good_code.lua OK
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -681,7 +681,7 @@ Checking spec/samples/bad_code.lua Failure
spec/samples/bad_code.lua:8:10: variable opt was previously defined as an argument on line 7
spec/samples/bad_code.lua:9:11: accessing undefined variable hepler
-Checking spec/samples/python_code.lua Syntax error
+Checking spec/samples/python_code.lua 1 error
spec/samples/python_code.lua:1:6: expected '=' near '__future__'
@@ -695,18 +695,18 @@ Total: 5 warnings / 1 error in 3 files
return {{"111", "global", 1, 1}, {"321", "uninit", 6, 8}}
spec/samples/good_code.lua
%s
-return {5, 7, 7, "this code is actually bad"}
+return {{"011",[3]=5,[4]=7,[24]="this code is actually bad"}}
spec/samples/bad_code.lua
%s
return {}]]):format(python_mtime, good_mtime, tostring(tonumber(bad_mtime) - 1)))
fh:close()
assert.equal([[
-Checking spec/samples/good_code.lua Syntax error
+Checking spec/samples/good_code.lua 1 error
spec/samples/good_code.lua:5:7: this code is actually bad
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -714,12 +714,12 @@ Checking spec/samples/bad_code.lua Failure
spec/samples/bad_code.lua:8:10: variable opt was previously defined as an argument on line 7
spec/samples/bad_code.lua:9:11: accessing undefined variable hepler
-Checking spec/samples/python_code.lua Failure
+Checking spec/samples/python_code.lua 2 warnings
spec/samples/python_code.lua:1:1: setting non-standard global variable global
spec/samples/python_code.lua:6:8: accessing uninitialized variable uninit
-Checking spec/samples/unused_code.lua Failure
+Checking spec/samples/unused_code.lua 9 warnings
spec/samples/unused_code.lua:3:18: unused argument baz
spec/samples/unused_code.lua:4:8: unused loop variable i
@@ -742,7 +742,7 @@ Total: 16 warnings / 1 error in 4 files
it("uses multithreading", function()
assert.equal([[
Checking spec/samples/good_code.lua OK
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 5 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -750,7 +750,7 @@ Checking spec/samples/bad_code.lua Failure
spec/samples/bad_code.lua:8:10: variable opt was previously defined as an argument on line 7
spec/samples/bad_code.lua:9:11: accessing undefined variable hepler
-Checking spec/samples/python_code.lua Syntax error
+Checking spec/samples/python_code.lua 1 error
spec/samples/python_code.lua:1:6: expected '=' near '__future__'
@@ -797,7 +797,7 @@ not ok 3 spec/samples/bad_code.lua:3:23: (W212) unused variable length argument
not ok 4 spec/samples/bad_code.lua:7:10: (W111) setting non-standard global variable 'embrace'
not ok 5 spec/samples/bad_code.lua:8:10: (W412) variable 'opt' was previously defined as an argument on line 7
not ok 6 spec/samples/bad_code.lua:9:11: (W113) accessing undefined variable 'hepler'
-not ok 7 spec/samples/python_code.lua:1:6: expected '=' near '__future__'
+not ok 7 spec/samples/python_code.lua:1:6: (E011) expected '=' near '__future__'
]], get_output "spec/samples/good_code.lua spec/samples/bad_code.lua spec/samples/python_code.lua --std=lua52 --formatter TAP --codes --no-config")
end)
@@ -821,8 +821,8 @@ not ok 7 spec/samples/python_code.lua:1:6: expected '=' near '__future__'
-
-
+
+
]], get_output "spec/samples/good_code.lua spec/samples/bad_code.lua spec/samples/python_code.lua --std=lua52 --formatter JUnit --no-config")
@@ -840,13 +840,17 @@ spec/samples/bad_code.lua:9:11: accessing undefined variable 'hepler'
spec/samples/python_code.lua:1:6: expected '=' near '__future__'
]], get_output "spec/samples/good_code.lua spec/samples/bad_code.lua spec/samples/python_code.lua --std=lua52 --formatter plain --no-config")
+ assert.equal([[
+spec/samples/404.lua: I/O error
+]], get_output "spec/samples/404.lua --formatter plain --no-config")
+
assert.equal([[
spec/samples/bad_code.lua:3:16: (W211) unused function 'helper'
spec/samples/bad_code.lua:3:23: (W212) unused variable length argument
spec/samples/bad_code.lua:7:10: (W111) setting non-standard global variable 'embrace'
spec/samples/bad_code.lua:8:10: (W412) variable 'opt' was previously defined as an argument on line 7
spec/samples/bad_code.lua:9:11: (W113) accessing undefined variable 'hepler'
-spec/samples/python_code.lua:1:6: expected '=' near '__future__'
+spec/samples/python_code.lua:1:6: (E011) expected '=' near '__future__'
]], get_output "spec/samples/good_code.lua spec/samples/bad_code.lua spec/samples/python_code.lua --std=lua52 --formatter plain --codes --no-config")
end)
@@ -856,19 +860,18 @@ spec/samples/python_code.lua:1:6: expected '=' near '__future__'
end)
it("expands folders", function()
- local output = get_output "spec/samples -qqq --no-config"
- assert.truthy(output:match("^Total: %d+ warnings / 1 error in 20 files\n$"))
+ assert.matches("^Total: %d+ warnings / %d+ errors in 20 files\n$", get_output "spec/samples -qqq --no-config")
end)
describe("config", function()
describe("loading", function()
it("uses .luacheckrc in current directory if possible", function()
assert.equal([[
-Checking nested/ab.lua Failure
+Checking nested/ab.lua 1 warning
nested/ab.lua:1:10: accessing undefined variable b
-Checking nested/nested/abc.lua Failure
+Checking nested/nested/abc.lua 2 warnings
nested/nested/abc.lua:1:7: accessing undefined variable a
nested/nested/abc.lua:1:13: accessing undefined variable c
@@ -879,12 +882,12 @@ Total: 3 warnings / 0 errors in 2 files
it("does not use .luacheckrc in current directory with --no-config", function()
assert.equal([[
-Checking nested/ab.lua Failure
+Checking nested/ab.lua 2 warnings
nested/ab.lua:1:7: accessing undefined variable a
nested/ab.lua:1:10: accessing undefined variable b
-Checking nested/nested/abc.lua Failure
+Checking nested/nested/abc.lua 3 warnings
nested/nested/abc.lua:1:7: accessing undefined variable a
nested/nested/abc.lua:1:10: accessing undefined variable b
@@ -896,11 +899,11 @@ Total: 5 warnings / 0 errors in 2 files
it("uses .luacheckrc in upper directory", function()
assert.equal([[
-Checking ab.lua Failure
+Checking ab.lua 1 warning
ab.lua:1:10: accessing undefined variable b
-Checking nested/abc.lua Failure
+Checking nested/abc.lua 2 warnings
nested/abc.lua:1:7: accessing undefined variable a
nested/abc.lua:1:13: accessing undefined variable c
@@ -927,7 +930,7 @@ Total: 0 warnings / 0 errors in 1 file
it("uses per-file overrides", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 4 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
@@ -950,11 +953,11 @@ Total: 0 warnings / 0 errors in 1 file
it("uses all overrides prefixing file name", function()
assert.equal([[
-Checking spec/samples/unused_secondaries.lua Failure
+Checking spec/samples/unused_secondaries.lua 1 warning
spec/samples/unused_secondaries.lua:12:1: value assigned to variable o is unused
-Checking spec/samples/unused_code.lua Failure
+Checking spec/samples/unused_code.lua 7 warnings
spec/samples/unused_code.lua:3:18: unused argument baz
spec/samples/unused_code.lua:4:8: unused loop variable i
@@ -970,14 +973,14 @@ Total: 8 warnings / 0 errors in 2 files
it("allows reenabling warnings ignored in config using --enable", function()
assert.equal([[
-Checking spec/samples/bad_code.lua Failure
+Checking spec/samples/bad_code.lua 4 warnings
spec/samples/bad_code.lua:3:16: unused function helper
spec/samples/bad_code.lua:3:23: unused variable length argument
spec/samples/bad_code.lua:7:10: setting non-standard global variable embrace
spec/samples/bad_code.lua:9:11: accessing undefined variable hepler
-Checking spec/samples/unused_code.lua Failure
+Checking spec/samples/unused_code.lua 1 warning
spec/samples/unused_code.lua:5:13: unused variable q
@@ -997,62 +1000,62 @@ Codes: true
it("uses exclude_files option", function()
assert.equal([[
-Checking spec/samples/argparse.lua Failure
-Checking spec/samples/compat.lua Failure
-Checking spec/samples/custom_std_inline_options.lua Failure
-Checking spec/samples/global_inline_options.lua Failure
-Checking spec/samples/globals.lua Failure
-Checking spec/samples/inline_options.lua Failure
-Checking spec/samples/python_code.lua Syntax error
-Checking spec/samples/read_globals.lua Failure
-Checking spec/samples/read_globals_inline_options.lua Failure
-Checking spec/samples/redefined.lua Failure
-Checking spec/samples/unused_code.lua Failure
-Checking spec/samples/unused_secondaries.lua Failure
-
-Total: 56 warnings / 1 error in 14 files
+Checking spec/samples/argparse.lua 6 warnings
+Checking spec/samples/compat.lua 4 warnings
+Checking spec/samples/custom_std_inline_options.lua 3 warnings / 1 error
+Checking spec/samples/global_inline_options.lua 3 warnings
+Checking spec/samples/globals.lua 2 warnings
+Checking spec/samples/inline_options.lua 7 warnings / 2 errors
+Checking spec/samples/python_code.lua 1 error
+Checking spec/samples/read_globals.lua 5 warnings
+Checking spec/samples/read_globals_inline_options.lua 3 warnings
+Checking spec/samples/redefined.lua 7 warnings
+Checking spec/samples/unused_code.lua 9 warnings
+Checking spec/samples/unused_secondaries.lua 4 warnings
+
+Total: 53 warnings / 4 errors in 14 files
]], get_output "spec/samples --config=spec/configs/exclude_files_config.luacheckrc -qq")
end)
it("loads exclude_files option correctly from upper directory", function()
assert.equal([[
-Checking argparse.lua Failure
-Checking compat.lua Failure
-Checking custom_std_inline_options.lua Failure
-Checking global_inline_options.lua Failure
-Checking globals.lua Failure
-Checking inline_options.lua Failure
-Checking python_code.lua Syntax error
-Checking read_globals.lua Failure
-Checking read_globals_inline_options.lua Failure
-Checking redefined.lua Failure
-Checking unused_code.lua Failure
-Checking unused_secondaries.lua Failure
-
-Total: 56 warnings / 1 error in 14 files
+Checking argparse.lua 6 warnings
+Checking compat.lua 4 warnings
+Checking custom_std_inline_options.lua 3 warnings / 1 error
+Checking global_inline_options.lua 3 warnings
+Checking globals.lua 2 warnings
+Checking inline_options.lua 7 warnings / 2 errors
+Checking python_code.lua 1 error
+Checking read_globals.lua 5 warnings
+Checking read_globals_inline_options.lua 3 warnings
+Checking redefined.lua 7 warnings
+Checking unused_code.lua 9 warnings
+Checking unused_secondaries.lua 4 warnings
+
+Total: 53 warnings / 4 errors in 14 files
]], get_output(". --config=spec/configs/exclude_files_config.luacheckrc -qq", "spec/samples/"))
end)
it("combines excluded files from config and cli", function()
assert.equal([[
-Checking argparse.lua Failure
-Checking compat.lua Failure
-Checking custom_std_inline_options.lua Failure
-Checking global_inline_options.lua Failure
-Checking globals.lua Failure
-Checking inline_options.lua Failure
-Checking python_code.lua Syntax error
-Checking redefined.lua Failure
-Checking unused_code.lua Failure
-Checking unused_secondaries.lua Failure
-
-Total: 48 warnings / 1 error in 12 files
+Checking argparse.lua 6 warnings
+Checking compat.lua 4 warnings
+Checking custom_std_inline_options.lua 3 warnings / 1 error
+Checking global_inline_options.lua 3 warnings
+Checking globals.lua 2 warnings
+Checking inline_options.lua 7 warnings / 2 errors
+Checking python_code.lua 1 error
+Checking redefined.lua 7 warnings
+Checking unused_code.lua 9 warnings
+Checking unused_secondaries.lua 4 warnings
+
+Total: 45 warnings / 4 errors in 12 files
]], get_output(". --config=spec/configs/exclude_files_config.luacheckrc -qq --exclude-files './read*'", "spec/samples/"))
end)
it("allows defining custom stds", function()
assert.equal([[
-Checking spec/samples/globals.lua Failure
+Checking spec/samples/globals.lua 2 warnings
spec/samples/globals.lua:1:15: accessing undefined variable rawlen
spec/samples/globals.lua:1:22: accessing undefined variable tostring
@@ -1061,7 +1064,7 @@ Total: 2 warnings / 0 errors in 1 file
]], get_output "spec/samples/globals.lua --config=spec/configs/custom_stds_config.luacheckrc")
assert.equal([[
-Checking spec/samples/globals.lua Failure
+Checking spec/samples/globals.lua 2 warnings
spec/samples/globals.lua:1:1: accessing undefined variable print
spec/samples/globals.lua:1:15: accessing undefined variable rawlen
@@ -1070,7 +1073,7 @@ Total: 2 warnings / 0 errors in 1 file
]], get_output "spec/samples/globals.lua --config=spec/configs/custom_stds_config.luacheckrc --std=other_std")
assert.equal([[
-Checking spec/samples/globals.lua Failure
+Checking spec/samples/globals.lua 1 warning
spec/samples/globals.lua:1:15: accessing undefined variable rawlen
@@ -1078,7 +1081,7 @@ Total: 1 warning / 0 errors in 1 file
]], get_output "spec/samples/globals.lua --config=spec/configs/custom_stds_config.luacheckrc --std=+other_std")
assert.equal([[
-Checking spec/samples/globals.lua Failure
+Checking spec/samples/globals.lua 1 warning
spec/samples/globals.lua:1:7: accessing undefined variable setfenv
@@ -1088,7 +1091,7 @@ Total: 1 warning / 0 errors in 1 file
it("allows importing options with require", function()
assert.equal([[
-Checking spec/samples/globals.lua Failure
+Checking spec/samples/globals.lua 1 warning
spec/samples/globals.lua:1:7: (W113) accessing undefined variable setfenv
@@ -1098,16 +1101,16 @@ Total: 1 warning / 0 errors in 1 file
end)
describe("error handling", function()
- it("raises fatal error on config with syntax errors", function()
+ it("raises critical error on config with syntax errors", function()
assert.equal([[
-Fatal error: Couldn't load configuration from spec/configs/bad_config.luacheckrc: syntax error
+Critical error: Couldn't load configuration from spec/configs/bad_config.luacheckrc: syntax error
]], get_output "spec/samples/empty.lua --config=spec/configs/bad_config.luacheckrc")
assert.equal(3, get_exitcode "spec/samples/empty.lua --config=spec/configs/bad_config.luacheckrc")
end)
- it("raises fatal error on non-existent config", function()
+ it("raises critical error on non-existent config", function()
assert.equal([[
-Fatal error: Couldn't find configuration file spec/configs/config_404.luacheckrc
+Critical error: Couldn't find configuration file spec/configs/config_404.luacheckrc
]], get_output "spec/samples/empty.lua --config=spec/configs/config_404.luacheckrc")
assert.equal(3, get_exitcode "spec/samples/empty.lua --config=spec/configs/config_404.luacheckrc")
end)
diff --git a/spec/format_spec.lua b/spec/format_spec.lua
index 68d81d74..8da7c3ba 100644
--- a/spec/format_spec.lua
+++ b/spec/format_spec.lua
@@ -6,22 +6,23 @@ end
describe("format", function()
it("returns formatted report", function()
- assert.equal([[Checking stdin Failure
+ assert.equal([[Checking stdin 1 warning
stdin:2:7: unused global variable foo
-Checking foo.lua Failure
+Checking foo.lua 1 warning
foo.lua:2:7: unused global variable foo
Checking bar.lua OK
-Checking baz.lua Syntax error
+Checking baz.lua 1 error
baz.lua:4:3: something went wrong
Total: 2 warnings / 1 error in 4 files]], remove_color(format({
warnings = 2,
errors = 1,
+ fatals = 0,
{
{
code = "131",
@@ -40,29 +41,32 @@ Total: 2 warnings / 1 error in 4 files]], remove_color(format({
},
{},
{
- error = "syntax",
- line = 4,
- column = 3,
- offset = 20,
- msg = "something went wrong"
+ {
+ code = "011",
+ line = 4,
+ column = 3,
+ msg = "something went wrong"
+ }
}
}, {"stdin", "foo.lua", "bar.lua", "baz.lua"}, {})))
end)
it("does not output OK messages with options.quiet >= 1", function()
- assert.equal([[Checking stdin Failure
+ assert.equal([[Checking stdin 1 warning
stdin:2:7: unused global variable foo
-Checking foo.lua Failure
+Checking foo.lua 1 warning / 1 error
foo.lua:2:7: unused global variable foo
+ foo.lua:3:10: invalid inline option
Checking baz.lua Syntax error
-Total: 2 warnings / 1 error in 4 files]], remove_color(format({
+Total: 2 warnings / 1 error in 3 files, couldn't check 1 file]], remove_color(format({
warnings = 2,
errors = 1,
+ fatals = 1,
{
{
code = "131",
@@ -77,23 +81,29 @@ Total: 2 warnings / 1 error in 4 files]], remove_color(format({
name = "foo",
line = 2,
column = 7
+ },
+ {
+ code = "021",
+ line = 3,
+ column = 10
}
},
{},
{
- error = "syntax"
+ fatal = "syntax"
}
}, {"stdin", "foo.lua", "bar.lua", "baz.lua"}, {quiet = 1})))
end)
it("does not output warnings with options.quiet >= 2", function()
- assert.equal([[Checking stdin Failure
-Checking foo.lua Failure
+ assert.equal([[Checking stdin 1 warning
+Checking foo.lua 1 warning
Checking baz.lua Syntax error
-Total: 2 warnings / 1 error in 4 files]], remove_color(format({
+Total: 2 warnings / 0 errors in 3 files, couldn't check 1 file]], remove_color(format({
warnings = 2,
- errors = 1,
+ errors = 0,
+ fatals = 1,
{
{
code = "131",
@@ -112,15 +122,16 @@ Total: 2 warnings / 1 error in 4 files]], remove_color(format({
},
{},
{
- error = "syntax"
+ fatal = "syntax"
}
}, {"stdin", "foo.lua", "bar.lua", "baz.lua"}, {quiet = 2})))
end)
it("does not output file info with options.quiet == 3", function()
- assert.equal("Total: 2 warnings / 1 error in 4 files", remove_color(format({
+ assert.equal("Total: 2 warnings / 0 errors in 3 files, couldn't check 1 file", remove_color(format({
warnings = 2,
- errors = 1,
+ errors = 0,
+ fatals = 1,
{
{
code = "131",
@@ -139,26 +150,27 @@ Total: 2 warnings / 1 error in 4 files]], remove_color(format({
},
{},
{
- error = "syntax"
+ fatal = "syntax"
}
}, {"stdin", "foo.lua", "bar.lua", "baz.lua"}, {quiet = 3})))
end)
it("does not color output if options.color == false", function()
- assert.equal([[Checking stdin Failure
+ assert.equal([[Checking stdin 1 warning
stdin:2:7: unused global variable 'foo'
-Checking foo.lua Failure
+Checking foo.lua 1 warning
foo.lua:2:7: unused global variable 'foo'
Checking bar.lua OK
Checking baz.lua Syntax error
-Total: 2 warnings / 1 error in 4 files]], format({
+Total: 2 warnings / 0 errors in 3 files, couldn't check 1 file]], format({
warnings = 2,
- errors = 1,
+ errors = 0,
+ fatals = 1,
{
{
code = "131",
@@ -177,7 +189,7 @@ Total: 2 warnings / 1 error in 4 files]], format({
},
{},
{
- error = "syntax"
+ fatal = "syntax"
}
}, {"stdin", "foo.lua", "bar.lua", "baz.lua"}, {color = false}))
end)
diff --git a/spec/luacheck_spec.lua b/spec/luacheck_spec.lua
index 23792899..c415e384 100644
--- a/spec/luacheck_spec.lua
+++ b/spec/luacheck_spec.lua
@@ -32,7 +32,8 @@ describe("luacheck", function()
it("works on empty list", function()
assert.same({
warnings = 0,
- errors = 0
+ errors = 0,
+ fatals = 0
}, luacheck({}))
end)
@@ -76,14 +77,16 @@ describe("luacheck", function()
}
},
{
- error = "syntax",
- line = 1,
- column = 6,
- offset = 6,
- msg = "expected '=' near '__future__'"
+ {
+ code = "011",
+ line = 1,
+ column = 6,
+ msg = "expected '=' near '__future__'"
+ }
},
warnings = 5,
- errors = 1
+ errors = 1,
+ fatals = 0
}, luacheck({
"spec/samples/good_code.lua",
"spec/samples/bad_code.lua",
@@ -118,14 +121,16 @@ describe("luacheck", function()
}
},
{
- error = "syntax",
- line = 1,
- column = 6,
- offset = 6,
- msg = "expected '=' near '__future__'"
+ {
+ code = "011",
+ line = 1,
+ column = 6,
+ msg = "expected '=' near '__future__'"
+ }
},
warnings = 3,
- errors = 1
+ errors = 1,
+ fatals = 0
}, luacheck({
"spec/samples/good_code.lua",
"spec/samples/bad_code.lua",
@@ -154,14 +159,16 @@ describe("luacheck", function()
}
},
{
- error = "syntax",
- line = 1,
- column = 6,
- offset = 6,
- msg = "expected '=' near '__future__'"
+ {
+ code = "011",
+ line = 1,
+ column = 6,
+ msg = "expected '=' near '__future__'"
+ }
},
warnings = 2,
- errors = 1
+ errors = 1,
+ fatals = 0
}, luacheck({
"spec/samples/good_code.lua",
"spec/samples/bad_code.lua",
@@ -198,7 +205,8 @@ describe("check_strings", function()
it("works on empty list", function()
assert.same({
warnings = 0,
- errors = 0
+ errors = 0,
+ fatals = 0
}, luacheck.check_strings({}))
end)
@@ -213,14 +221,16 @@ describe("check_strings", function()
}
},
{
- error = "syntax",
- line = 1,
- column = 8,
- offset = 8,
- msg = "unexpected symbol near 'return'"
+ {
+ code = "011",
+ line = 1,
+ column = 8,
+ msg = "unexpected symbol near 'return'"
+ }
},
warnings = 1,
- errors = 1
+ errors = 1,
+ fatals = 0
}, luacheck.check_strings({"return foo", "return return"}))
end)
@@ -228,18 +238,20 @@ describe("check_strings", function()
assert.same({
{},
{
- error = "syntax",
- line = 1,
- column = 8,
- offset = 8,
- msg = "unexpected symbol near 'return'"
+ {
+ code = "011",
+ line = 1,
+ column = 8,
+ msg = "unexpected symbol near 'return'"
+ }
},
warnings = 0,
- errors = 1
+ errors = 1,
+ fatals = 0
}, luacheck.check_strings({"return foo", "return return"}, {ignore = {"113"}}))
end)
- it("ignores tables", function()
+ it("ignores tables with .fatal field", function()
assert.same({
{
{
@@ -250,11 +262,12 @@ describe("check_strings", function()
}
},
{
- error = "I/O"
+ fatal = "I/O"
},
warnings = 1,
- errors = 1
- }, luacheck.check_strings({"return foo", {error = "I/O"}}))
+ errors = 0,
+ fatals = 1
+ }, luacheck.check_strings({"return foo", {fatal = "I/O"}}))
end)
end)
@@ -268,10 +281,10 @@ describe("get_report", function()
assert.is_table(luacheck.get_report("return foo"))
end)
- it("returns nil, error on syntax error", function()
- local res, err = luacheck.get_report("return return")
- assert.is_nil(res)
- assert.same({line = 1, column = 8, offset = 8, msg = "unexpected symbol near 'return'"}, err)
+ it("returns a table with single error event on syntax error", function()
+ local report = luacheck.get_report("return return")
+ assert.is_table(report)
+ assert.same({code = "011", line = 1, column = 8, msg = "unexpected symbol near 'return'"}, report[1])
end)
end)
@@ -302,7 +315,8 @@ describe("process_reports", function()
},
{},
warnings = 1,
- errors = 0
+ errors = 0,
+ fatals = 0
}, luacheck.process_reports({luacheck.get_report("return foo"), luacheck.get_report("return math")}))
end)
@@ -325,7 +339,8 @@ describe("process_reports", function()
}
},
warnings = 2,
- errors = 0
+ errors = 0,
+ fatals = 0
}, luacheck.process_reports({luacheck.get_report("return foo"), luacheck.get_report("return math")}, {
std = "none"
}))
diff --git a/src/luacheck/cache.lua b/src/luacheck/cache.lua
index f9419899..76f4dea5 100644
--- a/src/luacheck/cache.lua
+++ b/src/luacheck/cache.lua
@@ -12,7 +12,7 @@ local fields = {
"code", "name", "line", "column", "prev_line", "prev_column", "secondary", "self", "func",
"filtered", "top", "invalid", "unpaired", "read_only", "global", "filtered_111",
"filtered_121", "filtered_131", "filtered_112", "filtered_122", "filtered_113", "definition",
- "in_module"}
+ "in_module", "msg"}
-- Converts table with fields into table with indexes.
local function compress(t)
@@ -83,11 +83,6 @@ end
-- Serializes check result into a string.
function cache.serialize(events)
- if events.error then
- return ("return {%d,%d,%d,%s}"):format(
- events.line, events.column, events.offset, ("%q"):format(events.msg))
- end
-
local strings = {}
local buffer = {"", "return {"}
@@ -171,17 +166,6 @@ local function load_cached(cached)
return
end
- -- Is it a syntax error message?
- if type(res[1]) == "number" then
- return {
- error = "syntax",
- line = res[1],
- column = res[2],
- offset = res[3],
- msg = res[4]
- }
- end
-
local decompressed = {}
for i, event in ipairs(res) do
diff --git a/src/luacheck/check.lua b/src/luacheck/check.lua
index 15f79637..e9572786 100644
--- a/src/luacheck/check.lua
+++ b/src/luacheck/check.lua
@@ -154,10 +154,7 @@ function ChState:warn_empty_block(location, do_end)
})
end
---- Checks source.
--- Returns an array of warnings.
--- Raises {line = line, column = column, offset = offset, msg = msg} on syntax errors.
-local function check(src)
+local function check_or_throw(src)
local ast, comments, code_lines = parse(src)
local chstate = ChState()
local line = linearize(chstate, ast)
@@ -168,4 +165,24 @@ local function check(src)
return chstate.warnings
end
+--- Checks source.
+-- Returns an array of warnings and errors. Codes for errors start with "0".
+-- Syntax errors (with code "011") have message stored in .msg field.
+local function check(src)
+ local warnings, err = utils.pcall(check_or_throw, src)
+
+ if warnings then
+ return warnings
+ else
+ local syntax_error = {
+ code = "011",
+ line = err.line,
+ column = err.column,
+ msg = err.msg
+ }
+
+ return {syntax_error}
+ end
+end
+
return check
diff --git a/src/luacheck/filter.lua b/src/luacheck/filter.lua
index b5fb30d9..6ebda97d 100644
--- a/src/luacheck/filter.lua
+++ b/src/luacheck/filter.lua
@@ -41,7 +41,7 @@ local function get_defined_and_used_globals(file_report, opts)
local defined, globally_defined, used = {}, {}, {}
for _, warning in ipairs(file_report) do
- if warning.code and warning.code:match("11.") then
+ if warning.code:match("11.") then
if warning.code == "111" then
if (opts.inline and warning.definition) or core_utils.is_definition(opts, warning) then
if (opts.inline and warning.in_module) or opts.module then
@@ -86,7 +86,7 @@ local function filter_implicit_defs_file(file_report, opts, globally_defined, gl
local res = {}
for _, warning in ipairs(file_report) do
- if warning.code and warning.code:match("11.") then
+ if warning.code:match("11.") then
if warning.code == "111" then
if (opts.inline and warning.in_module) or opts.module then
if not locally_defined[warning.name] then
@@ -125,7 +125,7 @@ local function filter_implicit_defs(report, opts)
local info = get_implicit_defs_info(report, opts)
for i, file_report in ipairs(report) do
- if not file_report.error then
+ if not file_report.fatal then
res[i] = filter_implicit_defs_file(file_report, opts[i], info.globally_defined, info.globally_used, info.locally_defined[i])
else
res[i] = file_report
@@ -256,16 +256,16 @@ end
local function filter_file_report(report, opts)
local res = {}
- for _, warning in ipairs(report) do
- if warning.code and ((opts.inline and warning.read_only) or warning.code:match("11[12]")
- and not warning.module and opts.read_globals[warning.name]) and not (
- (opts.inline and warning.global) or (opts.globals[warning.name] and not opts.read_globals[warning.name])) then
- warning.code = "12" .. warning.code:sub(3, 3)
+ for _, event in ipairs(report) do
+ if ((opts.inline and event.read_only) or event.code:match("11[12]")
+ and not event.module and opts.read_globals[event.name]) and not (
+ (opts.inline and event.global) or (opts.globals[event.name] and not opts.read_globals[event.name])) then
+ event.code = "12" .. event.code:sub(3, 3)
end
- if (not warning.code and opts.inline) or (warning.code and (not warning.filtered and
- not warning["filtered_" .. warning.code] or not opts.inline) and not filter.filters(opts, warning)) then
- table.insert(res, warning)
+ if event.code == "011" or (event.code:match("02.") and opts.inline) or (event.code:sub(1, 1) ~= "0" and (not event.filtered and
+ not event["filtered_" .. event.code] or not opts.inline) and not filter.filters(opts, event)) then
+ table.insert(res, event)
end
end
@@ -277,7 +277,7 @@ local function filter_report(report, opts)
local res = {}
for i, file_report in ipairs(report) do
- if not file_report.error then
+ if not file_report.fatal then
res[i] = filter_file_report(file_report, opts[i])
else
res[i] = file_report
diff --git a/src/luacheck/format.lua b/src/luacheck/format.lua
index 4e302a2d..40a4984f 100644
--- a/src/luacheck/format.lua
+++ b/src/luacheck/format.lua
@@ -3,6 +3,10 @@ local utils = require "luacheck.utils"
local color_support = not utils.is_windows or os.getenv("ANSICON")
local message_formats = {
+ ["011"] = function(w) return w.msg end,
+ ["021"] = "invalid inline option",
+ ["022"] = "unpaired push directive",
+ ["023"] = "unpaired pop directive",
["111"] = function(w)
if w.module then return "setting non-module global variable %s"
else return "setting non-standard global variable %s" end end,
@@ -45,12 +49,6 @@ local message_formats = {
}
local function get_message_format(warning)
- if warning.invalid then
- return "invalid inline option"
- elseif warning.unpaired then
- return "unpaired inline option"
- end
-
local message_format = message_formats[warning.code]
if type(message_format) == "function" then
@@ -101,20 +99,43 @@ local function capitalize(str)
return str:gsub("^.", string.upper)
end
-local function error_type(file_report)
- return capitalize(file_report.error) .. " error"
+local function fatal_type(file_report)
+ return capitalize(file_report.fatal) .. " error"
+end
+
+local function count_warnings_errors(events)
+ local warnings, errors = 0, 0
+
+ for _, event in ipairs(events) do
+ if event.code:sub(1, 1) == "0" then
+ errors = errors + 1
+ else
+ warnings = warnings + 1
+ end
+ end
+
+ return warnings, errors
end
local function format_file_report_header(report, file_name, _, color)
local label = "Checking " .. file_name
local status
- if report.error then
- status = format_color(error_type(report), color, "bright")
+ if report.fatal then
+ status = format_color(fatal_type(report), color, "bright")
elseif #report == 0 then
status = format_color("OK", color, "bright", "green")
else
- status = format_color("Failure", color, "bright", "red")
+ local warnings, errors = count_warnings_errors(report)
+
+ if warnings > 0 then
+ status = format_color(tostring(warnings).." warning"..plural(warnings), color, "bright", "red")
+ end
+
+ if errors > 0 then
+ status = status and (status.." / ") or ""
+ status = status..(format_color(tostring(errors).." error"..plural(errors), color, "bright"))
+ end
end
return label .. (" "):rep(math.max(50 - #label, 1)) .. status
@@ -124,33 +145,29 @@ local function format_location(file, location)
return ("%s:%d:%d"):format(file, location.line, location.column)
end
-local function format_warning(file_name, warning, codes, color)
- local message_format = get_message_format(warning)
- local message = message_format:format(warning.name and format_name(warning.name, color), warning.prev_line)
+local function event_code(event)
+ return (event.code:sub(1, 1) == "0" and "E" or "W")..event.code
+end
- if warning.code and codes then
- message = ("(W%s) %s"):format(warning.code, message)
- end
+local function format_event(file_name, event, codes, color)
+ local message_format = get_message_format(event)
+ local message = message_format:format(event.name and format_name(event.name, color), event.prev_line)
- return format_location(file_name, warning) .. ": " .. message
-end
+ if codes then
+ message = ("(%s) %s"):format(event_code(event), message)
+ end
-local function format_error_msg(file_name, error_report)
- return format_location(file_name, error_report) .. ": " .. error_report.msg
+ return format_location(file_name, event) .. ": " .. message
end
local function format_file_report(report, file_name, codes, color)
local buf = {format_file_report_header(report, file_name, codes, color)}
- if report.msg or #report > 0 then
+ if #report > 0 then
table.insert(buf, "")
- for _, warning in ipairs(report) do
- table.insert(buf, " " .. format_warning(file_name, warning, codes, color))
- end
-
- if report.msg then
- table.insert(buf, " " .. format_error_msg(file_name, report))
+ for _, event in ipairs(report) do
+ table.insert(buf, " " .. format_event(file_name, event, codes, color))
end
table.insert(buf, "")
@@ -166,7 +183,7 @@ function formatters.default(report, file_names, codes, quiet, color)
if quiet <= 2 then
for i, file_report in ipairs(report) do
- if quiet == 0 or file_report.error or #file_report > 0 then
+ if quiet == 0 or file_report.fatal or #file_report > 0 then
table.insert(buf, (quiet == 2 and format_file_report_header or format_file_report) (
file_report, file_names[i], codes, color))
end
@@ -177,12 +194,17 @@ function formatters.default(report, file_names, codes, quiet, color)
end
end
- table.insert(buf, ("Total: %s warning%s / %s error%s in %d file%s"):format(
+ local total = ("Total: %s warning%s / %s error%s in %d file%s"):format(
format_number(report.warnings, color), plural(report.warnings),
format_number(report.errors, color), plural(report.errors),
- #report, plural(#report)
- ))
+ #report - report.fatals, plural(#report - report.fatals))
+
+ if report.fatals > 0 then
+ total = total..(", couldn't check %s file%s"):format(
+ report.fatals, plural(report.fatals))
+ end
+ table.insert(buf, total)
return table.concat(buf, "\n")
end
@@ -190,17 +212,13 @@ function formatters.TAP(report, file_names, codes)
local buf = {}
for i, file_report in ipairs(report) do
- if file_report.error then
- if file_report.msg then
- table.insert(buf, ("not ok %d %s"):format(#buf + 1, format_error_msg(file_names[i], file_report)))
- else
- table.insert(buf, ("not ok %d %s: %s error"):format(#buf + 1, file_names[i], error_type(file_report)))
- end
+ if file_report.fatal then
+ table.insert(buf, ("not ok %d %s: %s"):format(#buf + 1, file_names[i], fatal_type(file_report)))
elseif #file_report == 0 then
table.insert(buf, ("ok %d %s"):format(#buf + 1, file_names[i]))
else
for _, warning in ipairs(file_report) do
- table.insert(buf, ("not ok %d %s"):format(#buf + 1, format_warning(file_names[i], warning, codes)))
+ table.insert(buf, ("not ok %d %s"):format(#buf + 1, format_event(file_names[i], warning, codes)))
end
end
end
@@ -214,7 +232,7 @@ function formatters.JUnit(report, file_names)
local num_testcases = 0
for _, file_report in ipairs(report) do
- if file_report.error or #file_report == 0 then
+ if file_report.fatal or #file_report == 0 then
num_testcases = num_testcases + 1
else
num_testcases = num_testcases + #file_report
@@ -224,25 +242,17 @@ function formatters.JUnit(report, file_names)
table.insert(buf, ([[]]):format(num_testcases))
for file_i, file_report in ipairs(report) do
- if file_report.error then
+ if file_report.fatal then
table.insert(buf, ([[ ]]):format(file_names[file_i], file_names[file_i]))
-
- if file_report.msg then
- table.insert(buf, ([[ ]]):format(
- error_type(file_report), format_error_msg(file_names[file_i], file_report)))
- else
- table.insert(buf, ([[ ]]):format(error_type(file_report)))
- end
-
+ table.insert(buf, ([[ ]]):format(fatal_type(file_report)))
table.insert(buf, [[ ]])
elseif #file_report == 0 then
table.insert(buf, ([[ ]]):format(file_names[file_i], file_names[file_i]))
else
- for warning_i, warning in ipairs(file_report) do
- local warning_type = warning.code and ("W" .. warning.code) or "Inline option"
- table.insert(buf, ([[ ]]):format(file_names[file_i], warning_i, file_names[file_i]))
+ for event_i, event in ipairs(file_report) do
+ table.insert(buf, ([[ ]]):format(file_names[file_i], event_i, file_names[file_i]))
table.insert(buf, ([[ ]]):format(
- warning_type, format_warning(file_names[file_i], warning)))
+ event_code(event), format_event(file_names[file_i], event)))
table.insert(buf, [[ ]])
end
end
@@ -256,15 +266,11 @@ function formatters.plain(report, file_names, codes)
local buf = {}
for i, file_report in ipairs(report) do
- if file_report.error then
- if file_report.msg then
- table.insert(buf, format_error_msg(file_names[i], file_report))
- else
- table.insert(buf, ("%s: %s error"):format(file_names[i], error_type(file_report)))
- end
+ if file_report.fatal then
+ table.insert(buf, ("%s: %s"):format(file_names[i], fatal_type(file_report)))
else
- for _, warning in ipairs(file_report) do
- table.insert(buf, format_warning(file_names[i], warning, codes))
+ for _, event in ipairs(file_report) do
+ table.insert(buf, format_event(file_names[i], event, codes))
end
end
end
diff --git a/src/luacheck/init.lua b/src/luacheck/init.lua
index bb4f5d1a..3a60d12d 100644
--- a/src/luacheck/init.lua
+++ b/src/luacheck/init.lua
@@ -39,27 +39,34 @@ local function validate_options(fname, items, opts)
end
end
--- Returns report for a string or nil, {line = line, column = column, offset = offset, msg = msg} in case of syntax error.
+-- Returns report for a string. Report is an array of warnings and errors.
function luacheck.get_report(src)
assert(type(src) == "string", ("bad argument #1 to 'luacheck.get_report' (string expected, got %s)"):format(type(src)))
- return utils.pcall(check, src)
+ return check(src)
end
--- Applies options to reports. Reports with .error field are unchanged.
+-- Applies options to reports. Reports with .fatal field are unchanged.
-- Options are applied to reports[i] in order: options, options[i], options[i][1], options[i][2], ...
--- Returns new array of reports, adds .warnings and .errors fields.
+-- Returns new array of reports, adds .warnings, .errors and .fatals fields to this array.
function luacheck.process_reports(reports, opts)
assert(type(reports) == "table", ("bad argument #1 to 'luacheck.process_reports' (table expected, got %s)"):format(type(reports)))
validate_options("luacheck.process_reports", reports, opts)
local report = filter.filter(reports, opts)
report.warnings = 0
report.errors = 0
+ report.fatals = 0
for _, file_report in ipairs(report) do
- if file_report.error then
- report.errors = report.errors + 1
+ if file_report.fatal then
+ report.fatals = report.fatals + 1
else
- report.warnings = report.warnings + #file_report
+ for _, event in ipairs(file_report) do
+ if event.code:sub(1, 1) == "0" then
+ report.errors = report.errors + 1
+ else
+ report.warnings = report.warnings + 1
+ end
+ end
end
end
@@ -67,7 +74,7 @@ function luacheck.process_reports(reports, opts)
end
-- Checks strings with options, returns report.
--- Error reports are unchanged.
+-- Tables with .fatal field are unchanged.
function luacheck.check_strings(srcs, opts)
assert(type(srcs) == "table", ("bad argument #1 to 'luacheck.check_strings' (table expected, got %s)"):format(type(srcs)))
@@ -82,17 +89,10 @@ function luacheck.check_strings(srcs, opts)
local reports = {}
for i, src in ipairs(srcs) do
- if type(src) == "table" then
+ if type(src) == "table" and src.fatal then
reports[i] = src
else
- local report, err = luacheck.get_report(src)
-
- if report then
- reports[i] = report
- else
- err.error = "syntax"
- reports[i] = err
- end
+ reports[i] = luacheck.get_report(src)
end
end
@@ -113,7 +113,7 @@ function luacheck.check_files(files, opts)
local srcs = {}
for i, file in ipairs(files) do
- srcs[i] = utils.read_file(file) or {error = "I/O"}
+ srcs[i] = utils.read_file(file) or {fatal = "I/O"}
end
return luacheck.check_strings(srcs, opts)
diff --git a/src/luacheck/inline_options.lua b/src/luacheck/inline_options.lua
index af8b3e6e..d89f9df8 100644
--- a/src/luacheck/inline_options.lua
+++ b/src/luacheck/inline_options.lua
@@ -182,9 +182,9 @@ end
-- Mutates shape of warnings in events according to inline options.
-- Warnings which are simply filtered are marked with .filtered.
--- Returns array of unpaired push/pop comments.
+-- Returns arrays of unpaired push events and unpaired pop events.
local function handle_events(events, per_line_opts)
- local unpaired_comments = {}
+ local unpaired_pushes, unpaired_pops = {}, {}
local unfiltered_warnings = {}
local option_stack = utils.Stack()
local boundaries = utils.Stack()
@@ -213,12 +213,12 @@ local function handle_events(events, per_line_opts)
elseif event.pop then
if boundaries.size == 0 or (boundaries.top.closure and not event.closure) then
-- Unpaired pop boundary, do nothing.
- table.insert(unpaired_comments, event)
+ table.insert(unpaired_pops, event)
else
if event.closure then
-- There could be unpaired push boundaries, pop them.
while not boundaries.top.closure do
- table.insert(unpaired_comments, boundaries:pop())
+ table.insert(unpaired_pushes, boundaries:pop())
end
end
@@ -242,7 +242,7 @@ local function handle_events(events, per_line_opts)
apply_inline_options(option_stack, per_line_opts, unfiltered_warnings)
end
- return unpaired_comments
+ return unpaired_pushes, unpaired_pops
end
-- Filteres warnings using inline options, adds invalid comments.
@@ -254,9 +254,10 @@ end
-- .in_module is added to 111 warnings that are in module due to inline options.
-- .read_only is added to 111 and 112 warnings related to read only globals.
-- .global is added to 111 and 112 related to regular globals.
--- Invalid comments have same shape as warnings except they don't have .code field.
--- Instead, they may have .invalid or .unpaired field for syntactically invalid inline options and unpaired
--- push/pop options, correspondingly.
+-- Invalid comments have same shape as warnings, with codes:
+-- 021 - syntactically invalid comment;
+-- 022 - unpaired push comment;
+-- 023 - unpaired pop comment.
local function handle_inline_options(ast, comments, code_lines, warnings)
-- Create array of all events sorted by location.
-- This includes inline options, warnings and implicit push/pop operations corresponding to closure starts/ends.
@@ -271,14 +272,18 @@ local function handle_inline_options(ast, comments, code_lines, warnings)
add_closure_boundaries(ast, events)
local per_line_opts, invalid_comments = add_inline_options(events, comments, code_lines)
core_utils.sort_by_location(events)
- local unpaired_comments = handle_events(events, per_line_opts)
+ local unpaired_pushes, unpaired_pops = handle_events(events, per_line_opts)
for _, comment in ipairs(invalid_comments) do
- table.insert(warnings, {invalid = true, line = comment.location.line, column = comment.location.column})
+ table.insert(warnings, {code = "021", line = comment.location.line, column = comment.location.column})
end
- for _, event in ipairs(unpaired_comments) do
- table.insert(warnings, {unpaired = true, line = event.line, column = event.column})
+ for _, event in ipairs(unpaired_pushes) do
+ table.insert(warnings, {code = "022", line = event.line, column = event.column})
+ end
+
+ for _, event in ipairs(unpaired_pops) do
+ table.insert(warnings, {code = "023", line = event.line, column = event.column})
end
return warnings
diff --git a/src/luacheck/main.lua b/src/luacheck/main.lua
index 9bdc54b6..c277eab5 100644
--- a/src/luacheck/main.lua
+++ b/src/luacheck/main.lua
@@ -11,16 +11,16 @@ local fs = require "luacheck.fs"
local Globber = require "luacheck.globber"
local utils = require "luacheck.utils"
-local function fatal(msg)
- io.stderr:write("Fatal error: "..msg.."\n")
+local function critical(msg)
+ io.stderr:write("Critical error: "..msg.."\n")
os.exit(3)
end
local function global_error_handler(err)
if type(err) == "table" and err.pattern then
- fatal("Invalid pattern '" .. err.pattern .. "'")
+ critical("Invalid pattern '" .. err.pattern .. "'")
else
- fatal(debug.traceback(
+ critical(debug.traceback(
("Luacheck %s bug (please report at github.com/mpeterv/luacheck/issues):\n%s"):format(luacheck._VERSION, err), 2))
end
end
@@ -300,7 +300,7 @@ Otherwise, the pattern matches warning code.]])
end
end
- return sparse_mtimes, cache.load(cache_filename, cache_files, cache_mtimes) or fatal(
+ return sparse_mtimes, cache.load(cache_filename, cache_files, cache_mtimes) or critical(
("Couldn't load cache from %s: data corrupted"):format(cache_filename))
end
@@ -323,17 +323,6 @@ Otherwise, the pattern matches warning code.]])
return res
end
- local function get_report(source)
- local report, err = luacheck.get_report(source)
-
- if report then
- return report
- else
- err.error = "syntax"
- return err
- end
- end
-
-- Returns sparse array of new reports.
local function get_new_reports(files, srcs, jobs)
local dense_srcs = {}
@@ -347,7 +336,7 @@ Otherwise, the pattern matches warning code.]])
end
local map = jobs and multithreading.has_lanes and multithreading.pmap or utils.map
- local dense_res = map(get_report, dense_srcs, jobs)
+ local dense_res = map(luacheck.get_report, dense_srcs, jobs)
local res = {}
@@ -376,7 +365,7 @@ Otherwise, the pattern matches warning code.]])
end
end
- return cache.update(cache_filename, cache_files, cache_mtimes, cache_reports) or fatal(
+ return cache.update(cache_filename, cache_files, cache_mtimes, cache_reports) or critical(
("Couldn't save cache to %s: I/O error"):format(cache_filename))
end
@@ -403,7 +392,7 @@ Otherwise, the pattern matches warning code.]])
for i, file in ipairs(files) do
if bad_files[i] then
- res[i] = {error = bad_files[i]}
+ res[i] = {fatal = bad_files[i]}
else
res[i] = cached_reports[file] or new_reports[i]
end
@@ -453,14 +442,14 @@ Otherwise, the pattern matches warning code.]])
ok, formatter = config.relative_require(conf, formatter)
if not ok then
- fatal(("Couldn't load custom formatter '%s': %s"):format(args.formatter, formatter))
+ critical(("Couldn't load custom formatter '%s': %s"):format(args.formatter, formatter))
end
end
ok, output = pcall(formatter, report, file_names, args)
if not ok then
- fatal(("Couldn't run custom formatter '%s': %s"):format(tostring(args.formatter), output))
+ critical(("Couldn't run custom formatter '%s': %s"):format(tostring(args.formatter), output))
end
return output
@@ -478,7 +467,7 @@ Otherwise, the pattern matches warning code.]])
conf, err = config.load_config(args.config)
if not conf then
- fatal(err)
+ critical(err)
end
end
@@ -502,9 +491,9 @@ Otherwise, the pattern matches warning code.]])
local exit_code
- if report.errors > 0 then
+ if report.fatals > 0 then
exit_code = 2
- elseif report.warnings > 0 then
+ elseif report.warnings > 0 or report.errors > 0 then
exit_code = 1
else
exit_code = 0