diff options
-rw-r--r-- | changelog.md | 1 | ||||
-rw-r--r-- | locale/zh-cn/script.lua | 4 | ||||
-rw-r--r-- | script/core/diagnostics/missing-return-value.lua | 62 | ||||
-rw-r--r-- | script/parser/guide.lua | 2 | ||||
-rw-r--r-- | script/proto/diagnostic.lua | 1 | ||||
-rw-r--r-- | script/vm/function.lua | 26 | ||||
-rw-r--r-- | test/diagnostics/common.lua | 38 |
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') |