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
|
local files = require 'files'
local guide = require 'parser.guide'
local define = require 'proto.define'
local lang = require 'language'
local vm = require 'vm.vm'
local config = require 'config.config'
local glob = require 'glob'
local function hasGet(loc)
if not loc.ref then
return false
end
local weak
for _, ref in ipairs(loc.ref) do
if ref.type == 'getlocal' then
if not ref.next then
return 'strong'
end
local nextType = ref.next.type
if nextType ~= 'setmethod'
and nextType ~= 'setfield'
and nextType ~= 'setindex' then
return 'strong'
else
weak = true
end
end
end
if weak then
return 'weak'
else
return nil
end
end
local function isMyTable(loc)
local value = loc.value
if value and value.type == 'table' then
return true
end
return false
end
local function isToBeClosed(source)
if not source.attrs then
return false
end
for _, attr in ipairs(source.attrs) do
if attr[1] == 'close' then
return true
end
end
return false
end
local function isDocClass(source)
if not source.bindDocs then
return false
end
for _, doc in ipairs(source.bindDocs) do
if doc.type == 'doc.class' then
return true
end
end
return false
end
---@param source parser.object
local function isDeclareFunctionParam(source)
if source.parent.type ~= 'funcargs' then
return false
end
local func = source.parent.parent
return vm.isEmptyFunction(func)
end
return function (uri, callback)
local ast = files.getState(uri)
if not ast then
return
end
local isMeta = vm.isMetaFile(uri)
local ignorePatterns = config.get(uri, 'Lua.diagnostics.unusedLocalExclude')
local ignore = glob.glob(ignorePatterns)
guide.eachSourceType(ast.ast, 'local', function (source)
local name = source[1]
if name == '_'
or name == ast.ENVMode then
return
end
if ignore(name) then
return
end
if isToBeClosed(source) then
return
end
if isDocClass(source) then
return
end
if isMeta and isDeclareFunctionParam(source) then
return
end
local data = hasGet(source)
if data == 'strong' then
return
end
if data == 'weak' then
if not isMyTable(source) then
return
end
end
callback {
start = source.start,
finish = source.finish,
tags = { define.DiagnosticTag.Unnecessary },
message = lang.script('DIAG_UNUSED_LOCAL', name),
}
if source.ref then
for _, ref in ipairs(source.ref) do
callback {
start = ref.start,
finish = ref.finish,
tags = { define.DiagnosticTag.Unnecessary },
message = lang.script('DIAG_UNUSED_LOCAL', name),
}
end
end
end)
end
|