summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2023-07-20 18:08:35 +0800
committer最萌小汐 <sumneko@hotmail.com>2023-07-20 18:08:35 +0800
commit297ac3aabb38c22648f501038e1e66b6c8f9f936 (patch)
treee9c40686abd45a1aeba3e6d863d015c2117c8429
parente7bc0940a32a99adc2bbce746d118e59faddcc07 (diff)
downloadlua-language-server-297ac3aabb38c22648f501038e1e66b6c8f9f936.zip
new diagnostic: `missing-fields`
-rw-r--r--changelog.md1
-rw-r--r--script/core/diagnostics/missing-fields.lua72
-rw-r--r--script/proto/diagnostic.lua1
-rw-r--r--test/diagnostics/common.lua150
-rw-r--r--test/diagnostics/type-check.lua1
5 files changed, 223 insertions, 2 deletions
diff --git a/changelog.md b/changelog.md
index 0d4ec8a6..10aa311a 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,7 @@
# changelog
## 3.6.24
+* `NEW` diagnostic: `missing-fields`
* `FIX` shake of `codeLens`
* `FIX` [#2145]
diff --git a/script/core/diagnostics/missing-fields.lua b/script/core/diagnostics/missing-fields.lua
new file mode 100644
index 00000000..e23352bc
--- /dev/null
+++ b/script/core/diagnostics/missing-fields.lua
@@ -0,0 +1,72 @@
+local vm = require 'vm'
+local files = require 'files'
+local guide = require 'parser.guide'
+local await = require 'await'
+
+---@async
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+
+ ---@async
+ guide.eachSourceType(state.ast, 'table', function (src)
+ await.delay()
+
+ local defs = vm.getDefs(src)
+ local requiresKeys = {}
+ for _, def in ipairs(defs) do
+ if def.type == 'doc.class' then
+ if not def.fields then
+ goto continue
+ end
+ if def.bindSource then
+ if guide.isInRange(def.bindSource, src.start) then
+ goto continue
+ end
+ end
+ for _, field in ipairs(def.fields) do
+ if not field.optional
+ and not vm.compileNode(field):isNullable() then
+ local key = vm.getKeyName(field)
+ if key and not requiresKeys[key] then
+ requiresKeys[key] = true
+ requiresKeys[#requiresKeys+1] = key
+ end
+ end
+ end
+ end
+ ::continue::
+ end
+
+ if #requiresKeys == 0 then
+ return
+ end
+
+ local myKeys = {}
+ for _, field in ipairs(src) do
+ local key = vm.getKeyName(field)
+ if key then
+ myKeys[key] = true
+ end
+ end
+
+ local missedKeys = {}
+ for _, key in ipairs(requiresKeys) do
+ if not myKeys[key] then
+ missedKeys[#missedKeys+1] = ('`%s`'):format(key)
+ end
+ end
+
+ if #missedKeys == 0 then
+ return
+ end
+
+ callback {
+ start = src.start,
+ finish = src.finish,
+ message = string.format('Missing fields: %s', table.concat(missedKeys, ', ')),
+ }
+ end)
+end
diff --git a/script/proto/diagnostic.lua b/script/proto/diagnostic.lua
index 8175a2c5..9c095531 100644
--- a/script/proto/diagnostic.lua
+++ b/script/proto/diagnostic.lua
@@ -62,6 +62,7 @@ m.register {
'missing-return-value',
'redundant-return-value',
'missing-return',
+ 'missing-fields',
} {
group = 'unbalanced',
severity = 'Warning',
diff --git a/test/diagnostics/common.lua b/test/diagnostics/common.lua
index a1dbe819..d061b4e4 100644
--- a/test/diagnostics/common.lua
+++ b/test/diagnostics/common.lua
@@ -156,13 +156,13 @@ print(A) -- no warning
TEST [[
---@type iolib
-_ENV = {}
+_ENV = io
<!print!>(stderr) -- `print` is warning but `stderr` is not
]]
TEST [[
---@type iolib
-local _ENV = {}
+local _ENV = io
<!print!>(stderr) -- `print` is warning but `stderr` is not
]]
@@ -2206,6 +2206,7 @@ end
TEST [[
---@diagnostic disable: unused-local
+---@diagnostic disable: missing-fields
---@class A
---@field private x number
local mt = {}
@@ -2220,6 +2221,7 @@ end
TEST [[
---@diagnostic disable: unused-local
+---@diagnostic disable: missing-fields
---@class A
---@field private x number
local mt = {}
@@ -2268,3 +2270,147 @@ local function foo(_ENV)
Joe = "human"
end
]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@type A
+local t = <!{}!>
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@type A
+local t = <!{
+ x = 1,
+}!>
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@type A
+local t = <!{
+ x = 1,
+ y = 2,
+}!>
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@type A
+local t = {
+ x = 1,
+ y = 2,
+ z = 3,
+}
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@type A
+local t = {
+ x = 1,
+ z = 3,
+}
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@param a A
+local function f(a) end
+
+f <!{}!>
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@param a A
+local function f(a) end
+
+f <!{
+ x = 1,
+}!>
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@param a A
+local function f(a) end
+
+f <!{
+ x = 1,
+ y = 2,
+}!>
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@param a A
+local function f(a) end
+
+f {
+ x = 1,
+ y = 2,
+ z = 3,
+}
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+---@field y? number
+---@field z number
+
+---@param a A
+local function f(a) end
+
+f {
+ x = 1,
+ z = 3,
+}
+]]
diff --git a/test/diagnostics/type-check.lua b/test/diagnostics/type-check.lua
index dd9d1198..adfef561 100644
--- a/test/diagnostics/type-check.lua
+++ b/test/diagnostics/type-check.lua
@@ -174,6 +174,7 @@ m.ints = {}
]]
TEST [[
+---@diagnostic disable: missing-fields
---@class A
---@field x A