summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2019-03-01 17:57:08 +0800
committer最萌小汐 <sumneko@hotmail.com>2019-03-01 17:57:08 +0800
commitf6570295633065a319e695211c05cddc71c1c4a6 (patch)
treea9f36cc8cf3d2e2a52bf46cbdbf932c567b44a21 /server
parent1113d28c032be9ef216e23f35c10ed751296601f (diff)
downloadlua-language-server-f6570295633065a319e695211c05cddc71c1c4a6.zip
未定义全局变量
Diffstat (limited to 'server')
-rw-r--r--server/src/core/diagnostics.lua149
-rw-r--r--server/src/vm/local.lua9
-rw-r--r--server/src/vm/source.lua22
-rw-r--r--server/src/vm/vm.lua34
-rw-r--r--server/test/diagnostics/init.lua11
5 files changed, 136 insertions, 89 deletions
diff --git a/server/src/core/diagnostics.lua b/server/src/core/diagnostics.lua
index 068ad37b..e2c7c5ec 100644
--- a/server/src/core/diagnostics.lua
+++ b/server/src/core/diagnostics.lua
@@ -12,67 +12,65 @@ local mt = {}
mt.__index = mt
function mt:searchUnusedLocals(callback)
- local results = self.results
- for _, var in ipairs(results.locals) do
- if var.key == '_'
- or var.key == '_ENV'
- or var.key == ''
- then
- goto NEXT_VAR
+ self.vm:eachSource(function (source)
+ local loc = source:bindLocal()
+ if not loc then
+ return
end
- if var.hide then
- goto NEXT_VAR
+ local name = loc:getName()
+ if name == '_' or name == '_ENV' or name == '' then
+ return
end
- local ok = self.vm:eachInfo(var, function (info)
+ if source:action() ~= 'local' then
+ return
+ end
+ if loc:getFlag 'hide' then
+ return
+ end
+ local used = loc:eachInfo(function (info)
if info.type == 'get' then
return true
end
- if info.type == 'local' then
- if info.source.start == 0 then
- return true
- end
- end
end)
- if ok then
- goto NEXT_VAR
+ if not used then
+ callback(source.start, source.finish, name)
end
- callback(var.source.start, var.source.finish, var.key)
- ::NEXT_VAR::
- end
+ end)
end
function mt:searchUndefinedGlobal(callback)
- local globalValue = self.vm.lsp.globalValue
- globalValue:eachField(function (index, field)
- if field.value.lib then
- goto NEXT_VAR
+ self.vm:eachSource(function (source)
+ if not source:getFlag 'global' then
+ return
end
- if not field.uris[self.vm.uri] then
- goto NEXT_VAR
+ local value = source:bindValue()
+ if not value then
+ return
end
- if type(index) ~= 'string' then
- goto NEXT_VAR
+ if source:action() ~= 'get' then
+ return
end
- if config.config.diagnostics.globals[index] then
- goto NEXT_VAR
+ if value:getLib() then
+ return
end
- if index == '' then
- goto NEXT_VAR
+ local name = source:getName()
+ if name == '' then
+ return
+ end
+ if type(name) ~= 'string' then
+ return
+ end
+ if config.config.diagnostics.globals[name] then
+ return
end
- local ok = field.value:eachInfo(function (info)
+ local defined = value:eachInfo(function (info)
if info.type == 'set' then
return true
end
end)
- if ok then
- goto NEXT_VAR
+ if not defined then
+ callback(source.start, source.finish, name)
end
- self.vm:eachInfo(field, function (info)
- if info.type == 'get' then
- callback(info.source.start, info.source.finish, tostring(index))
- end
- end)
- ::NEXT_VAR::
end)
end
@@ -229,7 +227,7 @@ function mt:doDiagnostics(func, code, callback)
if config.config.diagnostics.disable[code] then
return
end
- self[func](self, function (start, finish, ...)
+ func(self, function (start, finish, ...)
local data = callback(...)
data.code = code
data.start = start
@@ -244,61 +242,60 @@ end
return function (vm, lines, uri)
local session = setmetatable({
vm = vm,
- results = vm.results,
lines = lines,
uri = uri,
datas = {},
}, mt)
-- 未使用的局部变量
- session:doDiagnostics('searchUnusedLocals', 'unused-local', function (key)
+ session:doDiagnostics(session.searchUnusedLocals, 'unused-local', function (key)
return {
level = DiagnosticSeverity.Information,
message = lang.script('DIAG_UNUSED_LOCAL', key),
}
end)
-- 读取未定义全局变量
- session:doDiagnostics('searchUndefinedGlobal', 'undefined-global', function (key)
+ session:doDiagnostics(session.searchUndefinedGlobal, 'undefined-global', function (key)
return {
level = DiagnosticSeverity.Warning,
message = lang.script('DIAG_UNDEFINED_GLOBAL', key),
}
end)
-- 未使用的Label
- session:doDiagnostics('searchUnusedLabel', 'unused-label', function (key)
- return {
- level =DiagnosticSeverity.Hint,
- message = lang.script('DIAG_UNUSED_LABEL', key)
- }
- end)
+ --session:doDiagnostics(session.searchUnusedLabel, 'unused-label', function --(key)
+ -- return {
+ -- level =DiagnosticSeverity.Hint,
+ -- message = lang.script('DIAG_UNUSED_LABEL', key)
+ -- }
+ --end)
-- 只有空格与制表符的行,以及后置空格
- session:doDiagnostics('searchSpaces', 'trailing-space', function (message)
- return {
- level = DiagnosticSeverity.Hint,
- message = message,
- }
- end)
+ --session:doDiagnostics(session.searchSpaces, 'trailing-space', function --(message)
+ -- return {
+ -- level = DiagnosticSeverity.Hint,
+ -- message = message,
+ -- }
+ --end)
-- 重定义局部变量
- session:doDiagnostics('searchRedefinition', 'redefined-local', function (key, related)
- return {
- level = DiagnosticSeverity.Information,
- message = lang.script('DIAG_REDEFINED_LOCAL', key),
- related = related,
- }
- end)
+ --session:doDiagnostics(session.searchRedefinition, 'redefined-local', --function (key, related)
+ -- return {
+ -- level = DiagnosticSeverity.Information,
+ -- message = lang.script('DIAG_REDEFINED_LOCAL', key),
+ -- related = related,
+ -- }
+ --end)
-- 以括号开始的一行(可能被误解析为了上一行的call)
- session:doDiagnostics('searchNewLineCall', 'newline-call', function ()
- return {
- level = DiagnosticSeverity.Information,
- message = lang.script.DIAG_PREVIOUS_CALL,
- }
- end)
+ --session:doDiagnostics(session.searchNewLineCall, 'newline-call', function ()
+ -- return {
+ -- level = DiagnosticSeverity.Information,
+ -- message = lang.script.DIAG_PREVIOUS_CALL,
+ -- }
+ --end)
-- 调用函数时的参数数量是否超过函数的接收数量
- session:doDiagnostics('searchRedundantParameters', 'remainder-parameters', function (max, passed)
- return {
- level = DiagnosticSeverity.Information,
- message = lang.script('DIAG_OVER_MAX_ARGS', max, passed),
- }
- end)
+ --session:doDiagnostics(session.searchRedundantParameters, --'remainder-parameters', function (max, passed)
+ -- return {
+ -- level = DiagnosticSeverity.Information,
+ -- message = lang.script('DIAG_OVER_MAX_ARGS', max, passed),
+ -- }
+ --end)
return session.datas
end
diff --git a/server/src/vm/local.lua b/server/src/vm/local.lua
index f1c33ecf..75f41db2 100644
--- a/server/src/vm/local.lua
+++ b/server/src/vm/local.lua
@@ -31,7 +31,10 @@ end
function mt:eachInfo(callback)
for _, info in ipairs(self) do
- callback(info)
+ local res = callback(info)
+ if res ~= nil then
+ return res
+ end
end
end
@@ -49,6 +52,10 @@ function mt:getFlag(name)
return self._flag[name]
end
+function mt:getName()
+ return self.name
+end
+
return function (name, source, value)
if not value then
error('Local must has a value')
diff --git a/server/src/vm/source.lua b/server/src/vm/source.lua
index 5406298b..6685b95f 100644
--- a/server/src/vm/source.lua
+++ b/server/src/vm/source.lua
@@ -2,9 +2,11 @@ local mt = {}
mt.__index = mt
mt._hasInstant = true
-function mt:bindLocal(loc)
+function mt:bindLocal(loc, action)
if loc then
self._bindLocal = loc
+ self._action = action
+ loc:addInfo(action, self)
else
return self._bindLocal
end
@@ -50,6 +52,24 @@ function mt:getUri()
return self._uri
end
+function mt:setFlag(name, v)
+ if not self._flag then
+ self._flag = {}
+ end
+ self._flag[name] = v
+end
+
+function mt:getFlag(name)
+ if not self._flag then
+ return nil
+ end
+ return self._flag[name]
+end
+
+function mt:getName()
+ return self[1]
+end
+
return function (source)
if source._hasInstant then
return false
diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua
index 1a892100..64419d72 100644
--- a/server/src/vm/vm.lua
+++ b/server/src/vm/vm.lua
@@ -350,12 +350,18 @@ function mt:getName(name, source)
end
local loc = self:loadLocal(name)
if loc then
- source:bindLocal(loc)
+ source:bindLocal(loc, 'get')
return loc:getValue()
end
+ local global = source:bindValue()
+ if global then
+ return global
+ end
+ source:setFlag('global', true)
local ENV = self:loadLocal('_ENV')
local ENVValue = ENV:getValue()
- local global = ENVValue:getChild(name) or ENVValue:setChild(name, createValue('any', source))
+ global = ENVValue:getChild(name) or ENVValue:setChild(name, createValue('any', source))
+ source:bindValue(global, 'get')
return global
end
@@ -363,10 +369,16 @@ function mt:setName(name, source, value)
self:instantSource(source)
local loc = self:loadLocal(name)
if loc then
- source:bindLocal(loc)
+ source:bindLocal(loc, 'set')
loc:setValue(value)
return
end
+ local global = source:bindValue()
+ if global then
+ return global
+ end
+ source:setFlag('global', true)
+ source:bindValue(global, 'set')
local ENV = self:loadLocal('_ENV')
local ENVValue = ENV:getValue()
ENVValue:setChild(name, value)
@@ -1031,13 +1043,13 @@ function mt:instantSource(source)
end
end
-function mt:bindLocal(source, loc)
+function mt:bindLocal(source, loc, action)
if not source then
return
end
self:instantSource(source)
if loc then
- source:bindLocal(loc)
+ source:bindLocal(loc, action)
else
return source:bindLocal()
end
@@ -1065,7 +1077,7 @@ function mt:createLocal(key, source, value)
loc = createLocal(key, source, value)
self:saveLocal(key, loc)
- self:bindLocal(source, loc)
+ self:bindLocal(source, loc, 'local')
return loc
end
@@ -1081,6 +1093,13 @@ function mt:createEnvironment(ast)
self.env = env
end
+function mt:eachSource(callback)
+ local sources = self.sources
+ for i = 1, #sources do
+ callback(sources[i])
+ end
+end
+
local function compile(ast, lsp, uri)
local vm = setmetatable({
funcs = {},
@@ -1099,9 +1118,6 @@ local function compile(ast, lsp, uri)
-- 检查所有没有调用过的函数,调用一遍
vm:callLeftFuncions()
- vm.scope = nil
- vm.chunk = nil
-
return vm
end
diff --git a/server/test/diagnostics/init.lua b/server/test/diagnostics/init.lua
index 9ab41aed..e8d483ed 100644
--- a/server/test/diagnostics/init.lua
+++ b/server/test/diagnostics/init.lua
@@ -1,4 +1,5 @@
local core = require 'core'
+local buildVM = require 'vm'
local parser = require 'parser'
local service = require 'service'
@@ -43,7 +44,7 @@ function TEST(script)
local ast = parser:ast(new_script)
assert(ast)
local lines = parser:lines(new_script)
- local vm = core.vm(ast, lsp)
+ local vm = buildVM(ast, lsp)
assert(vm)
local datas = core.diagnostics(vm, lines, 'test')
local results = {}
@@ -71,7 +72,7 @@ print(<!X!>)
print(<!Log!>)
print(_VERSION)
print(<!y!>)
-print(z)
+print(<!z!>)
z = 1
]]
@@ -154,6 +155,12 @@ end
]]
TEST [[
+local mt = {}
+function mt:f()
+end
+]]
+
+TEST [[
local function f(<!self!>)
end
f()