-
-
Notifications
You must be signed in to change notification settings - Fork 423
Expand file tree
/
Copy pathundefined-doc-name.lua
More file actions
134 lines (124 loc) · 4.05 KB
/
undefined-doc-name.lua
File metadata and controls
134 lines (124 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
local files = require 'files'
local guide = require 'parser.guide'
local lang = require 'language'
local vm = require 'vm'
--- Check if name is a generic parameter from a class context
---@param source parser.object The doc.type.name source
---@param name string The type name to check
---@param uri uri The file URI
---@return boolean
local function isClassGenericParam(source, name, uri)
-- Find containing doc node
local doc = guide.getParentTypes(source, {
['doc.return'] = true,
['doc.param'] = true,
['doc.type'] = true,
['doc.field'] = true,
['doc.overload'] = true,
['doc.vararg'] = true,
})
if not doc then
return false
end
-- Walk up to find a doc node with bindGroup (intermediate doc.type nodes don't have it)
while doc and not doc.bindGroup do
doc = doc.parent
end
if not doc then
return false
end
-- Check bindGroup for class/alias with matching generic sign
local bindGroup = doc.bindGroup
if bindGroup then
for _, other in ipairs(bindGroup) do
if (other.type == 'doc.class' or other.type == 'doc.alias') and other.signs then
for _, sign in ipairs(other.signs) do
if sign[1] == name then
return true
end
end
end
end
end
-- Check direct class reference (for doc.field, doc.overload, doc.operator)
if doc.class and doc.class.signs then
for _, sign in ipairs(doc.class.signs) do
if sign[1] == name then
return true
end
end
end
-- Check if bound to a method on a generic class
-- Find the function from any doc in the bindGroup
local func = nil
if bindGroup then
for _, other in ipairs(bindGroup) do
local bindSource = other.bindSource
if bindSource then
if bindSource.type == 'function' then
-- doc.return binds directly to function
func = bindSource
break
else
-- doc.param binds to local param, find containing function
func = guide.getParentFunction(bindSource)
if func then
break
end
end
end
end
end
-- If we found a function, check if it's a method on a generic class
if func and func.parent then
local parent = func.parent
if parent.type == 'setmethod' or parent.type == 'setfield' or parent.type == 'setindex' then
local classGlobal = vm.getDefinedClass(uri, parent.node)
if classGlobal then
for _, set in ipairs(classGlobal:getSets(uri)) do
if set.type == 'doc.class' and set.signs then
for _, sign in ipairs(set.signs) do
if sign[1] == name then
return true
end
end
end
end
end
end
end
return false
end
return function (uri, callback)
local state = files.getState(uri)
if not state then
return
end
if not state.ast.docs then
return
end
guide.eachSource(state.ast.docs, function (source)
if source.type ~= 'doc.extends.name'
and source.type ~= 'doc.type.name' then
return
end
if source.parent.type == 'doc.class' then
return
end
local name = source[1]
if name == '...' or name == '_' or name == 'self' then
return
end
if isClassGenericParam(source, name, uri) then
return
end
if #vm.getDocSets(uri, name) > 0 then
return
end
callback {
start = source.start,
finish = source.finish,
message = lang.script('DIAG_UNDEFINED_DOC_NAME', name)
}
end)
end