diff options
-rw-r--r-- | .luarc.json | 3 | ||||
-rw-r--r-- | changelog.md | 2 | ||||
-rw-r--r-- | locale/en-us/script.lua | 2 | ||||
-rw-r--r-- | locale/zh-cn/script.lua | 2 | ||||
-rw-r--r-- | meta/template/coroutine.lua | 1 | ||||
-rw-r--r-- | script/core/code-action.lua | 40 | ||||
-rw-r--r-- | script/core/diagnostics/await-in-sync.lua | 26 | ||||
-rw-r--r-- | script/proto/define.lua | 2 | ||||
-rw-r--r-- | test/diagnostics/init.lua | 17 |
9 files changed, 91 insertions, 4 deletions
diff --git a/.luarc.json b/.luarc.json index 2a2fcd2f..a5eed93c 100644 --- a/.luarc.json +++ b/.luarc.json @@ -9,7 +9,8 @@ "close-non-object" ], "neededFileStatus": { - "undefined-field": "Any" + "undefined-field": "Any", + "await-in-sync": "any" }, "ignoredFiles": "Opened", "libraryFiles": "Opened" diff --git a/changelog.md b/changelog.md index 963a236c..ff4a8b19 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,8 @@ * `NEW` file encoding supports `utf16le` and `utf16be` * `NEW` `LuaDoc` annotations: + `---@async`: mark a function as async +* `NEW` diagnostics: + + `await-in-sync`: check if calls async function in sync function. disabled by default. * `CHG` `LuaDoc` supports unicode * `CHG` no longer asks to trust plugin in VSCode, because VSCode already provides the workspace trust feature * `CHG` skip huge files (>= 10 MB) diff --git a/locale/en-us/script.lua b/locale/en-us/script.lua index fde50ae9..eb8c12ee 100644 --- a/locale/en-us/script.lua +++ b/locale/en-us/script.lua @@ -43,6 +43,7 @@ DIAG_IMPLICIT_ANY = 'Can not infer type.' DIAG_DEPRECATED = 'Deprecated.' DIAG_DIFFERENT_REQUIRES = 'The same file is required with different names.' DIAG_REDUNDANT_RETURN = 'Redundant return.' +DIAG_AWAIT_IN_SYNC = 'Async function can only be called in async function.' DIAG_CIRCLE_DOC_CLASS = 'Circularly inherited classes.' DIAG_DOC_FIELD_NO_CLASS = 'The field must be defined after the class.' @@ -191,6 +192,7 @@ ACTION_FIX_INSERT_SPACE = 'Insert space.' ACTION_JSON_TO_LUA = 'Convert JSON to Lua' ACTION_DISABLE_DIAG_LINE= 'Disable diagnostics on this line ({}).' ACTION_DISABLE_DIAG_FILE= 'Disable diagnostics in this file ({}).' +ACTION_MARK_ASYNC = 'Mark current function as async.' COMMAND_DISABLE_DIAG = 'Disable diagnostics' COMMAND_MARK_GLOBAL = 'Mark defined global' diff --git a/locale/zh-cn/script.lua b/locale/zh-cn/script.lua index 120ce765..2843d2b0 100644 --- a/locale/zh-cn/script.lua +++ b/locale/zh-cn/script.lua @@ -43,6 +43,7 @@ DIAG_IMPLICIT_ANY = '无法推测出类型。' DIAG_DEPRECATED = '已废弃。' DIAG_DIFFERENT_REQUIRES = '使用了不同的名字 require 了同一个文件。' DIAG_REDUNDANT_RETURN = '冗余返回。' +DIAG_AWAIT_IN_SYNC = '只能在标记为异步的函数中调用异步函数。' DIAG_CIRCLE_DOC_CLASS = '循环继承的类。' DIAG_DOC_FIELD_NO_CLASS = '字段必须定义在类之后。' @@ -190,6 +191,7 @@ ACTION_FIX_INSERT_SPACE = '插入空格' ACTION_JSON_TO_LUA = '把 JSON 转成 Lua' ACTION_DISABLE_DIAG_LINE= '在此行禁用诊断 ({})。' ACTION_DISABLE_DIAG_FILE= '在此文件禁用诊断 ({})。' +ACTION_MARK_ASYNC = '将当前函数标记为异步。' COMMAND_DISABLE_DIAG = '禁用诊断' COMMAND_MARK_GLOBAL = '标记全局变量' diff --git a/meta/template/coroutine.lua b/meta/template/coroutine.lua index 804c84c6..7d8e2cb2 100644 --- a/meta/template/coroutine.lua +++ b/meta/template/coroutine.lua @@ -55,6 +55,7 @@ function coroutine.status(co) end function coroutine.wrap(f) end ---#DES 'coroutine.yield' +---@async ---@return ... function coroutine.yield(...) end diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 8256107e..ad048c48 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -308,6 +308,44 @@ local function solveTrailingSpace(uri, diag, results) } end +local function solveAwaitInSync(uri, diag, results) + local state = files.getState(uri) + if not state then + return + end + local start, finish = converter.unpackRange(uri, diag.range) + local parentFunction + guide.eachSourceType(state.ast, 'function', function (source) + if source.start > finish + or source.finish < start then + return + end + if not parentFunction or parentFunction.start < source.start then + parentFunction = source + end + end) + if not parentFunction then + return + end + local row = guide.rowColOf(parentFunction.start) + local pos = guide.positionOf(row, 0) + results[#results+1] = { + title = lang.script.ACTION_MARK_ASYNC, + kind = 'quickfix', + edit = { + changes = { + [uri] = { + { + start = pos, + finish = pos, + newText = '---@async\n', + } + } + } + }, + } +end + local function solveDiagnostic(uri, diag, start, results) if diag.source == lang.script.DIAG_SYNTAX_CHECK then solveSyntax(uri, diag, results) @@ -326,6 +364,8 @@ local function solveDiagnostic(uri, diag, start, results) solveAmbiguity1(uri, diag, results) elseif diag.code == 'trailing-space' then solveTrailingSpace(uri, diag, results) + elseif diag.code == 'await-in-sync' then + solveAwaitInSync(uri, diag, results) end disableDiagnostic(uri, diag.code, start, results) end diff --git a/script/core/diagnostics/await-in-sync.lua b/script/core/diagnostics/await-in-sync.lua new file mode 100644 index 00000000..5fb6467d --- /dev/null +++ b/script/core/diagnostics/await-in-sync.lua @@ -0,0 +1,26 @@ +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, 'call', function (source) + local currentFunc = guide.getParentFunction(source) + if currentFunc and vm.isAsync(currentFunc) then + return + end + if not vm.isAsync(source.node, true) then + return + end + callback { + start = source.node.start, + finish = source.node.finish, + message = lang.script('DIAG_AWAIT_IN_SYNC'), + } + end) +end diff --git a/script/proto/define.lua b/script/proto/define.lua index 713857af..2409f972 100644 --- a/script/proto/define.lua +++ b/script/proto/define.lua @@ -44,6 +44,7 @@ m.DiagnosticDefaultSeverity = { ['no-implicit-any'] = 'Information', ['deprecated'] = 'Warning', ['different-requires'] = 'Warning', + ['await-in-sync'] = 'Warning', ['type-check'] = 'Warning', ['duplicate-doc-class'] = 'Warning', @@ -98,6 +99,7 @@ m.DiagnosticDefaultNeededFileStatus = { ['no-implicit-any'] = 'None', ['deprecated'] = 'Opened', ['different-requires'] = 'Any', + ['await-in-sync'] = 'None', ['type-check'] = 'None', ['duplicate-doc-class'] = 'Any', diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua index ab55cd92..6d97c7f6 100644 --- a/test/diagnostics/init.lua +++ b/test/diagnostics/init.lua @@ -6,6 +6,7 @@ local catch = require 'catch' config.get 'Lua.diagnostics.neededFileStatus'['deprecated'] = 'Any' config.get 'Lua.diagnostics.neededFileStatus'['type-check'] = 'Any' +config.get 'Lua.diagnostics.neededFileStatus'['await-in-sync'] = 'Any' rawset(_G, 'TEST', true) @@ -1348,12 +1349,22 @@ end f() ]] ----TODO(arthur) -do return end - TEST [[ ---@type file* local f f:read '*a' f:read('*a') ]] + +TEST [[ +function F() + <!coroutine.yield!>() +end +]] + +TEST [[ +---@async +function F() + coroutine.yield() +end +]] |