Skip to content

Commit bbe49f6

Browse files
authored
Merge pull request #2770 from NeOzay/inconsistent-behavior-(missing-fields)
improve the missing-fields logic to be able to correctly handle classes defined several times
2 parents ed8559e + 585cc20 commit bbe49f6

File tree

3 files changed

+170
-33
lines changed

3 files changed

+170
-33
lines changed

Diff for: changelog.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
* `CHG` Improve performance of multithreaded `--check` and `undefined-field` diagnostic
1010
* `FIX` Addons can now self-recommend as expected. Fixed by correcting the `wholeMatch` function
1111
* `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)
12-
* `NEW` added lua regular expression support for Lua.doc.<scope>Name [#2753](https://github.com/LuaLS/lua-language-server/pull/2753)
12+
* `NEW` Added lua regular expression support for `Lua.doc.<scope>Name` [#2753](https://github.com/LuaLS/lua-language-server/pull/2753)
1313
* `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)
1414
* `CHG` Change spacing of parameter inlay hints to match other LSPs, like `rust-analyzer`
1515
* `FIX` Inconsistent type narrow behavior of function call args [#2758](https://github.com/LuaLS/lua-language-server/issues/2758)
16+
* `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)
1617
* `FIX` Typos in annotation descriptions
1718
* `NEW` You can now click on "References" in CodeLen to display the reference list
1819
* `FIX` incorrect `CompletionItemKind` for postfix snippets [#2773](https://github.com/LuaLS/lua-language-server/pull/2773)

Diff for: script/core/diagnostics/missing-fields.lua

+46-32
Original file line numberDiff line numberDiff line change
@@ -15,61 +15,75 @@ return function (uri, callback)
1515
guide.eachSourceType(state.ast, 'table', function (src)
1616
await.delay()
1717

18+
vm.removeNode(src) -- the node is not updated correctly, reason still unknown
1819
local defs = vm.getDefs(src)
20+
local sortedDefs = {}
1921
for _, def in ipairs(defs) do
20-
if def.type == 'doc.class' and def.bindSource then
21-
if guide.isInRange(def.bindSource, src.start) then
22+
if def.type == 'doc.class' then
23+
if def.bindSource and guide.isInRange(def.bindSource, src.start) then
2224
return
2325
end
26+
local className = def.class[1]
27+
if not sortedDefs[className] then
28+
sortedDefs[className] = {}
29+
end
30+
local samedefs = sortedDefs[className]
31+
samedefs[#samedefs+1] = def
2432
end
2533
if def.type == 'doc.type.array'
2634
or def.type == 'doc.type.table' then
2735
return
2836
end
2937
end
38+
39+
local myKeys
3040
local warnings = {}
31-
for _, def in ipairs(defs) do
32-
if def.type == 'doc.class' then
33-
if not def.fields then
34-
return
41+
for className, samedefs in pairs(sortedDefs) do
42+
local missedKeys = {}
43+
for _, def in ipairs(samedefs) do
44+
if not def.fields or #def.fields == 0 then
45+
goto continue
46+
end
47+
48+
if not myKeys then
49+
myKeys = {}
50+
for _, field in ipairs(src) do
51+
local key = vm.getKeyName(field) or field.tindex
52+
if key then
53+
myKeys[key] = true
54+
end
55+
end
3556
end
3657

37-
local requiresKeys = {}
3858
for _, field in ipairs(def.fields) do
3959
if not field.optional
4060
and not vm.compileNode(field):isNullable() then
4161
local key = vm.getKeyName(field)
42-
if key and not requiresKeys[key] then
43-
requiresKeys[key] = true
44-
requiresKeys[#requiresKeys+1] = key
62+
if not key then
63+
local fieldnode = vm.compileNode(field.field)[1]
64+
if fieldnode and fieldnode.type == 'doc.type.integer' then
65+
---@cast fieldnode parser.object
66+
key = vm.getKeyName(fieldnode)
67+
end
4568
end
46-
end
47-
end
4869

49-
if #requiresKeys == 0 then
50-
return
51-
end
52-
local myKeys = {}
53-
for _, field in ipairs(src) do
54-
local key = vm.getKeyName(field)
55-
if key then
56-
myKeys[key] = true
57-
end
58-
end
59-
60-
local missedKeys = {}
61-
for _, key in ipairs(requiresKeys) do
62-
if not myKeys[key] then
63-
missedKeys[#missedKeys+1] = ('`%s`'):format(key)
70+
if key and not myKeys[key] then
71+
if type(key) == "number" then
72+
missedKeys[#missedKeys+1] = ('`[%s]`'):format(key)
73+
else
74+
missedKeys[#missedKeys+1] = ('`%s`'):format(key)
75+
end
76+
end
6477
end
6578
end
79+
::continue::
80+
end
6681

67-
if #missedKeys == 0 then
68-
return
69-
end
70-
71-
warnings[#warnings+1] = lang.script('DIAG_MISSING_FIELDS', def.class[1], table.concat(missedKeys, ', '))
82+
if #missedKeys == 0 then
83+
return
7284
end
85+
86+
warnings[#warnings+1] = lang.script('DIAG_MISSING_FIELDS', className, table.concat(missedKeys, ', '))
7387
end
7488

7589
if #warnings == 0 then

Diff for: test/diagnostics/missing-fields.lua

+122
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,125 @@ local t = {
231231
y = 1,
232232
}
233233
]]
234+
235+
TEST [[
236+
---@diagnostic disable: unused-local
237+
238+
---@class Foo
239+
---@field a number
240+
---@field b number
241+
---@field c number
242+
243+
---@class Foo
244+
245+
---@class Bar
246+
---@field ba number
247+
---@field bb number
248+
---@field bc number
249+
250+
---@class Bar
251+
---@field bd number
252+
253+
---@type Foo|Bar
254+
local x = {
255+
ba = 1,
256+
bb = 2,
257+
bc = 3,
258+
bd = 4,
259+
}
260+
]]
261+
262+
TEST [[
263+
---@diagnostic disable: unused-local
264+
265+
---@class Foo
266+
---@field a number
267+
---@field b number
268+
---@field c number
269+
270+
---@class Foo
271+
272+
---@class Bar
273+
---@field ba number
274+
---@field bb number
275+
---@field bc number
276+
277+
---@class Bar
278+
---@field bd number
279+
280+
---@type Foo|Bar
281+
local x = {
282+
a = 1,
283+
b = 2,
284+
c = 3,
285+
}
286+
]]
287+
288+
TEST [[
289+
---@diagnostic disable: unused-local
290+
291+
---@class Foo
292+
---@field a number
293+
---@field b number
294+
---@field c number
295+
296+
---@class Foo
297+
298+
---@class Bar
299+
---@field ba number
300+
---@field bb number
301+
---@field bc number
302+
303+
---@class Bar
304+
---@field bd number
305+
306+
---@type Foo|Bar
307+
local x = <!{
308+
a = 1,
309+
b = 2,
310+
}!>
311+
]]
312+
313+
TEST [[
314+
---@diagnostic disable: unused-local
315+
316+
---@class Foo
317+
---@field a number
318+
---@field b number
319+
---@field c number
320+
321+
---@class Foo
322+
323+
---@class Bar
324+
---@field ba number
325+
---@field bb number
326+
---@field bc number
327+
328+
---@class Bar
329+
---@field bd number
330+
331+
---@type Foo|Bar
332+
local x = <!{
333+
ba = 1,
334+
bb = 2,
335+
bd = 4,
336+
}!>
337+
]]
338+
339+
TEST[[
340+
---@class A
341+
---@field [1] string
342+
---@field x number
343+
344+
---@type A
345+
local t = {x = 1, ""}
346+
]]
347+
348+
TEST[[
349+
---@class A
350+
---@field [1] string
351+
---@field x number
352+
353+
---@type A
354+
local t = <!{x = 1}!>
355+
]]

0 commit comments

Comments
 (0)