diff options
-rw-r--r-- | .luarc.json | 6 | ||||
-rw-r--r-- | changelog.md | 1 | ||||
-rw-r--r-- | locale/en-us/script.lua | 4 | ||||
-rw-r--r-- | locale/pt-br/script.lua | 2 | ||||
-rw-r--r-- | locale/zh-cn/script.lua | 4 | ||||
-rw-r--r-- | locale/zh-tw/script.lua | 2 | ||||
-rw-r--r-- | locale/zh-tw/setting.lua | 1 | ||||
-rw-r--r-- | script/core/diagnostics/missing-parameter.lua | 84 | ||||
-rw-r--r-- | script/core/diagnostics/redundant-parameter.lua | 43 | ||||
-rw-r--r-- | script/proto/define.lua | 2 | ||||
-rw-r--r-- | script/vm/node.lua | 16 | ||||
-rw-r--r-- | test/diagnostics/common.lua | 44 |
12 files changed, 167 insertions, 42 deletions
diff --git a/.luarc.json b/.luarc.json index 993be427..c0b893a3 100644 --- a/.luarc.json +++ b/.luarc.json @@ -7,7 +7,11 @@ "undefined-field": "Any", "await-in-sync": "Any", "not-yieldable": "Any", - "discard-returns": "Any" + "discard-returns": "Any", + "redundant-parameter": "Any", + "missing-parameter": "Any", + "redundant-value": "Any", + "deprecated": "Any" }, "ignoredFiles": "Opened", "libraryFiles": "Opened" diff --git a/changelog.md b/changelog.md index 667276e2..bb62b8a2 100644 --- a/changelog.md +++ b/changelog.md @@ -23,6 +23,7 @@ local x = true local y = x--[[@as integer]] -- y is `integer` here ``` +* `NEW` diagnostic: `missing-parameter` * `CHG` diagnostic: no longer mark `redundant-parameter` as `Unnecessary` * `FIX` diagnostic: `unused-function` does not recognize recursion * `FIX` [#1051](https://github.com/sumneko/lua-language-server/issues/1051) diff --git a/locale/en-us/script.lua b/locale/en-us/script.lua index a166cf47..f37f53ff 100644 --- a/locale/en-us/script.lua +++ b/locale/en-us/script.lua @@ -33,7 +33,9 @@ DIAG_PREVIOUS_CALL = DIAG_PREFIELD_CALL = 'Will be interpreted as `{}{}`. It may be necessary to add a `,` or `;`.' DIAG_OVER_MAX_ARGS = -'The function takes only {:d} parameters, but you passed {:d}.' +'The function received a maximum of {:d} arguments, but got {:d}.' +DIAG_MISS_ARGS = +'the function received at least {:d} arguments, but got {:d}.' DIAG_OVER_MAX_VALUES = 'Only has {} variables, but you set {} values.' DIAG_AMBIGUITY_1 = diff --git a/locale/pt-br/script.lua b/locale/pt-br/script.lua index 4076c223..a62fefad 100644 --- a/locale/pt-br/script.lua +++ b/locale/pt-br/script.lua @@ -34,6 +34,8 @@ DIAG_PREFIELD_CALL = 'Será interpretado como `{}{}`. Pode ser necessário adicionar uma `,` ou `;`.' DIAG_OVER_MAX_ARGS = 'A função aceita apenas os parâmetros {:d}, mas você passou {:d}.' +DIAG_MISS_ARGS = -- TODO: need translate! +'the function received at least {:d} arguments, but got {:d}.' DIAG_OVER_MAX_VALUES = -- TODO: need translate! 'Only has {} variables, but you set {} values.' DIAG_AMBIGUITY_1 = diff --git a/locale/zh-cn/script.lua b/locale/zh-cn/script.lua index 9c5b5ec7..e38d6d4a 100644 --- a/locale/zh-cn/script.lua +++ b/locale/zh-cn/script.lua @@ -33,7 +33,9 @@ DIAG_PREVIOUS_CALL = DIAG_PREFIELD_CALL = '会被解释为 `{}{}`。你可能需要加一个`,`或`;`。' DIAG_OVER_MAX_ARGS = -'函数只接收 {:d} 个参数,但你传了 {:d} 个。' +'函数最多接收 {:d} 个参数,但获得了 {:d} 个。' +DIAG_MISS_ARGS = +'函数最少接收 {:d} 个参数,但获得了 {:d} 个。' DIAG_OVER_MAX_VALUES = '只有 {} 个变量,但你设置了 {} 个值。' DIAG_AMBIGUITY_1 = diff --git a/locale/zh-tw/script.lua b/locale/zh-tw/script.lua index 887ebd53..a3674bd3 100644 --- a/locale/zh-tw/script.lua +++ b/locale/zh-tw/script.lua @@ -34,6 +34,8 @@ DIAG_PREFIELD_CALL = '會被直譯為 `{}{}`。你可能需要加一個`,`或`;`。' DIAG_OVER_MAX_ARGS = '函式只接收 {:d} 個參數,但你傳了 {:d} 個。' +DIAG_MISS_ARGS = -- TODO: need translate! +'the function received at least {:d} arguments, but got {:d}.' DIAG_OVER_MAX_VALUES = '只有 {} 個變數,但你設定了 {} 個值。' DIAG_AMBIGUITY_1 = diff --git a/locale/zh-tw/setting.lua b/locale/zh-tw/setting.lua index 012304f4..fec64c9e 100644 --- a/locale/zh-tw/setting.lua +++ b/locale/zh-tw/setting.lua @@ -245,4 +245,3 @@ config.diagnostics['empty-block'] = '空程式碼區塊' config.diagnostics['redundant-value'] = '賦值操作時,值的數量比被賦值的對象多' - diff --git a/script/core/diagnostics/missing-parameter.lua b/script/core/diagnostics/missing-parameter.lua new file mode 100644 index 00000000..34cbdab6 --- /dev/null +++ b/script/core/diagnostics/missing-parameter.lua @@ -0,0 +1,84 @@ +local files = require 'files' +local guide = require 'parser.guide' +local vm = require 'vm' +local lang = require 'language' + +local function countCallArgs(source) + local result = 0 + if not source.args then + return 0 + end + result = result + #source.args + return result +end + +---@return integer +local function countFuncArgs(source) + if not source.args or #source.args == 0 then + return 0 + end + local count = 0 + for i = #source.args, 1, -1 do + local arg = source.args[i] + if arg.type ~= '...' + and not vm.compileNode(arg):isNullable() then + return i + end + end + return count +end + +local function getFuncArgs(func) + local funcArgs + local defs = vm.getDefs(func) + for _, def in ipairs(defs) do + if def.type == 'function' + or def.type == 'doc.type.function' then + local args = countFuncArgs(def) + if not funcArgs or args < funcArgs then + funcArgs = args + end + end + end + return funcArgs +end + +return function (uri, callback) + local state = files.getState(uri) + if not state then + return + end + + guide.eachSourceType(state.ast, 'call', function (source) + local callArgs = countCallArgs(source) + if callArgs == 0 then + return + end + + local func = source.node + local funcArgs = getFuncArgs(func) + + if not funcArgs then + return + end + + local delta = callArgs - funcArgs + if delta >= 0 then + return + end + callback { + start = source.start, + finish = source.finish, + } + for i = #source.args - delta + 1, #source.args do + local arg = source.args[i] + if arg then + callback { + start = arg.start, + finish = arg.finish, + message = lang.script('DIAG_MISS_ARGS', funcArgs, callArgs) + } + end + end + end) +end diff --git a/script/core/diagnostics/redundant-parameter.lua b/script/core/diagnostics/redundant-parameter.lua index 564e0810..2f921f3a 100644 --- a/script/core/diagnostics/redundant-parameter.lua +++ b/script/core/diagnostics/redundant-parameter.lua @@ -2,7 +2,6 @@ local files = require 'files' local guide = require 'parser.guide' local vm = require 'vm' local lang = require 'language' -local define = require 'proto.define' local function countCallArgs(source) local result = 0 @@ -14,64 +13,38 @@ local function countCallArgs(source) end local function countFuncArgs(source) - local result = 0 if not source.args or #source.args == 0 then - return result + return 0 end if source.args[#source.args].type == '...' then return math.maxinteger + else + return #source.args end - result = result + #source.args - return result -end - -local function countOverLoadArgs(source, doc) - local result = 0 - local func = doc.overload - if not func.args or #func.args == 0 then - return result - end - if func.args[#func.args].type == '...' then - return math.maxinteger - end - result = result + #func.args - return result end local function getFuncArgs(func) local funcArgs local defs = vm.getDefs(func) for _, def in ipairs(defs) do - if def.value then - def = def.value - end - if def.type == 'function' then + if def.type == 'function' + or def.type == 'doc.type.function' then local args = countFuncArgs(def) if not funcArgs or args > funcArgs then funcArgs = args end - if def.bindDocs then - for _, doc in ipairs(def.bindDocs) do - if doc.type == 'doc.overload' then - args = countOverLoadArgs(def, doc) - if not funcArgs or args > funcArgs then - funcArgs = args - end - end - end - end end end return funcArgs end return function (uri, callback) - local ast = files.getState(uri) - if not ast then + local state = files.getState(uri) + if not state then return end - guide.eachSourceType(ast.ast, 'call', function (source) + guide.eachSourceType(state.ast, 'call', function (source) local callArgs = countCallArgs(source) if callArgs == 0 then return diff --git a/script/proto/define.lua b/script/proto/define.lua index 389cdf88..9da67039 100644 --- a/script/proto/define.lua +++ b/script/proto/define.lua @@ -29,6 +29,7 @@ m.DiagnosticDefaultSeverity = { ['newline-call'] = 'Information', ['newfield-call'] = 'Warning', ['redundant-parameter'] = 'Warning', + ['missing-parameter'] = 'Warning', ['redundant-return'] = 'Warning', ['ambiguity-1'] = 'Warning', ['lowercase-global'] = 'Information', @@ -88,6 +89,7 @@ m.DiagnosticDefaultNeededFileStatus = { ['newline-call'] = 'Any', ['newfield-call'] = 'Any', ['redundant-parameter'] = 'Opened', + ['missing-parameter'] = 'Opened', ['redundant-return'] = 'Opened', ['ambiguity-1'] = 'Any', ['lowercase-global'] = 'Any', diff --git a/script/vm/node.lua b/script/vm/node.lua index 87fcc0c5..92604c3c 100644 --- a/script/vm/node.lua +++ b/script/vm/node.lua @@ -7,6 +7,7 @@ local ws = require 'workspace.workspace' vm.nodeCache = {} ---@class vm.node +---@field [integer] vm.object local mt = {} mt.__index = mt mt.type = 'vm.node' @@ -85,6 +86,7 @@ function mt:isFalsy() end for _, c in ipairs(self) do if c.type == 'nil' + or (c.type == 'global' and c.cate == 'type' and c.name == 'nil') or (c.type == 'boolean' and c[1] == false) or (c.type == 'doc.type.boolean' and c[1] == false) then return true @@ -93,6 +95,20 @@ function mt:isFalsy() return false end +---@return boolean +function mt:isNullable() + if self.optional then + return true + end + for _, c in ipairs(self) do + if c.type == 'nil' + or (c.type == 'global' and c.cate == 'type' and c.name == 'nil') then + return true + end + end + return false +end + ---@return vm.node function mt:copyTruly() local newNode = vm.createNode() diff --git a/test/diagnostics/common.lua b/test/diagnostics/common.lua index e6808784..b8d0bcd8 100644 --- a/test/diagnostics/common.lua +++ b/test/diagnostics/common.lua @@ -163,7 +163,7 @@ print() ]] TEST [[ -pairs +print {} {} ]] @@ -242,6 +242,44 @@ m:x(1, <!2!>, <!3!>, <!4!>) ]] TEST [[ +local function x(a, b) + return a, b +end +<!x(1)!> +]] + +TEST [[ +local function x(a, b, ...) + return a, b, ... +end +x(1, 2) +]] + +TEST [[ +---@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 @@ -1383,13 +1421,13 @@ TEST [[ ]] TEST [[ -return ('1'):gsub() +return ('1'):upper() ]] TEST [[ local value value = '1' -value = value:gsub() +value = value:upper() ]] TEST [[ |