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 diff --git a/locale/en-us/script.lua b/locale/en-us/script.lua index f8a38b9ab..af2b24259 100644 --- a/locale/en-us/script.lua +++ b/locale/en-us/script.lua @@ -132,6 +132,18 @@ DIAG_MISSING_LOCAL_EXPORT_DOC_PARAM = 'Missing @param annotation for parameter `{}` in exported local function `{}`.' 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_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_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 = diff --git a/locale/en-us/setting.lua b/locale/en-us/setting.lua index 0c136333a..a9659d50b 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 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'] = diff --git a/script/core/diagnostics/helper/missing-doc-helper.lua b/script/core/diagnostics/helper/missing-doc-helper.lua index 116173f2d..b4c36ec8d 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 @@ -36,14 +36,25 @@ 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 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, bindDocsSource, callback, commentId, + paramId, returnId) + 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 source.bindDocs then + if noRealArgs and not source.returns and not bindDocsSource.bindDocs then callback { - start = source.start, - finish = source.finish, + start = diagnosticRangeSource.start, + finish = diagnosticRangeSource.finish, message = lang.script(commentId, functionName), } end @@ -53,7 +64,7 @@ local function checkFunction(source, callback, commentId, paramId, returnId) 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, @@ -67,7 +78,7 @@ local function checkFunction(source, callback, commentId, paramId, returnId) 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, @@ -79,5 +90,28 @@ 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, nil, nil, 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.method[1] + checkFunctionNamed(functionName, source.value, source, nil, 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 new file mode 100644 index 000000000..1138d36d1 --- /dev/null +++ b/script/core/diagnostics/missing-export-doc.lua @@ -0,0 +1,42 @@ +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() + 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 + -- 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') + end) + + ---@async + guide.eachSourceType(state.ast, 'setmethod', function (source) + await.delay() + helper.CheckMethod(source, callback, 'DIAG_MISSING_EXPORTED_METHOD_DOC_COMMENT', + 'DIAG_MISSING_EXPORTED_METHOD_DOC_PARAM', + 'DIAG_MISSING_EXPORTED_METHOD_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..803f90e86 --- /dev/null +++ b/test/diagnostics/missing-export-doc.lua @@ -0,0 +1,102 @@ +TEST [[ +local M = {} + + + +---comment +function M.f2() +end +]] + +TEST [[ +local M = {} + +function M.f1() +end + +---@param p integer +function M.f2(p) +end +]] + +TEST [[ +local M = {} + +function M.f1() + return +end + +---@return integer +function M.f2() + return 42 +end +]] + +TEST [[ +local M = {} + +M.f1 = + +---comment +M.f1 = function() +end +]] + +TEST [[ +local M = {} + +M.f1 = function() +end + +---@param p integer +M.f1 = function(p) +end +]] + +TEST [[ +local M = {} + +M.f1 = function() + return +end + +---@return integer +M.f2 = function() + return 42 +end +]] + + +TEST [[ +local M = {} + +function () end + +---comment +function M:f2() +end +]] + +TEST [[ +local M = {} + +function M:f1() +end + +---@param p integer +function M:f2(p) +end +]] + +TEST [[ +local M = {} + +function M:f1() + return +end + +---@return integer +function M:f2() + return 42 +end +]]