From d8c334415c9cc1d434256c04aab25b7958eeff29 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 01:21:31 +1300 Subject: [PATCH 01/16] feat(diagnostics): add missing-export-doc minimal implementation --- locale/en-us/setting.lua | 2 + .../core/diagnostics/missing-export-doc.lua | 31 ++++ script/proto/diagnostic.lua | 1 + test/diagnostics/init.lua | 1 + test/diagnostics/missing-export-doc.lua | 175 ++++++++++++++++++ 5 files changed, 210 insertions(+) create mode 100644 script/core/diagnostics/missing-export-doc.lua create mode 100644 test/diagnostics/missing-export-doc.lua diff --git a/locale/en-us/setting.lua b/locale/en-us/setting.lua index 0c136333a..ec0a7d0c6 100644 --- a/locale/en-us/setting.lua +++ b/locale/en-us/setting.lua @@ -413,6 +413,8 @@ config.diagnostics['missing-global-doc'] = 'Missing annotations for globals! Global functions must have a comment and annotations for all parameters and return values.' config.diagnostics['missing-local-export-doc'] = 'Missing annotations for exported locals! Exported local functions must have a comment and annotations for all parameters and return values.' +config.diagnostics['missing-export-doc'] = +'Missing annotations for exported locals! Exported local functions must have a comment and annotations for all parameters and return values.' config.diagnostics['missing-parameter'] = 'Enable diagnostics for function calls where the number of arguments is less than the number of annotated function parameters.' config.diagnostics['missing-return'] = diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua new file mode 100644 index 000000000..3f705ff2c --- /dev/null +++ b/script/core/diagnostics/missing-export-doc.lua @@ -0,0 +1,31 @@ +local files = require 'files' +local guide = require 'parser.guide' +local await = require 'await' +local helper = require 'core.diagnostics.helper.missing-doc-helper' + +---@async +return function (uri, callback) + local state = files.getState(uri) + + if not state then + return + end + + if not state.ast then + return + end + + ---@async + guide.eachSourceType(state.ast, 'setfield', function (source) + await.delay() + helper.CheckFunction(source.value, callback, 'DIAG_MISSING_GLOBAL_DOC_COMMENT', 'DIAG_MISSING_GLOBAL_DOC_PARAM', + 'DIAG_MISSING_GLOBAL_DOC_RETURN') + end) + + ---@async + guide.eachSourceType(state.ast, 'setmethod', function (source) + await.delay() + helper.CheckFunction(source.method, callback, 'DIAG_MISSING_GLOBAL_DOC_COMMENT', 'DIAG_MISSING_GLOBAL_DOC_PARAM', + 'DIAG_MISSING_GLOBAL_DOC_RETURN') + end) +end diff --git a/script/proto/diagnostic.lua b/script/proto/diagnostic.lua index 72761493e..d2493f3ea 100644 --- a/script/proto/diagnostic.lua +++ b/script/proto/diagnostic.lua @@ -107,6 +107,7 @@ m.register { 'incomplete-signature-doc', 'missing-global-doc', 'missing-local-export-doc', + 'missing-export-doc', } { group = 'luadoc', severity = 'Warning', diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua index fc97e4389..0e84d6dd7 100644 --- a/test/diagnostics/init.lua +++ b/test/diagnostics/init.lua @@ -102,6 +102,7 @@ check 'lowercase-global' check 'missing-fields' check 'missing-global-doc' check 'missing-local-export-doc' +check 'missing-export-doc' check 'missing-parameter' check 'missing-return-value' check 'missing-return' diff --git a/test/diagnostics/missing-export-doc.lua b/test/diagnostics/missing-export-doc.lua new file mode 100644 index 000000000..3d9422161 --- /dev/null +++ b/test/diagnostics/missing-export-doc.lua @@ -0,0 +1,175 @@ +-- check global functions +TEST [[ +local mod = {} + +local + +---comment +local function fl1() +end + +local function fl2() +end + +function FG0() +end + +mod.fl0 = fl0 +mod.fl1 = fl1 +return mod +]] + +TEST [[ +local mod = {} + +local function flp0() + print(p) +end + +---comment +local function flp1() + print(p) +end + +---comment +---@param p any +local function flp2(p) + print(p) +end + +mod.flp0 = flp0 +mod.flp1 = flp1 +return mod +]] + +TEST [[ +local mod = {} + +local function flpp0(, ) + print(p0, p1) +end + +---comment +local function flpp1(, ) + print(p0, p1) +end + +---comment +---@param p0 any +local function flpp2(p0, ) + print(p0, p1) +end + +---comment +---@param p0 any +---@param p1 any +local function flpp3(p0, p1) + print(p0, p1) +end + +mod.flpp0 = flpp0 +mod.flpp1 = flpp1 +mod.flpp2 = flpp2 +mod.flpp3 = flpp3 +return mod +]] + +TEST [[ +local mod = {} + +local function flr0() + return +end + +---comment +local function flr1() + return +end + +---comment +---@return integer +local function flr2() + return 0 +end + +mod.flr0 = flr0 +mod.flr1 = flr1 +mod.flr2 = flr2 +return mod +]] + +TEST [[ +local mod = {} + +local function flrr0() + return , +end + +---comment +local function flrr1() + return , +end + +---comment +---@return integer +local function flrr2() + return 0, +end + +---comment +---@return integer +---@return integer +local function flrr3() + return 0, 1 +end + +mod.flrr0 = flrr0 +mod.flrr1 = flrr1 +mod.flrr2 = flrr2 +return mod +]] + +TEST [[ +local mod = {} + +local function flpr0() + print(p) + return +end + +---comment +local function flpr1() + print(p) + return +end + +---comment +---@param p any +local function flpr2(p) + print(p) + return +end + +---comment +---@return integer +local function flpr3() + print(p) + return 0 +end + +---comment +---@param p any +---@return integer +local function flpr4(p) + print(p) + return 0 +end + +mod.flpr0 = flpr0 +mod.flpr1 = flpr1 +mod.flpr2 = flpr2 +mod.flpr3 = flpr3 +mod.flpr4 = flpr4 +return mod +]] From af9892d865934e975ad21b8b4c50e7766c8d04d5 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 02:15:45 +1300 Subject: [PATCH 02/16] feat(diagnostics): add translations for missing-export-doc messages --- locale/en-us/script.lua | 12 +++++++++ .../diagnostics/helper/missing-doc-helper.lua | 26 +++++++++++++++++-- .../core/diagnostics/missing-export-doc.lua | 10 ++++--- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/locale/en-us/script.lua b/locale/en-us/script.lua index f8a38b9ab..13fe68856 100644 --- a/locale/en-us/script.lua +++ b/locale/en-us/script.lua @@ -130,6 +130,18 @@ DIAG_MISSING_LOCAL_EXPORT_DOC_COMMENT = 'Missing comment for exported local function `{}`.' DIAG_MISSING_LOCAL_EXPORT_DOC_PARAM = 'Missing @param annotation for parameter `{}` in exported local function `{}`.' +DIAG_MISSING_EXPORTED_METHOD_DOC_RETURN = +'Missing @return annotation at index `{}` in exported method `{}`.' +DIAG_MISSING_EXPORTED_METHOD_DOC_COMMENT = +'Missing comment for exported method `{}`.' +DIAG_MISSING_EXPORTED_METHOD_DOC_PARAM = +'Missing @param annotation for parameter `{}` in exported method `{}`.' +DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN = +'Missing @return annotation at index `{}` in exported field `{}`.' +DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT = +'Missing comment for exported field `{}`.' +DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM = +'Missing @param annotation for parameter `{}` in exported field `{}`.' DIAG_MISSING_LOCAL_EXPORT_DOC_RETURN = 'Missing @return annotation at index `{}` in exported local function `{}`.' DIAG_INCOMPLETE_SIGNATURE_DOC_PARAM = diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index 116173f2d..20e529678 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -36,8 +36,13 @@ local function findReturn(docs, index) return false end -local function checkFunction(source, callback, commentId, paramId, returnId) - local functionName = source.parent[1] +---@param functionName string +---@param source parser.object +---@param callback fun(result: any) +---@param commentId string +---@param paramId string +---@param returnId string +local function checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) local argCount = source.args and #source.args or 0 if argCount == 0 and not source.returns and not source.bindDocs then @@ -79,5 +84,22 @@ local function checkFunction(source, callback, commentId, paramId, returnId) end end +---@param source parser.object +---@param callback fun(result: any) +---@param commentId string +---@param paramId string +---@param returnId string +local function checkFunction(source, callback, commentId, paramId, returnId) + local functionName = source.parent[1] + checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) +end + +local function checkMethod(source, callback, commentId, paramId, returnId) + local functionName = source[1] + checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) +end + m.CheckFunction = checkFunction +m.CheckFunctionNamed = checkFunctionNamed +m.CheckMethod = checkMethod return m diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua index 3f705ff2c..13557190a 100644 --- a/script/core/diagnostics/missing-export-doc.lua +++ b/script/core/diagnostics/missing-export-doc.lua @@ -18,14 +18,16 @@ return function (uri, callback) ---@async guide.eachSourceType(state.ast, 'setfield', function (source) await.delay() - helper.CheckFunction(source.value, callback, 'DIAG_MISSING_GLOBAL_DOC_COMMENT', 'DIAG_MISSING_GLOBAL_DOC_PARAM', - 'DIAG_MISSING_GLOBAL_DOC_RETURN') + helper.CheckFunctionNamed(source.field[1], source.value, callback, 'DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT', + 'DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM', + 'DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN') end) ---@async guide.eachSourceType(state.ast, 'setmethod', function (source) await.delay() - helper.CheckFunction(source.method, callback, 'DIAG_MISSING_GLOBAL_DOC_COMMENT', 'DIAG_MISSING_GLOBAL_DOC_PARAM', - 'DIAG_MISSING_GLOBAL_DOC_RETURN') + helper.CheckMethod(source.method, callback, 'DIAG_MISSING_EXPORTED_METHOD_DOC_COMMENT', + 'DIAG_MISSING_EXPORTED_METHOD_DOC_PARAM', + 'DIAG_MISSING_EXPORTED_METHOD_DOC_RETURN') end) end From 9e4659dd85a20313269ef17ea8d18c9c12d380b3 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 02:22:46 +1300 Subject: [PATCH 03/16] test(diagnostics): add tests for all missing-export-doc cases --- test/diagnostics/missing-export-doc.lua | 168 +++++++----------------- 1 file changed, 49 insertions(+), 119 deletions(-) diff --git a/test/diagnostics/missing-export-doc.lua b/test/diagnostics/missing-export-doc.lua index 3d9422161..3f48532f4 100644 --- a/test/diagnostics/missing-export-doc.lua +++ b/test/diagnostics/missing-export-doc.lua @@ -1,175 +1,105 @@ --- check global functions TEST [[ -local mod = {} +local M = {} -local - ----comment -local function fl1() -end - -local function fl2() + end - -function FG0() + +---comment +function M.f2() end - -mod.fl0 = fl0 -mod.fl1 = fl1 -return mod ]] TEST [[ -local mod = {} - -local function flp0() - print(p) -end +local M = {} ----comment -local function flp1() - print(p) +function M.f1() end ----comment ----@param p any -local function flp2(p) - print(p) +---@param p integer +function M.f2(p) end - -mod.flp0 = flp0 -mod.flp1 = flp1 -return mod ]] TEST [[ -local mod = {} +local M = {} -local function flpp0(, ) - print(p0, p1) +function M.f1() + return end ----comment -local function flpp1(, ) - print(p0, p1) +---@return integer +function M.f2() + return 42 end +]] ----comment ----@param p0 any -local function flpp2(p0, ) - print(p0, p1) +TEST [[ +local M = {} + + end ---comment ----@param p0 any ----@param p1 any -local function flpp3(p0, p1) - print(p0, p1) +M.f1 = function() end - -mod.flpp0 = flpp0 -mod.flpp1 = flpp1 -mod.flpp2 = flpp2 -mod.flpp3 = flpp3 -return mod ]] TEST [[ -local mod = {} - -local function flr0() - return -end +local M = {} ----comment -local function flr1() - return +M.f1 = function() end ----comment ----@return integer -local function flr2() - return 0 +---@param p integer +M.f1 = function(p) end - -mod.flr0 = flr0 -mod.flr1 = flr1 -mod.flr2 = flr2 -return mod ]] TEST [[ -local mod = {} +local M = {} -local function flrr0() - return , +M.f1 = function() + return end ----comment -local function flrr1() - return , +---@return integer +M.f2 = function() + return 42 end +]] ----comment ----@return integer -local function flrr2() - return 0, + +TEST [[ +local M = {} + + end ---comment ----@return integer ----@return integer -local function flrr3() - return 0, 1 +function M:f2() end - -mod.flrr0 = flrr0 -mod.flrr1 = flrr1 -mod.flrr2 = flrr2 -return mod ]] TEST [[ -local mod = {} +local M = {} -local function flpr0() - print(p) - return +function M:f1() end ----comment -local function flpr1() - print(p) - return +---@param p integer +function M:f2(p) end +]] ----comment ----@param p any -local function flpr2(p) - print(p) - return -end +TEST [[ +local M = {} ----comment ----@return integer -local function flpr3() - print(p) - return 0 +function M:f1() + return end ----comment ----@param p any ---@return integer -local function flpr4(p) - print(p) - return 0 +function M:f2() + return 42 end - -mod.flpr0 = flpr0 -mod.flpr1 = flpr1 -mod.flpr2 = flpr2 -mod.flpr3 = flpr3 -mod.flpr4 = flpr4 -return mod ]] From 655a97fd40906e9f4e310276dddbd6df9584d102 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 02:31:56 +1300 Subject: [PATCH 04/16] test(diagnostics): make missing comment diagnostics have consistent ranges with other similar errors --- test/diagnostics/missing-export-doc.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/diagnostics/missing-export-doc.lua b/test/diagnostics/missing-export-doc.lua index 3f48532f4..de69dead2 100644 --- a/test/diagnostics/missing-export-doc.lua +++ b/test/diagnostics/missing-export-doc.lua @@ -1,8 +1,7 @@ TEST [[ local M = {} - -end + ---comment function M.f2() @@ -36,8 +35,7 @@ end TEST [[ local M = {} - -end + ---comment M.f1 = function() @@ -72,8 +70,7 @@ end TEST [[ local M = {} - -end + ---comment function M:f2() From 6743fbd971019aa32d2350858cd97883f3231050 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 03:41:28 +1300 Subject: [PATCH 05/16] fix(diagnostics): fix missing-export-doc triggering for missing-local-export-doc --- script/core/diagnostics/helper/missing-doc-helper.lua | 10 ++++++++-- script/core/diagnostics/missing-export-doc.lua | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index 20e529678..61b1f26ab 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -1,6 +1,6 @@ -local lang = require 'language' +local lang = require 'language' -local m = {} +local m = {} local function findParam(docs, param) if not docs then @@ -94,6 +94,12 @@ local function checkFunction(source, callback, commentId, paramId, returnId) checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) end + +---@param source parser.object +---@param callback fun(result: any) +---@param commentId string +---@param paramId string +---@param returnId string local function checkMethod(source, callback, commentId, paramId, returnId) local functionName = source[1] checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua index 13557190a..0c7d7727a 100644 --- a/script/core/diagnostics/missing-export-doc.lua +++ b/script/core/diagnostics/missing-export-doc.lua @@ -18,6 +18,7 @@ return function (uri, callback) ---@async guide.eachSourceType(state.ast, 'setfield', function (source) await.delay() + if source.value.type ~= "function" then return end helper.CheckFunctionNamed(source.field[1], source.value, callback, 'DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT', 'DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM', 'DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN') From f644444ab5928789b4b3ffb679f1b108ded571be Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:22:08 +1300 Subject: [PATCH 06/16] fix(diagnostics): fix methods never being accepted for missing-export-doc --- .../core/diagnostics/helper/missing-doc-helper.lua | 14 ++++++++------ script/core/diagnostics/missing-export-doc.lua | 5 +++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index 61b1f26ab..c5bc1761a 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -38,14 +38,16 @@ end ---@param functionName string ---@param source parser.object +---@param bindDocsSource parser.object? sometimes the object with the bindDocs isn't the function, use this to specify what has them ---@param callback fun(result: any) ---@param commentId string ---@param paramId string ---@param returnId string -local function checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) +local function checkFunctionNamed(functionName, source, bindDocsSource, callback, commentId, paramId, returnId) local argCount = source.args and #source.args or 0 + bindDocsSource = bindDocsSource or source - if argCount == 0 and not source.returns and not source.bindDocs then + if argCount == 0 and not source.returns and not bindDocsSource.bindDocs then callback { start = source.start, finish = source.finish, @@ -58,7 +60,7 @@ local function checkFunctionNamed(functionName, source, callback, commentId, par local argName = arg[1] if argName ~= 'self' and argName ~= '_' then - if not findParam(source.bindDocs, argName) then + if not findParam(bindDocsSource.bindDocs, argName) then callback { start = arg.start, finish = arg.finish, @@ -91,7 +93,7 @@ end ---@param returnId string local function checkFunction(source, callback, commentId, paramId, returnId) local functionName = source.parent[1] - checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) + checkFunctionNamed(functionName, source, nil, callback, commentId, paramId, returnId) end @@ -101,8 +103,8 @@ end ---@param paramId string ---@param returnId string local function checkMethod(source, callback, commentId, paramId, returnId) - local functionName = source[1] - checkFunctionNamed(functionName, source, callback, commentId, paramId, returnId) + local functionName = source.method[1] + checkFunctionNamed(functionName, source.method, source.value, callback, commentId, paramId, returnId) end m.CheckFunction = checkFunction diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua index 0c7d7727a..a1194ef3f 100644 --- a/script/core/diagnostics/missing-export-doc.lua +++ b/script/core/diagnostics/missing-export-doc.lua @@ -19,7 +19,8 @@ return function (uri, callback) guide.eachSourceType(state.ast, 'setfield', function (source) await.delay() if source.value.type ~= "function" then return end - helper.CheckFunctionNamed(source.field[1], source.value, callback, 'DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT', + helper.CheckFunctionNamed(source.field[1], source.value, source.value, callback, + 'DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT', 'DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM', 'DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN') end) @@ -27,7 +28,7 @@ return function (uri, callback) ---@async guide.eachSourceType(state.ast, 'setmethod', function (source) await.delay() - helper.CheckMethod(source.method, callback, 'DIAG_MISSING_EXPORTED_METHOD_DOC_COMMENT', + helper.CheckMethod(source, callback, 'DIAG_MISSING_EXPORTED_METHOD_DOC_COMMENT', 'DIAG_MISSING_EXPORTED_METHOD_DOC_PARAM', 'DIAG_MISSING_EXPORTED_METHOD_DOC_RETURN') end) From 65909aa9ea589f26fa5f8974197fed4c47023f66 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:26:55 +1300 Subject: [PATCH 07/16] fix(diagnostics): fix undocumented method returns never being ignored for missing-export-doc --- .../diagnostics/helper/missing-doc-helper.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index c5bc1761a..b52bb5567 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -38,19 +38,19 @@ end ---@param functionName string ---@param source parser.object ----@param bindDocsSource parser.object? sometimes the object with the bindDocs isn't the function, use this to specify what has them +---@param diagnosticRangeSource? parser.object sometimes the object with the data isn't the one that needs the diagnostics ---@param callback fun(result: any) ---@param commentId string ---@param paramId string ---@param returnId string -local function checkFunctionNamed(functionName, source, bindDocsSource, callback, commentId, paramId, returnId) - local argCount = source.args and #source.args or 0 - bindDocsSource = bindDocsSource or source +local function checkFunctionNamed(functionName, source, diagnosticRangeSource, callback, commentId, paramId, returnId) + diagnosticRangeSource = diagnosticRangeSource or source + local argCount = diagnosticRangeSource.args and #diagnosticRangeSource.args or 0 - if argCount == 0 and not source.returns and not bindDocsSource.bindDocs then + if argCount == 0 and not source.returns and not source.bindDocs then callback { - start = source.start, - finish = source.finish, + start = diagnosticRangeSource.start, + finish = diagnosticRangeSource.finish, message = lang.script(commentId, functionName), } end @@ -60,7 +60,7 @@ local function checkFunctionNamed(functionName, source, bindDocsSource, callback local argName = arg[1] if argName ~= 'self' and argName ~= '_' then - if not findParam(bindDocsSource.bindDocs, argName) then + if not findParam(source.bindDocs, argName) then callback { start = arg.start, finish = arg.finish, @@ -104,7 +104,7 @@ end ---@param returnId string local function checkMethod(source, callback, commentId, paramId, returnId) local functionName = source.method[1] - checkFunctionNamed(functionName, source.method, source.value, callback, commentId, paramId, returnId) + checkFunctionNamed(functionName, source.value, source.method, callback, commentId, paramId, returnId) end m.CheckFunction = checkFunction From dd52dcc7f081aeb391801459804bfdaf52974146 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:32:18 +1300 Subject: [PATCH 08/16] fix(diagnostics): fix undocumented method returns never being ignored for missing-export-doc --- script/core/diagnostics/missing-export-doc.lua | 2 +- test/diagnostics/missing-export-doc.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua index a1194ef3f..88ca8c965 100644 --- a/script/core/diagnostics/missing-export-doc.lua +++ b/script/core/diagnostics/missing-export-doc.lua @@ -19,7 +19,7 @@ return function (uri, callback) guide.eachSourceType(state.ast, 'setfield', function (source) await.delay() if source.value.type ~= "function" then return end - helper.CheckFunctionNamed(source.field[1], source.value, source.value, callback, + helper.CheckFunctionNamed(source.field[1], source.value, nil, callback, 'DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT', 'DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM', 'DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN') diff --git a/test/diagnostics/missing-export-doc.lua b/test/diagnostics/missing-export-doc.lua index de69dead2..c0c556aef 100644 --- a/test/diagnostics/missing-export-doc.lua +++ b/test/diagnostics/missing-export-doc.lua @@ -35,7 +35,7 @@ end TEST [[ local M = {} - +M.f1 = ---comment M.f1 = function() From b24a140946b683139b5813d770c5a4de2fb8175d Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:40:02 +1300 Subject: [PATCH 09/16] fix(diagnostics): fix bind doc comments not being detected for a.b = c style in missing-export-doc --- .../diagnostics/helper/missing-doc-helper.lua | 15 +++++++++------ script/core/diagnostics/missing-export-doc.lua | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index b52bb5567..f06135b1a 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -39,15 +39,18 @@ end ---@param functionName string ---@param source parser.object ---@param diagnosticRangeSource? parser.object sometimes the object with the data isn't the one that needs the diagnostics +---@param bindDocsSource? parser.object sometimes the object with the bind docs isn't the value (`a.b = c` syntax) ---@param callback fun(result: any) ---@param commentId string ---@param paramId string ---@param returnId string -local function checkFunctionNamed(functionName, source, diagnosticRangeSource, callback, commentId, paramId, returnId) +local function checkFunctionNamed(functionName, source, diagnosticRangeSource, bindDocsSource, callback, commentId, + paramId, returnId) diagnosticRangeSource = diagnosticRangeSource or source + bindDocsSource = bindDocsSource or source local argCount = diagnosticRangeSource.args and #diagnosticRangeSource.args or 0 - if argCount == 0 and not source.returns and not source.bindDocs then + if argCount == 0 and not source.returns and not bindDocsSource.bindDocs then callback { start = diagnosticRangeSource.start, finish = diagnosticRangeSource.finish, @@ -60,7 +63,7 @@ local function checkFunctionNamed(functionName, source, diagnosticRangeSource, c local argName = arg[1] if argName ~= 'self' and argName ~= '_' then - if not findParam(source.bindDocs, argName) then + if not findParam(bindDocsSource.bindDocs, argName) then callback { start = arg.start, finish = arg.finish, @@ -74,7 +77,7 @@ local function checkFunctionNamed(functionName, source, diagnosticRangeSource, c if source.returns then for _, ret in ipairs(source.returns) do for index, expr in ipairs(ret) do - if not findReturn(source.bindDocs, index) then + if not findReturn(bindDocsSource.bindDocs, index) then callback { start = expr.start, finish = expr.finish, @@ -93,7 +96,7 @@ end ---@param returnId string local function checkFunction(source, callback, commentId, paramId, returnId) local functionName = source.parent[1] - checkFunctionNamed(functionName, source, nil, callback, commentId, paramId, returnId) + checkFunctionNamed(functionName, source, nil, nil, callback, commentId, paramId, returnId) end @@ -104,7 +107,7 @@ end ---@param returnId string local function checkMethod(source, callback, commentId, paramId, returnId) local functionName = source.method[1] - checkFunctionNamed(functionName, source.value, source.method, callback, commentId, paramId, returnId) + checkFunctionNamed(functionName, source.value, source.method, nil, callback, commentId, paramId, returnId) end m.CheckFunction = checkFunction diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua index 88ca8c965..b1c5ca162 100644 --- a/script/core/diagnostics/missing-export-doc.lua +++ b/script/core/diagnostics/missing-export-doc.lua @@ -19,7 +19,7 @@ return function (uri, callback) guide.eachSourceType(state.ast, 'setfield', function (source) await.delay() if source.value.type ~= "function" then return end - helper.CheckFunctionNamed(source.field[1], source.value, nil, callback, + helper.CheckFunctionNamed(source.field[1], source.value, nil, source, callback, 'DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT', 'DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM', 'DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN') From 6c613e6d45fd14737597858ab7c506e70ea96640 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:53:40 +1300 Subject: [PATCH 10/16] test(diagnostics): the function node on a method isn't a direct ancestor in the ast so just wrap the args and name in the diagnostic for missing-export-doc --- script/core/diagnostics/helper/missing-doc-helper.lua | 2 +- script/core/diagnostics/missing-export-doc.lua | 8 +++++++- test/diagnostics/missing-export-doc.lua | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index f06135b1a..dfda9f800 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -107,7 +107,7 @@ end ---@param returnId string local function checkMethod(source, callback, commentId, paramId, returnId) local functionName = source.method[1] - checkFunctionNamed(functionName, source.value, source.method, nil, callback, commentId, paramId, returnId) + checkFunctionNamed(functionName, source.value, source, nil, callback, commentId, paramId, returnId) end m.CheckFunction = checkFunction diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua index b1c5ca162..fd3935a6b 100644 --- a/script/core/diagnostics/missing-export-doc.lua +++ b/script/core/diagnostics/missing-export-doc.lua @@ -19,7 +19,13 @@ return function (uri, callback) guide.eachSourceType(state.ast, 'setfield', function (source) await.delay() if source.value.type ~= "function" then return end - helper.CheckFunctionNamed(source.field[1], source.value, nil, source, callback, + + -- TODO: find a better way to distinguish a.b = function and function a.b, or alternatively make them both work + -- the same way? + -- the issue is they have very similar ASTs but bindDocs is either inside or outside value + + helper.CheckFunctionNamed(source.field[1], source.value, nil, source.bindDocs and source or source.value, + callback, 'DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT', 'DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM', 'DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN') diff --git a/test/diagnostics/missing-export-doc.lua b/test/diagnostics/missing-export-doc.lua index c0c556aef..b7bc0d277 100644 --- a/test/diagnostics/missing-export-doc.lua +++ b/test/diagnostics/missing-export-doc.lua @@ -70,7 +70,7 @@ end TEST [[ local M = {} - +function end ---comment function M:f2() From ab2dfbf604817f6dae7966ef9419e7df5af4da3b Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:55:36 +1300 Subject: [PATCH 11/16] fix(diagnostics): fix arg list using the diagnostic node rather than the source node for missing-export-doc --- script/core/diagnostics/helper/missing-doc-helper.lua | 2 +- test/diagnostics/missing-export-doc.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index dfda9f800..76d285ce5 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -48,7 +48,7 @@ local function checkFunctionNamed(functionName, source, diagnosticRangeSource, b paramId, returnId) diagnosticRangeSource = diagnosticRangeSource or source bindDocsSource = bindDocsSource or source - local argCount = diagnosticRangeSource.args and #diagnosticRangeSource.args or 0 + local argCount = source.args and #source.args or 0 if argCount == 0 and not source.returns and not bindDocsSource.bindDocs then callback { diff --git a/test/diagnostics/missing-export-doc.lua b/test/diagnostics/missing-export-doc.lua index b7bc0d277..803f90e86 100644 --- a/test/diagnostics/missing-export-doc.lua +++ b/test/diagnostics/missing-export-doc.lua @@ -70,7 +70,7 @@ end TEST [[ local M = {} -function end +function () end ---comment function M:f2() From 497eb212d40d8b76085f237f383a415a87f5d6fb Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:03:08 +1300 Subject: [PATCH 12/16] fix(diagnostics): fix arg list thinking self was an arg with type specified preventing comment diagnostics on methods for missing-export-doc --- script/core/diagnostics/helper/missing-doc-helper.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index 76d285ce5..b4c36ec8d 100644 --- a/script/core/diagnostics/helper/missing-doc-helper.lua +++ b/script/core/diagnostics/helper/missing-doc-helper.lua @@ -49,8 +49,9 @@ local function checkFunctionNamed(functionName, source, diagnosticRangeSource, b diagnosticRangeSource = diagnosticRangeSource or source bindDocsSource = bindDocsSource or source local argCount = source.args and #source.args or 0 + local noRealArgs = argCount == 0 or (argCount == 1 and source.args[1][1] == 'self') - if argCount == 0 and not source.returns and not bindDocsSource.bindDocs then + if noRealArgs and not source.returns and not bindDocsSource.bindDocs then callback { start = diagnosticRangeSource.start, finish = diagnosticRangeSource.finish, From a46f95960dca1105308c76ae4ad6a0d2b0bc4740 Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:03:29 +1300 Subject: [PATCH 13/16] fix(diagnostics): fix unbalanced assignments causing a nil index for missing-export-doc --- script/core/diagnostics/missing-export-doc.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/script/core/diagnostics/missing-export-doc.lua b/script/core/diagnostics/missing-export-doc.lua index fd3935a6b..1138d36d1 100644 --- a/script/core/diagnostics/missing-export-doc.lua +++ b/script/core/diagnostics/missing-export-doc.lua @@ -18,6 +18,7 @@ return function (uri, callback) ---@async guide.eachSourceType(state.ast, 'setfield', function (source) await.delay() + if not source.value then return end -- if the assignment is unbalanced then there is no value if source.value.type ~= "function" then return end -- TODO: find a better way to distinguish a.b = function and function a.b, or alternatively make them both work From e2368ad2f30f0b83a3486be1d05a03271a2b40bd Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:06:15 +1300 Subject: [PATCH 14/16] feat(diagnostics): write an actual description for missing-export-doc --- locale/en-us/setting.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/en-us/setting.lua b/locale/en-us/setting.lua index ec0a7d0c6..a9659d50b 100644 --- a/locale/en-us/setting.lua +++ b/locale/en-us/setting.lua @@ -414,7 +414,7 @@ config.diagnostics['missing-global-doc'] = config.diagnostics['missing-local-export-doc'] = 'Missing annotations for exported locals! Exported local functions must have a comment and annotations for all parameters and return values.' config.diagnostics['missing-export-doc'] = -'Missing annotations for exported locals! Exported local functions must have a comment and annotations for all parameters and return values.' +'Missing annotations for exported functions! Exported functions must have a comment and annotations for all parameters and return values.' config.diagnostics['missing-parameter'] = 'Enable diagnostics for function calls where the number of arguments is less than the number of annotated function parameters.' config.diagnostics['missing-return'] = From 03a6197f8a03241d857ee42d5d7709f66c9062fb Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:10:14 +1300 Subject: [PATCH 15/16] update changelog.md --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index b6caa5050..a48547ec1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ # changelog ## Unreleased +* `NEW` diagnostic: `missing-export-doc` ## 3.16.0 From 7f1284c0ca89b1194d23712ca93b3e69962f248b Mon Sep 17 00:00:00 2001 From: Nathan <47441022+NathanSnail@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:13:50 +1300 Subject: [PATCH 16/16] fix ordering of DIAG_* translations --- locale/en-us/script.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/locale/en-us/script.lua b/locale/en-us/script.lua index 13fe68856..af2b24259 100644 --- a/locale/en-us/script.lua +++ b/locale/en-us/script.lua @@ -130,20 +130,20 @@ DIAG_MISSING_LOCAL_EXPORT_DOC_COMMENT = 'Missing comment for exported local function `{}`.' DIAG_MISSING_LOCAL_EXPORT_DOC_PARAM = 'Missing @param annotation for parameter `{}` in exported local function `{}`.' -DIAG_MISSING_EXPORTED_METHOD_DOC_RETURN = -'Missing @return annotation at index `{}` in exported method `{}`.' +DIAG_MISSING_LOCAL_EXPORT_DOC_RETURN = +'Missing @return annotation at index `{}` in exported local function `{}`.' DIAG_MISSING_EXPORTED_METHOD_DOC_COMMENT = 'Missing comment for exported method `{}`.' DIAG_MISSING_EXPORTED_METHOD_DOC_PARAM = 'Missing @param annotation for parameter `{}` in exported method `{}`.' -DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN = -'Missing @return annotation at index `{}` in exported field `{}`.' +DIAG_MISSING_EXPORTED_METHOD_DOC_RETURN = +'Missing @return annotation at index `{}` in exported method `{}`.' DIAG_MISSING_EXPORTED_FIELD_DOC_COMMENT = 'Missing comment for exported field `{}`.' DIAG_MISSING_EXPORTED_FIELD_DOC_PARAM = 'Missing @param annotation for parameter `{}` in exported field `{}`.' -DIAG_MISSING_LOCAL_EXPORT_DOC_RETURN = -'Missing @return annotation at index `{}` in exported local function `{}`.' +DIAG_MISSING_EXPORTED_FIELD_DOC_RETURN = +'Missing @return annotation at index `{}` in exported field `{}`.' DIAG_INCOMPLETE_SIGNATURE_DOC_PARAM = 'Incomplete signature. Missing @param annotation for parameter `{}`.' DIAG_INCOMPLETE_SIGNATURE_DOC_RETURN =