Skip to content

Commit

Permalink
Adds table field checks for #39
Browse files Browse the repository at this point in the history
  • Loading branch information
arichard4 committed Apr 29, 2022
1 parent 815cf79 commit 071f25e
Show file tree
Hide file tree
Showing 9 changed files with 1,092 additions and 10 deletions.
2 changes: 2 additions & 0 deletions docsrc/warnings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ Code Description
312 Value of an argument is unused.
313 Value of a loop variable is unused.
314 Value of a field in a table literal is unused.
315 Unused table field
321 Accessing uninitialized local variable.
325 Accessing unitialized table field
331 Value assigned to a local variable is mutated but never accessed.
341 Mutating uninitialized local variable.
411 Redefining a local variable.
Expand Down
1 change: 1 addition & 0 deletions luacheck-dev-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ build = {
["luacheck.stages.detect_empty_blocks"] = "src/luacheck/stages/detect_empty_blocks.lua",
["luacheck.stages.detect_empty_statements"] = "src/luacheck/stages/detect_empty_statements.lua",
["luacheck.stages.detect_globals"] = "src/luacheck/stages/detect_globals.lua",
["luacheck.stages.check_table_fields"] = "src/luacheck/stages/check_table_fields.lua",
["luacheck.stages.detect_reversed_fornum_loops"] = "src/luacheck/stages/detect_reversed_fornum_loops.lua",
["luacheck.stages.detect_unbalanced_assignments"] = "src/luacheck/stages/detect_unbalanced_assignments.lua",
["luacheck.stages.detect_uninit_accesses"] = "src/luacheck/stages/detect_uninit_accesses.lua",
Expand Down
17 changes: 9 additions & 8 deletions spec/cli_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -738,18 +738,19 @@ Total: 8 warnings / 3 errors in 2 files

it("shows correct ranges for files with utf8", function()
assert.equal([[
Checking spec/samples/utf8.lua 4 warnings
Checking spec/samples/utf8.lua 5 warnings
spec/samples/utf8.lua:2:1-4: setting undefined field '분야 명' of global 'math'
spec/samples/utf8.lua:2:16-19: accessing undefined field '値' of global 'math'
spec/samples/utf8.lua:3:25-25: unused variable 't'
spec/samples/utf8.lua:4:5-28: value assigned to field 'päällekkäinen nimi a\u{200B}b' is overwritten on line 5 before use
spec/samples/utf8.lua:5:5-28: value assigned to table field 't'.'päällekkäinen nimi a​b' is unused
Checking spec/samples/utf8_error.lua 1 error
spec/samples/utf8_error.lua:2:11-11: expected statement near 'о'
Total: 4 warnings / 1 error in 2 files
Total: 5 warnings / 1 error in 2 files
]], get_output "spec/samples/utf8.lua spec/samples/utf8_error.lua --ranges --no-config")
end)

Expand Down Expand Up @@ -1218,10 +1219,10 @@ Checking spec/samples/redefined.lua 7 warnings
Checking spec/samples/reversed_fornum.lua 1 warning
Checking spec/samples/unused_code.lua 10 warnings
Checking spec/samples/unused_secondaries.lua 4 warnings
Checking spec/samples/utf8.lua 4 warnings
Checking spec/samples/utf8.lua 5 warnings
Checking spec/samples/utf8_error.lua 1 error
Total: 73 warnings / 5 errors in 19 files
Total: 74 warnings / 5 errors in 19 files
]]):gsub("(spec/samples)/", "%1"..package.config:sub(1, 1)),
get_output "spec/samples --config=spec/configs/exclude_files_config.luacheckrc -qq --exclude-files spec/samples/global_fields.lua")
end)
Expand All @@ -1243,10 +1244,10 @@ Checking redefined.lua 7 warnings
Checking reversed_fornum.lua 1 warning
Checking unused_code.lua 10 warnings
Checking unused_secondaries.lua 4 warnings
Checking utf8.lua 4 warnings
Checking utf8.lua 5 warnings
Checking utf8_error.lua 1 error
Total: 73 warnings / 5 errors in 19 files
Total: 74 warnings / 5 errors in 19 files
]], get_output(". --config=spec/configs/exclude_files_config.luacheckrc -qq --exclude-files global_fields.lua", "spec/samples/"))
end)

Expand All @@ -1265,10 +1266,10 @@ Checking redefined.lua 7 warnings
Checking reversed_fornum.lua 1 warning
Checking unused_code.lua 10 warnings
Checking unused_secondaries.lua 4 warnings
Checking utf8.lua 4 warnings
Checking utf8.lua 5 warnings
Checking utf8_error.lua 1 error
Total: 65 warnings / 5 errors in 17 files
Total: 66 warnings / 5 errors in 17 files
]], get_output(". --config=spec/configs/exclude_files_config.luacheckrc -qq --exclude-files global_fields.lua --exclude-files " .. quote("./read*"), "spec/samples/"))
end)

Expand Down
157 changes: 157 additions & 0 deletions spec/table_field_limitations_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
local helper = require "spec.helper"

local function assert_warnings(warnings, src)
assert.same(warnings, helper.get_stage_warnings("check_table_fields", src))
end

describe("table field todo tests", function()
it("does nothing for globals", function()
assert_warnings({}, [[
x = {}
x[1] = 1
x[2] = x.y
x[1] = 1
y[1] = 1
y[2] = x.y
y[1] = 1
]])
end)

it("can't parse complicated values out", function()
assert_warnings({}, [[
local val = nil
local t = {}
t[1] = val
print(t[1])
]])
end)

it("does nothing for nested tables", function()
assert_warnings({}, [[
local x = {}
x[1] = {}
x[1][1] = 1
x[1][1] = x[1][2]
return x
]])
end)

-- Because of possible multiple return
it("assumes tables initialized from functions can have arbitrary keys set", function()
assert_warnings({
{code = "315", line = 3, column = 3, end_column = 3, name = 'x', field = 'y', set_is_nil = ''},
}, [[
local function func() return 1 end
local x = {func()}
x.y = x[2]
]])
end)

it("does nothing for table parameters that aren't declared in scope", function()
assert_warnings({}, [[
function func(x)
x[1] = x.z
x[1] = 1
end
]])
end)

it("doesn't handle metatables", function()
assert_warnings({}, [[
local x = setmetatable({}, {})
x[1] = 1
print(x[2])
]])
end)

it("detects unused and undefined table fields inside control blocks, but not between them", function()
assert_warnings({
{line = 4, column = 13, name = 'x', end_column = 13, field = 'z', code = '325', },
{line = 10, column = 13, name = 'x', end_column = 13, field = 'z', code = '325', },
{line = 16, column = 13, name = 'x', end_column = 13, field = 'z', code = '325', },
{line = 22, column = 13, name = 'x', end_column = 13, field = 'z', code = '325', },
{line = 28, column = 13, name = 'x', end_column = 13, field = 'z', code = '325', },
{line = 34, column = 13, name = 'x', end_column = 13, field = 'z', code = '325', },
}, [[
do
local x = {}
x.y = 1
x[1] = x.z
end
if true then
local x = {}
x.y = 1
x[1] = x.z
end
while true do
local x = {}
x.y = 1
x[1] = x.z
end
repeat
local x = {}
x.y = 1
x[1] = x.z
until false
for i=1,2 do
local x = {}
x.y = 1
x[1] = x.z
end
for _,_ in pairs({}) do
local x = {}
x.y = 1
x[1] = x.z
end
]])
end)

it("stops checking referenced upvalues if function call is known to not have table as an upvalue", function()
assert_warnings({}, [[
local x = {}
x[1] = 1
local function printx() x = 1 end
local function ret2() return 2 end
ret2()
x[1] = 1
local y = {}
y[1] = 1
function y.printx() y = 1 end
function y.ret2() return 2 end
y.ret2()
y[1] = 1
]])
end)

it("stops checking if a function is called", function()
assert_warnings({
{line = 8, column = 3, name = 'y', end_column = 3, field = 'x', code = '315', set_is_nil = '' },
{line = 8, column = 9, name = 'y', end_column = 9, field = 'a', code = '325', },
{line = 14, column = 9, name = 't', end_column = 9, field = 'a', code = '325', },
}, [[
local x = {}
x.y = 1
print("Unrelated text")
x.y = 2
x[1] = x.z
local y = {}
y.x = y.a
y.x = 1
function y:func() return 1 end
y:func()
local t = {}
t.x = t.a
local var = 'func'
t.x = y[var]() + 1
]])
end)
end)
Loading

0 comments on commit 071f25e

Please sign in to comment.