summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changelog.md1
-rw-r--r--locale/zh-cn/script.lua4
-rw-r--r--script/core/diagnostics/missing-return-value.lua62
-rw-r--r--script/parser/guide.lua2
-rw-r--r--script/proto/diagnostic.lua1
-rw-r--r--script/vm/function.lua26
-rw-r--r--test/diagnostics/common.lua38
7 files changed, 121 insertions, 13 deletions
diff --git a/changelog.md b/changelog.md
index 21a42be6..844f71d1 100644
--- a/changelog.md
+++ b/changelog.md
@@ -7,6 +7,7 @@
* `param-type-mismatch`
* `unknown-cast-variable`
* `cast-type-mismatch`
+ * `missing-return-value`
* `NEW` settings:
* `diagnostics.groupSeverity`
* `diagnostics.groupFileStatus`
diff --git a/locale/zh-cn/script.lua b/locale/zh-cn/script.lua
index 85ebc44d..ee6ce2b5 100644
--- a/locale/zh-cn/script.lua
+++ b/locale/zh-cn/script.lua
@@ -128,6 +128,10 @@ DIAG_UNKNOWN_CAST_VARIABLE =
'未知的类型转换变量 `{}`。'
DIAG_CAST_TYPE_MISMATCH =
'不能将 `{ref}` 转换为 `{def}`。'
+DIAG_MISSING_RETURN_VALUE =
+'至少需要 {min} 个返回值,但此处只返回 {rmax} 个值。'
+DIAG_MISSING_RETURN_VALUE =
+'至少需要 {min} 个返回值,但此处只返回 {rmin} 到 {rmax} 个值。'
MWS_NOT_SUPPORT =
'{} 目前还不支持多工作目录,我可能需要重启才能支持新的工作目录...'
diff --git a/script/core/diagnostics/missing-return-value.lua b/script/core/diagnostics/missing-return-value.lua
new file mode 100644
index 00000000..491475c7
--- /dev/null
+++ b/script/core/diagnostics/missing-return-value.lua
@@ -0,0 +1,62 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local vm = require 'vm'
+local lang = require 'language'
+
+local function hasDocReturn(func)
+ if not func.bindDocs then
+ return false
+ end
+ for _, doc in ipairs(func.bindDocs) do
+ if doc.type == 'doc.return' then
+ return true
+ end
+ end
+ return false
+end
+
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+
+ guide.eachSourceType(state.ast, 'function', function (source)
+ if not hasDocReturn(source) then
+ return
+ end
+ local min = vm.countReturnsOfFunction(source)
+ if min == 0 then
+ return
+ end
+ local returns = source.returns
+ if not returns then
+ return
+ end
+ for _, ret in ipairs(returns) do
+ local rmin, rmax = vm.countList(ret)
+ if rmax < min then
+ if rmin == rmax then
+ callback {
+ start = ret.start,
+ finish = ret.start + #'return',
+ message = lang.script('DIAG_MISSING_RETURN_VALUE', {
+ min = min,
+ rmax = rmax,
+ }),
+ }
+ else
+ callback {
+ start = ret.start,
+ finish = ret.start + #'return',
+ message = lang.script('DIAG_MISSING_RETURN_VALUE', {
+ min = min,
+ rmin = rmin,
+ rmax = rmax,
+ }),
+ }
+ end
+ end
+ end
+ end)
+end
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 56239fb1..a91a6f68 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -12,7 +12,7 @@ local type = type
---@field tag string
---@field args { [integer]: parser.object, start: integer, finish: integer }
---@field locals parser.object[]
----@field returns parser.object[]
+---@field returns? parser.object[]
---@field exps parser.object[]
---@field keys parser.object[]
---@field uri uri
diff --git a/script/proto/diagnostic.lua b/script/proto/diagnostic.lua
index 59f33693..5972150c 100644
--- a/script/proto/diagnostic.lua
+++ b/script/proto/diagnostic.lua
@@ -58,6 +58,7 @@ m.register {
'unbalanced-assignments',
'redundant-parameter',
'missing-parameter',
+ 'missing-return-value',
} {
group = 'unbalanced',
severity = 'Warning',
diff --git a/script/vm/function.lua b/script/vm/function.lua
index f992845f..8e3662e2 100644
--- a/script/vm/function.lua
+++ b/script/vm/function.lua
@@ -86,24 +86,15 @@ end
function vm.countReturnsOfFunction(func, mark)
if func.type == 'function' then
local min, max
- if func.returns then
- for _, ret in ipairs(func.returns) do
- local rmin, rmax = vm.countList(ret, mark)
- if not min or rmin < min then
- min = rmin
- end
- if not max or rmax > max then
- max = rmax
- end
- end
- end
+ local hasDocReturn
if func.bindDocs then
local lastReturn
local n = 0
local dmin, dmax
for _, doc in ipairs(func.bindDocs) do
if doc.type == 'doc.return' then
- for _, ret in ipairs(doc) do
+ hasDocReturn = true
+ for _, ret in ipairs(doc.returns) do
n = n + 1
lastReturn = ret
dmax = n
@@ -128,6 +119,17 @@ function vm.countReturnsOfFunction(func, mark)
max = dmax
end
end
+ if not hasDocReturn and func.returns then
+ for _, ret in ipairs(func.returns) do
+ local rmin, rmax = vm.countList(ret, mark)
+ if not min or rmin < min then
+ min = rmin
+ end
+ if not max or rmax > max then
+ max = rmax
+ end
+ end
+ end
return min or 0, max or math.huge
end
if func.type == 'doc.type.function' then
diff --git a/test/diagnostics/common.lua b/test/diagnostics/common.lua
index e88fbf43..5e65b410 100644
--- a/test/diagnostics/common.lua
+++ b/test/diagnostics/common.lua
@@ -1704,3 +1704,41 @@ function t:init() end
TEST [[
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
+]]
+
+do return end
+TEST [[
+---@return number
+function F()
+ X = 1<!!>
+end
+]]
+
+TEST [[
+---@return number, number?
+function F()
+ return 1, 1, <!1!>
+end
+]]
+util.arrayRemove(disables, 'redundant-return')