summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsumneko <sumneko@hotmail.com>2019-04-18 16:32:36 +0800
committersumneko <sumneko@hotmail.com>2019-04-18 16:32:36 +0800
commitf077aa010aa2ae0a2cc6edbc345eaf4056b96e2b (patch)
treec45f7cf10a5fed43afc0a93eb9106961c67b931c
parentcc8fc15d26a1dfd2f30485ba21f2f313141932d0 (diff)
downloadlua-language-server-f077aa010aa2ae0a2cc6edbc345eaf4056b96e2b.zip
class的一些诊断
-rw-r--r--server/src/core/diagnostics.lua117
-rw-r--r--server/src/emmy/class.lua18
-rw-r--r--server/src/emmy/manager.lua17
-rw-r--r--server/src/method/textDocument/completion.lua2
-rw-r--r--server/src/parser/ast.lua2
-rw-r--r--server/src/vm/emmy.lua12
-rw-r--r--server/test/diagnostics/init.lua23
7 files changed, 152 insertions, 39 deletions
diff --git a/server/src/core/diagnostics.lua b/server/src/core/diagnostics.lua
index 73f8c8ce..33037d5f 100644
--- a/server/src/core/diagnostics.lua
+++ b/server/src/core/diagnostics.lua
@@ -374,26 +374,6 @@ function mt:searchRedundantValue(callback)
end)
end
-function mt:doDiagnostics(func, code, callback)
- if config.config.diagnostics.disable[code] then
- return
- end
- func(self, function (start, finish, ...)
- local data = callback(...)
- data.code = code
- data.start = start
- data.finish = finish
- self.datas[#self.datas+1] = data
- end)
- if coroutine.isyieldable() then
- if self.vm:isRemoved() then
- coroutine.yield('stop')
- else
- coroutine.yield()
- end
- end
-end
-
function mt:searchUndefinedEnvChild(callback)
self.vm:eachSource(function (source)
if not source:get 'global' then
@@ -421,6 +401,95 @@ function mt:searchUndefinedEnvChild(callback)
end)
end
+function mt:checkEmmyClass(source, callback)
+ local class = source:get 'emmy.class'
+ if not class then
+ return
+ end
+ -- class重复定义
+ local name = class:getName()
+ local related = {}
+ self.vm.emmyMgr:eachClass(name, function (class)
+ local src = class:getSource()
+ if src ~= source then
+ related[#related+1] = {
+ start = src.start,
+ finish = src.finish,
+ uri = src.uri,
+ }
+ end
+ end)
+ if #related > 0 then
+ callback(source.start, source.finish, lang.script.DIAG_DUPLICATE_CLASS ,related)
+ end
+ -- 继承不存在的class
+ local extends = class.extends
+ if not extends then
+ return
+ end
+ local parent = self.vm.emmyMgr:eachClass(extends, function (parent)
+ return parent
+ end)
+ if not parent then
+ callback(source[2].start, source[2].finish, lang.script.DIAG_UNDEFINED_CLASS)
+ return
+ end
+
+ -- class循环继承
+ local related = {}
+ local current = class
+ for _ = 1, 10 do
+ if parent:getName() == class:getName() then
+ callback(source.start, source.finish, lang.script.DIAG_CYCLIC_EXTENDS, related)
+ break
+ end
+ local extends = current.extends
+ if not extends then
+ break
+ end
+ related[#related+1] = {
+ start = current:getSource().start,
+ finish = current:getSource().finish,
+ uri = current:getSource().uri,
+ }
+ current = parent
+ parent = self.vm.emmyMgr:eachClass(extends, function (parent)
+ return parent
+ end)
+ if not parent then
+ break
+ end
+ end
+end
+
+function mt:searchEmmyLua(callback)
+ self.vm:eachSource(function (source)
+ if source.type == 'emmyClass' then
+ self:checkEmmyClass(source, callback)
+ end
+ end)
+end
+
+function mt:doDiagnostics(func, code, callback)
+ if config.config.diagnostics.disable[code] then
+ return
+ end
+ func(self, function (start, finish, ...)
+ local data = callback(...)
+ data.code = code
+ data.start = start
+ data.finish = finish
+ self.datas[#self.datas+1] = data
+ end)
+ if coroutine.isyieldable() then
+ if self.vm:isRemoved() then
+ coroutine.yield('stop')
+ else
+ coroutine.yield()
+ end
+ end
+end
+
return function (vm, lines, uri)
local session = setmetatable({
vm = vm,
@@ -538,5 +607,13 @@ return function (vm, lines, uri)
message = lang.script('DIAG_OVER_MAX_VALUES', max, passed),
}
end)
+ -- Emmy相关的检查
+ session:doDiagnostics(session.searchEmmyLua, 'emmy-lua', function (message, related)
+ return {
+ level = DiagnosticSeverity.Warning,
+ message = message,
+ related = related,
+ }
+ end)
return session.datas
end
diff --git a/server/src/emmy/class.lua b/server/src/emmy/class.lua
index 33a01be2..f1101e91 100644
--- a/server/src/emmy/class.lua
+++ b/server/src/emmy/class.lua
@@ -1,3 +1,5 @@
+local listMgr = require 'vm.list'
+
local mt = {}
mt.__index = mt
mt.type = 'emmy.class'
@@ -6,11 +8,19 @@ function mt:getType()
return self.name
end
-return function (class, parent)
+function mt:getName()
+ return self.name
+end
+
+function mt:getSource()
+ return listMgr.get(self.source)
+end
+
+return function (source)
local self = setmetatable({
- name = class[1],
- source = class.id,
- parent = parent and parent.id,
+ name = source[1][1],
+ source = source.id,
+ extends = source[2] and source[2][1],
}, mt)
return self
end
diff --git a/server/src/emmy/manager.lua b/server/src/emmy/manager.lua
index 8ca102ca..99b46420 100644
--- a/server/src/emmy/manager.lua
+++ b/server/src/emmy/manager.lua
@@ -32,13 +32,18 @@ function mt:eachClass(name, callback)
if not list then
return
end
- for _, class in pairs(list) do
- callback(class)
+ for k, class in pairs(list) do
+ if k ~= 'version' then
+ local res = callback(class)
+ if res ~= nil then
+ return res
+ end
+ end
end
end
-function mt:addClass(class, parent)
- local className = class[1]
+function mt:addClass(source)
+ local className = source[1][1]
self:flushClass(className)
local list = self._class[className]
local version = listMgr.getVersion()
@@ -48,8 +53,8 @@ function mt:addClass(class, parent)
}
self._class[className] = list
end
- list[class.id] = newClass(class, parent)
- return list[class.id]
+ list[source.id] = newClass(source)
+ return list[source.id]
end
function mt:remove()
diff --git a/server/src/method/textDocument/completion.lua b/server/src/method/textDocument/completion.lua
index 2f638979..7f60708b 100644
--- a/server/src/method/textDocument/completion.lua
+++ b/server/src/method/textDocument/completion.lua
@@ -121,7 +121,7 @@ return function (lsp, params)
local items = fastCompletion(lsp, params, lines)
--local items = finishCompletion(lsp, params, lines)
if not items then
- return
+ return nil
end
for i, item in ipairs(items) do
diff --git a/server/src/parser/ast.lua b/server/src/parser/ast.lua
index 7ac3db06..3078631d 100644
--- a/server/src/parser/ast.lua
+++ b/server/src/parser/ast.lua
@@ -1115,6 +1115,8 @@ local Defs = {
EmmyClass = function (class, extends)
return {
type = 'emmyClass',
+ start = class.start,
+ finish = (extends or class).finish,
[1] = class,
[2] = extends,
}
diff --git a/server/src/vm/emmy.lua b/server/src/vm/emmy.lua
index 4ab42c93..b2f38693 100644
--- a/server/src/vm/emmy.lua
+++ b/server/src/vm/emmy.lua
@@ -2,14 +2,10 @@ local mt = require 'vm.manager'
function mt:doEmmyClass(action)
local emmyMgr = self.emmyMgr
- local class = action[1]
- local parent = action[2]
- self:instantSource(class)
- if parent then
- self:instantSource(parent)
- end
- local emmyClass = emmyMgr:addClass(class, parent)
- self.emmy = emmyClass
+ self:instantSource(action)
+ local class = emmyMgr:addClass(action)
+ self.emmy = class
+ action:set('emmy.class', class)
end
function mt:doEmmyIncomplete(action)
diff --git a/server/test/diagnostics/init.lua b/server/test/diagnostics/init.lua
index 557a2475..7bb25f00 100644
--- a/server/test/diagnostics/init.lua
+++ b/server/test/diagnostics/init.lua
@@ -332,3 +332,26 @@ local function x()
print(loc)
end
]]
+
+TEST [[
+---@class <!Class!>
+---@class <!Class!>
+]]
+
+TEST [[
+---@class A : <!B!>
+]]
+
+TEST [[
+---@class <!A : B!>
+---@class <!B : C!>
+---@class <!C : D!>
+---@class <!D : A!>
+]]
+
+TEST [[
+---@class A : B
+---@class B : C
+---@class C : D
+---@class D
+]]