diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-04-23 23:24:23 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-04-23 23:24:23 +0800 |
commit | 3f815c836beb054a13f8d250f6f05a54778b72ba (patch) | |
tree | 04e39933feecbc34cd8ef36c86f838ea8181c635 | |
parent | a7afda10d2ea044a8ea3c83d4656736a6969a101 (diff) | |
download | lua-language-server-3f815c836beb054a13f8d250f6f05a54778b72ba.zip |
new diagnostic: `need-check-nil`
-rw-r--r-- | changelog.md | 1 | ||||
-rw-r--r-- | script/core/diagnostics/need-check-nil.lua | 39 | ||||
-rw-r--r-- | script/proto/define.lua | 16 | ||||
-rw-r--r-- | script/vm/compiler.lua | 3 | ||||
-rw-r--r-- | script/vm/node.lua | 2 | ||||
-rw-r--r-- | script/vm/sign.lua | 2 | ||||
-rw-r--r-- | test/diagnostics/common.lua | 34 |
7 files changed, 86 insertions, 11 deletions
diff --git a/changelog.md b/changelog.md index eb1aaf78..ff2d2c1e 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,7 @@ * `NEW` generic: resolve `T[]` by `table<integer, type>` or `---@field [integer] type` * `NEW` resolve `class[1]` by `---@field [integer] type` * `NEW` diagnostic: `missing-parameter` +* `NEW` diagnostic: `need-check-nil` * `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/script/core/diagnostics/need-check-nil.lua b/script/core/diagnostics/need-check-nil.lua new file mode 100644 index 00000000..8654a7a6 --- /dev/null +++ b/script/core/diagnostics/need-check-nil.lua @@ -0,0 +1,39 @@ +local files = require 'files' +local guide = require 'parser.guide' +local vm = require 'vm' +local lang = require 'language' + +return function (uri, callback) + local state = files.getState(uri) + if not state then + return + end + + guide.eachSourceType(state.ast, 'getlocal', function (src) + local checkNil + local nxt = src.next + if nxt then + if nxt.type == 'getfield' + or nxt.type == 'getmethod' + or nxt.type == 'getindex' + or nxt.type == 'call' then + checkNil = true + end + end + local call = src.parent + if call and call.type == 'call' and call.node == src then + checkNil = true + end + if not checkNil then + return + end + local node = vm.compileNode(src) + if node:hasFalsy() then + callback { + start = src.start, + finish = src.finish, + message = lang.script('DIAG_MISS_NEED_CHECK_NIL'), + } + end + end) +end diff --git a/script/proto/define.lua b/script/proto/define.lua index 9da67039..fb60c56c 100644 --- a/script/proto/define.lua +++ b/script/proto/define.lua @@ -9,10 +9,10 @@ m.DiagnosticSeverity = { } ---@alias DiagnosticDefaultSeverity ----| '"Hint"' ----| '"Information"' ----| '"Warning"' ----| '"Error"' +---| 'Hint' +---| 'Information' +---| 'Warning' +---| 'Error' --- 诊断类型与默认等级 ---@type table<string, DiagnosticDefaultSeverity> @@ -48,6 +48,7 @@ m.DiagnosticDefaultSeverity = { ['await-in-sync'] = 'Warning', ['not-yieldable'] = 'Warning', ['discard-returns'] = 'Warning', + ['need-check-nil'] = 'Warning', ['type-check'] = 'Warning', ['duplicate-doc-alias'] = 'Warning', @@ -64,9 +65,9 @@ m.DiagnosticDefaultSeverity = { } ---@alias DiagnosticDefaultNeededFileStatus ----| '"Any"' ----| '"Opened"' ----| '"None"' +---| 'Any' +---| 'Opened' +---| 'None' -- 文件状态 m.FileStatus = { @@ -108,6 +109,7 @@ m.DiagnosticDefaultNeededFileStatus = { ['await-in-sync'] = 'None', ['not-yieldable'] = 'None', ['discard-returns'] = 'Opened', + ['need-check-nil'] = 'Opened', ['type-check'] = 'None', ['duplicate-doc-alias'] = 'Any', diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index 4917d33a..1f33a784 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -1435,9 +1435,8 @@ local compilerSwitch = util.switch() elseif r1 == false then vm.setNode(source, node1) else - vm.getNode(source):merge(node1) - vm.getNode(source):setTruly() vm.getNode(source):merge(node2) + vm.getNode(source):addOptional() end end if source.op.type == 'or' then diff --git a/script/vm/node.lua b/script/vm/node.lua index d52c2a84..06023ca5 100644 --- a/script/vm/node.lua +++ b/script/vm/node.lua @@ -80,7 +80,7 @@ function mt:isOptional() end ---@return boolean -function mt:isFalsy() +function mt:hasFalsy() if self.optional then return true end diff --git a/script/vm/sign.lua b/script/vm/sign.lua index 78d61022..795916fa 100644 --- a/script/vm/sign.lua +++ b/script/vm/sign.lua @@ -128,7 +128,7 @@ function mt:resolve(uri, args, removeGeneric) local function buildArgNode(argNode, knownTypes) local newArgNode = vm.createNode() for n in argNode:eachObject() do - if argNode:isFalsy() then + if argNode:hasFalsy() then goto CONTINUE end local view = infer.viewObject(n) diff --git a/test/diagnostics/common.lua b/test/diagnostics/common.lua index dca826a1..72b2db6c 100644 --- a/test/diagnostics/common.lua +++ b/test/diagnostics/common.lua @@ -1460,3 +1460,37 @@ 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!>() +]] |