summaryrefslogtreecommitdiff
path: root/test/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'test/diagnostics')
-rw-r--r--test/diagnostics/ambiguity-1.lua29
-rw-r--r--test/diagnostics/assign-type-mismatch.lua481
-rw-r--r--test/diagnostics/await-in-sync.lua132
-rw-r--r--test/diagnostics/cast-local-type.lua334
-rw-r--r--test/diagnostics/cast-type-mismatch.lua13
-rw-r--r--test/diagnostics/circle-doc-class.lua14
-rw-r--r--test/diagnostics/close-non-object.lua18
-rw-r--r--test/diagnostics/code-after-break.lua7
-rw-r--r--test/diagnostics/common.lua2270
-rw-r--r--test/diagnostics/count-down-loop.lua29
-rw-r--r--test/diagnostics/deprecated.lua21
-rw-r--r--test/diagnostics/discard-returns.lua17
-rw-r--r--test/diagnostics/doc-field-no-class.lua16
-rw-r--r--test/diagnostics/duplicate-doc-alias.lua10
-rw-r--r--test/diagnostics/duplicate-doc-field.lua38
-rw-r--r--test/diagnostics/duplicate-doc-param.lua12
-rw-r--r--test/diagnostics/duplicate-index.lua24
-rw-r--r--test/diagnostics/duplicate-set-field.lua74
-rw-r--r--test/diagnostics/empty-block.lua32
-rw-r--r--test/diagnostics/global-element.lua34
-rw-r--r--test/diagnostics/global-in-nil-env.lua44
-rw-r--r--test/diagnostics/incomplete-signature-doc.lua167
-rw-r--r--test/diagnostics/init.lua115
-rw-r--r--test/diagnostics/inject-field.lua84
-rw-r--r--test/diagnostics/invisible.lua145
-rw-r--r--test/diagnostics/lowercase-global.lua39
-rw-r--r--test/diagnostics/missing-fields.lua233
-rw-r--r--test/diagnostics/missing-global-doc.lua36
-rw-r--r--test/diagnostics/missing-local-export-doc.lua175
-rw-r--r--test/diagnostics/missing-parameter.lua90
-rw-r--r--test/diagnostics/missing-return-value.lua34
-rw-r--r--test/diagnostics/missing-return.lua158
-rw-r--r--test/diagnostics/need-check-nil.lua68
-rw-r--r--test/diagnostics/newfield-call.lua15
-rw-r--r--test/diagnostics/newline-call.lua34
-rw-r--r--test/diagnostics/not-yieldable.lua48
-rw-r--r--test/diagnostics/param-type-mismatch.lua248
-rw-r--r--test/diagnostics/redefined-local.lua22
-rw-r--r--test/diagnostics/redundant-parameter.lua214
-rw-r--r--test/diagnostics/redundant-return-value.lua32
-rw-r--r--test/diagnostics/redundant-return.lua34
-rw-r--r--test/diagnostics/redundant-value.lua7
-rw-r--r--test/diagnostics/return-type-mismatch.lua167
-rw-r--r--test/diagnostics/trailing-space.lua32
-rw-r--r--test/diagnostics/type-check.lua1262
-rw-r--r--test/diagnostics/unbalanced-assignments.lua34
-rw-r--r--test/diagnostics/undefined-doc-class.lua3
-rw-r--r--test/diagnostics/undefined-doc-name.lua19
-rw-r--r--test/diagnostics/undefined-doc-param.lua21
-rw-r--r--test/diagnostics/undefined-env-child.lua36
-rw-r--r--test/diagnostics/undefined-field.lua148
-rw-r--r--test/diagnostics/undefined-global.lua36
-rw-r--r--test/diagnostics/unknown-cast-variable.lua8
-rw-r--r--test/diagnostics/unknown-diag-code.lua3
-rw-r--r--test/diagnostics/unknown-operator.lua4
-rw-r--r--test/diagnostics/unreachable-code.lua71
-rw-r--r--test/diagnostics/unused-function.lua48
-rw-r--r--test/diagnostics/unused-label.lua3
-rw-r--r--test/diagnostics/unused-local.lua99
-rw-r--r--test/diagnostics/unused-vararg.lua6
60 files changed, 3956 insertions, 3691 deletions
diff --git a/test/diagnostics/ambiguity-1.lua b/test/diagnostics/ambiguity-1.lua
new file mode 100644
index 00000000..6b8e41da
--- /dev/null
+++ b/test/diagnostics/ambiguity-1.lua
@@ -0,0 +1,29 @@
+TEST [[
+local x
+x = <!x or 0 + 1!>
+]]
+
+TEST [[
+local x, y
+x = <!x + y or 0!>
+]]
+
+TEST [[
+local x, y, z
+x = x and y or '' .. z
+]]
+
+TEST [[
+local x
+x = x or -1
+]]
+
+TEST [[
+local x
+x = x or (0 + 1)
+]]
+
+TEST [[
+local x, y
+x = (x + y) or 0
+]]
diff --git a/test/diagnostics/assign-type-mismatch.lua b/test/diagnostics/assign-type-mismatch.lua
new file mode 100644
index 00000000..dc55a7da
--- /dev/null
+++ b/test/diagnostics/assign-type-mismatch.lua
@@ -0,0 +1,481 @@
+local config = require 'config'
+
+TEST [[
+local m = {}
+
+---@type integer[]
+m.ints = {}
+]]
+
+TEST [[
+---@class A
+---@field x A
+
+---@type A
+local t
+
+t.x = {}
+]]
+
+TEST [[
+---@class A
+---@field x integer
+
+---@type A
+local t
+
+<!t.x!> = true
+]]
+
+TEST [[
+---@class A
+---@field x integer
+
+---@type A
+local t
+
+---@type boolean
+local y
+
+<!t.x!> = y
+]]
+
+TEST [[
+---@class A
+local m
+
+m.x = 1
+
+---@type A
+local t
+
+<!t.x!> = true
+]]
+
+TEST [[
+---@class A
+local m
+
+---@type integer
+m.x = 1
+
+<!m.x!> = true
+]]
+
+TEST [[
+---@class A
+local mt
+
+---@type integer
+mt.x = 1
+
+function mt:init()
+ <!self.x!> = true
+end
+]]
+
+TEST [[
+---@class A
+---@field x integer
+
+---@type A
+local t = {
+ <!x!> = true
+}
+]]
+
+TEST [[
+---@type boolean[]
+local t = {}
+
+t[5] = nil
+]]
+
+TEST [[
+---@type table<string, true>
+local t = {}
+
+t['x'] = nil
+]]
+
+TEST [[
+---@type [boolean]
+local t = { <![1]!> = nil }
+
+t = nil
+]]
+
+TEST [[
+local t = { true }
+
+t[1] = nil
+]]
+
+TEST [[
+---@class A
+local t = {
+ x = 1
+}
+
+<!t.x!> = true
+]]
+
+TEST [[
+---@type number
+local t
+
+t = 1
+]]
+
+TEST [[
+---@type number
+local t
+
+---@type integer
+local y
+
+t = y
+]]
+
+TEST [[
+---@class A
+local m
+
+---@type number
+m.x = 1
+
+<!m.x!> = {}
+]]
+
+TEST [[
+local n
+
+if G then
+ n = {}
+else
+ n = nil
+end
+
+local t = {
+ x = n,
+}
+]]
+
+TEST [[
+---@type boolean[]
+local t = {}
+
+---@type boolean?
+local x
+
+t[#t+1] = x
+]]
+
+TEST [[
+---@type number
+local n
+---@type integer
+local i
+
+<?i?> = n
+]]
+
+config.set(nil, 'Lua.type.castNumberToInteger', true)
+TEST [[
+---@type number
+local n
+---@type integer
+local i
+
+i = n
+]]
+
+config.set(nil, 'Lua.type.castNumberToInteger', false)
+TEST [[
+---@type number|boolean
+local nb
+
+---@type number
+local n
+
+<?n?> = nb
+]]
+
+config.set(nil, 'Lua.type.weakUnionCheck', true)
+TEST [[
+---@type number|boolean
+local nb
+
+---@type number
+local n
+
+n = nb
+]]
+
+config.set(nil, 'Lua.type.weakUnionCheck', false)
+TEST [[
+---@class Option: string
+
+---@param x Option
+local function f(x) end
+
+---@type Option
+local x = 'aaa'
+
+f(x)
+]]
+config.set(nil, 'Lua.type.weakUnionCheck', true)
+
+TEST [[
+---@type number
+local <!x!> = 'aaa'
+]]
+TEST [[
+---@class X
+
+---@class A
+local mt = G
+
+---@type X
+mt._x = nil
+]]
+config.set(nil, 'Lua.type.weakUnionCheck', false)
+
+config.set(nil, 'Lua.type.weakNilCheck', true)
+TEST [[
+---@type number?
+local nb
+
+---@type number
+local n
+
+n = nb
+]]
+
+TEST [[
+---@type number|nil
+local nb
+
+---@type number
+local n
+
+n = nb
+]]
+config.set(nil, 'Lua.type.weakNilCheck', false)
+
+TEST [[
+---@class A
+local a = {}
+
+---@class B
+local <!b!> = a
+]]
+
+TEST [[
+---@class A
+local a = {}
+
+---@class B: A
+local b = a
+]]
+
+TEST [[
+---@class A
+local a = {}
+a.__index = a
+
+---@class B: A
+local b = setmetatable({}, a)
+]]
+
+TEST [[
+---@class A
+local a = {}
+
+---@class B: A
+local b = setmetatable({}, {__index = a})
+]]
+
+TEST [[
+---@class A
+local a = {}
+
+---@class B
+local <!b!> = setmetatable({}, {__index = a})
+]]
+
+TEST [[
+---@class A
+---@field x number?
+local a
+
+---@class B
+---@field x number
+local b
+
+b.x = a.x
+]]
+
+TEST [[
+
+---@class A
+---@field x number?
+local a
+
+---@type number
+local t
+
+t = a.x
+]]
+
+TEST [[
+local mt = {}
+mt.x = 1
+mt.x = nil
+]]
+
+config.set(nil, 'Lua.type.weakUnionCheck', true)
+TEST [[
+---@type number
+local x = G
+]]
+
+TEST [[
+---@generic T
+---@param x T
+---@return T
+local function f(x)
+ return x
+end
+]]
+config.set(nil, 'Lua.type.weakUnionCheck', false)
+
+
+TEST [[
+---@alias test boolean
+
+---@type test
+local <!test!> = 4
+]]
+
+TEST [[
+---@class MyClass
+local MyClass = {}
+
+function MyClass:new()
+ ---@class MyClass
+ local myObject = setmetatable({
+ initialField = true
+ }, self)
+
+ print(myObject.initialField)
+end
+]]
+
+TEST [[
+---@class T
+local t = {
+ x = nil
+}
+
+t.x = 1
+]]
+
+TEST [[
+---@type {[1]: string, [10]: number, xx: boolean}
+local t = {
+ <!true!>,
+ <![10]!> = 's',
+ <!xx!> = 1,
+}
+]]
+
+TEST [[
+---@type boolean[]
+local t = { <!1!>, <!2!>, <!3!> }
+]]
+
+TEST [[
+---@type boolean[]
+local t = { true, false, nil }
+]]
+
+TEST [[
+---@type boolean|nil
+local x
+
+---@type boolean[]
+local t = { true, false, x }
+]]
+
+TEST [[
+---@enum Enum
+local t = {
+ x = 1,
+ y = 2,
+}
+
+---@type Enum
+local y
+
+---@type integer
+local x = y
+]]
+
+TEST [[
+---@type string|string[]|string[][]
+local t = {{'a'}}
+]]
+
+TEST [[
+local A = "Hello"
+local B = "World"
+
+---@alias myLiteralAliases `A` | `B`
+
+---@type myLiteralAliases
+local x = A
+]]
+
+TEST [[
+local enum = { a = 1, b = 2 }
+
+---@type { [integer] : boolean }
+local t = {
+ <![enum.a]!> = 1,
+ <![enum.b]!> = 2,
+ <![3]!> = 3,
+}
+]]
+
+TEST [[
+---@class SomeClass
+---@field [1] string
+-- ...
+
+---@param some_param SomeClass|SomeClass[]
+local function some_fn(some_param) return end
+
+some_fn { { "test" } } -- <- diagnostic: "Cannot assign `table` to `string`."
+]]
+
+TEST [[
+---@type string[]
+local arr = {
+ <!3!>,
+}
+]]
+
+TEST [[
+---@type (string|boolean)[]
+local arr2 = {
+ <!3!>, -- no warnings
+}
+]]
+
+TEST [[
+local t = {}
+t.a = 1
+t.a = 2
+return t
+]]
diff --git a/test/diagnostics/await-in-sync.lua b/test/diagnostics/await-in-sync.lua
new file mode 100644
index 00000000..323c1113
--- /dev/null
+++ b/test/diagnostics/await-in-sync.lua
@@ -0,0 +1,132 @@
+TEST [[
+function F()
+ <!coroutine.yield!>()
+end
+]]
+
+TEST [[
+---@async
+function F()
+ coroutine.yield()
+end
+]]
+
+TEST [[
+---@type async fun()
+local f
+
+function F()
+ <!f!>()
+end
+]]
+
+TEST [[
+---@type async fun()
+local f
+
+---@async
+function F()
+ f()
+end
+]]
+
+TEST [[
+local function f(cb)
+ cb()
+end
+
+return function()
+ <!f>(function () ---@async
+ return nil
+ end)
+end
+]]
+
+TEST [[
+local function f(cb)
+ pcall(cb)
+end
+
+return function()
+ <!f!>(function () ---@async
+ return nil
+ end)
+end
+]]
+
+TEST [[
+---@param c any
+local function f(c)
+ return c
+end
+
+return function ()
+ f(function () ---@async
+ return nil
+ end)
+end
+]]
+
+TEST [[
+---@param ... any
+local function f(...)
+ return ...
+end
+
+return function ()
+ f(function () ---@async
+ return nil
+ end)
+end
+]]
+
+TEST [[
+---@vararg any
+local function f(...)
+ return ...
+end
+
+return function ()
+ f(function () ---@async
+ return nil
+ end)
+end
+]]
+
+TEST [[
+local function f(...)
+ return ...
+end
+
+return function ()
+ f(function () ---@async
+ return nil
+ end)
+end
+]]
+
+TEST [[
+local function f(...)
+ return ...
+end
+
+return function ()
+ f(function () ---@async
+ return nil
+ end)
+end
+]]
+
+TEST [[
+local function f(cb)
+ cb()
+end
+
+local function af()
+ <!f!>(function () ---@async
+ return nil
+ end)
+end
+
+return af
+]]
diff --git a/test/diagnostics/cast-local-type.lua b/test/diagnostics/cast-local-type.lua
new file mode 100644
index 00000000..f79bf48d
--- /dev/null
+++ b/test/diagnostics/cast-local-type.lua
@@ -0,0 +1,334 @@
+TEST [[
+local x = 0
+
+<!x!> = true
+]]
+
+TEST [[
+---@type integer
+local x
+
+<!x!> = true
+]]
+
+TEST [[
+---@type unknown
+local x
+
+x = nil
+]]
+
+TEST [[
+---@type unknown
+local x
+
+x = 1
+]]
+
+TEST [[
+---@type unknown|nil
+local x
+
+x = 1
+]]
+
+TEST [[
+local x = {}
+
+x = nil
+]]
+
+TEST [[
+---@type string
+local x
+
+<?x?> = nil
+]]
+
+TEST [[
+---@type string?
+local x
+
+x = nil
+]]
+
+TEST [[
+---@type table
+local x
+
+<!x!> = nil
+]]
+
+TEST [[
+local x
+
+x = nil
+]]
+
+TEST [[
+---@type integer
+local x
+
+---@type number
+<!x!> = f()
+]]
+
+TEST [[
+---@type number
+local x
+
+---@type integer
+x = f()
+]]
+
+TEST [[
+---@type number|boolean
+local x
+
+---@type string
+<!x!> = f()
+]]
+
+TEST [[
+---@type number|boolean
+local x
+
+---@type boolean
+x = f()
+]]
+
+TEST [[
+---@type number|boolean
+local x
+
+---@type boolean|string
+<!x!> = f()
+]]
+
+TEST [[
+---@type boolean
+local x
+
+if not x then
+ return
+end
+
+x = f()
+]]
+
+TEST [[
+---@type boolean
+local x
+
+---@type integer
+local y
+
+<!x!> = y
+]]
+
+TEST [[
+local y = true
+
+local x
+x = 1
+x = y
+]]
+
+TEST [[
+local t = {}
+
+local x = 0
+x = x + #t
+]]
+
+TEST [[
+local x = 0
+
+x = 1.0
+]]
+
+TEST [[
+---@class A
+
+local t = {}
+
+---@type A
+local a
+
+t = a
+]]
+
+TEST [[
+---@type integer
+local x
+
+x = 1.0
+]]
+
+TEST [[
+---@type integer
+local x
+
+<!x!> = 1.5
+]]
+
+TEST [[
+---@type integer
+local x
+
+x = 1 + G
+]]
+
+TEST [[
+---@type integer
+local x
+
+x = 1 + G
+]]
+
+TEST [[
+---@alias A integer
+
+---@type A
+local a
+
+---@type integer
+local b
+
+b = a
+]]
+
+TEST [[
+---@type string[]
+local t
+
+<!t!> = 'xxx'
+]]
+
+TEST [[
+---@type 1|2
+local x
+
+x = 1
+x = 2
+<!x!> = 3
+]]
+
+TEST [[
+---@type 'x'|'y'
+local x
+
+x = 'x'
+x = 'y'
+<!x!> = 'z'
+]]
+
+TEST [[
+local t = {
+ x = 1,
+}
+
+local x
+t[x] = true
+]]
+
+TEST [[
+---@type table<string, string>
+local x
+
+---@type table<number, string>
+local y
+
+<!x!> = y
+]]
+
+TEST [[
+---@type table<string, string>
+local x
+
+---@type table<string, number>
+local y
+
+<!x!> = y
+]]
+
+TEST [[
+---@type table<string, string>
+local x
+
+---@type table<string, string>
+local y
+
+x = y
+]]
+
+TEST [[
+---@type { x: number, y: number }
+local t1
+
+---@type { x: number }
+local t2
+
+<!t1!> = t2
+]]
+
+TEST [[
+---@type { x: number, [integer]: number }
+local t1
+
+---@type { x: number }
+local t2
+
+<!t1!> = t2
+]]
+
+TEST [[
+local x
+
+if X then
+ x = 'A'
+elseif X then
+ x = 'B'
+else
+ x = 'C'
+end
+
+local y = x
+
+<!y!> = nil
+]]
+(function (diags)
+ local diag = diags[1]
+ assert(diag.message == [[
+已显式定义变量的类型为 `string` ,不能再将其类型转换为 `nil`。
+- `nil` 无法匹配 `string`
+- 类型 `nil` 无法匹配 `string`]])
+end)
+
+TEST [[
+---@type 'A'|'B'|'C'|'D'|'E'|'F'|'G'|'H'|'I'|'J'|'K'|'L'|'M'|'N'|'O'|'P'|'Q'|'R'|'S'|'T'|'U'|'V'|'W'|'X'|'Y'|'Z'
+local x
+
+<!x!> = nil
+]]
+(function (diags)
+ local diag = diags[1]
+ assert(diag.message == [[
+已显式定义变量的类型为 `'A'|'B'|'C'|'D'|'E'...(+21)` ,不能再将其类型转换为 `nil`。
+- `nil` 无法匹配 `'A'|'B'|'C'|'D'|'E'...(+21)`
+- `nil` 无法匹配 `'A'|'B'|'C'|'D'|'E'...(+21)` 中的任何子类
+- 类型 `nil` 无法匹配 `'Z'`
+- 类型 `nil` 无法匹配 `'Y'`
+- 类型 `nil` 无法匹配 `'X'`
+- 类型 `nil` 无法匹配 `'W'`
+- 类型 `nil` 无法匹配 `'V'`
+- 类型 `nil` 无法匹配 `'U'`
+- 类型 `nil` 无法匹配 `'T'`
+- 类型 `nil` 无法匹配 `'S'`
+- 类型 `nil` 无法匹配 `'R'`
+- 类型 `nil` 无法匹配 `'Q'`
+...(+13)
+- 类型 `nil` 无法匹配 `'C'`
+- 类型 `nil` 无法匹配 `'B'`
+- 类型 `nil` 无法匹配 `'A'`]])
+end)
diff --git a/test/diagnostics/cast-type-mismatch.lua b/test/diagnostics/cast-type-mismatch.lua
new file mode 100644
index 00000000..9fba58f6
--- /dev/null
+++ b/test/diagnostics/cast-type-mismatch.lua
@@ -0,0 +1,13 @@
+TEST [[
+---@type string|boolean
+local t
+
+---@cast t string
+]]
+
+TEST [[
+---@type string|boolean
+local t
+
+---@cast t <!number!>
+]]
diff --git a/test/diagnostics/circle-doc-class.lua b/test/diagnostics/circle-doc-class.lua
new file mode 100644
index 00000000..089b0c9b
--- /dev/null
+++ b/test/diagnostics/circle-doc-class.lua
@@ -0,0 +1,14 @@
+TEST [[
+---@class <!A : B!>
+---@class <!B : C!>
+---@class <!C : D!>
+---@class <!D : A!>
+]]
+
+TEST [[
+---@class A : B
+---@class B : C
+---@class C : D
+---@class D
+]]
+
diff --git a/test/diagnostics/close-non-object.lua b/test/diagnostics/close-non-object.lua
new file mode 100644
index 00000000..11b882b7
--- /dev/null
+++ b/test/diagnostics/close-non-object.lua
@@ -0,0 +1,18 @@
+TEST [[
+local _ <close> = <!1!>
+]]
+
+TEST [[
+local _ <close> = <!''!>
+]]
+
+TEST [[
+local c <close> = <!(function () return 1 end)()!>
+]]
+
+TEST [[
+---@type unknown
+local t
+
+local _ <close> = t
+]]
diff --git a/test/diagnostics/code-after-break.lua b/test/diagnostics/code-after-break.lua
new file mode 100644
index 00000000..a150948b
--- /dev/null
+++ b/test/diagnostics/code-after-break.lua
@@ -0,0 +1,7 @@
+TEST [[
+while true do
+ break
+ <!print()
+ print()!>
+end
+]]
diff --git a/test/diagnostics/common.lua b/test/diagnostics/common.lua
deleted file mode 100644
index a1dbe819..00000000
--- a/test/diagnostics/common.lua
+++ /dev/null
@@ -1,2270 +0,0 @@
-local config = require 'config'
-local util = require 'utility'
-
-local disables = config.get(nil, 'Lua.diagnostics.disable')
-
-TEST [[
-local <!x!>
-]]
-
-TEST [[
-local y
-local x <close> = y
-]]
-
-TEST [[
-local function x()
-end
-x()
-]]
-
-TEST [[
-return function (x)
- x.a = 1
-end
-]]
-
-TEST [[
-local <!t!> = {}
-<!t!>.a = 1
-]]
-
-TEST [[
-local <!function <!x!>()
-end!>
-]]
-
-
-TEST [[
-local <!x!> = <!function () end!>
-]]
-
-TEST [[
-local <!x!>
-<!x!> = <!function () end!>
-]]
-
-TEST [[
-local <!function x()
-end!>
-local <!function <!y!>()
- x()
-end!>
-]]
-
-TEST [[
-local print, _G
-print(<!x!>)
-print(<!log!>)
-print(<!X!>)
-print(<!Log!>)
-print(<!y!>)
-print(Z)
-print(_G)
-Z = 1
-]]
-
-TEST [[
-::<!LABEL!>::
-]]
-
-TEST [[
-<! !>
-]]
-
-TEST [[
-
-<! !>
-]]
-
-TEST [[
-X = 1<! !>
-]]
-
-TEST [[
-X = [=[
- ]=]
-]]
-
-TEST [[
--- xxxx
-]]
-
-TEST [[
--- [=[
- ]=]
-]]
-
-TEST [[
-local x
-print(x)
-local <!x!>
-print(x)
-]]
-
-TEST [[
-local x
-print(x)
-local <!x!>
-print(x)
-local <!x!>
-print(x)
-]]
-
-TEST [[
-local _
-print(_)
-local _
-print(_)
-local _ENV
-<!print!>(_ENV) -- 由于重定义了_ENV,因此print变为了未定义全局变量
-]]
-
-TEST [[
-local x
-return x, function (<!x!>)
- return x
-end
-]]
-
-TEST [[
-print(1)
-_ENV = nil
-]]
-
-TEST [[
----@diagnostic disable: undefined-global
-_ENV = nil
-<!print!>(<!A!>) -- `print` and `A` should warning
-]]
-
-TEST [[
----@diagnostic disable: undefined-global
-local _ENV = nil
-<!print!>(<!A!>) -- `print` and `A` should warning
-]]
-
-TEST [[
-_ENV = {}
-print(A) -- no warning
-]]
-
-TEST [[
-local _ENV = {}
-print(A) -- no warning
-]]
-
-TEST [[
----@type iolib
-_ENV = {}
-<!print!>(stderr) -- `print` is warning but `stderr` is not
-]]
-
-TEST [[
----@type iolib
-local _ENV = {}
-<!print!>(stderr) -- `print` is warning but `stderr` is not
-]]
-
-TEST [[
-local _ENV = { print = print }
-print(1)
-]]
-
-util.arrayInsert(disables, 'undefined-env-child')
-TEST [[
-_ENV = nil
-<!GLOBAL!> = 1 --> _ENV.GLOBAL = 1
-]]
-
-TEST [[
-_ENV = nil
-local _ = <!print!> --> local _ = _ENV.print
-]]
-
-TEST [[
-_ENV = {}
-GLOBAL = 1 --> _ENV.GLOBAL = 1
-]]
-
-TEST [[
-_ENV = {}
-local _ = print --> local _ = _ENV.print
-]]
-
-TEST [[
-GLOBAL = 1
-_ENV = nil
-]]
-
-util.arrayRemove(disables, 'undefined-env-child')
-TEST [[
-<!print()
-('string')!>:sub(1, 1)
-]]
-
-TEST [[
-print()
-('string')
-]]
-
-TEST [[
-print
-{}
-{}
-]]
-
-TEST [[
-local x
-return x
- : f(1)
- : f(1)
-]]
-
-TEST [[
-return {
- <!print
- 'string'!>
-}
-]]
-
-TEST [[
-return {
- <!print
- {
- x = 1,
- }!>
-}
-]]
-
-TEST [[
-print()
-'string'
-]]
-
-TEST [[
-print
-{
- x = 1,
-}
-]]
-
-TEST [[
-local function x(a, b)
- return a, b
-end
-x(1, 2, <!3!>)
-]]
-
-TEST [[
-local function x(a, b, ...)
- return a, b, ...
-end
-x(1, 2, 3, 4, 5)
-]]
-
-TEST [[
----@type fun(a, b, ...)
-local x
-x(1, 2, 3, 4, 5)
-]]
-
-TEST [[
-local m = {}
-function m:x(a, b)
- return a, b
-end
-m:x(1, 2, <!3!>)
-]]
-
-TEST [[
-local m = {}
-function m:x(a, b)
- return a, b
-end
-m.x(m, 2, 3, <!4!>)
-]]
-
-TEST [[
-local m = {}
-function m.x(a, b)
- return a, b
-end
-m:x(1, <!2!>, <!3!>, <!4!>)
-]]
-
-TEST [[
-local function x(a, b)
- return a, b
-end
-x(1)
-]]
-
-TEST [[
----@param a integer
----@param b integer
-local function x(a, b)
- return a, b
-end
-<!x(1)!>
-]]
-
-TEST [[
----@param a integer
----@param b integer
-local function x(a, b)
- return a, b
-end
-<!x()!>
-]]
-
-TEST [[
----@param a integer
----@param b integer
----@param ... integer
-local function x(a, b, ...)
- return a, b, ...
-end
-x(1, 2)
-]]
-
-TEST [[
----@diagnostic disable: unused-local
-
----@param a integer
----@param b integer
-local function f(a, b)
-end
-
-f(...)
-]]
-
-TEST [[
----@diagnostic disable: unused-local
-
----@param a integer
----@param b integer
-local function f(a, b)
-end
-
-local function return2Numbers()
- return 1, 2
-end
-
-f(return2Numbers())
-]]
-
-TEST [[
----@param a integer
----@param b? integer
-local function x(a, b)
- return a, b
-end
-x(1)
-]]
-
-TEST [[
----@param b integer?
-local function x(a, b)
- return a, b
-end
-x(1)
-]]
-
-TEST [[
----@param b integer|nil
-local function x(a, b)
- return a, b
-end
-x(1)
-]]
-
-TEST [[
-local m = {}
-function m.x()
-end
-m:x()
-]]
-
-TEST [[
-InstanceName = 1
-Instance = _G[InstanceName]
-]]
-
-TEST [[
-local _ = (''):sub(1, 2)
-]]
-
-TEST [=[
-return [[
-
-]]
-]=]
-
-util.arrayInsert(disables, 'close-non-object')
-TEST [[
-local _ <close> = function () end
-]]
-util.arrayRemove(disables, 'close-non-object')
-
-TEST [[
-local _ <close> = <!1!>
-]]
-
-TEST [[
-local _ <close> = <!''!>
-]]
-
-TEST [[
-local c <close> = <!(function () return 1 end)()!>
-]]
-
-util.arrayInsert(disables, 'unused-local')
-TEST [[
-local f = <!function () end!>
-]]
-
-TEST [[
-local f;f = <!function () end!>
-]]
-
-TEST [[
-local <!function f() end!>
-]]
-
-TEST [[
-local <!function f()
- f()
-end!>
-]]
-
-
-TEST [[
-local <!function test()
-end!>
-
-local <!function foo ()
-end!>
-]]
-
-util.arrayRemove(disables, 'unused-local')
-TEST [[
-local mt, x
-function mt:m()
- function x:m()
- end
-end
-return mt, x
-]]
-
-TEST [[
-local mt = {}
-function mt:f()
-end
-return mt
-]]
-
-TEST [[
-local <!mt!> = {}
-function <!mt!>:f()
-end
-]]
-
-TEST [[
-local <!x!> = {}
-<!x!>.a = 1
-]]
-
-TEST [[
-local <!x!> = {}
-<!x!>['a'] = 1
-]]
-
-TEST [[
-local function f(<!self!>)
- return 'something'
-end
-f()
-]]
-
-TEST [[
-local function f(<!...!>)
- return 'something'
-end
-f()
-]]
-
-TEST [[
-local function f(var)
- print(var)
-end
-local var
-f(var)
-]]
-
-TEST [[
-local function f(a, b)
- return a, b
-end
-f(1, 2, <!3!>, <!4!>)
-]]
-
-TEST [[
-local mt = {}
-function mt:f(a, b)
- return a, b
-end
-mt.f(mt, 2, 3, <!4!>)
-]]
-
-
-TEST [[
-local mt = {}
-function mt.f(a, b)
- return a, b
-end
-mt:f(1, <!2!>, <!3!>, <!4!>)
-]]
-
-TEST [[
-local mt = {}
-function mt:f(a, b)
- return a, b
-end
-mt:f(1, 2, <!3!>, <!4!>)
-]]
-
-TEST [[
-local function f(a, b, ...)
- return a, b, ...
-end
-f(1, 2, 3, 4)
-]]
-
-TEST [[
-local _ = next({}, 1, <!2!>)
-print(1, 2, 3, 4, 5)
-]]
-
-TEST [[
-local function f(callback)
- callback(1, 2, 3)
-end
-f(function () end)
-]]
-
---TEST [[
---local realTostring = tostring
---tostring = function () end
---tostring(<!1!>)
---tostring = realTostring
---tostring(1)
---]]
-
-TEST [[
-<!aa!> = 1
-tostring = 1
-ROOT = 1
-_G.bb = 1
-]]
-
-TEST [[
-local f = load('')
-if f then
- f(1, 2, 3)
-end
-]]
-
-TEST [[
-local _ = <!unpack!>
-]]
-
-TEST [[
-X = table[<!x!>]
-]]
-
-TEST [[
-return {
- <!x!> = 1,
- y = 2,
- <!x!> = 3,
-}
-]]
-
-TEST [[
-return {
- x = 1,
- y = 2,
-}, {
- x = 1,
- y = 2,
-}
-]]
-
-TEST [[
-local m = {}
-function m.open()
-end
-
-m:open()
-]]
-
-TEST [[
-local m = {}
-function m:open()
-end
-
-m.open(m)
-]]
-
-TEST [[
-<!if true then
-end!>
-]]
-
-TEST [[
-<!if true then
-else
-end!>
-]]
-
-TEST [[
-if true then
-else
- return
-end
-]]
-
-TEST [[
-while true do
-end
-]]
-
-TEST [[
-<!for _ = 1, 10 do
-end!>
-]]
-
-TEST [[
-<!for _ in pairs({}) do
-end!>
-]]
-
-TEST [[
-local _ = 1, <!2!>
-]]
-
-TEST [[
-_ = 1, <!2!>
-]]
-
-TEST [[
-function X()
- do
- local k
- print(k)
- end
- local k = 1
- print(k)
-end
-]]
-
-TEST [[
-function X()
- local loc
- print(loc)
-end
-]]
-
-TEST [[
-local <!t!> = {}
-<!t!>[1] = 1
-]]
-
-TEST [[
-T1 = 1
-_ENV.T2 = 1
-_G.T3 = 1
-_ENV._G.T4 = 1
-_G._G._G.T5 = 1
-rawset(_G, 'T6', 1)
-rawset(_ENV, 'T7', 1)
-print(T1)
-print(T2)
-print(T3)
-print(T4)
-print(T5)
-print(T6)
-print(T7)
-]]
-
-TEST [[
-local x
-x = <!x or 0 + 1!>
-]]
-
-TEST [[
-local x, y
-x = <!x + y or 0!>
-]]
-
-TEST [[
-local x, y, z
-x = x and y or '' .. z
-]]
-
-TEST [[
-local x
-x = x or -1
-]]
-
-TEST [[
-local x
-x = x or (0 + 1)
-]]
-
-TEST [[
-local x, y
-x = (x + y) or 0
-]]
-
-TEST [[
-local t = {}
-t.a = 1
-t.a = 2
-return t
-]]
-
-TEST [[
-table.insert({}, 1, 2, <!3!>)
-]]
-
-TEST [[
-while true do
- break
- <!print()
- print()!>
-end
-]]
-
-TEST [[
-local x, <!y!>, <!z!> = 1
-print(x, y, z)
-]]
-
-TEST [[
-local x, y, <!z!> = 1, 2
-print(x, y, z)
-]]
-
-TEST [[
-local x, y, z = print()
-print(x, y, z)
-]]
-
-TEST [[
-local x, y, z
-print(x, y, z)
-]]
-
-TEST [[
-local x, y, z
-x, <!y!>, <!z!> = 1
-print(x, y, z)
-]]
-
-TEST [[
-X, <!Y!>, <!Z!> = 1
-]]
-
-TEST [[
-T = {}
-T.x, <!T.y!>, <!T.z!> = 1
-]]
-
-TEST [[
-T = {}
-T['x'], <!T['y']!>, <!T['z']!> = 1
-]]
-
---TEST [[
------@class <!Class!>
------@class <!Class!>
---]]
-
-TEST [[
----@alias <!A!> integer
----@alias <!A!> integer
-]]
-
-TEST [[
----@class A : <!B!>
-]]
-
-TEST [[
----@class <!A : B!>
----@class <!B : C!>
----@class <!C : D!>
----@class <!D : A!>
-]]
-
-TEST [[
----@class A : B
----@class B : C
----@class C : D
----@class D
-]]
-
-TEST [[
----@type <!A!>
-]]
-
-TEST [[
----@class A
----@type A|<!B!>|<!C!>
-]]
-
-TEST [[
----@class AAA
----@alias B AAA
-
----@type B
-]]
-
-TEST [[
----@alias B <!AAA!>
-]]
-
-TEST [[
----@class A
----@class B
----@alias <!A!> B
-]]
-
-TEST [[
----@param <!x!> <!Class!>
-]]
-
-TEST [[
----@class Class
----@param <!y!> Class
-local function f(x)
- return x
-end
-f()
-]]
-
-TEST [[
----@class Class
----@param <!y!> Class
-function F(x)
- return x
-end
-F()
-]]
-
-TEST [[
----@class Class
----@param <!x!> Class
----@param y Class
----@param <!x!> Class
-local function f(x, y)
- return x, y
-end
-
-local _
-f(_, _)
-]]
-
-TEST [[
----@field <!x Class!>
----@class Class
-]]
-
-TEST [[
----@class Class
-
----@field <!x Class!>
-]]
-
-TEST [[
----@class Class
----
----@field x Class
-]]
-
-TEST [[
----@class Class
----@field <!x!> Class
----@field <!x!> Class
-]]
-
-TEST [[
----@class Class : any
-]]
-
-TEST [[
----@type fun(a: integer)
-local f
-f(1)
-]]
-
-TEST [[
----@class c
-c = {}
-]]
-
-TEST [[
----@generic T: any
----@param v T
----@param message any
----@return T
----@return any message
-function assert(v, message)
- return v, message
-end
-]]
-
-TEST [[
----@type string
----|
-]]
-
-TEST [[
----@type
----| 'xx'
-]]
-
-TEST [[
----@class class
-local t
-]]
----[==[
--- checkUndefinedField 通用
-TEST [[
----@class Foo
----@field field1 integer
-local mt = {}
-function mt:Constructor()
- self.field2 = 1
-end
-function mt:method1() return 1 end
-function mt.method2() return 2 end
-
----@class Bar: Foo
----@field field4 integer
-local mt2 = {}
-
----@type Foo
-local v
-print(v.field1 + 1)
-print(v.field2 + 1)
-print(v.<!field3!> + 1)
-print(v:method1())
-print(v.method2())
-print(v:<!method3!>())
-
----@type Bar
-local v2
-print(v2.field1 + 1)
-print(v2.field2 + 1)
-print(v2.<!field3!> + 1)
-print(v2.field4 + 1)
-print(v2:method1())
-print(v2.method2())
-print(v2:<!method3!>())
-
-local v3 = {}
-print(v3.abc)
-
----@class Bar2
-local mt3
-function mt3:method() return 1 end
-print(mt3:method())
-]]
-
--- checkUndefinedField 通过type找到class
-TEST [[
----@class Foo
-local Foo
-function Foo:method1() end
-
----@type Foo
-local v
-v:method1()
-v:<!method2!>() -- doc.class.name
-]]
-
--- checkUndefinedField 通过type找到class,涉及到 class 继承版
-TEST [[
----@class Foo
-local Foo
-function Foo:method1() end
----@class Bar: Foo
-local Bar
-function Bar:method3() end
-
----@type Bar
-local v
-v:method1()
-v:<!method2!>() -- doc.class.name
-v:method3()
-]]
-
--- checkUndefinedField 类名和类变量同名,类变量被直接使用
-TEST [[
----@class Foo
-local Foo
-function Foo:method1() end
-Foo:<!method2!>() -- doc.class
-Foo:<!method2!>() -- doc.class
-]]
-
--- checkUndefinedField 没有@class的不检测
-TEST [[
-local Foo
-function Foo:method1()
- return Foo:method2() -- table
-end
-]]
-
--- checkUndefinedField 类名和类变量不同名,类变量被直接使用、使用self
-TEST [[
----@class Foo
-local mt
-function mt:method1()
- mt.<!method2!>() -- doc.class
- self:method1()
- return self.<!method2!>() -- doc.class.name
-end
-]]
-
--- checkUndefinedField 当会推导成多个class类型时
-TEST [[
----@class Foo
-local mt
-function mt:method1() end
-
----@class Bar
-local mt2
-function mt2:method2() end
-
----@type Foo
-local v
----@type Bar
-local v2
-<!v2!> = v
-v2:method1()
-v2:<!method2!>()
-]]
-
-TEST [[
----@type table
-T1 = {}
-print(T1.f1)
----@type tablelib
-T2 = {}
-print(T2.<!f2!>)
-]]
---]==]
-TEST [[
----@overload fun(...)
-local function f() end
-
-f(1)
-]]
-
-TEST [[
-for i = <!10, 1!> do
- print(i)
-end
-]]
-
-TEST [[
-for i = <!10, 1, 5!> do
- print(i)
-end
-]]
-
-TEST [[
-for i = <!100, 10, 1!> do
- print(i)
-end
-]]
-
-TEST [[
-for i = <!1, -10!> do
- print(i)
-end
-]]
-
-TEST [[
-for i = 1, 1 do
- print(i)
-end
-]]
-
-TEST [[
-local m = {}
-
-function <!m:fff!>()
-end
-
-function <!m:fff!>()
-end
-
-return m
-]]
-
-TEST [[
-local m = {}
-
-function <!m:fff!>()
-end
-
-do
- function <!m:fff!>()
- end
-end
-
-return m
-]]
-
-TEST [[
-local m = {}
-
-m.x = true
-m.x = false
-
-return m
-]]
-
-TEST [[
-local m = {}
-
-m.x = io.open('')
-m.x = nil
-
-return m
-]]
-
-TEST [[
----@meta
-
----@class A
----@field a boolean
-
----@return A
-local function f() end
-
-local r = f()
-r.x = 1
-
-return r.x
-]]
-
-TEST [[
----@diagnostic disable-next-line
-x = 1
-]]
-
-TEST [[
----@diagnostic disable-next-line: lowercase-global
-x = 1
-]]
-
-TEST [[
----@diagnostic disable-next-line: unused-local
-<!x!> = 1
-]]
-
-TEST [[
----@diagnostic disable
-x = 1
-]]
-
-TEST [[
----@diagnostic disable
----@diagnostic enable
-<!x!> = 1
-]]
-
-TEST [[
----@diagnostic disable
----@diagnostic disable
----@diagnostic enable
-x = 1
-]]
-
-TEST [[
----@diagnostic disable-next-line: <!xxx!>
-]]
-
-TEST [[
-local mt = {}
-
-function mt:a(x)
- return self, x
-end
-
-function mt:b(y)
- self:a(1):b(2)
- return y
-end
-
-return mt
-]]
-
-TEST [[
-local function each()
- return function ()
- end
-end
-
-for x in each() do
- print(x)
-end
-]]
-
-TEST [[
----@type string
-local s
-
-print(s:upper())
-]]
-
-TEST [[
-local t = ().
-return t
-]]
-
-TEST [[
-return {
- [1] = 1,
- ['1'] = 1,
-}
-]]
-
-TEST [[
-return {
- [print()] = 1,
- [print()] = 1,
-}
-]]
-
-TEST [[
----@type { x: number, y: number}
----| "'resume'"
-]]
-
-TEST [[
-return {
- 1, <!2!>, 3,
- [<!2!>] = 4,
-}
-]]
-
-TEST [[
---- @class Emit
---- @field on fun(eventName: string, cb: function)
---- @field on fun(eventName: '"died"', cb: fun(i: integer))
---- @field on fun(eventName: '"won"', cb: fun(s: string))
-local emit = {}
-]]
-
-TEST [[
---- @class Emit
---- @field on fun(eventName: string, cb: function)
---- @field <!on!> fun(eventName: '"died"', cb: fun(i: integer))
---- @field on fun(eventName: '"won"', cb: fun(s: string))
---- @field <!on!> fun(eventName: '"died"', cb: fun(i: integer))
-local emit = {}
-]]
-
--- redundant-return
-TEST [[
-local function f()
- <!return!>
-end
-f()
-]]
-
-TEST [[
-local function f()
- return nil
-end
-f()
-]]
-
-TEST [[
-local function f()
- local function x()
- <!return!>
- end
- x()
- return true
-end
-f()
-]]
-
-TEST [[
-local function f()
- local function x()
- return true
- end
- return x()
-end
-f()
-]]
-
-TEST [[
----@type file*
-local f
-local _ = f:read '*a'
-local _ = f:read('*a')
-]]
-
-TEST [[
-function F()
- <!coroutine.yield!>()
-end
-]]
-
-TEST [[
----@async
-function F()
- coroutine.yield()
-end
-]]
-
-TEST [[
----@type async fun()
-local f
-
-function F()
- <!f!>()
-end
-]]
-
-TEST [[
----@type async fun()
-local f
-
----@async
-function F()
- f()
-end
-]]
-
-TEST [[
-local function f(cb)
- cb()
-end
-
-return function()
- <!f>(function () ---@async
- return nil
- end)
-end
-]]
-
-TEST [[
-local function f(cb)
- pcall(cb)
-end
-
-return function()
- <!f!>(function () ---@async
- return nil
- end)
-end
-]]
-
-TEST [[
----@param c any
-local function f(c)
- return c
-end
-
-return function ()
- f(function () ---@async
- return nil
- end)
-end
-]]
-
-TEST [[
----@param ... any
-local function f(...)
- return ...
-end
-
-return function ()
- f(function () ---@async
- return nil
- end)
-end
-]]
-
-TEST [[
----@vararg any
-local function f(...)
- return ...
-end
-
-return function ()
- f(function () ---@async
- return nil
- end)
-end
-]]
-
-TEST [[
-local function f(...)
- return ...
-end
-
-return function ()
- f(function () ---@async
- return nil
- end)
-end
-]]
-
-TEST [[
-local function f(...)
- return ...
-end
-
-return function ()
- f(function () ---@async
- return nil
- end)
-end
-]]
-
-TEST [[
----@nodiscard
-local function f()
- return 1
-end
-
-<!f()!>
-]]
-
-TEST [[
----@nodiscard
-local function f()
- return 1
-end
-
-X = f()
-]]
-
-config.get(nil, 'Lua.diagnostics.neededFileStatus')['not-yieldable'] = 'Any'
-TEST [[
----@param cb fun()
-local function f(cb)
- return cb
-end
-
----@async
-local function af()
- return nil
-end
-
-f(<!af!>)
-]]
-
-TEST [[
----@param cb async fun()
-local function f(cb)
- return cb
-end
-
----@async
-local function af()
- return nil
-end
-
-f(af)
-]]
-
-TEST [[
-local function f(cb)
- cb()
-end
-
-local function af()
- <!f!>(function () ---@async
- return nil
- end)
-end
-
-return af
-]]
-
-TEST [[
-local function f(cb)
- cb()
-end
-
----@async
-local function af()
- f(function () ---@async
- return nil
- end)
-end
-
-return af
-]]
-
-TEST [[
-local _ = type(function () ---@async
- return nil
-end)
-]]
-
-TEST [[
----@param ... number
-local function f(...)
- return ...
-end
-
-return f
-]]
-
-TEST [[
----@type fun(...: string)
-]]
-
-TEST [[
----@type fun(xxx, yyy, ...): boolean
-]]
-
-TEST [[
-local <!x!>
-
-return {
- x = 1,
-}
-]]
-
-TEST [[
----@class A #1
-]]
-
-TEST [[
----@class A 1
-]]
-
-TEST [[
-return ('1'):upper()
-]]
-
-TEST [[
-local value
-value = '1'
-value = value:upper()
-]]
-
-TEST [[
-T = {}
----@deprecated # comment
-T.x = 1
-
-print(<!T.x!>)
-]]
-
-TEST [[
-T = {}
-
----@deprecated
-function T:ff()
-end
-
-<!T:ff!>()
-]]
-
-TEST [[
----@type string?
-local x
-
-S = <!x!>:upper()
-]]
-
-TEST [[
----@type string?
-local x
-
-if x then
- S = x:upper()
-end
-]]
-
-TEST [[
----@type string?
-local x
-
-if not x then
- x = ''
-end
-
-S = x:upper()
-]]
-
-TEST [[
----@type fun()?
-local x
-
-S = <!x!>()
-]]
-
-TEST [[
----@type integer?
-local x
-
-T = {}
-T[<!x!>] = 1
-]]
-
-TEST [[
-local x, y
-local z = x and y
-
-print(z.y)
-]]
-
-TEST [[
-local x, y
-function x()
- y()
-end
-
-function y()
- x()
-end
-
-x()
-]]
-
-TEST [[
----@meta
-
----@param x fun()
-local function f1(x)
-end
-
----@return fun()
-local function f2()
-end
-
-f1(f2())
-]]
-
-TEST [[
----@meta
-
----@type fun():integer
-local f
-
----@param x integer
-local function foo(x) end
-
-foo(f())
-]]
-
-TEST [[
----@type string|table
-local n
-
-print(n.x)
-]]
-
-TEST [[
----@diagnostic disable: unused-local, unused-function, undefined-global
-
-function F() end
-
----@param x boolean
-function F(x) end
-
-F(k())
-]]
-
-TEST [[
-local function f()
- return 1, 2, 3
-end
-
-local function k()
-end
-
-k(<!f()!>)
-]]
-
-TEST [[
----@diagnostic disable: unused-local
-local function f()
- return 1, 2, 3
-end
-
----@param x integer
-local function k(x)
-end
-
-k(f())
-]]
-
-TEST [[
----@cast <!x!> integer
-]]
-
-TEST [[
----@diagnostic disable: unused-local
-local x, y
----@cast y number
-]]
-
-TEST [[
----@class A
-
----@class B
----@field [integer] A
----@field [A] true
-]]
-
-TEST [[
----@class A
-
----@class B
----@field [<!A!>] A
----@field [<!A!>] true
-]]
-
-TEST [[
----@diagnostic disable: unused-local
-
----@type 'x'
-local t
-
-local n = t:upper()
-]]
-
-TEST [[
----@diagnostic disable: unused-local
-
----@alias A 'x'
-
----@type A
-local t
-
-local n = t:upper()
-]]
-
-TEST [[
-local t = {}
-
-function t:init() end
-
-<!t.init()!>
-]]
-
-TEST [[
----@meta
-
-return function f(x, y, z) end
-]]
-
-util.arrayInsert(disables, 'redundant-return')
-TEST [[
----@return number
-function F()
- <!return!>
-end
-]]
-
-TEST [[
----@return number, number
-function F()
- <!return!> 1
-end
-]]
-
-TEST [[
----@return number, number?
-function F()
- return 1
-end
-]]
-
-TEST [[
----@return ...
-function F()
- return
-end
-]]
-
-TEST [[
----@return number, number?
-function F()
- return 1, 1, <!1!>
-end
-]]
-
-TEST [[
----@return number, number?
-function F()
- return 1, 1, <!1!>, <!2!>, <!3!>
-end
-]]
-
-TEST [[
----@meta
-
----@return number, number
-local function r2() end
-
----@return number, number?
-function F()
- return 1, <!r2()!>
-end
-]]
-
-TEST [[
----@return number
-function F()
- X = 1<!!>
-end
-]]
-
-TEST [[
-local A
----@return number
-function F()
- if A then
- return 1
- end<!!>
-end
-]]
-
-TEST [[
-local A, B
----@return number
-function F()
- if A then
- return 1
- elseif B then
- return 2
- end<!!>
-end
-]]
-
-TEST [[
-local A, B
----@return number
-function F()
- if A then
- return 1
- elseif B then
- return 2
- else
- return 3
- end
-end
-]]
-
-TEST [[
-local A, B
----@return number
-function F()
- if A then
- elseif B then
- return 2
- else
- return 3
- end<!!>
-end
-]]
-
-TEST [[
----@return any
-function F()
- X = 1
-end
-]]
-
-TEST [[
----@return any, number
-function F()
- X = 1<!!>
-end
-]]
-
-TEST [[
----@return number, any
-function F()
- X = 1<!!>
-end
-]]
-
-TEST [[
----@return any, any
-function F()
- X = 1
-end
-]]
-
-TEST [[
-local A
----@return number
-function F()
- for _ = 1, 10 do
- if A then
- return 1
- end
- end
- error('should not be here')
-end
-]]
-
-TEST [[
-local A
----@return number
-function F()
- while true do
- if A then
- return 1
- end
- end
-end
-]]
-
-TEST [[
-local A
----@return number
-function F()
- while A do
- if A then
- return 1
- end
- end<!!>
-end
-]]
-
-TEST [[
-local A
----@return number
-function F()
- while A do
- if A then
- return 1
- else
- return 2
- end
- end
-end
-]]
-
-TEST [[
----@return number?
-function F()
-
-end
-]]
-
-util.arrayRemove(disables, 'redundant-return')
-
-TEST [[
----@class A
----@operator <!xxx!>: A
-]]
-
-config.add(nil, 'Lua.diagnostics.unusedLocalExclude', 'll_*')
-
-TEST [[
-local <!xx!>
-local ll_1
-local ll_2
-local <!ll!>
-]]
-
-config.remove(nil, 'Lua.diagnostics.unusedLocalExclude', 'll_*')
-
-TEST [[
----@diagnostic disable: undefined-global
-
-if X then
- return false
-elseif X then
- return false
-else
- return false
-end
-<!return true!>
-]]
-
-TEST [[
----@diagnostic disable: undefined-global
-
-function X()
- if X then
- return false
- elseif X then
- return false
- else
- return false
- end
- <!return true!>
-end
-]]
-
-TEST [[
-while true do
-end
-
-<!print(1)!>
-]]
-
-TEST [[
-while true do
-end
-
-<!print(1)!>
-]]
-
-TEST [[
-while X do
- X = 1
-end
-
-print(1)
-]]
-
-TEST [[
----@diagnostic disable: undefined-global
-
-while true do
- if not X then
- break
- end
-end
-
-print(1)
-
-do return end
-]]
-
-TEST [[
----@type unknown
-local t
-
-local _ <close> = t
-]]
-
-TEST [[
----@meta
----@diagnostic disable: duplicate-set-field
----@class A
-local m = {}
-
-function m.ff() end
-
-function m.ff(x) end
-
-m.ff(1)
-]]
-
-TEST [[
-local done = false
-
-local function set_done()
- done = true
-end
-
-while not done do
- set_done()
-end
-
-print(1)
-]]
-
-TEST [[
----@class A
----@field private x number
----@field protected y number
----@field public z number
-local t
-print(t.x)
-]]
-
-TEST [[
----@class A
----@field private x number
----@field protected y number
----@field public z number
-
----@type A
-local t
-
-print(t.<!x!>)
-]]
-
-TEST [[
----@class A
----@field private x number
----@field protected y number
----@field public z number
-
----@class B: A
-local t
-
-print(t.y)
-]]
-
-TEST [[
----@class A
----@field private x number
----@field protected y number
----@field public z number
-
----@class B: A
-
----@type B
-local t
-
-print(t.<!y!>)
-]]
-
-TEST [[
----@class A
----@field private x number
----@field protected y number
----@field public z number
-
----@class B: A
-
----@type B
-local t
-
-print(t.z)
-]]
-
-TEST [[
----@class A
----@field _id number
-
----@type A
-local t
-
-print(t._id)
-]]
-
-config.set(nil, 'Lua.doc.privateName', { '_*' })
-TEST [[
----@class A
----@field _id number
-
----@type A
-local t
-
-print(t.<!_id!>)
-
----@class B: A
-local t2
-
-print(t2.<!_id!>)
-]]
-config.set(nil, 'Lua.doc.privateName', nil)
-
-config.set(nil, 'Lua.doc.protectedName', { '_*' })
-TEST [[
----@class A
----@field _id number
-
----@type A
-local t
-
-print(t.<!_id!>)
-
----@class B: A
-local t2
-
-print(t2._id)
-]]
-config.set(nil, 'Lua.doc.protectedName', nil)
-
-TEST [[
----@class A
----@field private x number
-local mt = {}
-
-function mt:init()
- print(self.x)
-end
-]]
-
-TEST [[
----@diagnostic disable: unused-local
----@class A
----@field private x number
-local mt = {}
-
-function mt:init()
- ---@type A
- local obj = {}
-
- obj.x = 1
-end
-]]
-
-TEST [[
----@diagnostic disable: unused-local
----@class A
----@field private x number
-local mt = {}
-
-mt.init = function ()
- ---@type A
- local obj = {}
-
- obj.x = 1
-end
-]]
-
-TEST [[
----@class A
-X = {}
-
-function <!X.f!>() end
-
-function <!X.f!>() end
-]]
-
-TEST [[
----@meta
-
----@class A
-X = {}
-
-function X.f() end
-
-function X.f() end
-]]
-
-TEST [[
----@class A
-X = {}
-
-if true then
- function X.f() end
-else
- function X.f() end
-end
-]]
-
-TESTWITH 'global-in-nil-env' [[
-local function foo(_ENV)
- Joe = "human"
-end
-]]
diff --git a/test/diagnostics/count-down-loop.lua b/test/diagnostics/count-down-loop.lua
new file mode 100644
index 00000000..f4e385f5
--- /dev/null
+++ b/test/diagnostics/count-down-loop.lua
@@ -0,0 +1,29 @@
+TEST [[
+for i = <!10, 1!> do
+ print(i)
+end
+]]
+
+TEST [[
+for i = <!10, 1, 5!> do
+ print(i)
+end
+]]
+
+TEST [[
+for i = <!100, 10, 1!> do
+ print(i)
+end
+]]
+
+TEST [[
+for i = <!1, -10!> do
+ print(i)
+end
+]]
+
+TEST [[
+for i = 1, 1 do
+ print(i)
+end
+]]
diff --git a/test/diagnostics/deprecated.lua b/test/diagnostics/deprecated.lua
new file mode 100644
index 00000000..c5486752
--- /dev/null
+++ b/test/diagnostics/deprecated.lua
@@ -0,0 +1,21 @@
+TEST [[
+local _ = <!unpack!>
+]]
+
+TEST [[
+T = {}
+---@deprecated # comment
+T.x = 1
+
+print(<!T.x!>)
+]]
+
+TEST [[
+T = {}
+
+---@deprecated
+function T:ff()
+end
+
+<!T:ff!>()
+]]
diff --git a/test/diagnostics/discard-returns.lua b/test/diagnostics/discard-returns.lua
new file mode 100644
index 00000000..2e348390
--- /dev/null
+++ b/test/diagnostics/discard-returns.lua
@@ -0,0 +1,17 @@
+TEST [[
+---@nodiscard
+local function f()
+ return 1
+end
+
+<!f()!>
+]]
+
+TEST [[
+---@nodiscard
+local function f()
+ return 1
+end
+
+X = f()
+]]
diff --git a/test/diagnostics/doc-field-no-class.lua b/test/diagnostics/doc-field-no-class.lua
new file mode 100644
index 00000000..87db518c
--- /dev/null
+++ b/test/diagnostics/doc-field-no-class.lua
@@ -0,0 +1,16 @@
+TEST [[
+---@field <!x Class!>
+---@class Class
+]]
+
+TEST [[
+---@class Class
+
+---@field <!x Class!>
+]]
+
+TEST [[
+---@class Class
+---
+---@field x Class
+]]
diff --git a/test/diagnostics/duplicate-doc-alias.lua b/test/diagnostics/duplicate-doc-alias.lua
new file mode 100644
index 00000000..0373fee9
--- /dev/null
+++ b/test/diagnostics/duplicate-doc-alias.lua
@@ -0,0 +1,10 @@
+TEST [[
+---@alias <!A!> integer
+---@alias <!A!> integer
+]]
+
+TEST [[
+---@class A
+---@class B
+---@alias <!A!> B
+]]
diff --git a/test/diagnostics/duplicate-doc-field.lua b/test/diagnostics/duplicate-doc-field.lua
new file mode 100644
index 00000000..8f385335
--- /dev/null
+++ b/test/diagnostics/duplicate-doc-field.lua
@@ -0,0 +1,38 @@
+TEST [[
+---@class Class
+---@field <!x!> Class
+---@field <!x!> Class
+]]
+
+TEST [[
+--- @class Emit
+--- @field on fun(eventName: string, cb: function)
+--- @field on fun(eventName: '"died"', cb: fun(i: integer))
+--- @field on fun(eventName: '"won"', cb: fun(s: string))
+local emit = {}
+]]
+
+TEST [[
+--- @class Emit
+--- @field on fun(eventName: string, cb: function)
+--- @field <!on!> fun(eventName: '"died"', cb: fun(i: integer))
+--- @field on fun(eventName: '"won"', cb: fun(s: string))
+--- @field <!on!> fun(eventName: '"died"', cb: fun(i: integer))
+local emit = {}
+]]
+
+TEST [[
+---@class A
+
+---@class B
+---@field [integer] A
+---@field [A] true
+]]
+
+TEST [[
+---@class A
+
+---@class B
+---@field [<!A!>] A
+---@field [<!A!>] true
+]]
diff --git a/test/diagnostics/duplicate-doc-param.lua b/test/diagnostics/duplicate-doc-param.lua
new file mode 100644
index 00000000..42eb73d3
--- /dev/null
+++ b/test/diagnostics/duplicate-doc-param.lua
@@ -0,0 +1,12 @@
+TEST [[
+---@class Class
+---@param <!x!> Class
+---@param y Class
+---@param <!x!> Class
+local function f(x, y)
+ return x, y
+end
+
+local _
+f(_, _)
+]]
diff --git a/test/diagnostics/duplicate-index.lua b/test/diagnostics/duplicate-index.lua
new file mode 100644
index 00000000..3289c736
--- /dev/null
+++ b/test/diagnostics/duplicate-index.lua
@@ -0,0 +1,24 @@
+TEST [[
+return {
+ <!x!> = 1,
+ y = 2,
+ <!x!> = 3,
+}
+]]
+
+TEST [[
+return {
+ x = 1,
+ y = 2,
+}, {
+ x = 1,
+ y = 2,
+}
+]]
+
+TEST [[
+return {
+ 1, <!2!>, 3,
+ [<!2!>] = 4,
+}
+]]
diff --git a/test/diagnostics/duplicate-set-field.lua b/test/diagnostics/duplicate-set-field.lua
new file mode 100644
index 00000000..469bc3ea
--- /dev/null
+++ b/test/diagnostics/duplicate-set-field.lua
@@ -0,0 +1,74 @@
+TEST [[
+local m = {}
+
+function <!m:fff!>()
+end
+
+function <!m:fff!>()
+end
+
+return m
+]]
+
+TEST [[
+local m = {}
+
+function <!m:fff!>()
+end
+
+do
+ function <!m:fff!>()
+ end
+end
+
+return m
+]]
+
+TEST [[
+local m = {}
+
+m.x = true
+m.x = false
+
+return m
+]]
+
+TEST [[
+local m = {}
+
+m.x = io.open('')
+m.x = nil
+
+return m
+]]
+
+TEST [[
+---@class A
+X = {}
+
+function <!X.f!>() end
+
+function <!X.f!>() end
+]]
+
+TEST [[
+---@meta
+
+---@class A
+X = {}
+
+function X.f() end
+
+function X.f() end
+]]
+
+TEST [[
+---@class A
+X = {}
+
+if true then
+ function X.f() end
+else
+ function X.f() end
+end
+]]
diff --git a/test/diagnostics/empty-block.lua b/test/diagnostics/empty-block.lua
new file mode 100644
index 00000000..750397a4
--- /dev/null
+++ b/test/diagnostics/empty-block.lua
@@ -0,0 +1,32 @@
+TEST [[
+<!if true then
+end!>
+]]
+
+TEST [[
+<!if true then
+else
+end!>
+]]
+
+TEST [[
+if true then
+else
+ return
+end
+]]
+
+TEST [[
+while true do
+end
+]]
+
+TEST [[
+<!for _ = 1, 10 do
+end!>
+]]
+
+TEST [[
+<!for _ in pairs({}) do
+end!>
+]]
diff --git a/test/diagnostics/global-element.lua b/test/diagnostics/global-element.lua
index 0e4cdd61..0c31bade 100644
--- a/test/diagnostics/global-element.lua
+++ b/test/diagnostics/global-element.lua
@@ -1,31 +1,5 @@
local config = require 'config'
-local util = require 'utility'
--- disable all default groups to make isolated tests
-config.set(nil, 'Lua.diagnostics.groupFileStatus',
-{
- ['ambiguity'] = 'None',
- ['await'] = 'None',
- ['codestyle'] = 'None',
- ['conventions'] = 'None',
- ['duplicate'] = 'None',
- ['global'] = 'None',
- ['luadoc'] = 'None',
- ['redefined'] = 'None',
- ['strict'] = 'None',
- ['strong'] = 'None',
- ['type-check'] = 'None',
- ['unbalanced'] = 'None',
- ['unused'] = 'None'
-})
-
--- enable single diagnostic that is to be tested
-config.set(nil, 'Lua.diagnostics.neededFileStatus',
-{
- ['global-element'] = 'Any!' -- override groupFileStatus
-})
-
--- check that local elements are not warned about
TEST [[
local x = 123
x = 321
@@ -87,11 +61,3 @@ function GLOBAL_CLOSURE()
<!elem2!> = 2
end
]]
-
--- reset configurations
-config.set(nil, 'Lua.diagnostics.groupFileStatus',
-{})
-config.set(nil, 'Lua.diagnostics.neededFileStatus',
-{})
-config.set(nil, 'Lua.diagnostics.globals',
-{})
diff --git a/test/diagnostics/global-in-nil-env.lua b/test/diagnostics/global-in-nil-env.lua
new file mode 100644
index 00000000..a0b8cd3e
--- /dev/null
+++ b/test/diagnostics/global-in-nil-env.lua
@@ -0,0 +1,44 @@
+TEST [[
+local _
+print(_)
+local _
+print(_)
+local _ENV
+<!print!>(_ENV) -- 由于重定义了_ENV,因此print变为了未定义全局变量
+]]
+
+TEST [[
+_ENV = nil
+<!print!>(<!A!>) -- `print` and `A` should warning
+]]
+
+TEST [[
+local _ENV = nil
+<!print!>(<!A!>) -- `print` and `A` should warning
+]]
+
+TEST [[
+_ENV = {}
+print(A) -- no warning
+]]
+
+TEST [[
+local _ENV = {}
+print(A) -- no warning
+]]
+
+TEST [[
+_ENV = nil
+<!GLOBAL!> = 1 --> _ENV.GLOBAL = 1
+]]
+
+TEST [[
+_ENV = nil
+local _ = <!print!> --> local _ = _ENV.print
+]]
+
+TEST [[
+local function foo(_ENV)
+ Joe = "human"
+end
+]]
diff --git a/test/diagnostics/incomplete-signature-doc.lua b/test/diagnostics/incomplete-signature-doc.lua
index c3099cd2..7cd144c0 100644
--- a/test/diagnostics/incomplete-signature-doc.lua
+++ b/test/diagnostics/incomplete-signature-doc.lua
@@ -1,31 +1,21 @@
-local config = require 'config'
-local util = require 'utility'
-
--- disable all default groups to make isolated tests
-config.set(nil, 'Lua.diagnostics.groupFileStatus',
-{
- ['ambiguity'] = 'None',
- ['await'] = 'None',
- ['codestyle'] = 'None',
- ['conventions'] = 'None',
- ['duplicate'] = 'None',
- ['global'] = 'None',
- ['luadoc'] = 'None',
- ['redefined'] = 'None',
- ['strict'] = 'None',
- ['strong'] = 'None',
- ['type-check'] = 'None',
- ['unbalanced'] = 'None',
- ['unused'] = 'None'
-})
-
--- enable single diagnostic that is to be tested
-config.set(nil, 'Lua.diagnostics.neededFileStatus',
-{
- ['incomplete-signature-doc'] = 'Any!' -- override groupFileStatus
-})
-
--- check global functions
+-- -------------------------------------
+-- about the structure of these test cases
+--
+-- the following test cases are grouped by the number of parameters and return values of the functions
+-- so first global functions with:
+-- no parameter and return value (FG), one parameter (FGP), two parameters (FGPP),
+-- one return value (FGR), two return values (FGRR) and parameter and return value (FGPR)
+-- after that, these groups are also done for local functions (FL, FLP, ...)
+--
+-- in these groups, different versions of documentation are tested:
+-- no comment, simple comment, @async annotation (which is no signature doc),
+-- incomplete signature doc (only part of the necessary @param or @return annotations, if possible) - the only cases that should generating warnings
+-- and complete signature docs (all necessary @param and @return annotations)
+-- -------------------------------------
+
+-- global functions no parameter, no return value
+-- no incomplete signature docs possible
+
TEST [[
function FG0()
end
@@ -33,15 +23,26 @@ end
---comment
function FG1()
end
+
+---@async
+function FG1_()
+end
]]
+-- global functions with single parameter, no return value
+-- no incomplete signature docs possible
TEST [[
function FGP0(p)
print(p)
end
---comment
-function FGP1(<!p!>)
+function FGP1(p)
+ print(p)
+end
+
+---@async
+function FGP1_(p)
print(p)
end
@@ -52,13 +53,20 @@ function FGP2(p)
end
]]
+-- global functions with two parameters, no return value
+-- incomplete signature docs when exactly one of the parameters is documented
TEST [[
function FGPP0(p0, p1)
print(p0, p1)
end
---comment
-function FGPP1(<!p0!>, <!p1!>)
+function FGPP1(p0, p1)
+ print(p0, p1)
+end
+
+---@async
+function FGPP1_(p0, p1)
print(p0, p1)
end
@@ -69,6 +77,12 @@ function FGPP2(p0, <!p1!>)
end
---comment
+---@param p1 any
+function FGPP2_(<!p0!>, p1)
+ print(p0, p1)
+end
+
+---comment
---@param p0 any
---@param p1 any
function FGPP3(p0, p1)
@@ -76,6 +90,8 @@ function FGPP3(p0, p1)
end
]]
+-- global functions with no parameter, single return value
+-- no incomplete signature docs possible
TEST [[
function FGR0()
return 0
@@ -83,7 +99,12 @@ end
---comment
function FGR1()
- return <!0!>
+ return 0
+end
+
+---@async
+function FGR1_()
+ return 0
end
---comment
@@ -93,6 +114,8 @@ function FGR2()
end
]]
+-- global functions with no parameter, two return values
+-- incomplete signature docs when exactly one of the return values is documented
TEST [[
function FGRR0()
return 0, 1
@@ -100,7 +123,12 @@ end
---comment
function FGRR1()
- return <!0!>, <!1!>
+ return 0, 1
+end
+
+---@async
+function FGRR1_()
+ return 0, 1
end
---comment
@@ -117,6 +145,8 @@ function FGRR3()
end
]]
+-- global functions with one parameter, one return value
+-- incomplete signature docs when exactly one of parameter or return value is documented
TEST [[
function FGPR0(p)
print(p)
@@ -124,9 +154,15 @@ function FGPR0(p)
end
---comment
-function FGPR1(<!p!>)
+function FGPR1(p)
print(p)
- return <!0!>
+ return 0
+end
+
+---@async
+function FGPR1_(p)
+ print(p)
+ return 0
end
---comment
@@ -152,8 +188,8 @@ function FGPR4(p)
end
]]
--- check local functions
-
+-- local functions with no parameter, no return value
+-- no incomplete signature docs possible
TEST [[
local function FL0()
end
@@ -165,8 +201,13 @@ local function FL1()
end
FL1()
+
+---@async
+local function FL1_()
]]
+-- local functions with single parameter, no return value
+-- no incomplete signature docs possible
TEST [[
local function FLP0(p)
print(p)
@@ -175,12 +216,17 @@ end
FLP0(0)
---comment
-local function FLP1(<!p!>)
+local function FLP1(p)
print(p)
end
FLP1(0)
+---@async
+local function FLP1_(p)
+ print(p)
+end
+
---comment
---@param p any
local function FLP2(p)
@@ -190,6 +236,8 @@ end
FLP2(0)
]]
+-- local functions with two parameters, no return value
+-- incomplete signature docs when exactly one of the parameters is documented
TEST [[
local function FLPP0(p0, p1)
print(p0, p1)
@@ -198,12 +246,17 @@ end
FLPP0(0, 1)
---comment
-local function FLPP1(<!p0!>, <!p1!>)
+local function FLPP1(p0, p1)
print(p0, p1)
end
FLPP1(0, 1)
+---@async
+local function FLPP1_(p0, p1)
+ print(p0, p1)
+end
+
---comment
---@param p0 any
local function FLPP2(p0, <!p1!>)
@@ -222,6 +275,8 @@ end
FLPP3(0, 1)
]]
+-- local functions with no parameter, single return value
+-- no incomplete signature docs possible
TEST [[
local function FLR0()
return 0
@@ -231,7 +286,12 @@ local vr0 = FLR0()
---comment
local function FLR1()
- return <!0!>
+ return 0
+end
+
+---@async
+local function FLR1_()
+ return 0
end
local vr1 = FLR1()
@@ -245,6 +305,8 @@ end
local vr2 = FLR2()
]]
+-- local functions with no parameter, two return values
+-- incomplete signature docs when exactly one of the return values is documented
TEST [[
local function FLRR0()
return 0, 1
@@ -254,11 +316,16 @@ local vrr0, _ = FLRR0()
---comment
local function FLRR1()
- return <!0!>, <!1!>
+ return 0, 1
end
local vrr1, _ = FLRR1()
+---@async
+local function FLRR1_()
+ return 0, 1
+end
+
---comment
---@return integer
local function FLRR2()
@@ -277,6 +344,8 @@ end
local vrr3, _ = FLRR3()
]]
+-- local functions with one parameter, one return value
+-- incomplete signature docs when exactly one of parameter or return value is documented
TEST [[
local function FLPR0(p)
print(p)
@@ -286,9 +355,15 @@ end
local vpr0 = FLPR0(0)
---comment
-local function FLPR1(<!p!>)
+local function FLPR1(p)
print(p)
- return <!0!>
+ return 0
+end
+
+---@async
+local function FLPR1_(p)
+ print(p)
+ return 0
end
local vpr1 = FLPR1(0)
@@ -321,11 +396,3 @@ end
local vpr4 = FLPR4(0)
]]
-
--- reset configurations
-config.set(nil, 'Lua.diagnostics.groupFileStatus',
-{})
-config.set(nil, 'Lua.diagnostics.neededFileStatus',
-{})
-config.set(nil, 'Lua.diagnostics.globals',
-{}) \ No newline at end of file
diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua
index fbea6680..99a5dc24 100644
--- a/test/diagnostics/init.lua
+++ b/test/diagnostics/init.lua
@@ -4,9 +4,15 @@ local config = require 'config'
local util = require 'utility'
local catch = require 'catch'
-config.get(nil, 'Lua.diagnostics.neededFileStatus')['deprecated'] = 'Any'
-config.get(nil, 'Lua.diagnostics.neededFileStatus')['type-check'] = 'Any'
-config.get(nil, 'Lua.diagnostics.neededFileStatus')['await-in-sync'] = 'Any'
+local status = config.get(nil, 'Lua.diagnostics.neededFileStatus')
+
+for key in pairs(status) do
+ status[key] = 'Any!'
+end
+
+config.set('nil', 'Lua.type.castNumberToInteger', false)
+config.set('nil', 'Lua.type.weakUnionCheck', false)
+config.set('nil', 'Lua.type.weakNilCheck', false)
rawset(_G, 'TEST', true)
@@ -32,9 +38,14 @@ function TEST(script)
files.setText(TESTURI, newScript)
files.open(TESTURI)
local origins = {}
+ local filteds = {}
local results = {}
core(TESTURI, false, function (result)
- results[#results+1] = { result.start, result.finish }
+ if DIAG_CARE == result.code
+ or DIAG_CARE == '*' then
+ results[#results+1] = { result.start, result.finish }
+ filteds[#filteds+1] = result
+ end
origins[#origins+1] = result
end)
@@ -49,43 +60,69 @@ function TEST(script)
files.remove(TESTURI)
return function (callback)
- callback(origins)
+ callback(filteds)
end
end
-function TESTWITH(code)
- return function (script)
- local newScript, catched = catch(script, '!')
- files.setText(TESTURI, newScript)
- files.open(TESTURI)
- local origins = {}
- local results = {}
- core(TESTURI, false, function (result)
- if code ~= result.code then
- return
- end
- results[#results+1] = { result.start, result.finish }
- origins[#origins+1] = result
- end)
-
- if results[1] then
- if not founded(catched['!'] or {}, results) then
- error(('%s\n%s'):format(util.dump(catched['!']), util.dump(results)))
- end
- else
- assert(#catched['!'] == 0)
- end
-
- files.remove(TESTURI)
-
- return function (callback)
- callback(origins)
- end
- end
+local function check(name)
+ DIAG_CARE = name
+ require('diagnostics.' .. name)
end
-require 'diagnostics.common'
-require 'diagnostics.type-check'
-require 'diagnostics.incomplete-signature-doc'
-require 'diagnostics.missing-global-doc'
-require 'diagnostics.global-element'
+check 'ambiguity-1'
+check 'assign-type-mismatch'
+check 'await-in-sync'
+check 'cast-local-type'
+check 'cast-type-mismatch'
+check 'circle-doc-class'
+check 'close-non-object'
+check 'code-after-break'
+check 'count-down-loop'
+check 'deprecated'
+check 'discard-returns'
+check 'doc-field-no-class'
+check 'duplicate-doc-alias'
+check 'duplicate-doc-field'
+check 'duplicate-doc-param'
+check 'duplicate-index'
+check 'duplicate-set-field'
+check 'empty-block'
+check 'global-element'
+check 'global-in-nil-env'
+check 'incomplete-signature-doc'
+check 'inject-field'
+check 'invisible'
+check 'lowercase-global'
+check 'missing-fields'
+check 'missing-global-doc'
+check 'missing-local-export-doc'
+check 'missing-parameter'
+check 'missing-return-value'
+check 'missing-return'
+check 'need-check-nil'
+check 'newfield-call'
+check 'newline-call'
+check 'not-yieldable'
+check 'param-type-mismatch'
+check 'redefined-local'
+check 'redundant-parameter'
+check 'redundant-return-value'
+check 'redundant-return'
+check 'redundant-value'
+check 'return-type-mismatch'
+check 'trailing-space'
+check 'unbalanced-assignments'
+check 'undefined-doc-class'
+check 'undefined-doc-name'
+check 'undefined-doc-param'
+check 'undefined-env-child'
+check 'undefined-field'
+check 'undefined-global'
+check 'unknown-cast-variable'
+check 'unknown-diag-code'
+check 'unknown-operator'
+check 'unreachable-code'
+check 'unused-function'
+check 'unused-label'
+check 'unused-local'
+check 'unused-vararg'
diff --git a/test/diagnostics/inject-field.lua b/test/diagnostics/inject-field.lua
new file mode 100644
index 00000000..9bb0f8fc
--- /dev/null
+++ b/test/diagnostics/inject-field.lua
@@ -0,0 +1,84 @@
+TEST [[
+---@class Class
+local m = {}
+
+m.xx = 1 -- OK
+
+---@type Class
+local m
+
+m.xx = 1 -- OK
+m.<!yy!> = 1 -- Warning
+]]
+
+TEST [[
+---@class Class
+local m = {}
+
+m.xx = 1 -- OK
+
+---@class Class
+local m
+
+m.xx = 1 -- OK
+m.yy = 1 -- OK
+]]
+
+TEST [[
+---@type { xx: number }
+local m
+
+m.xx = 1 -- OK
+m.<!yy!> = 1 -- Warning
+]]
+
+TEST [[
+---@type { xx: number, [any]: any }
+local m
+
+m.xx = 1 -- OK
+m.yy = 1 -- OK
+]]
+
+TEST [[
+---@class Class
+---@field x number
+
+---@type Class
+local t
+
+t.x = 1 -- OK
+t.<!y!> = 2 -- Warning
+]]
+
+TEST [[
+---@class Class
+---@field x number
+---@field [any] any
+
+---@type Class
+local t
+
+t.x = 1 -- OK
+t.y = 2 -- OK
+]]
+
+
+TEST [[
+---@class (exact) Class
+---@field x number
+local m = {
+ x = 1, -- OK
+ <!y!> = 2, -- Warning
+}
+
+m.x = 1 -- OK
+m.<!y!> = 2 -- Warning
+
+function m:init() -- OK
+ self.x = 1 -- OK
+ self.<!y!> = 2 -- Warning
+ function self:<!xx!>() -- Warning
+ end
+end
+]]
diff --git a/test/diagnostics/invisible.lua b/test/diagnostics/invisible.lua
new file mode 100644
index 00000000..2fc6791e
--- /dev/null
+++ b/test/diagnostics/invisible.lua
@@ -0,0 +1,145 @@
+local config = require 'config'
+
+TEST [[
+---@class A
+---@field private x number
+---@field protected y number
+---@field public z number
+local t
+print(t.x)
+]]
+
+TEST [[
+---@class A
+---@field private x number
+---@field protected y number
+---@field public z number
+
+---@type A
+local t
+
+print(t.<!x!>)
+]]
+
+TEST [[
+---@class A
+---@field private x number
+---@field protected y number
+---@field public z number
+
+---@class B: A
+local t
+
+print(t.y)
+]]
+
+TEST [[
+---@class A
+---@field private x number
+---@field protected y number
+---@field public z number
+
+---@class B: A
+
+---@type B
+local t
+
+print(t.<!y!>)
+]]
+
+TEST [[
+---@class A
+---@field private x number
+---@field protected y number
+---@field public z number
+
+---@class B: A
+
+---@type B
+local t
+
+print(t.z)
+]]
+TEST [[
+---@class A
+---@field _id number
+
+---@type A
+local t
+
+print(t._id)
+]]
+
+config.set(nil, 'Lua.doc.privateName', { '_*' })
+TEST [[
+---@class A
+---@field _id number
+
+---@type A
+local t
+
+print(t.<!_id!>)
+
+---@class B: A
+local t2
+
+print(t2.<!_id!>)
+]]
+config.set(nil, 'Lua.doc.privateName', nil)
+
+config.set(nil, 'Lua.doc.protectedName', { '_*' })
+TEST [[
+---@class A
+---@field _id number
+
+---@type A
+local t
+
+print(t.<!_id!>)
+
+---@class B: A
+local t2
+
+print(t2._id)
+]]
+config.set(nil, 'Lua.doc.protectedName', nil)
+
+TEST [[
+---@class A
+---@field private x number
+local mt = {}
+
+function mt:init()
+ print(self.x)
+end
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@diagnostic disable: missing-fields
+---@class A
+---@field private x number
+local mt = {}
+
+function mt:init()
+ ---@type A
+ local obj = {}
+
+ obj.x = 1
+end
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@diagnostic disable: missing-fields
+---@class A
+---@field private x number
+local mt = {}
+
+mt.init = function ()
+ ---@type A
+ local obj = {}
+
+ obj.x = 1
+end
+]]
diff --git a/test/diagnostics/lowercase-global.lua b/test/diagnostics/lowercase-global.lua
new file mode 100644
index 00000000..bf73b8c8
--- /dev/null
+++ b/test/diagnostics/lowercase-global.lua
@@ -0,0 +1,39 @@
+TEST [[
+<!aa!> = 1
+tostring = 1
+ROOT = 1
+_G.bb = 1
+]]
+
+TEST [[
+---@diagnostic disable-next-line
+x = 1
+]]
+
+TEST [[
+---@diagnostic disable-next-line: lowercase-global
+x = 1
+]]
+
+TEST [[
+---@diagnostic disable-next-line: unused-local
+<!x!> = 1
+]]
+
+TEST [[
+---@diagnostic disable
+x = 1
+]]
+
+TEST [[
+---@diagnostic disable
+---@diagnostic enable
+<!x!> = 1
+]]
+
+TEST [[
+---@diagnostic disable
+---@diagnostic disable
+---@diagnostic enable
+x = 1
+]]
diff --git a/test/diagnostics/missing-fields.lua b/test/diagnostics/missing-fields.lua
new file mode 100644
index 00000000..ab87f81d
--- /dev/null
+++ b/test/diagnostics/missing-fields.lua
@@ -0,0 +1,233 @@
+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,
+}
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+---@class A
+---@field x number
+local t = {}
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+
+---@class A
+---@field x number
+
+---@class A
+local t = {}
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+
+---@class Foo
+---@field a number
+---@field b number
+---@field c number
+
+---@type Foo|Foo[]
+local a = {
+ {
+ a = 1,
+ b = 2,
+ c = 3,
+ }
+}
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+
+---@class Foo
+---@field a number
+---@field b number
+---@field c number
+
+---@class Bar
+---@field ba number
+---@field bb number
+---@field bc number
+
+---@type Foo|Bar
+local b = {
+ a = 1,
+ b = 2,
+ c = 3,
+}
+]]
+
+TEST [[
+---@class A
+---@field x integer
+
+---@type A
+return <!{}!>
+]]
+
+TEST [[
+---@class A
+---@field x number
+
+---@class B
+---@field y number
+
+---@type A|B
+local t = <!{
+ z = 1,
+}!>
+]]
+
+TEST [[
+---@class A
+---@field x number
+
+---@class B
+---@field y number
+
+---@type A|B
+local t = {
+ y = 1,
+}
+]]
diff --git a/test/diagnostics/missing-global-doc.lua b/test/diagnostics/missing-global-doc.lua
index 2ebc237a..de5250fd 100644
--- a/test/diagnostics/missing-global-doc.lua
+++ b/test/diagnostics/missing-global-doc.lua
@@ -1,31 +1,3 @@
-local config = require 'config'
-local util = require 'utility'
-
--- disable all default groups to make isolated tests
-config.set(nil, 'Lua.diagnostics.groupFileStatus',
-{
- ['ambiguity'] = 'None',
- ['await'] = 'None',
- ['codestyle'] = 'None',
- ['conventions'] = 'None',
- ['duplicate'] = 'None',
- ['global'] = 'None',
- ['luadoc'] = 'None',
- ['redefined'] = 'None',
- ['strict'] = 'None',
- ['strong'] = 'None',
- ['type-check'] = 'None',
- ['unbalanced'] = 'None',
- ['unused'] = 'None'
-})
-
--- enable single diagnostic that is to be tested
-config.set(nil, 'Lua.diagnostics.neededFileStatus',
-{
- ['missing-global-doc'] = 'Any!' -- override groupFileStatus
-})
-
-
-- check global functions
TEST [[
<!function FG0()
@@ -323,11 +295,3 @@ end
local vpr4 = FLPR4(0)
]]
-
--- reset configurations
-config.set(nil, 'Lua.diagnostics.groupFileStatus',
-{})
-config.set(nil, 'Lua.diagnostics.neededFileStatus',
-{})
-config.set(nil, 'Lua.diagnostics.globals',
-{}) \ No newline at end of file
diff --git a/test/diagnostics/missing-local-export-doc.lua b/test/diagnostics/missing-local-export-doc.lua
new file mode 100644
index 00000000..3d942216
--- /dev/null
+++ b/test/diagnostics/missing-local-export-doc.lua
@@ -0,0 +1,175 @@
+-- check global functions
+TEST [[
+local mod = {}
+
+local <!function fl0()
+end!>
+
+---comment
+local function fl1()
+end
+
+local function fl2()
+end
+
+function FG0()
+end
+
+mod.fl0 = fl0
+mod.fl1 = fl1
+return mod
+]]
+
+TEST [[
+local mod = {}
+
+local function flp0(<!p!>)
+ print(p)
+end
+
+---comment
+local function flp1(<!p!>)
+ print(p)
+end
+
+---comment
+---@param p any
+local function flp2(p)
+ print(p)
+end
+
+mod.flp0 = flp0
+mod.flp1 = flp1
+return mod
+]]
+
+TEST [[
+local mod = {}
+
+local function flpp0(<!p0!>, <!p1!>)
+ print(p0, p1)
+end
+
+---comment
+local function flpp1(<!p0!>, <!p1!>)
+ print(p0, p1)
+end
+
+---comment
+---@param p0 any
+local function flpp2(p0, <!p1!>)
+ print(p0, p1)
+end
+
+---comment
+---@param p0 any
+---@param p1 any
+local function flpp3(p0, p1)
+ print(p0, p1)
+end
+
+mod.flpp0 = flpp0
+mod.flpp1 = flpp1
+mod.flpp2 = flpp2
+mod.flpp3 = flpp3
+return mod
+]]
+
+TEST [[
+local mod = {}
+
+local function flr0()
+ return <!0!>
+end
+
+---comment
+local function flr1()
+ return <!0!>
+end
+
+---comment
+---@return integer
+local function flr2()
+ return 0
+end
+
+mod.flr0 = flr0
+mod.flr1 = flr1
+mod.flr2 = flr2
+return mod
+]]
+
+TEST [[
+local mod = {}
+
+local function flrr0()
+ return <!0!>, <!1!>
+end
+
+---comment
+local function flrr1()
+ return <!0!>, <!1!>
+end
+
+---comment
+---@return integer
+local function flrr2()
+ return 0, <!1!>
+end
+
+---comment
+---@return integer
+---@return integer
+local function flrr3()
+ return 0, 1
+end
+
+mod.flrr0 = flrr0
+mod.flrr1 = flrr1
+mod.flrr2 = flrr2
+return mod
+]]
+
+TEST [[
+local mod = {}
+
+local function flpr0(<!p!>)
+ print(p)
+ return <!0!>
+end
+
+---comment
+local function flpr1(<!p!>)
+ print(p)
+ return <!0!>
+end
+
+---comment
+---@param p any
+local function flpr2(p)
+ print(p)
+ return <!0!>
+end
+
+---comment
+---@return integer
+local function flpr3(<!p!>)
+ print(p)
+ return 0
+end
+
+---comment
+---@param p any
+---@return integer
+local function flpr4(p)
+ print(p)
+ return 0
+end
+
+mod.flpr0 = flpr0
+mod.flpr1 = flpr1
+mod.flpr2 = flpr2
+mod.flpr3 = flpr3
+mod.flpr4 = flpr4
+return mod
+]]
diff --git a/test/diagnostics/missing-parameter.lua b/test/diagnostics/missing-parameter.lua
new file mode 100644
index 00000000..154d630b
--- /dev/null
+++ b/test/diagnostics/missing-parameter.lua
@@ -0,0 +1,90 @@
+
+TEST [[
+local function x(a, b)
+ return a, b
+end
+x(1)
+]]
+
+TEST [[
+---@param a integer
+---@param b integer
+local function x(a, b)
+ return a, b
+end
+<!x(1)!>
+]]
+
+TEST [[
+---@param a integer
+---@param b integer
+local function x(a, b)
+ return a, b
+end
+<!x()!>
+]]
+
+TEST [[
+---@param a integer
+---@param b integer
+---@param ... integer
+local function x(a, b, ...)
+ return a, b, ...
+end
+x(1, 2)
+]]
+
+TEST [[
+---@param a integer
+---@param b integer
+local function f(a, b)
+end
+
+f(...)
+]]
+
+TEST [[
+---@param a integer
+---@param b integer
+local function f(a, b)
+end
+
+local function return2Numbers()
+ return 1, 2
+end
+
+f(return2Numbers())
+]]
+
+TEST [[
+---@param a integer
+---@param b? integer
+local function x(a, b)
+ return a, b
+end
+x(1)
+]]
+
+TEST [[
+---@param b integer?
+local function x(a, b)
+ return a, b
+end
+x(1)
+]]
+
+TEST [[
+---@param b integer|nil
+local function x(a, b)
+ return a, b
+end
+x(1)
+]]
+
+TEST [[
+local t = {}
+
+function t:init() end
+
+<!t.init()!>
+]]
diff --git a/test/diagnostics/missing-return-value.lua b/test/diagnostics/missing-return-value.lua
new file mode 100644
index 00000000..3bad7974
--- /dev/null
+++ b/test/diagnostics/missing-return-value.lua
@@ -0,0 +1,34 @@
+TEST [[
+---@type fun():number
+local function f()
+ <!return!>
+end
+]]
+
+TEST [[
+---@return number
+function F()
+ <!return!>
+end
+]]
+
+TEST [[
+---@return number, number
+function F()
+ <!return!> 1
+end
+]]
+
+TEST [[
+---@return number, number?
+function F()
+ return 1
+end
+]]
+
+TEST [[
+---@return ...
+function F()
+ return
+end
+]]
diff --git a/test/diagnostics/missing-return.lua b/test/diagnostics/missing-return.lua
new file mode 100644
index 00000000..b8c1e7d3
--- /dev/null
+++ b/test/diagnostics/missing-return.lua
@@ -0,0 +1,158 @@
+TEST [[
+---@type fun():number
+local function f()
+<!!>end
+]]
+
+TEST [[
+---@type fun():number?
+local function f()
+end
+]]
+
+TEST [[
+---@type fun():...
+local function f()
+end
+]]
+
+TEST [[
+---@return number
+function F()
+ X = 1<!!>
+end
+]]
+TEST [[
+local A
+---@return number
+function F()
+ if A then
+ return 1
+ end<!!>
+end
+]]
+
+TEST [[
+local A, B
+---@return number
+function F()
+ if A then
+ return 1
+ elseif B then
+ return 2
+ end<!!>
+end
+]]
+
+TEST [[
+local A, B
+---@return number
+function F()
+ if A then
+ return 1
+ elseif B then
+ return 2
+ else
+ return 3
+ end
+end
+]]
+
+TEST [[
+local A, B
+---@return number
+function F()
+ if A then
+ elseif B then
+ return 2
+ else
+ return 3
+ end<!!>
+end
+]]
+
+TEST [[
+---@return any
+function F()
+ X = 1
+end
+]]
+
+TEST [[
+---@return any, number
+function F()
+ X = 1<!!>
+end
+]]
+
+TEST [[
+---@return number, any
+function F()
+ X = 1<!!>
+end
+]]
+
+TEST [[
+---@return any, any
+function F()
+ X = 1
+end
+]]
+
+TEST [[
+local A
+---@return number
+function F()
+ for _ = 1, 10 do
+ if A then
+ return 1
+ end
+ end
+ error('should not be here')
+end
+]]
+
+TEST [[
+local A
+---@return number
+function F()
+ while true do
+ if A then
+ return 1
+ end
+ end
+end
+]]
+
+TEST [[
+local A
+---@return number
+function F()
+ while A do
+ if A then
+ return 1
+ end
+ end<!!>
+end
+]]
+
+TEST [[
+local A
+---@return number
+function F()
+ while A do
+ if A then
+ return 1
+ else
+ return 2
+ end
+ end
+end
+]]
+
+TEST [[
+---@return number?
+function F()
+
+end
+]]
diff --git a/test/diagnostics/need-check-nil.lua b/test/diagnostics/need-check-nil.lua
new file mode 100644
index 00000000..c4e3bba6
--- /dev/null
+++ b/test/diagnostics/need-check-nil.lua
@@ -0,0 +1,68 @@
+TEST [[
+---@type string?
+local x
+
+local s = <!x!>:upper()
+]]
+
+TEST [[
+---@type string?
+local x
+
+S = <!x!>:upper()
+]]
+
+TEST [[
+---@type string?
+local x
+
+if x then
+ S = x:upper()
+end
+]]
+
+TEST [[
+---@type string?
+local x
+
+if not x then
+ x = ''
+end
+
+S = x:upper()
+]]
+
+TEST [[
+---@type fun()?
+local x
+
+S = <!x!>()
+]]
+
+TEST [[
+---@type integer?
+local x
+
+T = {}
+T[<!x!>] = 1
+]]
+
+TEST [[
+local x, y
+local z = x and y
+
+print(z.y)
+]]
+
+TEST [[
+local x, y
+function x()
+ y()
+end
+
+function y()
+ x()
+end
+
+x()
+]]
diff --git a/test/diagnostics/newfield-call.lua b/test/diagnostics/newfield-call.lua
new file mode 100644
index 00000000..63de9db9
--- /dev/null
+++ b/test/diagnostics/newfield-call.lua
@@ -0,0 +1,15 @@
+TEST [[
+return {
+ <!print
+ 'string'!>
+}
+]]
+
+TEST [[
+return {
+ <!print
+ {
+ x = 1,
+ }!>
+}
+]]
diff --git a/test/diagnostics/newline-call.lua b/test/diagnostics/newline-call.lua
new file mode 100644
index 00000000..ca160aa3
--- /dev/null
+++ b/test/diagnostics/newline-call.lua
@@ -0,0 +1,34 @@
+TEST [[
+<!print()
+('string')!>:sub(1, 1)
+]]
+
+TEST [[
+print()
+('string')
+]]
+
+TEST [[
+print
+{}
+{}
+]]
+
+TEST [[
+local x
+return x
+ : f(1)
+ : f(1)
+]]
+
+TEST [[
+print()
+'string'
+]]
+
+TEST [[
+print
+{
+ x = 1,
+}
+]]
diff --git a/test/diagnostics/not-yieldable.lua b/test/diagnostics/not-yieldable.lua
new file mode 100644
index 00000000..81e972ee
--- /dev/null
+++ b/test/diagnostics/not-yieldable.lua
@@ -0,0 +1,48 @@
+TEST [[
+---@param cb fun()
+local function f(cb)
+ return cb
+end
+
+---@async
+local function af()
+ return nil
+end
+
+f(<!af!>)
+]]
+
+TEST [[
+---@param cb async fun()
+local function f(cb)
+ return cb
+end
+
+---@async
+local function af()
+ return nil
+end
+
+f(af)
+]]
+
+TEST [[
+local function f(cb)
+ cb()
+end
+
+---@async
+local function af()
+ f(function () ---@async
+ return nil
+ end)
+end
+
+return af
+]]
+
+TEST [[
+local _ = type(function () ---@async
+ return nil
+end)
+]]
diff --git a/test/diagnostics/param-type-mismatch.lua b/test/diagnostics/param-type-mismatch.lua
new file mode 100644
index 00000000..e31e9933
--- /dev/null
+++ b/test/diagnostics/param-type-mismatch.lua
@@ -0,0 +1,248 @@
+TEST [[
+---@param x number
+local function f(x) end
+
+f(<!true!>)
+]]
+
+TEST [[
+---@class A
+
+---@param n A
+local function f(n)
+end
+
+---@class B
+local a = {}
+
+---@type A?
+a.x = XX
+
+f(a.x)
+]]
+TEST [[
+---@alias A string|boolean
+
+---@param x string|boolean
+local function f(x) end
+
+---@type A
+local x
+
+f(x)
+]]
+
+TEST [[
+---@alias A string|boolean
+
+---@param x A
+local function f(x) end
+
+---@type string|boolean
+local x
+
+f(x)
+]]
+
+TEST [[
+---@param b boolean
+local function f(b)
+end
+
+---@type boolean
+local t
+
+if t then
+ f(t)
+end
+]]
+
+TEST [[
+---@enum A
+local t = {
+ x = 1,
+ y = 2,
+}
+
+---@param x A
+local function f(x)
+end
+
+f(<!t!>)
+f(t.x)
+f(1)
+f(<!3!>)
+]]
+
+TEST [[
+---@enum A
+local t = {
+ x = { h = 1 },
+ y = { h = 2 },
+}
+
+---@param x A
+local function f(x)
+end
+
+f(t.x)
+f(t.y)
+f(<!{ h = 1 }!>)
+]]
+
+TEST [[
+---@enum(key) A
+local t = {
+ x = 1,
+ ['y'] = 2,
+}
+
+---@param x A
+local function f(x)
+end
+
+f('x')
+f('y')
+f(<!'z'!>)
+]]
+
+TEST [[
+---@generic T: string | boolean | table
+---@param x T
+---@return T
+local function f(x)
+ return x
+end
+
+f(<!1!>)
+]]
+
+TEST [[
+---@param opts {a:number, b:number}
+local function foo(opts)
+
+end
+
+---@param opts {a:number, b:number}
+local function bar(opts)
+ foo(opts)
+end
+]]
+
+TEST [[
+---@param opts {a:number, b:number}
+local function foo(opts)
+
+end
+
+---@param opts {c:number, d:number}
+local function bar(opts)
+ foo(<!opts!>) -- this should raise linting error
+end
+]]
+
+TEST [[
+---@param opts {[number]: boolean}
+local function foo(opts)
+
+end
+
+---@param opts {[1]: boolean}
+local function bar(opts)
+ foo(opts)
+end
+]]
+
+TEST [[
+---@generic T
+---@param v1 T
+---@param v2 T|table
+local function func(v1, v2)
+end
+
+func('hello', 'world')
+]]
+
+TEST [[
+---@generic T1, T2, T3, T4, T5
+---@param f fun(): T1?, T2?, T3?, T4?, T5?
+---@return T1?, T2?, T3?, T4?, T5?
+local function foo(f)
+ return f()
+end
+
+local a, b = foo(function()
+ return 1
+end)
+]]
+
+TEST [[
+---@generic T1, T2, T3, T4, T5
+---@param f fun(): T1|nil, T2|nil, T3|nil, T4|nil, T5|nil
+---@return T1?, T2?, T3?, T4?, T5?
+local function foo(f)
+ return f()
+end
+
+local a, b = foo(function()
+ return 1
+end)
+]]
+
+TEST [[
+---@param v integer
+---@return boolean
+local function is_string(v)
+ return type(v) == 'string'
+end
+
+print(is_string(3))
+]]
+
+TEST [[
+---@param p integer|string
+local function get_val(p)
+ local is_number = type(p) == 'number'
+ return is_number and p or p
+end
+
+get_val('hi')
+]]
+
+TEST [[
+---@class Class
+local Class = {}
+
+---@param source string
+function Class.staticCreator(source)
+
+end
+
+Class.staticCreator(<!true!>)
+Class<!:!>staticCreator() -- Expecting a waring
+]]
+
+TEST [[
+---@class A
+
+---@class B : A
+
+---@class C : B
+
+---@class D : B
+
+---@param x A
+local function func(x) end
+
+---@type C|D
+local var
+func(var)
+]]
+
+TEST [[
+---@class MyClass
+---@overload fun(x : string) : MyClass
+local MyClass = {}
+
+local w = MyClass(<!1!>)
+]]
diff --git a/test/diagnostics/redefined-local.lua b/test/diagnostics/redefined-local.lua
new file mode 100644
index 00000000..c594ed2c
--- /dev/null
+++ b/test/diagnostics/redefined-local.lua
@@ -0,0 +1,22 @@
+TEST [[
+local x
+print(x)
+local <!x!>
+print(x)
+]]
+
+TEST [[
+local x
+print(x)
+local <!x!>
+print(x)
+local <!x!>
+print(x)
+]]
+
+TEST [[
+local x
+return x, function (<!x!>)
+ return x
+end
+]]
diff --git a/test/diagnostics/redundant-parameter.lua b/test/diagnostics/redundant-parameter.lua
new file mode 100644
index 00000000..fabe3340
--- /dev/null
+++ b/test/diagnostics/redundant-parameter.lua
@@ -0,0 +1,214 @@
+TEST [[
+local function x(a, b)
+ return a, b
+end
+x(1, 2, <!3!>)
+]]
+
+TEST [[
+local function x(a, b, ...)
+ return a, b, ...
+end
+x(1, 2, 3, 4, 5)
+]]
+
+TEST [[
+---@type fun(a, b, ...)
+local x
+x(1, 2, 3, 4, 5)
+]]
+
+TEST [[
+local m = {}
+function m:x(a, b)
+ return a, b
+end
+m:x(1, 2, <!3!>)
+]]
+
+TEST [[
+local m = {}
+function m:x(a, b)
+ return a, b
+end
+m.x(m, 2, 3, <!4!>)
+]]
+
+TEST [[
+local m = {}
+function m.x(a, b)
+ return a, b
+end
+m:x(1, <!2!>, <!3!>, <!4!>)
+]]
+
+TEST [[
+local m = {}
+function m.x()
+end
+m:x()
+]]
+
+TEST [[
+local function f(a, b)
+ return a, b
+end
+f(1, 2, <!3!>, <!4!>)
+]]
+
+TEST [[
+local mt = {}
+function mt:f(a, b)
+ return a, b
+end
+mt.f(mt, 2, 3, <!4!>)
+]]
+
+TEST [[
+local mt = {}
+function mt.f(a, b)
+ return a, b
+end
+mt:f(1, <!2!>, <!3!>, <!4!>)
+]]
+
+TEST [[
+local mt = {}
+function mt:f(a, b)
+ return a, b
+end
+mt:f(1, 2, <!3!>, <!4!>)
+]]
+
+TEST [[
+local function f(a, b, ...)
+ return a, b, ...
+end
+f(1, 2, 3, 4)
+]]
+
+TEST [[
+local _ = next({}, 1, <!2!>)
+print(1, 2, 3, 4, 5)
+]]
+
+TEST [[
+local function f(callback)
+ callback(1, 2, 3)
+end
+f(function () end)
+]]
+
+--TEST [[
+--local realTostring = tostring
+--tostring = function () end
+--tostring(<!1!>)
+--tostring = realTostring
+--tostring(1)
+--]]
+
+TEST [[
+local f = load('')
+if f then
+ f(1, 2, 3)
+end
+]]
+
+TEST [[
+local m = {}
+function m.open()
+end
+
+m:open()
+]]
+
+TEST [[
+local m = {}
+function m:open()
+end
+
+m.open(m)
+]]
+
+TEST [[
+table.insert({}, 1, 2, <!3!>)
+]]
+
+TEST [[
+---@overload fun(...)
+local function f() end
+
+f(1)
+]]
+
+TEST [[
+function F() end
+
+---@param x boolean
+function F(x) end
+
+F(k())
+]]
+
+TEST [[
+local function f()
+ return 1, 2, 3
+end
+
+local function k()
+end
+
+k(<!f()!>)
+]]
+
+TEST [[
+---@diagnostic disable: unused-local
+local function f()
+ return 1, 2, 3
+end
+
+---@param x integer
+local function k(x)
+end
+
+k(f())
+]]
+
+TEST [[
+---@meta
+
+---@param x fun()
+local function f1(x)
+end
+
+---@return fun()
+local function f2()
+end
+
+f1(f2())
+]]
+
+TEST [[
+---@meta
+
+---@type fun():integer
+local f
+
+---@param x integer
+local function foo(x) end
+
+foo(f())
+]]
+
+TEST [[
+---@meta
+---@diagnostic disable: duplicate-set-field
+---@class A
+local m = {}
+
+function m.ff() end
+
+function m.ff(x) end
+
+m.ff(1)
+]]
diff --git a/test/diagnostics/redundant-return-value.lua b/test/diagnostics/redundant-return-value.lua
new file mode 100644
index 00000000..f3e2c584
--- /dev/null
+++ b/test/diagnostics/redundant-return-value.lua
@@ -0,0 +1,32 @@
+TEST [[
+---@type fun():number
+local function f()
+ return 1, <!true!>
+end
+]]
+
+TEST [[
+---@return number, number?
+function F()
+ return 1, 1, <!1!>
+end
+]]
+
+TEST [[
+---@return number, number?
+function F()
+ return 1, 1, <!1!>, <!2!>, <!3!>
+end
+]]
+
+TEST [[
+---@meta
+
+---@return number, number
+local function r2() end
+
+---@return number, number?
+function F()
+ return 1, <!r2()!>
+end
+]]
diff --git a/test/diagnostics/redundant-return.lua b/test/diagnostics/redundant-return.lua
new file mode 100644
index 00000000..11214aab
--- /dev/null
+++ b/test/diagnostics/redundant-return.lua
@@ -0,0 +1,34 @@
+TEST [[
+local function f()
+ <!return!>
+end
+f()
+]]
+
+TEST [[
+local function f()
+ return nil
+end
+f()
+]]
+
+TEST [[
+local function f()
+ local function x()
+ <!return!>
+ end
+ x()
+ return true
+end
+f()
+]]
+
+TEST [[
+local function f()
+ local function x()
+ return true
+ end
+ return x()
+end
+f()
+]]
diff --git a/test/diagnostics/redundant-value.lua b/test/diagnostics/redundant-value.lua
new file mode 100644
index 00000000..a63544df
--- /dev/null
+++ b/test/diagnostics/redundant-value.lua
@@ -0,0 +1,7 @@
+TEST [[
+local _ = 1, <!2!>
+]]
+
+TEST [[
+_ = 1, <!2!>
+]]
diff --git a/test/diagnostics/return-type-mismatch.lua b/test/diagnostics/return-type-mismatch.lua
new file mode 100644
index 00000000..aaf7807f
--- /dev/null
+++ b/test/diagnostics/return-type-mismatch.lua
@@ -0,0 +1,167 @@
+TEST [[
+---@return number
+function F()
+ return <!true!>
+end
+]]
+
+TEST [[
+---@return number?
+function F()
+ return 1
+end
+]]
+
+TEST [[
+---@return number?
+function F()
+ return nil
+end
+]]
+
+TEST [[
+---@return number, number
+local function f()
+ return 1, 1
+end
+
+---@return number, boolean
+function F()
+ return <!f()!>
+end
+]]
+
+TEST [[
+---@return boolean, number
+local function f()
+ return true, 1
+end
+
+---@return number, boolean
+function F()
+ return <!f()!>
+end
+]]
+
+TEST [[
+---@return boolean, number?
+local function f()
+ return true, 1
+end
+
+---@return number, boolean
+function F()
+ return 1, f()
+end
+]]
+
+TEST [[
+---@return number, number?
+local function f()
+ return 1, 1
+end
+
+---@return number, boolean, number
+function F()
+ return 1, <!f()!>
+end
+]]
+
+TEST [[
+---@class A
+---@field x number?
+
+---@return number
+function F()
+ ---@type A
+ local t
+ return t.x
+end
+]]
+
+TEST [[
+---@class A
+---@field x number?
+local t = {}
+
+---@return number
+function F()
+ return t.x
+end
+]]
+
+TEST [[
+---@param ... number
+local function f(...)
+end
+
+f(nil)
+]]
+
+TEST [[
+---@return number
+function F()
+ local n = 0
+ if true then
+ n = 1
+ end
+ return n
+end
+]]
+
+TEST [[
+---@param x boolean
+---@return number
+---@overload fun(): boolean
+local function f(x)
+ if x then
+ return 1
+ else
+ return false
+ end
+end
+]]
+
+TEST [[
+---@param x boolean
+---@return number
+---@overload fun()
+local function f(x)
+ if x then
+ return 1
+ else
+ return
+ end
+end
+]]
+
+TEST [[
+---@param x boolean
+---@return number
+---@overload fun()
+local function f(x)
+ if x then
+ return 1
+ end
+end
+]]
+
+TEST [[
+---@param x boolean
+---@return number
+---@overload fun(): boolean, boolean
+local function f(x)
+ if x then
+ return 1
+ else
+ return false, false
+ end
+end
+]]
+
+TEST [[
+---@type fun():number
+local function f()
+ return <!true!>
+end
+]]
diff --git a/test/diagnostics/trailing-space.lua b/test/diagnostics/trailing-space.lua
new file mode 100644
index 00000000..ff794714
--- /dev/null
+++ b/test/diagnostics/trailing-space.lua
@@ -0,0 +1,32 @@
+TEST [[
+<! !>
+]]
+
+TEST [[
+
+<! !>
+]]
+
+TEST [[
+X = 1<! !>
+]]
+
+TEST [[
+X = [=[
+ ]=]
+]]
+
+TEST [[
+-- xxxx
+]]
+
+TEST [[
+-- [=[
+ ]=]
+]]
+
+TEST [=[
+return [[
+
+]]
+]=]
diff --git a/test/diagnostics/type-check.lua b/test/diagnostics/type-check.lua
deleted file mode 100644
index 18e7190d..00000000
--- a/test/diagnostics/type-check.lua
+++ /dev/null
@@ -1,1262 +0,0 @@
-local config = require 'config'
-
-config.add(nil, 'Lua.diagnostics.disable', 'unused-local')
-config.add(nil, 'Lua.diagnostics.disable', 'unused-function')
-config.add(nil, 'Lua.diagnostics.disable', 'undefined-global')
-config.add(nil, 'Lua.diagnostics.disable', 'redundant-return')
-config.set(nil, 'Lua.type.castNumberToInteger', false)
-
-TEST [[
-local x = 0
-
-<!x!> = true
-]]
-
-TEST [[
----@type integer
-local x
-
-<!x!> = true
-]]
-
-TEST [[
----@type unknown
-local x
-
-x = nil
-]]
-
-TEST [[
----@type unknown
-local x
-
-x = 1
-]]
-
-TEST [[
----@type unknown|nil
-local x
-
-x = 1
-]]
-
-TEST [[
-local x = {}
-
-x = nil
-]]
-
-TEST [[
----@type string
-local x
-
-<?x?> = nil
-]]
-
-TEST [[
----@type string?
-local x
-
-x = nil
-]]
-
-TEST [[
----@type table
-local x
-
-<!x!> = nil
-]]
-
-TEST [[
-local x
-
-x = nil
-]]
-
-TEST [[
----@type integer
-local x
-
----@type number
-<!x!> = f()
-]]
-
-TEST [[
----@type number
-local x
-
----@type integer
-x = f()
-]]
-
-TEST [[
----@type number|boolean
-local x
-
----@type string
-<!x!> = f()
-]]
-
-TEST [[
----@type number|boolean
-local x
-
----@type boolean
-x = f()
-]]
-
-TEST [[
----@type number|boolean
-local x
-
----@type boolean|string
-<!x!> = f()
-]]
-
-TEST [[
----@type boolean
-local x
-
-if not x then
- return
-end
-
-x = f()
-]]
-
-TEST [[
----@type boolean
-local x
-
----@type integer
-local y
-
-<!x!> = y
-]]
-
-TEST [[
-local y = true
-
-local x
-x = 1
-x = y
-]]
-
-TEST [[
-local t = {}
-
-local x = 0
-x = x + #t
-]]
-
-TEST [[
-local x = 0
-
-x = 1.0
-]]
-
-TEST [[
----@class A
-
-local t = {}
-
----@type A
-local a
-
-t = a
-]]
-
-TEST [[
-local m = {}
-
----@type integer[]
-m.ints = {}
-]]
-
-TEST [[
----@class A
----@field x A
-
----@type A
-local t
-
-t.x = {}
-]]
-
-TEST [[
----@class A
----@field x integer
-
----@type A
-local t
-
-<!t.x!> = true
-]]
-
-TEST [[
----@class A
----@field x integer
-
----@type A
-local t
-
----@type boolean
-local y
-
-<!t.x!> = y
-]]
-
-TEST [[
----@class A
-local m
-
-m.x = 1
-
----@type A
-local t
-
-<!t.x!> = true
-]]
-
-TEST [[
----@class A
-local m
-
----@type integer
-m.x = 1
-
-<!m.x!> = true
-]]
-
-TEST [[
----@class A
-local mt
-
----@type integer
-mt.x = 1
-
-function mt:init()
- <!self.x!> = true
-end
-]]
-
-TEST [[
----@class A
----@field x integer
-
----@type A
-local t = {
- <!x!> = true
-}
-]]
-
-TEST [[
----@type boolean[]
-local t = {}
-
-t[5] = nil
-]]
-
-TEST [[
----@type table<string, true>
-local t = {}
-
-t['x'] = nil
-]]
-
-TEST [[
-local t = { true }
-
-t[1] = nil
-]]
-
-TEST [[
----@class A
-local t = {
- x = 1
-}
-
-<!t.x!> = true
-]]
-
-TEST [[
----@type number
-local t
-
-t = 1
-]]
-
-TEST [[
----@type number
-local t
-
----@type integer
-local y
-
-t = y
-]]
-
-TEST [[
----@class A
-local m
-
----@type number
-m.x = 1
-
-<!m.x!> = {}
-]]
-
-TEST [[
----@param x number
-local function f(x) end
-
-f(<!true!>)
-]]
-
-TEST [[
----@type integer
-local x
-
-x = 1.0
-]]
-
-TEST [[
----@type integer
-local x
-
-<!x!> = 1.5
-]]
-
-TEST [[
----@diagnostic disable:undefined-global
----@type integer
-local x
-
-x = 1 + G
-]]
-
-TEST [[
----@diagnostic disable:undefined-global
----@type integer
-local x
-
-x = 1 + G
-]]
-
-TEST [[
----@alias A integer
-
----@type A
-local a
-
----@type integer
-local b
-
-b = a
-]]
-
-TEST [[
----@type string|boolean
-local t
-
----@cast t string
-]]
-
-TEST [[
----@type string|boolean
-local t
-
----@cast t <!number!>
-]]
-
-TEST [[
-local n
-
-if G then
- n = {}
-else
- n = nil
-end
-
-local t = {
- x = n,
-}
-]]
-
-TEST [[
----@class A
-
----@param n A
-local function f(n)
-end
-
----@class B
-local a = {}
-
----@type A?
-a.x = XX
-
-f(a.x)
-]]
-
-TEST [[
----@type string?
-local x
-
-local s = <!x!>:upper()
-]]
-
-TEST [[
----@alias A string|boolean
-
----@param x string|boolean
-local function f(x) end
-
----@type A
-local x
-
-f(x)
-]]
-
-TEST [[
----@alias A string|boolean
-
----@param x A
-local function f(x) end
-
----@type string|boolean
-local x
-
-f(x)
-]]
-
-TEST [[
----@type boolean[]
-local t = {}
-
----@type boolean?
-local x
-
-t[#t+1] = x
-]]
-
-TEST [[
----@type number
-local n
----@type integer
-local i
-
-<?i?> = n
-]]
-
-config.set(nil, 'Lua.type.castNumberToInteger', true)
-TEST [[
----@type number
-local n
----@type integer
-local i
-
-i = n
-]]
-config.set(nil, 'Lua.type.castNumberToInteger', false)
-
-TEST [[
----@type number|boolean
-local nb
-
----@type number
-local n
-
-<?n?> = nb
-]]
-
-config.set(nil, 'Lua.type.weakUnionCheck', true)
-TEST [[
----@type number|boolean
-local nb
-
----@type number
-local n
-
-n = nb
-]]
-config.set(nil, 'Lua.type.weakUnionCheck', false)
-
-TEST [[
----@class Option: string
-
----@param x Option
-local function f(x) end
-
----@type Option
-local x = 'aaa'
-
-f(x)
-]]
-
-TEST [[
----@type number
-local <!x!> = 'aaa'
-]]
-
-TEST [[
----@return number
-function F()
- return <!true!>
-end
-]]
-
-TEST [[
----@return number?
-function F()
- return 1
-end
-]]
-
-TEST [[
----@return number?
-function F()
- return nil
-end
-]]
-
-TEST [[
----@return number, number
-local function f()
- return 1, 1
-end
-
----@return number, boolean
-function F()
- return <!f()!>
-end
-]]
-
-TEST [[
----@return boolean, number
-local function f()
- return true, 1
-end
-
----@return number, boolean
-function F()
- return <!f()!>
-end
-]]
-
-TEST [[
----@return boolean, number?
-local function f()
- return true, 1
-end
-
----@return number, boolean
-function F()
- return 1, f()
-end
-]]
-
-TEST [[
----@return number, number?
-local function f()
- return 1, 1
-end
-
----@return number, boolean, number
-function F()
- return 1, <!f()!>
-end
-]]
-
-TEST [[
----@class A
----@field x number?
-
----@return number
-function F()
- ---@type A
- local t
- return t.x
-end
-]]
-
-TEST [[
----@class A
----@field x number?
-local t = {}
-
----@return number
-function F()
- return t.x
-end
-]]
-
-TEST [[
----@param ... number
-local function f(...)
-end
-
-f(nil)
-]]
-
-TEST [[
----@return number
-function F()
- local n = 0
- if true then
- n = 1
- end
- return n
-end
-]]
-
-TEST [[
----@class X
-
----@class A
-local mt = G
-
----@type X
-mt._x = nil
-]]
-
-config.set(nil, 'Lua.type.weakNilCheck', true)
-TEST [[
----@type number?
-local nb
-
----@type number
-local n
-
-n = nb
-]]
-
-TEST [[
----@type number|nil
-local nb
-
----@type number
-local n
-
-n = nb
-]]
-config.set(nil, 'Lua.type.weakNilCheck', false)
-
-TEST [[
----@class A
-local a = {}
-
----@class B
-local <!b!> = a
-]]
-
-TEST [[
----@class A
-local a = {}
-
----@class B: A
-local b = a
-]]
-
-TEST [[
----@class A
-local a = {}
-a.__index = a
-
----@class B: A
-local b = setmetatable({}, a)
-]]
-
-TEST [[
----@class A
-local a = {}
-
----@class B: A
-local b = setmetatable({}, {__index = a})
-]]
-
-TEST [[
----@class A
-local a = {}
-
----@class B
-local <!b!> = setmetatable({}, {__index = a})
-]]
-
-TEST [[
----@class A
----@field x number?
-local a
-
----@class B
----@field x number
-local b
-
-b.x = a.x
-]]
-
-TEST [[
-
----@class A
----@field x number?
-local a
-
----@type number
-local t
-
-t = a.x
-]]
-
-TEST [[
-local mt = {}
-mt.x = 1
-mt.x = nil
-]]
-
-TEST [[
----@type string[]
-local t
-
-<!t!> = 'xxx'
-]]
-
-TEST [[
----@param b boolean
-local function f(b)
-end
-
----@type boolean
-local t
-
-if t then
- f(t)
-end
-]]
-
-config.set(nil, 'Lua.type.weakUnionCheck', true)
-TEST [[
----@type number
-local x = G
-]]
-
-TEST [[
----@generic T
----@param x T
----@return T
-local function f(x)
- return x
-end
-]]
-config.set(nil, 'Lua.type.weakUnionCheck', false)
-
-TEST [[
----@type 1|2
-local x
-
-x = 1
-x = 2
-<!x!> = 3
-]]
-
-TEST [[
----@type 'x'|'y'
-local x
-
-x = 'x'
-x = 'y'
-<!x!> = 'z'
-]]
-
-TEST [[
----@enum A
-local t = {
- x = 1,
- y = 2,
-}
-
----@param x A
-local function f(x)
-end
-
-f(<!t!>)
-f(t.x)
-f(1)
-f(<!3!>)
-]]
-
-TEST [[
----@enum A
-local t = {
- x = { h = 1 },
- y = { h = 2 },
-}
-
----@param x A
-local function f(x)
-end
-
-f(t.x)
-f(t.y)
-f(<!{ h = 1 }!>)
-]]
-
-TEST [[
-local t = {
- x = 1,
-}
-
-local x
-t[x] = true
-]]
-
-TEST [[
----@param x boolean
----@return number
----@overload fun(): boolean
-local function f(x)
- if x then
- return 1
- else
- return false
- end
-end
-]]
-
-TEST [[
----@param x boolean
----@return number
----@overload fun()
-local function f(x)
- if x then
- return 1
- else
- return
- end
-end
-]]
-
-TEST [[
----@param x boolean
----@return number
----@overload fun()
-local function f(x)
- if x then
- return 1
- end
-end
-]]
-
-TEST [[
----@param x boolean
----@return number
----@overload fun(): boolean, boolean
-local function f(x)
- if x then
- return 1
- else
- return false, false
- end
-end
-]]
-
-TEST [[
----@alias test boolean
-
----@type test
-local <!test!> = 4
-]]
-
-TEST [[
----@class MyClass
-local MyClass = {}
-
-function MyClass:new()
- ---@class MyClass
- local myObject = setmetatable({
- initialField = true
- }, self)
-
- print(myObject.initialField)
-end
-]]
-
-TEST [[
----@class T
-local t = {
- x = nil
-}
-
-t.x = 1
-]]
-
-TEST [[
----@generic T: string | boolean | table
----@param x T
----@return T
-local function f(x)
- return x
-end
-
-f(<!1!>)
-]]
-
-TEST [[
----@type table<string, string>
-local x
-
----@type table<number, string>
-local y
-
-<!x!> = y
-]]
-
-TEST [[
----@type table<string, string>
-local x
-
----@type table<string, number>
-local y
-
-<!x!> = y
-]]
-
-TEST [[
----@type table<string, string>
-local x
-
----@type table<string, string>
-local y
-
-x = y
-]]
-
-TEST [[
----@param opts {a:number, b:number}
-local function foo(opts)
-
-end
-
----@param opts {a:number, b:number}
-local function bar(opts)
- foo(opts)
-end
-]]
-
-TEST [[
----@param opts {a:number, b:number}
-local function foo(opts)
-
-end
-
----@param opts {c:number, d:number}
-local function bar(opts)
- foo(<!opts!>) -- this should raise linting error
-end
-]]
-
-TEST [[
----@param opts {[number]: boolean}
-local function foo(opts)
-
-end
-
----@param opts {[1]: boolean}
-local function bar(opts)
- foo(opts)
-end
-]]
-
-TEST [[
----@type {[1]: string, [10]: number, xx: boolean}
-local t = {
- <!true!>,
- <![10]!> = 's',
- <!xx!> = 1,
-}
-]]
-
-TEST [[
----@type { x: number, y: number }
-local t1
-
----@type { x: number }
-local t2
-
-<!t1!> = t2
-]]
-
-TEST [[
----@type { x: number, [integer]: number }
-local t1
-
----@type { x: number }
-local t2
-
-<!t1!> = t2
-]]
-
-TEST [[
----@type boolean[]
-local t = { <!1!>, <!2!>, <!3!> }
-]]
-
-TEST [[
----@type boolean[]
-local t = { true, false, nil }
-]]
-
-TEST [[
----@type boolean|nil
-local x
-
----@type boolean[]
-local t = { true, false, x }
-]]
-
-TEST [[
----@type fun():number
-local function f()
-<!!>end
-]]
-
-TEST [[
----@type fun():number
-local function f()
- <!return!>
-end
-]]
-
-TEST [[
----@type fun():number?
-local function f()
-end
-]]
-
-TEST [[
----@type fun():...
-local function f()
-end
-]]
-
-TEST [[
----@type fun():number
-local function f()
- return 1, <!true!>
-end
-]]
-
-TEST [[
----@type fun():number
-local function f()
- return <!true!>
-end
-]]
-
-TEST [[
----@enum Enum
-local t = {
- x = 1,
- y = 2,
-}
-
----@type Enum
-local y
-
----@type integer
-local x = y
-]]
-
-TEST [[
----@generic T
----@param v1 T
----@param v2 T|table
-local function func(v1, v2)
-end
-
-func('hello', 'world')
-]]
-
-TEST [[
----@generic T1, T2, T3, T4, T5
----@param f fun(): T1?, T2?, T3?, T4?, T5?
----@return T1?, T2?, T3?, T4?, T5?
-local function foo(f)
- return f()
-end
-
-local a, b = foo(function()
- return 1
-end)
-]]
-
-TEST [[
----@generic T1, T2, T3, T4, T5
----@param f fun(): T1|nil, T2|nil, T3|nil, T4|nil, T5|nil
----@return T1?, T2?, T3?, T4?, T5?
-local function foo(f)
- return f()
-end
-
-local a, b = foo(function()
- return 1
-end)
-]]
-
-TEST [[
----@type string|string[]|string[][]
-local t = {{'a'}}
-]]
-
-TEST [[
-local A = "Hello"
-local B = "World"
-
----@alias myLiteralAliases `A` | `B`
-
----@type myLiteralAliases
-local x = A
-]]
-
-TEST [[
-local enum = { a = 1, b = 2 }
-
----@type { [integer] : boolean }
-local t = {
- <![enum.a]!> = 1,
- <![enum.b]!> = 2,
- <![3]!> = 3,
-}
-]]
-
-TEST [[
-local x
-
-if X then
- x = 'A'
-elseif X then
- x = 'B'
-else
- x = 'C'
-end
-
-local y = x
-
-<!y!> = nil
-]]
-(function (diags)
- local diag = diags[1]
- assert(diag.message == [[
-已显式定义变量的类型为 `string` ,不能再将其类型转换为 `nil`。
-- `nil` 无法匹配 `string`
-- 类型 `nil` 无法匹配 `string`]])
-end)
-
-
-TEST [[
----@type 'A'|'B'|'C'|'D'|'E'|'F'|'G'|'H'|'I'|'J'|'K'|'L'|'M'|'N'|'O'|'P'|'Q'|'R'|'S'|'T'|'U'|'V'|'W'|'X'|'Y'|'Z'
-local x
-
-<!x!> = nil
-]]
-(function (diags)
- local diag = diags[1]
- assert(diag.message == [[
-已显式定义变量的类型为 `'A'|'B'|'C'|'D'|'E'...(+21)` ,不能再将其类型转换为 `nil`。
-- `nil` 无法匹配 `'A'|'B'|'C'|'D'|'E'...(+21)`
-- `nil` 无法匹配 `'A'|'B'|'C'|'D'|'E'...(+21)` 中的任何子类
-- 类型 `nil` 无法匹配 `'Z'`
-- 类型 `nil` 无法匹配 `'Y'`
-- 类型 `nil` 无法匹配 `'X'`
-- 类型 `nil` 无法匹配 `'W'`
-- 类型 `nil` 无法匹配 `'V'`
-- 类型 `nil` 无法匹配 `'U'`
-- 类型 `nil` 无法匹配 `'T'`
-- 类型 `nil` 无法匹配 `'S'`
-- 类型 `nil` 无法匹配 `'R'`
-- 类型 `nil` 无法匹配 `'Q'`
-...(+13)
-- 类型 `nil` 无法匹配 `'C'`
-- 类型 `nil` 无法匹配 `'B'`
-- 类型 `nil` 无法匹配 `'A'`]])
-end)
-
-TEST [[
----@param v integer
----@return boolean
-local function is_string(v)
- return type(v) == 'string'
-end
-
-print(is_string(3))
-]]
-
-TEST [[
----@class SomeClass
----@field [1] string
--- ...
-
----@param some_param SomeClass|SomeClass[]
-local function some_fn(some_param) return end
-
-some_fn { { "test" } } -- <- diagnostic: "Cannot assign `table` to `string`."
-]]
-
-TEST [[
----@param p integer|string
-local function get_val(p)
- local is_number = type(p) == 'number'
- return is_number and p or p
-end
-
-get_val('hi')
-]]
-
-TESTWITH 'param-type-mismatch' [[
----@class Class
-local Class = {}
-
----@param source string
-function Class.staticCreator(source)
-
-end
-
-Class.staticCreator(<!true!>)
-Class<!:!>staticCreator() -- Expecting a waring
-]]
-
-TESTWITH 'assign-type-mismatch' [[
----@type string[]
-local arr = {
- <!3!>,
-}
-]]
-
-TESTWITH 'assign-type-mismatch' [[
----@type (string|boolean)[]
-local arr2 = {
- <!3!>, -- no warnings
-}
-]]
-
-TEST [[
----@class A
-
----@class B : A
-
----@class C : B
-
----@class D : B
-
----@param x A
-local function func(x) end
-
----@type C|D
-local var
-func(var)
-]]
-
-config.remove(nil, 'Lua.diagnostics.disable', 'unused-local')
-config.remove(nil, 'Lua.diagnostics.disable', 'unused-function')
-config.remove(nil, 'Lua.diagnostics.disable', 'undefined-global')
-config.remove(nil, 'Lua.diagnostics.disable', 'redundant-return')
-config.set(nil, 'Lua.type.castNumberToInteger', true)
diff --git a/test/diagnostics/unbalanced-assignments.lua b/test/diagnostics/unbalanced-assignments.lua
new file mode 100644
index 00000000..a0d47f56
--- /dev/null
+++ b/test/diagnostics/unbalanced-assignments.lua
@@ -0,0 +1,34 @@
+TEST [[
+local x, <!y!>, <!z!> = 1
+]]
+
+TEST [[
+local x, y, <!z!> = 1, 2
+]]
+
+TEST [[
+local x, y, z = print()
+]]
+
+TEST [[
+local x, y, z
+]]
+
+TEST [[
+local x, y, z
+x, <!y!>, <!z!> = 1
+]]
+
+TEST [[
+X, <!Y!>, <!Z!> = 1
+]]
+
+TEST [[
+T = {}
+T.x, <!T.y!>, <!T.z!> = 1
+]]
+
+TEST [[
+T = {}
+T['x'], <!T['y']!>, <!T['z']!> = 1
+]]
diff --git a/test/diagnostics/undefined-doc-class.lua b/test/diagnostics/undefined-doc-class.lua
new file mode 100644
index 00000000..d10b89d8
--- /dev/null
+++ b/test/diagnostics/undefined-doc-class.lua
@@ -0,0 +1,3 @@
+TEST [[
+---@class A : <!B!>
+]]
diff --git a/test/diagnostics/undefined-doc-name.lua b/test/diagnostics/undefined-doc-name.lua
new file mode 100644
index 00000000..9a55108a
--- /dev/null
+++ b/test/diagnostics/undefined-doc-name.lua
@@ -0,0 +1,19 @@
+TEST [[
+---@type <!A!>
+]]
+
+TEST [[
+---@class A
+---@type A|<!B!>|<!C!>
+]]
+
+TEST [[
+---@class AAA
+---@alias B AAA
+
+---@type B
+]]
+
+TEST [[
+---@alias B <!AAA!>
+]]
diff --git a/test/diagnostics/undefined-doc-param.lua b/test/diagnostics/undefined-doc-param.lua
new file mode 100644
index 00000000..7bfbafa5
--- /dev/null
+++ b/test/diagnostics/undefined-doc-param.lua
@@ -0,0 +1,21 @@
+TEST [[
+---@param <!x!> Class
+]]
+
+TEST [[
+---@class Class
+---@param <!y!> Class
+local function f(x)
+ return x
+end
+f()
+]]
+
+TEST [[
+---@class Class
+---@param <!y!> Class
+function F(x)
+ return x
+end
+F()
+]]
diff --git a/test/diagnostics/undefined-env-child.lua b/test/diagnostics/undefined-env-child.lua
new file mode 100644
index 00000000..73904a74
--- /dev/null
+++ b/test/diagnostics/undefined-env-child.lua
@@ -0,0 +1,36 @@
+TEST [[
+---@type iolib
+_ENV = io
+<!print!>(stderr) -- `print` is warning but `stderr` is not
+]]
+
+TEST [[
+---@type iolib
+local _ENV = io
+<!print!>(stderr) -- `print` is warning but `stderr` is not
+]]
+
+TEST [[
+local _ENV = { print = print }
+print(1)
+]]
+
+TEST [[
+_ENV = {}
+GLOBAL = 1 --> _ENV.GLOBAL = 1
+]]
+
+TEST [[
+_ENV = {}
+local _ = print --> local _ = _ENV.print
+]]
+
+TEST [[
+GLOBAL = 1
+_ENV = nil
+]]
+
+TEST [[
+print(1)
+_ENV = nil
+]]
diff --git a/test/diagnostics/undefined-field.lua b/test/diagnostics/undefined-field.lua
new file mode 100644
index 00000000..aff329fb
--- /dev/null
+++ b/test/diagnostics/undefined-field.lua
@@ -0,0 +1,148 @@
+TEST [[
+---@class Foo
+---@field field1 integer
+local mt = {}
+function mt:Constructor()
+ self.field2 = 1
+end
+function mt:method1() return 1 end
+function mt.method2() return 2 end
+
+---@class Bar: Foo
+---@field field4 integer
+local mt2 = {}
+
+---@type Foo
+local v
+print(v.field1 + 1)
+print(v.field2 + 1)
+print(v.<!field3!> + 1)
+print(v:method1())
+print(v.method2())
+print(v:<!method3!>())
+
+---@type Bar
+local v2
+print(v2.field1 + 1)
+print(v2.field2 + 1)
+print(v2.<!field3!> + 1)
+print(v2.field4 + 1)
+print(v2:method1())
+print(v2.method2())
+print(v2:<!method3!>())
+
+local v3 = {}
+print(v3.abc)
+
+---@class Bar2
+local mt3
+function mt3:method() return 1 end
+print(mt3:method())
+]]
+
+-- checkUndefinedField 通过type找到class
+TEST [[
+---@class Foo
+local Foo
+function Foo:method1() end
+
+---@type Foo
+local v
+v:method1()
+v:<!method2!>() -- doc.class.name
+]]
+
+-- checkUndefinedField 通过type找到class,涉及到 class 继承版
+TEST [[
+---@class Foo
+local Foo
+function Foo:method1() end
+---@class Bar: Foo
+local Bar
+function Bar:method3() end
+
+---@type Bar
+local v
+v:method1()
+v:<!method2!>() -- doc.class.name
+v:method3()
+]]
+
+-- checkUndefinedField 类名和类变量同名,类变量被直接使用
+TEST [[
+---@class Foo
+local Foo
+function Foo:method1() end
+Foo:<!method2!>() -- doc.class
+Foo:<!method2!>() -- doc.class
+]]
+
+-- checkUndefinedField 没有@class的不检测
+TEST [[
+local Foo
+function Foo:method1()
+ return Foo:method2() -- table
+end
+]]
+
+-- checkUndefinedField 类名和类变量不同名,类变量被直接使用、使用self
+TEST [[
+---@class Foo
+local mt
+function mt:method1()
+ mt.<!method2!>() -- doc.class
+ self:method1()
+ return self.<!method2!>() -- doc.class.name
+end
+]]
+
+-- checkUndefinedField 当会推导成多个class类型时
+TEST [[
+---@class Foo
+local mt
+function mt:method1() end
+
+---@class Bar
+local mt2
+function mt2:method2() end
+
+---@type Foo
+local v
+---@type Bar
+local v2
+v2 = v
+v2:method1()
+v2:<!method2!>()
+]]
+
+TEST [[
+---@type table
+T1 = {}
+print(T1.f1)
+---@type tablelib
+T2 = {}
+print(T2.<!f2!>)
+]]
+
+TEST [[
+---@type string|table
+local n
+
+print(n.x)
+]]
+
+TEST [[
+---@type 'x'
+local t
+
+local n = t:upper()
+]]
+
+TEST [[
+---@alias A 'x'
+
+---@type A
+local t
+
+local n = t:upper()
+]]
diff --git a/test/diagnostics/undefined-global.lua b/test/diagnostics/undefined-global.lua
new file mode 100644
index 00000000..f5a6396c
--- /dev/null
+++ b/test/diagnostics/undefined-global.lua
@@ -0,0 +1,36 @@
+TEST [[
+local print, _G
+print(<!x!>)
+print(<!log!>)
+print(<!X!>)
+print(<!Log!>)
+print(<!y!>)
+print(Z)
+print(_G)
+Z = 1
+]]
+
+TEST [[
+X = table[<!x!>]
+]]
+TEST [[
+T1 = 1
+_ENV.T2 = 1
+_G.T3 = 1
+_ENV._G.T4 = 1
+_G._G._G.T5 = 1
+rawset(_G, 'T6', 1)
+rawset(_ENV, 'T7', 1)
+print(T1)
+print(T2)
+print(T3)
+print(T4)
+print(T5)
+print(T6)
+print(T7)
+]]
+
+TEST [[
+---@class c
+c = {}
+]]
diff --git a/test/diagnostics/unknown-cast-variable.lua b/test/diagnostics/unknown-cast-variable.lua
new file mode 100644
index 00000000..a347083f
--- /dev/null
+++ b/test/diagnostics/unknown-cast-variable.lua
@@ -0,0 +1,8 @@
+TEST [[
+---@cast <!x!> integer
+]]
+
+TEST [[
+local x, y
+---@cast y number
+]]
diff --git a/test/diagnostics/unknown-diag-code.lua b/test/diagnostics/unknown-diag-code.lua
new file mode 100644
index 00000000..33b41886
--- /dev/null
+++ b/test/diagnostics/unknown-diag-code.lua
@@ -0,0 +1,3 @@
+TEST [[
+---@diagnostic disable-next-line: <!xxx!>
+]]
diff --git a/test/diagnostics/unknown-operator.lua b/test/diagnostics/unknown-operator.lua
new file mode 100644
index 00000000..bb193f6a
--- /dev/null
+++ b/test/diagnostics/unknown-operator.lua
@@ -0,0 +1,4 @@
+TEST [[
+---@class A
+---@operator <!xxx!>: A
+]]
diff --git a/test/diagnostics/unreachable-code.lua b/test/diagnostics/unreachable-code.lua
new file mode 100644
index 00000000..4444252f
--- /dev/null
+++ b/test/diagnostics/unreachable-code.lua
@@ -0,0 +1,71 @@
+TEST [[
+if X then
+ return false
+elseif X then
+ return false
+else
+ return false
+end
+<!return true!>
+]]
+
+TEST [[
+function X()
+ if X then
+ return false
+ elseif X then
+ return false
+ else
+ return false
+ end
+ <!return true!>
+end
+]]
+
+TEST [[
+while true do
+end
+
+<!print(1)!>
+]]
+
+TEST [[
+while true do
+end
+
+<!print(1)!>
+]]
+
+TEST [[
+while X do
+ X = 1
+end
+
+print(1)
+]]
+
+TEST [[
+while true do
+ if not X then
+ break
+ end
+end
+
+print(1)
+
+do return end
+]]
+
+TEST [[
+local done = false
+
+local function set_done()
+ done = true
+end
+
+while not done do
+ set_done()
+end
+
+print(1)
+]]
diff --git a/test/diagnostics/unused-function.lua b/test/diagnostics/unused-function.lua
new file mode 100644
index 00000000..c2cea23a
--- /dev/null
+++ b/test/diagnostics/unused-function.lua
@@ -0,0 +1,48 @@
+TEST [[
+local <!function x()
+end!>
+]]
+
+TEST [[
+local x = <!function () end!>
+]]
+
+TEST [[
+local x
+x = <!function () end!>
+]]
+
+TEST [[
+local <!function x()
+end!>
+local <!function y()
+ x()
+end!>
+]]
+
+TEST [[
+local f = <!function () end!>
+]]
+
+TEST [[
+local f;f = <!function () end!>
+]]
+
+TEST [[
+local <!function f() end!>
+]]
+
+TEST [[
+local <!function f()
+ f()
+end!>
+]]
+
+
+TEST [[
+local <!function test()
+end!>
+
+local <!function foo ()
+end!>
+]]
diff --git a/test/diagnostics/unused-label.lua b/test/diagnostics/unused-label.lua
new file mode 100644
index 00000000..3a89a147
--- /dev/null
+++ b/test/diagnostics/unused-label.lua
@@ -0,0 +1,3 @@
+TEST [[
+::<!LABEL!>::
+]]
diff --git a/test/diagnostics/unused-local.lua b/test/diagnostics/unused-local.lua
new file mode 100644
index 00000000..425f3e1e
--- /dev/null
+++ b/test/diagnostics/unused-local.lua
@@ -0,0 +1,99 @@
+local config = require 'config'
+
+TEST [[
+local <!x!>
+]]
+
+TEST [[
+local y
+local x <close> = y
+]]
+
+TEST [[
+local function x()
+end
+x()
+]]
+
+TEST [[
+return function (x)
+ x.a = 1
+end
+]]
+
+TEST [[
+local <!t!> = {}
+<!t!>.a = 1
+]]
+
+TEST [[
+InstanceName = 1
+Instance = _G[InstanceName]
+]]
+
+TEST [[
+local _ = (''):sub(1, 2)
+]]
+
+TEST [[
+local mt, x
+function mt:m()
+ function x:m()
+ end
+end
+return mt, x
+]]
+
+TEST [[
+local mt = {}
+function mt:f()
+end
+return mt
+]]
+
+TEST [[
+local <!mt!> = {}
+function <!mt!>:f()
+end
+]]
+
+TEST [[
+local <!x!> = {}
+<!x!>.a = 1
+]]
+
+TEST [[
+local <!x!> = {}
+<!x!>['a'] = 1
+]]
+
+TEST [[
+local function f(<!self!>)
+ return 'something'
+end
+f()
+]]
+
+TEST [[
+local function f(var)
+ print(var)
+end
+local var
+f(var)
+]]
+
+TEST [[
+local <!t!> = {}
+<!t!>[1] = 1
+]]
+
+config.add(nil, 'Lua.diagnostics.unusedLocalExclude', 'll_*')
+
+TEST [[
+local <!xx!>
+local ll_1
+local ll_2
+local <!ll!>
+]]
+
+config.remove(nil, 'Lua.diagnostics.unusedLocalExclude', 'll_*')
diff --git a/test/diagnostics/unused-vararg.lua b/test/diagnostics/unused-vararg.lua
new file mode 100644
index 00000000..2bed4aab
--- /dev/null
+++ b/test/diagnostics/unused-vararg.lua
@@ -0,0 +1,6 @@
+TEST [[
+local function f(<!...!>)
+ return 'something'
+end
+f()
+]]