summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2022-04-22 03:18:35 +0800
committer最萌小汐 <sumneko@hotmail.com>2022-04-22 03:18:35 +0800
commit7881d1a3d91b59d2dd8c28a72453e0e6c44a902f (patch)
tree6c2466f3676d813ac9db469815f4af9834d1711a
parentb85ff57a116fb252a0da35e525264e0940af88c7 (diff)
downloadlua-language-server-7881d1a3d91b59d2dd8c28a72453e0e6c44a902f.zip
new diagnostic `missing-parameter`
-rw-r--r--.luarc.json6
-rw-r--r--changelog.md1
-rw-r--r--locale/en-us/script.lua4
-rw-r--r--locale/pt-br/script.lua2
-rw-r--r--locale/zh-cn/script.lua4
-rw-r--r--locale/zh-tw/script.lua2
-rw-r--r--locale/zh-tw/setting.lua1
-rw-r--r--script/core/diagnostics/missing-parameter.lua84
-rw-r--r--script/core/diagnostics/redundant-parameter.lua43
-rw-r--r--script/proto/define.lua2
-rw-r--r--script/vm/node.lua16
-rw-r--r--test/diagnostics/common.lua44
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 [[