diff --git a/changelog.md b/changelog.md index 04d013f36..d92faf22f 100644 --- a/changelog.md +++ b/changelog.md @@ -9,10 +9,11 @@ * `CHG` Improve performance of multithreaded `--check` and `undefined-field` diagnostic * `FIX` Addons can now self-recommend as expected. Fixed by correcting the `wholeMatch` function * `FIX` Now correctly evaluates the visibility of fields in a class when they are defined directly in the object. use for completion and invisible dianostic. [#2752](https://github.com/LuaLS/lua-language-server/issues/2752) -* `NEW` added lua regular expression support for Lua.doc.Name [#2753](https://github.com/LuaLS/lua-language-server/pull/2753) +* `NEW` Added lua regular expression support for `Lua.doc.Name` [#2753](https://github.com/LuaLS/lua-language-server/pull/2753) * `FIX` Bad triggering of the `inject-field` diagnostic, when the fields are declared at the creation of the object [#2746](https://github.com/LuaLS/lua-language-server/issues/2746) * `CHG` Change spacing of parameter inlay hints to match other LSPs, like `rust-analyzer` * `FIX` Inconsistent type narrow behavior of function call args [#2758](https://github.com/LuaLS/lua-language-server/issues/2758) +* `FIX` Improve the `missing-fields` logic to be able to correctly handle classes defined several times [#22770](https://github.com/LuaLS/lua-language-server/pull/2770) * `FIX` Typos in annotation descriptions * `NEW` You can now click on "References" in CodeLen to display the reference list * `FIX` incorrect `CompletionItemKind` for postfix snippets [#2773](https://github.com/LuaLS/lua-language-server/pull/2773) diff --git a/script/core/diagnostics/missing-fields.lua b/script/core/diagnostics/missing-fields.lua index 210920fd9..5ce650ec6 100644 --- a/script/core/diagnostics/missing-fields.lua +++ b/script/core/diagnostics/missing-fields.lua @@ -15,61 +15,75 @@ return function (uri, callback) guide.eachSourceType(state.ast, 'table', function (src) await.delay() + vm.removeNode(src) -- the node is not updated correctly, reason still unknown local defs = vm.getDefs(src) + local sortedDefs = {} for _, def in ipairs(defs) do - if def.type == 'doc.class' and def.bindSource then - if guide.isInRange(def.bindSource, src.start) then + if def.type == 'doc.class' then + if def.bindSource and guide.isInRange(def.bindSource, src.start) then return end + local className = def.class[1] + if not sortedDefs[className] then + sortedDefs[className] = {} + end + local samedefs = sortedDefs[className] + samedefs[#samedefs+1] = def end if def.type == 'doc.type.array' or def.type == 'doc.type.table' then return end end + + local myKeys local warnings = {} - for _, def in ipairs(defs) do - if def.type == 'doc.class' then - if not def.fields then - return + for className, samedefs in pairs(sortedDefs) do + local missedKeys = {} + for _, def in ipairs(samedefs) do + if not def.fields or #def.fields == 0 then + goto continue + end + + if not myKeys then + myKeys = {} + for _, field in ipairs(src) do + local key = vm.getKeyName(field) or field.tindex + if key then + myKeys[key] = true + end + end end - local requiresKeys = {} for _, field in ipairs(def.fields) do if not field.optional and not vm.compileNode(field):isNullable() then local key = vm.getKeyName(field) - if key and not requiresKeys[key] then - requiresKeys[key] = true - requiresKeys[#requiresKeys+1] = key + if not key then + local fieldnode = vm.compileNode(field.field)[1] + if fieldnode and fieldnode.type == 'doc.type.integer' then + ---@cast fieldnode parser.object + key = vm.getKeyName(fieldnode) + end end - end - end - if #requiresKeys == 0 then - return - end - local myKeys = {} - for _, field in ipairs(src) do - local key = vm.getKeyName(field) - if key then - myKeys[key] = true - end - end - - local missedKeys = {} - for _, key in ipairs(requiresKeys) do - if not myKeys[key] then - missedKeys[#missedKeys+1] = ('`%s`'):format(key) + if key and not myKeys[key] then + if type(key) == "number" then + missedKeys[#missedKeys+1] = ('`[%s]`'):format(key) + else + missedKeys[#missedKeys+1] = ('`%s`'):format(key) + end + end end end + ::continue:: + end - if #missedKeys == 0 then - return - end - - warnings[#warnings+1] = lang.script('DIAG_MISSING_FIELDS', def.class[1], table.concat(missedKeys, ', ')) + if #missedKeys == 0 then + return end + + warnings[#warnings+1] = lang.script('DIAG_MISSING_FIELDS', className, table.concat(missedKeys, ', ')) end if #warnings == 0 then diff --git a/test/diagnostics/missing-fields.lua b/test/diagnostics/missing-fields.lua index ab87f81d8..8c1ffbbb1 100644 --- a/test/diagnostics/missing-fields.lua +++ b/test/diagnostics/missing-fields.lua @@ -231,3 +231,125 @@ local t = { y = 1, } ]] + +TEST [[ +---@diagnostic disable: unused-local + +---@class Foo +---@field a number +---@field b number +---@field c number + +---@class Foo + +---@class Bar +---@field ba number +---@field bb number +---@field bc number + +---@class Bar +---@field bd number + +---@type Foo|Bar +local x = { + ba = 1, + bb = 2, + bc = 3, + bd = 4, +} +]] + +TEST [[ +---@diagnostic disable: unused-local + +---@class Foo +---@field a number +---@field b number +---@field c number + +---@class Foo + +---@class Bar +---@field ba number +---@field bb number +---@field bc number + +---@class Bar +---@field bd number + +---@type Foo|Bar +local x = { + a = 1, + b = 2, + c = 3, +} +]] + +TEST [[ +---@diagnostic disable: unused-local + +---@class Foo +---@field a number +---@field b number +---@field c number + +---@class Foo + +---@class Bar +---@field ba number +---@field bb number +---@field bc number + +---@class Bar +---@field bd number + +---@type Foo|Bar +local x = +]] + +TEST [[ +---@diagnostic disable: unused-local + +---@class Foo +---@field a number +---@field b number +---@field c number + +---@class Foo + +---@class Bar +---@field ba number +---@field bb number +---@field bc number + +---@class Bar +---@field bd number + +---@type Foo|Bar +local x = +]] + +TEST[[ +---@class A +---@field [1] string +---@field x number + +---@type A +local t = {x = 1, ""} +]] + +TEST[[ +---@class A +---@field [1] string +---@field x number + +---@type A +local t = +]] \ No newline at end of file