summaryrefslogtreecommitdiff
path: root/script/core/diagnostics/unused-local.lua
blob: 072cbd3110a2bc2dc7cebd69788fd2155ec36c3b (plain)
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
local files  = require 'files'
local guide  = require 'parser.guide'
local define = require 'proto.define'
local lang   = require 'language'

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

local function isDocParam(source)
    if not source.bindDocs then
        return false
    end
    for _, doc in ipairs(source.bindDocs) do
        if doc.type == 'doc.param' then
            if doc.param[1] == source[1] then
                return true
            end
        end
    end
    return false
end

return function (uri, callback)
    local ast = files.getState(uri)
    if not ast then
        return
    end
    guide.eachSourceType(ast.ast, 'local', function (source)
        local name = source[1]
        if name == '_'
        or name == ast.ENVMode then
            return
        end
        if source.tag == 'self' then
            return
        end
        if isToBeClosed(source) then
            return
        end
        if isDocClass(source) then
            return
        end
        if isDocParam(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