Skip to content

Commit 8aceaf9

Browse files
committed
fix: suppress undefined-doc-name warning for class generic parameters
When a generic class like Container<T> has methods that use T in their annotations (e.g., @return T[]), the diagnostic was incorrectly warning about T being undefined. Added isClassGenericParam() function that checks: 1. bindGroup for inline class/alias with matching generic signs 2. Direct class reference for doc.field, doc.overload, doc.operator 3. Method binding via vm.getDefinedClass for methods on generic classes Addresses maintainer feedback on PR #3330.
1 parent 3cd0a8d commit 8aceaf9

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

script/core/diagnostics/undefined-doc-name.lua

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,87 @@ local guide = require 'parser.guide'
33
local lang = require 'language'
44
local vm = require 'vm'
55

6+
--- Check if name is a generic parameter from a class context
7+
---@param source parser.object The doc.type.name source
8+
---@param name string The type name to check
9+
---@param uri uri The file URI
10+
---@return boolean
11+
local function isClassGenericParam(source, name, uri)
12+
-- Find containing doc node
13+
local doc = guide.getParentTypes(source, {
14+
['doc.return'] = true,
15+
['doc.param'] = true,
16+
['doc.type'] = true,
17+
['doc.field'] = true,
18+
['doc.overload'] = true,
19+
['doc.vararg'] = true,
20+
})
21+
if not doc then
22+
return false
23+
end
24+
25+
-- Walk up to find a doc node with bindGroup (intermediate doc.type nodes don't have it)
26+
while doc and not doc.bindGroup do
27+
doc = doc.parent
28+
end
29+
if not doc then
30+
return false
31+
end
32+
33+
-- Check bindGroup for class/alias with matching generic sign
34+
local bindGroup = doc.bindGroup
35+
if bindGroup then
36+
for _, other in ipairs(bindGroup) do
37+
if (other.type == 'doc.class' or other.type == 'doc.alias') and other.signs then
38+
for _, sign in ipairs(other.signs) do
39+
if sign[1] == name then
40+
return true
41+
end
42+
end
43+
end
44+
end
45+
end
46+
47+
-- Check direct class reference (for doc.field, doc.overload, doc.operator)
48+
if doc.class and doc.class.signs then
49+
for _, sign in ipairs(doc.class.signs) do
50+
if sign[1] == name then
51+
return true
52+
end
53+
end
54+
end
55+
56+
-- Check if bound to a method on a generic class
57+
if bindGroup then
58+
for _, other in ipairs(bindGroup) do
59+
local bindSource = other.bindSource
60+
if bindSource then
61+
-- For doc.return bound to function, check if function is a method
62+
if bindSource.type == 'function' and bindSource.parent then
63+
local parent = bindSource.parent
64+
if parent.type == 'setmethod' or parent.type == 'setfield' or parent.type == 'setindex' then
65+
local classGlobal = vm.getDefinedClass(uri, parent.node)
66+
if classGlobal then
67+
for _, set in ipairs(classGlobal:getSets(uri)) do
68+
if set.type == 'doc.class' and set.signs then
69+
for _, sign in ipairs(set.signs) do
70+
if sign[1] == name then
71+
return true
72+
end
73+
end
74+
end
75+
end
76+
end
77+
end
78+
end
79+
break -- Only check first bindSource
80+
end
81+
end
82+
end
83+
84+
return false
85+
end
86+
687
return function (uri, callback)
788
local state = files.getState(uri)
889
if not state then
@@ -25,6 +106,9 @@ return function (uri, callback)
25106
if name == '...' or name == '_' or name == 'self' then
26107
return
27108
end
109+
if isClassGenericParam(source, name, uri) then
110+
return
111+
end
28112
if #vm.getDocSets(uri, name) > 0 then
29113
return
30114
end

test/diagnostics/undefined-doc-name.lua

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,42 @@ TEST [[
1717
TEST [[
1818
---@alias B <!AAA!>
1919
]]
20+
21+
-- Generic class methods should not warn about class generic params
22+
TEST [[
23+
---@class Container<T>
24+
local Container = {}
25+
26+
---@return T[]
27+
function Container:getAll()
28+
return {}
29+
end
30+
]]
31+
32+
-- Inline class fields with generics should not warn
33+
TEST [[
34+
---@class Box<T>
35+
---@field value T
36+
]]
37+
38+
-- Multiple generic params should all be recognized
39+
TEST [[
40+
---@class Map<K, V>
41+
local Map = {}
42+
43+
---@param key K
44+
---@return V
45+
function Map:get(key)
46+
end
47+
]]
48+
49+
-- Undefined types SHOULD still warn (control case)
50+
TEST [[
51+
---@class Container<T>
52+
local Container = {}
53+
54+
---@return <!UndefinedType!>
55+
function Container:getBad()
56+
return {}
57+
end
58+
]]

0 commit comments

Comments
 (0)