diff options
Diffstat (limited to 'script')
27 files changed, 380 insertions, 144 deletions
diff --git a/script/client.lua b/script/client.lua index 4d338016..4d39cd0d 100644 --- a/script/client.lua +++ b/script/client.lua @@ -59,6 +59,23 @@ function m.getAbility(name) return current end +function m.getOffsetEncoding() + if m._offsetEncoding then + return m._offsetEncoding + end + local clientEncodings = m.getAbility 'offsetEncoding' + if type(clientEncodings) == 'table' then + for _, encoding in ipairs(clientEncodings) do + if encoding == 'utf-8' then + m._offsetEncoding = 'utf-8' + return m._offsetEncoding + end + end + end + m._offsetEncoding = 'utf-16' + return m._offsetEncoding +end + local function packMessage(...) local strs = table.pack(...) for i = 1, strs.n do @@ -255,6 +272,7 @@ function m.init(t) m.client(t.clientInfo.name) nonil.disable() lang(LOCALE or t.locale) + converter.setOffsetEncoding(m.getOffsetEncoding()) hookPrint() end diff --git a/script/config/loader.lua b/script/config/loader.lua index 03588634..e754be49 100644 --- a/script/config/loader.lua +++ b/script/config/loader.lua @@ -19,37 +19,43 @@ local m = {} function m.loadRCConfig(filename) local path = workspace.getAbsolutePath(filename) if not path then - return + m.lastRCConfig = nil + return nil end local buf = util.loadFile(path) if not buf then - return + m.lastRCConfig = nil + return nil end local suc, res = pcall(json.decode, buf) if not suc then errorMessage(lang.script('CONFIG_LOAD_ERROR', res)) - return + return m.lastRCConfig end + m.lastRCConfig = res return res end function m.loadLocalConfig(filename) local path = workspace.getAbsolutePath(filename) if not path then - return + m.lastLocalConfig = nil + return nil end local buf = util.loadFile(path) if not buf then errorMessage(lang.script('CONFIG_LOAD_FAILED', path)) - return + m.lastLocalConfig = nil + return nil end local firstChar = buf:match '%S' if firstChar == '{' then local suc, res = pcall(json.decode, buf) if not suc then errorMessage(lang.script('CONFIG_LOAD_ERROR', res)) - return + return m.lastLocalConfig end + m.lastLocalConfig = res return res else local suc, res = pcall(function () @@ -57,8 +63,9 @@ function m.loadLocalConfig(filename) end) if not suc then errorMessage(lang.script('CONFIG_LOAD_ERROR', res)) - return + return m.lastLocalConfig end + m.lastLocalConfig = res return res end end diff --git a/script/core/completion.lua b/script/core/completion.lua index e30c9c91..b7de7578 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -718,7 +718,8 @@ end local function isInString(state, position) return guide.eachSourceContain(state.ast, position, function (source) - if source.type == 'string' then + if source.type == 'string' + and source.start < position then return true end end) @@ -1629,6 +1630,7 @@ local function tryLuaDocCate(word, results) 'diagnostic', 'module', 'async', + 'nodiscard', } do if matchKey(word, docType) then results[#results+1] = { diff --git a/script/core/diagnostics/await-in-sync.lua b/script/core/diagnostics/await-in-sync.lua index bfb4af38..558a5ff0 100644 --- a/script/core/diagnostics/await-in-sync.lua +++ b/script/core/diagnostics/await-in-sync.lua @@ -4,25 +4,27 @@ local vm = require 'vm' local lang = require 'language' local await = require 'await' +---@async return function (uri, callback) local state = files.getState(uri) if not state then return end - guide.eachSourceType(state.ast, 'call', function (source) ---@async + ---@async + guide.eachSourceType(state.ast, 'call', function (source) local currentFunc = guide.getParentFunction(source) if currentFunc and vm.isAsync(currentFunc, false) then return end await.delay() - if not vm.isAsync(source.node, true) then + if vm.isAsyncCall(source) then + callback { + start = source.node.start, + finish = source.node.finish, + message = lang.script('DIAG_AWAIT_IN_SYNC'), + } return end - callback { - start = source.node.start, - finish = source.node.finish, - message = lang.script('DIAG_AWAIT_IN_SYNC'), - } end) end diff --git a/script/core/diagnostics/deprecated.lua b/script/core/diagnostics/deprecated.lua index 7cd9e00f..e9a1fef7 100644 --- a/script/core/diagnostics/deprecated.lua +++ b/script/core/diagnostics/deprecated.lua @@ -8,6 +8,7 @@ local await = require 'await' local noder = require 'core.noder' local types = {'getglobal', 'getfield', 'getindex', 'getmethod'} +---@async return function (uri, callback) local ast = files.getState(uri) if not ast then diff --git a/script/core/diagnostics/discard-returns.lua b/script/core/diagnostics/discard-returns.lua new file mode 100644 index 00000000..cef7ece5 --- /dev/null +++ b/script/core/diagnostics/discard-returns.lua @@ -0,0 +1,29 @@ +local files = require 'files' +local guide = require 'parser.guide' +local vm = require 'vm' +local await = require 'await' +local lang = require 'language' + +---@async +return function (uri, callback) + local state = files.getState(uri) + if not state then + return + end + ---@async + guide.eachSourceType(state.ast, 'call', function (source) + local parent = source.parent + if parent.type ~= 'function' + and parent.type ~= 'main' then + return + end + await.delay() + if vm.isNoDiscard(source.node, true) then + callback { + start = source.start, + finish = source.finish, + message = lang.script('DIAG_DISCARD_RETURNS'), + } + end + end) +end diff --git a/script/core/diagnostics/redundant-value.lua b/script/core/diagnostics/redundant-value.lua index edead570..6f60303b 100644 --- a/script/core/diagnostics/redundant-value.lua +++ b/script/core/diagnostics/redundant-value.lua @@ -4,6 +4,7 @@ local lang = require 'language' local guide = require 'parser.guide' local await = require 'await' +---@async return function (uri, callback) local state = files.getState(uri) if not state then diff --git a/script/core/diagnostics/type-check.lua b/script/core/diagnostics/type-check.lua index 3fa5050c..8728b169 100644 --- a/script/core/diagnostics/type-check.lua +++ b/script/core/diagnostics/type-check.lua @@ -412,6 +412,7 @@ local function matchParams(paramsTypes, i, arg) return false, messages end +---@async return function (uri, callback) local ast = files.getState(uri) if not ast then diff --git a/script/core/diagnostics/undefined-field.lua b/script/core/diagnostics/undefined-field.lua index 66b1f8c5..2e64f0cc 100644 --- a/script/core/diagnostics/undefined-field.lua +++ b/script/core/diagnostics/undefined-field.lua @@ -18,6 +18,7 @@ local SkipCheckClass = { ['lightuserdata'] = true, } +---@async return function (uri, callback) local ast = files.getState(uri) if not ast then diff --git a/script/core/diagnostics/undefined-global.lua b/script/core/diagnostics/undefined-global.lua index 640f521b..48c8a226 100644 --- a/script/core/diagnostics/undefined-global.lua +++ b/script/core/diagnostics/undefined-global.lua @@ -14,6 +14,7 @@ local requireLike = { ['load'] = true, } +---@async return function (uri, callback) local ast = files.getState(uri) if not ast then diff --git a/script/core/diagnostics/unused-function.lua b/script/core/diagnostics/unused-function.lua index ada4a23d..0e0c0003 100644 --- a/script/core/diagnostics/unused-function.lua +++ b/script/core/diagnostics/unused-function.lua @@ -18,6 +18,7 @@ local function isToBeClosed(source) return false end +---@async return function (uri, callback) local ast = files.getState(uri) if not ast then diff --git a/script/core/document-symbol.lua b/script/core/document-symbol.lua index 00299867..07794e60 100644 --- a/script/core/document-symbol.lua +++ b/script/core/document-symbol.lua @@ -235,6 +235,7 @@ local function buildSource(source, text, used, symbols) end end +---@async local function makeSymbol(uri) local ast = files.getState(uri) local text = files.getText(uri) diff --git a/script/core/hint.lua b/script/core/hint.lua index e094fc51..42390443 100644 --- a/script/core/hint.lua +++ b/script/core/hint.lua @@ -6,6 +6,7 @@ local guide = require 'parser.guide' local await = require 'await' local define = require 'proto.define' +---@async local function typeHint(uri, results, start, finish) local state = files.getState(uri) if not state then @@ -96,6 +97,7 @@ local function hasLiteralArgInCall(call) return false end +---@async local function paramName(uri, results, start, finish) local paramConfig = config.get 'Lua.hint.paramName' if not paramConfig or paramConfig == 'None' then @@ -158,6 +160,7 @@ local function paramName(uri, results, start, finish) end) end +---@async local function awaitHint(uri, results, start, finish) local awaitConfig = config.get 'Lua.hint.await' if not awaitConfig then @@ -173,7 +176,7 @@ local function awaitHint(uri, results, start, finish) end await.delay() local node = source.node - if not vm.isAsync(node, true) then + if not vm.isAsyncCall(source) then return end results[#results+1] = { @@ -185,6 +188,7 @@ local function awaitHint(uri, results, start, finish) end) end +---@async return function (uri, start, finish) local results = {} typeHint(uri, results, start, finish) diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua index aef28aa6..8389cbb4 100644 --- a/script/core/semantic-tokens.lua +++ b/script/core/semantic-tokens.lua @@ -373,6 +373,7 @@ config.watch(function (key, value) end end) +---@async return function (uri, start, finish) local state = files.getState(uri) local text = files.getText(uri) diff --git a/script/encoder/ansi.lua b/script/encoder/ansi.lua index 1016e668..f5273c51 100644 --- a/script/encoder/ansi.lua +++ b/script/encoder/ansi.lua @@ -7,14 +7,14 @@ end local m = {} -function m.decode(text) +function m.toutf8(text) if not unicode then return text end return unicode.a2u(text) end -function m.encode(text) +function m.fromutf8(text) if not unicode then return text end diff --git a/script/encoder/init.lua b/script/encoder/init.lua index d7753c1f..0011265a 100644 --- a/script/encoder/init.lua +++ b/script/encoder/init.lua @@ -1,6 +1,7 @@ local ansi = require 'encoder.ansi' -local utf16le = require 'encoder.utf16le' -local utf16be = require 'encoder.utf16be' +local utf16 = require 'encoder.utf16' +local utf16le = utf16('le', utf8.codepoint '�') +local utf16be = utf16('be', utf8.codepoint '�') ---@alias encoder.encoding '"utf8"'|'"utf16"'|'"utf16le"'|'"utf16be"' @@ -17,11 +18,11 @@ function m.len(encoding, s, i, j) j = j or #s if encoding == 'utf16' or encoding == 'utf16' then - local us = utf16le.encode(s:sub(i, j)) + local us = utf16le.fromutf8(s:sub(i, j)) return #us // 2 end if encoding == 'utf16be' then - local us = utf16be.encode(s:sub(i, j)) + local us = utf16be.fromutf8(s:sub(i, j)) return #us // 2 end if encoding == 'utf8' then @@ -43,8 +44,8 @@ function m.offset(encoding, s, n, i) if not line:find '[\x80-\xff]' then return n + i - 1 end - local us = utf16le.encode(line) - local os = utf16le.decode(us:sub(1, n * 2 - 2)) + local us = utf16le.fromutf8(line) + local os = utf16le.toutf8(us:sub(1, n * 2 - 2)) return #os + i end if encoding == 'utf16be' then @@ -52,8 +53,8 @@ function m.offset(encoding, s, n, i) if not line:find '[\x80-\xff]' then return n + i - 1 end - local us = utf16be.encode(line) - local os = utf16be.decode(us:sub(1, n * 2 - 2)) + local us = utf16be.fromutf8(line) + local os = utf16be.toutf8(us:sub(1, n * 2 - 2)) return #os + i end if encoding == 'utf8' then @@ -75,11 +76,11 @@ function m.encode(encoding, text, bom) return text end if encoding == 'ansi' then - return ansi.encode(text) + return ansi.fromutf8(text) end if encoding == 'utf16' or encoding == 'utf16le' then - text = utf16le.encode(text) + text = utf16le.fromutf8(text) if bom == 'yes' or bom == 'auto' then text = '\xFF\xFE' .. text @@ -87,7 +88,7 @@ function m.encode(encoding, text, bom) return text end if encoding == 'utf16be' then - text = utf16be.encode(text) + text = utf16be.fromutf8(text) if bom == 'yes' or bom == 'auto' then text = '\xFE\xFF' .. text @@ -106,14 +107,14 @@ function m.decode(encoding, text) return text end if encoding == 'ansi' then - return ansi.decode(text) + return ansi.toutf8(text) end if encoding == 'utf16' or encoding == 'utf16le' then - return utf16le.decode(text) + return utf16le.toutf8(text) end if encoding == 'utf16be' then - return utf16be.decode(text) + return utf16be.toutf8(text) end log.error('Unsupport encode encoding:', encoding) return text diff --git a/script/encoder/utf16.lua b/script/encoder/utf16.lua new file mode 100644 index 00000000..9e71de68 --- /dev/null +++ b/script/encoder/utf16.lua @@ -0,0 +1,147 @@ +local error = error +local strchar = string.char +local strbyte = string.byte +local strmatch = string.match +local utf8char = utf8.char +local tconcat = table.concat + +local function be_tochar(code) + return strchar((code >> 8) & 0xFF, code & 0xFF) +end + +local function be_tobyte(s, i) + local h, l = strbyte(s, i, i+1) + return (h << 8) | l +end + +local function le_tochar(code) + return strchar(code & 0xFF, (code >> 8) & 0xFF) +end + +local function le_tobyte(s, i) + local l, h = strbyte(s, i, i+1) + return (h << 8) | l +end + +local function utf16char(tochar, code) + if code < 0x10000 then + return tochar(code) + else + code = code - 0x10000 + return tochar(0xD800 + (code >> 10))..tochar(0xDC00 + (code & 0x3FF)) + end +end + +local function utf16next(s, n, tobyte) + if n > #s then + return + end + local code1 = tobyte(s, n) + if code1 < 0xD800 or code1 >= 0xE000 then + return n+2, code1 + elseif code1 >= 0xD800 and code1 < 0xDC00 then + n = n + 2 + if n > #s then + return n --invaild + end + local code2 = tobyte(s, n) + if code2 < 0xDC00 or code2 >= 0xE000 then + return n --invaild + end + local code = 0x10000 + ((code1 - 0xD800) << 10) + ((code2 - 0xDC00) & 0x3FF) + return n+2, code + else + return n+2 --invaild + end +end + +local function utf16codes(s, tobyte) + return function (_, n) + return utf16next(s, n, tobyte) + end, s, 1 +end + +local _utf8byte = utf8.codes "" +local function utf8byte(s, n) + local _, code = _utf8byte(s, n-1) + return code +end + +--[[ + U+0000.. U+007F 00..7F + U+0080.. U+07FF C2..DF 80..BF + U+0800.. U+0FFF E0 A0..BF 80..BF + U+1000.. U+CFFF E1..EC 80..BF 80..BF + U+D000.. U+D7FF ED 80..9F 80..BF + U+E000.. U+FFFF EE..EF 80..BF 80..BF + U+10000.. U+3FFFF F0 90..BF 80..BF 80..BF + U+40000.. U+FFFFF F1..F3 80..BF 80..BF 80..BF +U+100000..U+10FFFF F4 80..8F 80..BF 80..BF +]] +local function utf8next(s, n) + if n > #s then + return + end + if strmatch(s, "^[\0-\x7F]", n) then + return n+1, utf8byte(s, n) + elseif strmatch(s, "^[\xC2-\xDF][\x80-\xBF]", n) then + return n+2, utf8byte(s, n) + elseif strmatch(s, "^[\xE0-\xEF][\x80-\xBF][\x80-\xBF]", n) then + return n+3, utf8byte(s, n) + elseif strmatch(s, "^[\xF0-\xF4][\x80-\xBF][\x80-\xBF][\x80-\xBF]", n) then + return n+4, utf8byte(s, n) + else + return n+1 --invaild + end +end + +local function utf8codes(s) + return utf8next, s, 1 +end + +return function (what, replace) + local tobyte, tochar + if what == "be" then + tobyte = be_tobyte + tochar = be_tochar + else + tobyte = le_tobyte + tochar = le_tochar + end + local utf8replace = replace and utf8char(replace) + local utf16replace = replace and utf16char(tochar, replace) + local function toutf8(s) + local r = {} + for _, code in utf16codes(s, tobyte) do + if code == nil then + if replace then + r[#r+1] = utf8replace + else + error "invalid UTF-16 code" + end + else + r[#r+1] = utf8char(code) + end + end + return tconcat(r) + end + local function fromutf8(s) + local r = {} + for _, code in utf8codes(s) do + if code == nil then + if replace then + r[#r+1] = utf16replace + else + error "invalid UTF-8 code" + end + else + r[#r+1] = utf16char(tochar, code) + end + end + return tconcat(r) + end + return { + toutf8 = toutf8, + fromutf8 = fromutf8, + } +end diff --git a/script/encoder/utf16be.lua b/script/encoder/utf16be.lua deleted file mode 100644 index 5fc19b2c..00000000 --- a/script/encoder/utf16be.lua +++ /dev/null @@ -1,46 +0,0 @@ -local function tochar(code) - return string.char((code >> 8) & 0xFF, code & 0xFF) -end - -local function tobyte(s, i) - local h, l = string.byte(s, i, i+1) - return (h << 8) | l -end - -local function char(code) - if code <= 0xFFFF then - return tochar(code) - end - code = code - 0x10000 - return tochar(0xD800 + (code >> 10))..tochar(0xDC00 + (code & 0x3FF)) -end - -local m = {} - -function m.encode(s) - local r = {} - for _, c in utf8.codes(s, true) do - r[#r+1] = char(c) - end - return table.concat(r) -end - -function m.decode(s) - local r = {} - local i = 1 - while i < #s do - local code1 = tobyte(s, i) - if code1 >= 0xD800 and code1 < 0xE000 then - i = i + 2 - local code2 = tobyte(s, i) - local code = 0x10000 + ((code1 - 0xD800) << 10) + ((code2 - 0xDC00) & 0x3FF) - r[#r+1] = utf8.char(code) - else - r[#r+1] = utf8.char(code1) - end - i = i + 2 - end - return table.concat(r) -end - -return m diff --git a/script/encoder/utf16le.lua b/script/encoder/utf16le.lua deleted file mode 100644 index d51b4cfb..00000000 --- a/script/encoder/utf16le.lua +++ /dev/null @@ -1,46 +0,0 @@ -local function tochar(code) - return string.char(code & 0xFF, (code >> 8) & 0xFF) -end - -local function tobyte(s, i) - local l, h = string.byte(s, i, i+1) - return (h << 8) | l -end - -local function char(code) - if code <= 0xFFFF then - return tochar(code) - end - code = code - 0x10000 - return tochar(0xD800 + (code >> 10))..tochar(0xDC00 + (code & 0x3FF)) -end - -local m = {} - -function m.encode(s) - local r = {} - for _, c in utf8.codes(s, true) do - r[#r+1] = char(c) - end - return table.concat(r) -end - -function m.decode(s) - local r = {} - local i = 1 - while i < #s do - local code1 = tobyte(s, i) - if code1 >= 0xD800 and code1 < 0xE000 then - i = i + 2 - local code2 = tobyte(s, i) - local code = 0x10000 + ((code1 - 0xD800) << 10) + ((code2 - 0xDC00) & 0x3FF) - r[#r+1] = utf8.char(code) - else - r[#r+1] = utf8.char(code1) - end - i = i + 2 - end - return table.concat(r) -end - -return m diff --git a/script/files.lua b/script/files.lua index 9b22ea41..eca3d58d 100644 --- a/script/files.lua +++ b/script/files.lua @@ -120,7 +120,9 @@ end --- 设置文件文本 ---@param uri uri ---@param text string -function m.setText(uri, text, isTrust) +---@param isTrust boolean +---@param version integer +function m.setText(uri, text, isTrust, version) if not text then return end @@ -134,7 +136,6 @@ function m.setText(uri, text, isTrust) if not m.fileMap[uri] then m.fileMap[uri] = { uri = uri, - version = 0, } m.fileCount = m.fileCount + 1 create = true @@ -159,7 +160,7 @@ function m.setText(uri, text, isTrust) m.astMap[uri] = nil file.cache = {} file.cacheActiveTime = math.huge - file.version = file.version + 1 + file.version = version m.globalVersion = m.globalVersion + 1 await.close('files.version') m.onWatch('version') diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 6f7593c1..c332d4c0 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -1119,6 +1119,14 @@ local function parseAsync() } end +local function parseNoDiscard() + return { + type = 'doc.nodiscard', + start = getFinish(), + finish = getFinish(), + } +end + local function convertTokens() local tp, text = nextToken() if not tp then @@ -1164,6 +1172,8 @@ local function convertTokens() return parseModule() elseif text == 'async' then return parseAsync() + elseif text == 'nodiscard' then + return parseNoDiscard() end end diff --git a/script/proto/converter.lua b/script/proto/converter.lua index cf6331f1..9c75f056 100644 --- a/script/proto/converter.lua +++ b/script/proto/converter.lua @@ -2,7 +2,6 @@ local guide = require 'parser.guide' local files = require 'files' local encoder = require 'encoder' --- TODO local offsetEncoding = 'utf16' local m = {} @@ -178,4 +177,8 @@ function m.textEdit(range, newtext) } end +function m.setOffsetEncoding(encoding) + offsetEncoding = encoding:lower():gsub('%-', '') +end + return m diff --git a/script/proto/define.lua b/script/proto/define.lua index e4216be1..dbb6ba85 100644 --- a/script/proto/define.lua +++ b/script/proto/define.lua @@ -46,6 +46,7 @@ m.DiagnosticDefaultSeverity = { ['different-requires'] = 'Warning', ['await-in-sync'] = 'Warning', ['not-yieldable'] = 'Warning', + ['discard-returns'] = 'Warning', ['type-check'] = 'Warning', ['duplicate-doc-class'] = 'Warning', @@ -102,6 +103,7 @@ m.DiagnosticDefaultNeededFileStatus = { ['different-requires'] = 'Any', ['await-in-sync'] = 'None', ['not-yieldable'] = 'None', + ['discard-returns'] = 'Opened', ['type-check'] = 'None', ['duplicate-doc-class'] = 'Any', diff --git a/script/provider/capability.lua b/script/provider/capability.lua index 76cadc0d..b712defc 100644 --- a/script/provider/capability.lua +++ b/script/provider/capability.lua @@ -48,6 +48,7 @@ end function m.getIniter() local initer = { + offsetEncoding = client.getOffsetEncoding(), -- 文本同步方式 textDocumentSync = { -- 打开关闭文本时通知 diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua index 34bb10d4..c8d6c211 100644 --- a/script/provider/diagnostic.lua +++ b/script/provider/diagnostic.lua @@ -216,6 +216,8 @@ function m.doDiagnostic(uri) return end + local version = files.getVersion(uri) + await.setID('diag:' .. uri) local prog <close> = progress.create(lang.script.WINDOW_DIAGNOSING, 0.5) @@ -239,6 +241,7 @@ function m.doDiagnostic(uri) proto.notify('textDocument/publishDiagnostics', { uri = uri, + version = version, diagnostics = full, }) if #full > 0 then diff --git a/script/provider/provider.lua b/script/provider/provider.lua index 811dc4e0..36752d88 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -185,7 +185,7 @@ proto.on('textDocument/didChange', function (params) ---@async local uri = doc.uri --log.debug('changes', util.dump(changes)) local text = tm(uri, changes) - files.setText(uri, text, true) + files.setText(uri, text, true, doc.version) end) proto.on('textDocument/hover', function (params) ---@async @@ -834,14 +834,14 @@ do if not config.get 'Lua.hint.enable' then return end - await.close 'updateHint' - await.setID 'updateHint' - await.delay() - workspace.awaitReady() local visibles = files.getVisibles(uri) if not visibles then return end + await.close 'updateHint' + await.setID 'updateHint' + await.delay() + workspace.awaitReady() local edits = {} local hint = require 'core.hint' local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_HINT, 0.5) diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua index ed2299ec..f5c4e4e1 100644 --- a/script/vm/getDocs.lua +++ b/script/vm/getDocs.lua @@ -163,6 +163,23 @@ local function isDeprecated(value) return false end +function vm.isDeprecated(value, deep) + if deep then + local defs = vm.getDefs(value) + if #defs == 0 then + return false + end + for _, def in ipairs(defs) do + if not isDeprecated(def) then + return false + end + end + return true + else + return isDeprecated(value) + end +end + local function isAsync(value) if value.type == 'function' then if not value.bindDocs then @@ -183,38 +200,111 @@ local function isAsync(value) return value.async == true end -function vm.isDeprecated(value, deep) +function vm.isAsync(value, deep) + if isAsync(value) then + return true + end if deep then local defs = vm.getDefs(value) if #defs == 0 then return false end for _, def in ipairs(defs) do - if not isDeprecated(def) then - return false + if isAsync(def) then + return true end end - return true - else - return isDeprecated(value) end + return false end -function vm.isAsync(value, deep) +local function isNoDiscard(value) + if value.type == 'function' then + if not value.bindDocs then + return false + end + if value._nodiscard ~= nil then + return value._nodiscard + end + for _, doc in ipairs(value.bindDocs) do + if doc.type == 'doc.nodiscard' then + value._nodiscard = true + return true + end + end + value._nodiscard = false + return false + end + return false +end + +function vm.isNoDiscard(value, deep) + if isNoDiscard(value) then + return true + end if deep then local defs = vm.getDefs(value) if #defs == 0 then return false end for _, def in ipairs(defs) do - if isAsync(def) then + if isNoDiscard(def) then return true end end - return false - else - return isAsync(value) end + return false +end + +local function isCalledInFunction(param) + local func = guide.getParentFunction(param) + for _, ref in ipairs(param.ref) do + if ref.type == 'getlocal' then + if ref.parent.type == 'call' + and guide.getParentFunction(ref) == func then + return true + end + if ref.parent.type == 'callargs' + and ref.parent[1] == ref + and guide.getParentFunction(ref) == func then + if ref.parent.parent.node.special == 'pcall' + or ref.parent.parent.node.special == 'xpcall' then + return true + end + end + end + end + return false +end + +local function isLinkedCall(node, index) + for _, def in ipairs(vm.getDefs(node)) do + if def.type == 'function' then + local param = def.args and def.args[index] + if param then + if isCalledInFunction(param) then + return true + end + end + end + end + return false +end + +function vm.isAsyncCall(call) + if vm.isAsync(call.node, true) then + return true + end + if not call.args then + return + end + for i, arg in ipairs(call.args) do + if vm.isAsync(arg, true) + and isLinkedCall(call.node, i) then + return true + end + end + return false end local function makeDiagRange(uri, doc, results) |