diff options
35 files changed, 955 insertions, 495 deletions
diff --git a/server/main.lua b/server/main.lua index ac7860c5..685fce01 100644 --- a/server/main.lua +++ b/server/main.lua @@ -22,7 +22,7 @@ local function tryDebugger() log.info('Debugger startup, listen port: 11411') end ---pcall(tryDebugger) +pcall(tryDebugger) require 'utility' require 'global_protect' diff --git a/server/src/core/completion.lua b/server/src/core/completion.lua index 4a487441..d0da95cd 100644 --- a/server/src/core/completion.lua +++ b/server/src/core/completion.lua @@ -397,6 +397,14 @@ local function searchEmmyKeyword(vm, source, word, callback) end end +local function searchEmmyClass(vm, source, word, callback) + vm.emmyMgr:eachClass(function (class) + if matchKey(word, class:getName()) then + callback(class:getName(), class:getSource(), CompletionItemKind.Class) + end + end) +end + local function searchSource(vm, source, word, callback) if source.type == 'keyword' then searchAsKeyowrd(vm, source, word, callback) @@ -430,6 +438,9 @@ local function searchSource(vm, source, word, callback) searchEmmyKeyword(vm, source, word, callback) return end + if source:get 'target class' then + searchEmmyClass(vm, source, word, callback) + end end local function searchInRequire(vm, select, source, callback) @@ -650,11 +661,9 @@ local function makeList(source, pos, word) end, list end -local function searchToclose(text, word, callback, pos) - if #word > 0 then - pos = pos - 1 - end - if text:sub(pos, pos) ~= '*' then +local function searchToclose(text, source, word, callback) + local pos = source.start + if text:sub(pos-1, pos-1) ~= '*' then return false end if not matchKey(word, 'toclose') then @@ -685,7 +694,62 @@ local function keywordSource(vm, word, pos) } end -return function (vm, text, pos, word, oldText) +local function findStartPos(pos, buf) + local res = nil + for i = pos, 1, -1 do + local c = buf:sub(i, i) + if c:find '[%w_]' then + res = i + else + break + end + end + if not res then + for i = pos, 1, -1 do + local c = buf:sub(i, i) + if c == '.' or c == ':' or c == '|' then + res = i + break + elseif c == '#' or c == '@' then + res = i + 1 + break + elseif c:find '[%s%c]' then + else + break + end + end + end + if not res then + return pos + end + return res +end + +local function findWord(position, text) + local word = text + for i = position, 1, -1 do + local c = text:sub(i, i) + if not c:find '[%w_]' then + word = text:sub(i+1, position) + break + end + end + return word:match('^([%w_]*)') +end + +local function getSource(vm, pos, text, filter) + local word = findWord(pos, text) + local source = findSource(vm, pos, filter) + if source then + return source, pos, word + end + pos = findStartPos(pos, text) + source = findSource(vm, pos, filter) + or keywordSource(vm, word, pos) + return source, pos, word +end + +return function (vm, text, pos, oldText) local filter = { ['name'] = true, ['string'] = true, @@ -695,10 +759,7 @@ return function (vm, text, pos, word, oldText) ['emmyIncomplete'] = true, ['call'] = true, } - local source = findSource(vm, pos, filter) - or findSource(vm, pos-1, filter) - or findSource(vm, pos+1, filter) - or keywordSource(vm, word, pos) + local source, pos, word = getSource(vm, pos, text, filter) if not source then return nil end @@ -709,7 +770,7 @@ return function (vm, text, pos, word, oldText) end end local callback, list = makeList(source, pos, word) - if searchToclose(text, word, callback, pos) then + if searchToclose(text, source, word, callback) then return list end searchSpecial(vm, source, word, callback, pos) diff --git a/server/src/core/definition.lua b/server/src/core/definition.lua index a7296bfb..f096fb99 100644 --- a/server/src/core/definition.lua +++ b/server/src/core/definition.lua @@ -1,9 +1,11 @@ -local function parseValueSimily(vm, source, lsp) +local findSource = require 'core.find_source' +local Mode + +local function parseValueSimily(callback, vm, source) local key = source[1] if not key then return nil end - local positions = {} vm:eachSource(function (other) if other == source then goto CONTINUE @@ -11,210 +13,211 @@ local function parseValueSimily(vm, source, lsp) if other[1] == key and not other:bindLocal() and other:bindValue() - and other:action() == 'set' and source:bindValue() ~= other:bindValue() then - positions[#positions+1] = { - other.start, - other.finish, - } + if Mode == 'definition' then + if other:action() == 'set' then + callback(other) + end + elseif Mode == 'reference' then + if other:action() == 'set' or other:action() == 'get' then + callback(other) + end + end end :: CONTINUE :: end) - if #positions == 0 then - return nil - end - return positions end -local function parseValueCrossFile(vm, source, lsp) - local value = source:bindValue() - local positions = {} - value:eachInfo(function (info, src) - if info.type == 'local' and src.uri == value.uri then - positions[#positions+1] = { - src.start, - src.finish, - value.uri, - } - return true +local function parseLocal(callback, vm, source) + ---@type Local + local loc = source:bindLocal() + loc:eachInfo(function (info, src) + if Mode == 'definition' then + if info.type == 'set' or info.type == 'local' then + if src.id < source.id then + callback(src) + end + end + elseif Mode == 'reference' then + if info.type == 'set' or info.type == 'local' or info.type == 'return' or info.type == 'get' then + callback(src) + end end end) - if #positions > 0 then - return positions - end +end +local function parseValueByValue(callback, vm, source, value, isGlobal) value:eachInfo(function (info, src) - if info.type == 'set' and src.uri == value.uri then - positions[#positions+1] = { - src.start, - src.finish, - value.uri, - } + if Mode == 'definition' then + if info.type == 'set' or info.type == 'local' or info.type == 'return' then + if vm.uri == src:getUri() then + if isGlobal or source.id > src.id then + callback(src) + end + elseif value.uri == src:getUri() then + callback(src) + end + end + elseif Mode == 'reference' then + if info.type == 'set' or info.type == 'local' or info.type == 'return' or info.type == 'get' then + callback(src) + end end end) - if #positions > 0 then - return positions - end +end - value:eachInfo(function (info, src) - if info.type == 'return' and src.uri == value.uri then - positions[#positions+1] = { - src.start, - src.finish, - value.uri, - } +local function parseValue(callback, vm, source) + local value = source:bindValue() + local isGlobal + if value then + isGlobal = value:isGlobal() + parseValueByValue(callback, vm, source, value, isGlobal) + local emmy = value:getEmmy() + if emmy and emmy.type == 'emmy.type' then + ---@type EmmyType + local emmyType = emmy + emmyType:eachClass(function (class) + if class and class:getValue() then + parseValueByValue(callback, vm, source, class:getValue(), isGlobal) + end + end) end - end) - if #positions > 0 then - return positions end - - local destVM = lsp:getVM(value.uri) - if not destVM then - positions[#positions+1] = { - 0, 0, value.uri, - } - return positions + local parent = source:get 'parent' + for _ = 1, 3 do + if parent then + local ok = parent:eachInfo(function (info, src) + if Mode == 'definition' then + if info.type == 'set child' and info[1] == source[1] then + callback(src) + return true + end + elseif Mode == 'reference' then + if (info.type == 'set child' or info.type == 'get child') and info[1] == source[1] then + callback(src) + return true + end + end + end) + if ok then + break + end + parent = parent:getMetaMethod('__index') + end end + return isGlobal +end - local result = parseValueSimily(destVM, source, lsp) - if result then - for _, position in ipairs(result) do - positions[#positions+1] = position - position[3] = value.uri +local function parseLabel(callback, vm, label) + label:eachInfo(function (info, src) + if Mode == 'definition' then + if info.type == 'set' then + callback(src) + end + elseif Mode == 'reference' then + if info.type == 'set' or info.type == 'get' then + callback(src) + end end - end - if #positions > 0 then - return positions - end + end) +end - return nil +local function jumpUri(callback, vm, source) + local uri = source:get 'target uri' + callback { + start = 0, + finish = 0, + uri = uri + } end -local function parseLocal(vm, source, lsp) - local positions = {} - local loc = source:bindLocal() - local locSource = loc:getSource() - if locSource:get 'arg' then - positions[#positions+1] = { - locSource.start, - locSource.finish, - locSource:getUri(), - } - return positions - end - local value = source:bindValue() - if value and value.uri ~= '' and value.uri ~= vm.uri then - local positions = parseValueCrossFile(vm, source, lsp) - if positions and #positions > 0 then - return positions +local function parseClass(callback, vm, source) + local className = source:get 'target class' + vm.emmyMgr:eachClass(className, function (class) + if Mode == 'definition' then + if class.type == 'emmy.class' then + local src = class:getSource() + callback(src) + end + elseif Mode == 'reference' then + if class.type == 'emmy.class' or class.type == 'emmy.typeUnit' then + local src = class:getSource() + callback(src) + end end + end) +end + +local function parseFunction(callback, vm, source) + if Mode == 'reference' then + callback(source:bindFunction():getSource()) + source:bindFunction():eachInfo(function (info, src) + if info.type == 'set' or info.type == 'local' or info.type == 'get' then + callback(src) + end + end) end - positions[#positions+1] = { - locSource.start, - locSource.finish, - locSource:getUri(), - } - if #positions == 0 then - return nil - end - return positions end -local function parseValue(vm, source, lsp) - local positions = {} +local function makeList(source) + local list = {} local mark = {} - - local function callback(src) - if source == src then - return + return list, function (src) + if Mode == 'definition' then + if source == src then + return + end end if mark[src] then return end mark[src] = true - if src.start == 0 then - return - end local uri = src.uri if uri == '' then uri = nil end - positions[#positions+1] = { + list[#list+1] = { src.start, src.finish, - uri, + src.uri } end - - if source:bindValue() then - source:bindValue():eachInfo(function (info, src) - if info.type == 'set' or info.type == 'local' or info.type == 'return' then - callback(src) - end - end) - end - local parent = source:get 'parent' - if parent then - parent:eachInfo(function (info, src) - if info[1] == source[1] then - if info.type == 'set child' then - callback(src) - end - end - end) - end - if #positions == 0 then - return nil - end - return positions -end - -local function parseLabel(vm, label, lsp) - local positions = {} - label:eachInfo(function (info, src) - if info.type == 'set' then - positions[#positions+1] = { - src.start, - src.finish, - } - end - end) - if #positions == 0 then - return nil - end - return positions -end - -local function jumpUri(vm, source, lsp) - local uri = source:get 'target uri' - local positions = {} - positions[#positions+1] = { - 0, 0, uri, - } - return positions end -return function (vm, source, lsp) +return function (vm, pos, mode) + local source = findSource(vm, pos) if not source then return nil end + Mode = mode + local list, callback = makeList(source) + local isGlobal if source:bindLocal() then - return parseLocal(vm, source, lsp) + parseLocal(callback, vm, source) end if source:bindValue() then - return parseValue(vm, source, lsp) - or parseValueSimily(vm, source, lsp) + isGlobal = parseValue(callback, vm, source) end if source:bindLabel() then - return parseLabel(vm, source:bindLabel(), lsp) + parseLabel(callback, vm, source:bindLabel()) + end + if source:bindFunction() then + parseFunction(callback, vm, source) end if source:get 'target uri' then - return jumpUri(vm, source, lsp) + jumpUri(callback, vm, source) end if source:get 'in index' then - return parseValue(vm, source, lsp) - or parseValueSimily(vm, source, lsp) + isGlobal = parseValue(callback, vm, source) + end + if source:get 'target class' then + parseClass(callback, vm, source) end + + if #list == 0 then + parseValueSimily(callback, vm, source) + end + + return list, isGlobal end diff --git a/server/src/core/diagnostics.lua b/server/src/core/diagnostics.lua index d49f8da2..9f46d724 100644 --- a/server/src/core/diagnostics.lua +++ b/server/src/core/diagnostics.lua @@ -410,6 +410,9 @@ function mt:checkEmmyClass(source, callback) local name = class:getName() local related = {} self.vm.emmyMgr:eachClass(name, function (class) + if class.type ~= 'emmy.class' then + return + end local src = class:getSource() if src ~= source then related[#related+1] = { @@ -428,7 +431,9 @@ function mt:checkEmmyClass(source, callback) return end local parent = self.vm.emmyMgr:eachClass(extends, function (parent) - return parent + if parent.type == 'emmy.class' then + return parent + end end) if not parent then callback(source[2].start, source[2].finish, lang.script.DIAG_UNDEFINED_CLASS) @@ -439,10 +444,6 @@ function mt:checkEmmyClass(source, callback) 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 @@ -452,13 +453,32 @@ function mt:checkEmmyClass(source, callback) finish = current:getSource().finish, uri = current:getSource().uri, } - current = parent - parent = self.vm.emmyMgr:eachClass(extends, function (parent) - return parent + current = self.vm.emmyMgr:eachClass(extends, function (parent) + if parent.type == 'emmy.class' then + return parent + end end) - if not parent then + if not current then break end + if current:getName() == class:getName() then + callback(source.start, source.finish, lang.script.DIAG_CYCLIC_EXTENDS, related) + break + end + end +end + +function mt:checkEmmyType(source, callback) + for _, tpsource in ipairs(source) do + local name = tpsource[1] + local class = self.vm.emmyMgr:eachClass(name, function (class) + if class.type == 'emmy.class' then + return class + end + end) + if not class then + callback(tpsource.start, tpsource.finish, lang.script.DIAG_UNDEFINED_CLASS) + end end end @@ -466,6 +486,8 @@ function mt:searchEmmyLua(callback) self.vm:eachSource(function (source) if source.type == 'emmyClass' then self:checkEmmyClass(source, callback) + elseif source.type == 'emmyType' then + self:checkEmmyType(source, callback) end end) end diff --git a/server/src/core/hover/hover.lua b/server/src/core/hover/hover.lua index a7fcca19..058ddd4a 100644 --- a/server/src/core/hover/hover.lua +++ b/server/src/core/hover/hover.lua @@ -17,6 +17,11 @@ local OriginTypes = { } local function findClass(value) + -- 检查是否有emmy + local emmy = value:getEmmy() + if emmy then + return emmy:getType() + end -- 检查对象元表 local metaValue = value:getMetaTable() if not metaValue then diff --git a/server/src/core/implementation.lua b/server/src/core/implementation.lua index 1b8006b1..450b9a0c 100644 --- a/server/src/core/implementation.lua +++ b/server/src/core/implementation.lua @@ -166,6 +166,20 @@ local function jumpUri(vm, source, lsp) return positions end +local function parseClass(vm, source) + local className = source:get 'target class' + local positions = {} + vm.emmyMgr:eachClass(className, function (class) + local src = class:getSource() + positions[#positions+1] = { + src.start, + src.finish, + src.uri, + } + end) + return positions +end + return function (vm, source, lsp) if not source then return nil @@ -180,4 +194,11 @@ return function (vm, source, lsp) if source:get 'target uri' then return jumpUri(vm, source, lsp) end + if source:get 'in index' then + return parseValue(vm, source, lsp) + or parseValueSimily(vm, source, lsp) + end + if source:get 'target class' then + return parseClass(vm, source) + end end diff --git a/server/src/core/references.lua b/server/src/core/references.lua index 10d8b2df..33b38fec 100644 --- a/server/src/core/references.lua +++ b/server/src/core/references.lua @@ -1,13 +1,13 @@ local findSource = require 'core.find_source' local function parseResult(vm, source, declarat, callback) + local isGlobal if source:bindLabel() then source:bindLabel():eachInfo(function (info, src) if (declarat and info.type == 'set') or info.type == 'get' then callback(src) end end) - return end if source:bindLocal() then local loc = source:bindLocal() @@ -22,7 +22,6 @@ local function parseResult(vm, source, declarat, callback) callback(src) end end) - return end if source:bindFunction() then if declarat then @@ -40,6 +39,9 @@ local function parseResult(vm, source, declarat, callback) callback(src) end end) + if source:bindValue():isGlobal() then + isGlobal = true + end end local parent = source:get 'parent' if parent then @@ -51,6 +53,13 @@ local function parseResult(vm, source, declarat, callback) end end) end + --local emmy = source:getEmmy() + --if emmy then + -- if emmy.type == 'emmy.class' or emmy.type == 'emmy.type' --then +-- + -- end + --end + return isGlobal end return function (vm, pos, declarat) @@ -60,7 +69,7 @@ return function (vm, pos, declarat) end local positions = {} local mark = {} - parseResult(vm, source, declarat, function (src) + local isGlobal = parseResult(vm, source, declarat, function (src) if mark[src] then return end @@ -78,5 +87,5 @@ return function (vm, pos, declarat) uri, } end) - return positions + return positions, isGlobal end diff --git a/server/src/emmy/class.lua b/server/src/emmy/class.lua index f1101e91..84854fc5 100644 --- a/server/src/emmy/class.lua +++ b/server/src/emmy/class.lua @@ -1,5 +1,6 @@ local listMgr = require 'vm.list' +---@class EmmyClass local mt = {} mt.__index = mt mt.type = 'emmy.class' @@ -16,11 +17,28 @@ function mt:getSource() return listMgr.get(self.source) end -return function (source) +function mt:setValue(value) + self.value = value +end + +function mt:getValue() + return self.value +end + +function mt:eachChild(callback) + self._manager:eachClass(self.name, function (obj) + if obj.type == 'emmy.typeUnit' then + callback(obj) + end + end) +end + +return function (manager, source) local self = setmetatable({ name = source[1][1], source = source.id, extends = source[2] and source[2][1], + _manager = manager, }, mt) return self end diff --git a/server/src/emmy/manager.lua b/server/src/emmy/manager.lua index 99b46420..b86da6d2 100644 --- a/server/src/emmy/manager.lua +++ b/server/src/emmy/manager.lua @@ -1,5 +1,7 @@ local listMgr = require 'vm.list' local newClass = require 'emmy.class' +local newType = require 'emmy.type' +local newTypeUnit = require 'emmy.typeUnit' local mt = {} mt.__index = mt @@ -26,7 +28,7 @@ function mt:flushClass(name) list.version = version end -function mt:eachClass(name, callback) +function mt:eachClassByName(name, callback) self:flushClass(name) local list = self._class[name] if not list then @@ -42,27 +44,64 @@ function mt:eachClass(name, callback) end end -function mt:addClass(source) - local className = source[1][1] - self:flushClass(className) - local list = self._class[className] +function mt:eachClass(...) + local n = select('#', ...) + if n == 1 then + local callback = ... + for name in pairs(self._class) do + local res = self:eachClassByName(name, callback) + if res ~= nil then + return res + end + end + else + local name, callback = ... + return self:eachClassByName(name, callback) + end +end + +function mt:getClass(name) + self:flushClass(name) + local list = self._class[name] local version = listMgr.getVersion() if not list then list = { version = version, } - self._class[className] = list + self._class[name] = list end - list[source.id] = newClass(source) + return list +end + +function mt:addClass(source) + local className = source[1][1] + local list = self:getClass(className) + list[source.id] = newClass(self, source) return list[source.id] end +function mt:addType(source) + local typeObj = newType(self, source) + for i, obj in ipairs(source) do + local typeUnit = newTypeUnit(self, obj) + local className = obj[1] + local list = self:getClass(className) + typeUnit:setParent(typeObj) + list[source.id] = typeUnit + typeObj._childs[i] = typeUnit + obj:set('emmy.typeUnit', typeUnit) + end + return typeObj +end + function mt:remove() end return function () + ---@class emmyMgr local self = setmetatable({ _class = {}, + _type = {}, }, mt) return self end diff --git a/server/src/emmy/type.lua b/server/src/emmy/type.lua new file mode 100644 index 00000000..b7e451b2 --- /dev/null +++ b/server/src/emmy/type.lua @@ -0,0 +1,55 @@ +local listMgr = require 'vm.list' + +local function buildName(source) + local names = {} + for i, type in ipairs(source) do + names[i] = type[1] + end + return table.concat(names, '|') +end + +---@class EmmyType +local mt = {} +mt.__index = mt +mt.type = 'emmy.type' + +function mt:getType() + return self.name +end + +function mt:getName() + return self.name +end + +function mt:getSource() + return listMgr.get(self.source) +end + +function mt:eachClass(callback) + for _, typeUnit in ipairs(self._childs) do + ---@type EmmyTypeUnit + local emmyTypeUnit = typeUnit + emmyTypeUnit:getClass(callback) + end +end + +function mt:setValue(value) + self.value = value + for _, typeUnit in ipairs(self._childs) do + typeUnit:setValue(value) + end +end + +function mt:getValue() + return self.value +end + +return function (manager, source) + local self = setmetatable({ + name = buildName(source), + source = source.id, + _manager = manager, + _childs = {}, + }, mt) + return self +end diff --git a/server/src/emmy/typeUnit.lua b/server/src/emmy/typeUnit.lua new file mode 100644 index 00000000..73d7ea6b --- /dev/null +++ b/server/src/emmy/typeUnit.lua @@ -0,0 +1,51 @@ +local listMgr = require 'vm.list' + +---@class EmmyTypeUnit +local mt = {} +mt.__index = mt +mt.type = 'emmy.typeUnit' + +function mt:getType() + return self.name +end + +function mt:getName() + return self.name +end + +function mt:getSource() + return listMgr.get(self.source) +end + +function mt:getClass(callback) + self._manager:eachClass(self:getName(), function (class) + if class.type == 'emmy.class' then + callback(class) + end + end) +end + +function mt:setValue(value) + self.value = value +end + +function mt:getValue() + return self.value +end + +function mt:setParent(parent) + self.parent = parent +end + +function mt:getParent() + return self.parent +end + +return function (manager, source) + local self = setmetatable({ + name = source[1], + source = source.id, + _manager = manager, + }, mt) + return self +end diff --git a/server/src/method/initialize.lua b/server/src/method/initialize.lua index 82ff9640..5478e744 100644 --- a/server/src/method/initialize.lua +++ b/server/src/method/initialize.lua @@ -13,7 +13,6 @@ return function (lsp) capabilities = { hoverProvider = true, definitionProvider = true, - implementationProvider = true, referencesProvider = true, renameProvider = true, documentSymbolProvider = true, diff --git a/server/src/method/textDocument/completion.lua b/server/src/method/textDocument/completion.lua index 7f60708b..1b9aa73f 100644 --- a/server/src/method/textDocument/completion.lua +++ b/server/src/method/textDocument/completion.lua @@ -16,70 +16,27 @@ local function posToRange(lines, start, finish) } end -local function findStartPos(pos, buf) - local res = nil - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c:find '[%w_]' then - res = i - else - break - end - end - if not res then - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c == '.' or c == ':' then - res = i - elseif c:find '[%s%c]' then - else - break - end - end - end - if not res then - return pos - end - return res -end - -local function findWord(position, text) - local word = text - for i = position, 1, -1 do - local c = text:sub(i, i) - if not c:find '[%w_]' then - word = text:sub(i+1, position) - break - end - end - return word:match('^([%w_]*)') -end - local function fastCompletion(lsp, params, lines) local uri = params.textDocument.uri local text, oldText = lsp:getText(uri) -- lua是从1开始的,因此都要+1 local position = lines:positionAsChar(params.position.line + 1, params.position.character) - local word = findWord(position, text) - local startPos = findStartPos(position, text) local vm = lsp:getVM(uri) - if not vm or not startPos then + if not vm then vm = lsp:loadVM(uri) if not vm then return nil end end - startPos = startPos or position - local items = core.completion(vm, text, startPos, word, oldText) + local items = core.completion(vm, text, position, oldText) if not items or #items == 0 then vm = lsp:loadVM(uri) if not vm then return nil end - startPos = startPos or position - items = core.completion(vm, text, startPos, word) + items = core.completion(vm, text, position) if not items or #items == 0 then return nil end @@ -93,16 +50,13 @@ local function finishCompletion(lsp, params, lines) local text = lsp:getText(uri) -- lua是从1开始的,因此都要+1 local position = lines:positionAsChar(params.position.line + 1, params.position.character) - local word = findWord(position, text) - local startPos = findStartPos(position, text) local vm = lsp:loadVM(uri) if not vm then return nil end - startPos = startPos or position - local items = core.completion(vm, text, startPos, word) + local items = core.completion(vm, text, position) if not items or #items == 0 then return nil end diff --git a/server/src/method/textDocument/definition.lua b/server/src/method/textDocument/definition.lua index fe8d38a5..d33fd739 100644 --- a/server/src/method/textDocument/definition.lua +++ b/server/src/method/textDocument/definition.lua @@ -1,15 +1,5 @@ local core = require 'core' -local function checkWorkSpaceComplete(lsp, source) - if not source:bindValue() then - return - end - if not source:bindValue():get 'cross file' then - return - end - lsp:checkWorkSpaceComplete() -end - local function findResult(lsp, params) local uri = params.textDocument.uri local vm, lines = lsp:loadVM(uri) @@ -24,11 +14,9 @@ local function findResult(lsp, params) return nil end - checkWorkSpaceComplete(lsp, source) - - local positions = core.definition(vm, source, lsp) + local positions, isGlobal = core.definition(vm, position, 'definition', lsp) if not positions then - return nil + return nil, isGlobal end local locations = {} @@ -70,10 +58,10 @@ local function findResult(lsp, params) end if #locations == 0 then - return nil + return nil, isGlobal end - return locations + return locations, isGlobal end local LastTask @@ -83,27 +71,17 @@ return function (lsp, params) LastTask:remove() LastTask = nil end - local result = findResult(lsp, params) - if result then - return result - end return function (response) - local count = 0 + local clock = os.clock() LastTask = ac.loop(0.1, function () - local result = findResult(lsp, params) - if result then - response(result) - LastTask:remove() - LastTask = nil - return - end - count = count + 1 - if lsp:isWaitingCompile() and count < 10 then + local result, isGlobal = findResult(lsp, params) + if isGlobal and lsp:isWaitingCompile() and os.clock() - clock < 1 then return end - response(nil) + response(result) LastTask:remove() LastTask = nil end) + LastTask:onTimer() end end diff --git a/server/src/method/textDocument/publishDiagnostics.lua b/server/src/method/textDocument/publishDiagnostics.lua index fbe65bb3..3a4e4658 100644 --- a/server/src/method/textDocument/publishDiagnostics.lua +++ b/server/src/method/textDocument/publishDiagnostics.lua @@ -43,7 +43,7 @@ local function getRange(start, finish, lines) } end -local function createInfo(data, lines) +local function createInfo(lsp, data, lines) local diagnostic = { source = lang.script.DIAG_DIAGNOSTICS, range = getRange(data.start, data.finish, lines), @@ -54,6 +54,7 @@ local function createInfo(data, lines) if data.related then local related = {} for i, info in ipairs(data.related) do + local _, lines = lsp:getVM(info.uri) local message = info.message if not message then local start_line = lines:rowcol(info.start) @@ -144,7 +145,7 @@ return function (lsp, params) if vm then local datas = core.diagnostics(vm, lines, uri) for _, data in ipairs(datas) do - diagnostics[#diagnostics+1] = createInfo(data, lines) + diagnostics[#diagnostics+1] = createInfo(lsp, data, lines) end end if errs then diff --git a/server/src/method/textDocument/references.lua b/server/src/method/textDocument/references.lua index d969e919..ca4bed87 100644 --- a/server/src/method/textDocument/references.lua +++ b/server/src/method/textDocument/references.lua @@ -4,7 +4,7 @@ local LastTask local function findReferences(lsp, uri, position, declarat) local vm = lsp:getVM(uri) - local positions = core.references(vm, position, declarat) + local positions, isGlobal = core.definition(vm, position, 'reference') if not positions then return nil end @@ -48,10 +48,10 @@ local function findReferences(lsp, uri, position, declarat) end if #locations == 0 then - return nil + return nil, isGlobal end - return locations + return locations, isGlobal end return function (lsp, params) @@ -71,20 +71,16 @@ return function (lsp, params) local position = lines:positionAsChar(params.position.line + 1, params.position.character) return function (response) + local clock = os.clock() LastTask = ac.loop(0.1, function (t) - local positions = findReferences(lsp, uri, position, declarat) - if positions then - response(positions) - t:remove() - LastTask = nil - return - end - if lsp:isWaitingCompile() then + local positions, isGlobal = findReferences(lsp, uri, position, declarat) + if isGlobal and lsp:isWaitingCompile() and os.clock() - clock < 5 then return end - response(nil) + response(positions) t:remove() LastTask = nil end) + LastTask:onTimer() end end diff --git a/server/src/timer.lua b/server/src/timer.lua index 0ae5094f..f477dccf 100644 --- a/server/src/timer.lua +++ b/server/src/timer.lua @@ -193,6 +193,10 @@ function mt:remaining() return getRemaining(self) / 1000.0 end +function mt:onTimer() + self:_onTimer() +end + function ac.wait(timeout, onTimer) local t = setmetatable({ ['_timeout'] = mathMax(mathFloor(timeout * 1000.0), 1), diff --git a/server/src/vm/emmy.lua b/server/src/vm/emmy.lua index 6e5c2b13..1cd52a8a 100644 --- a/server/src/vm/emmy.lua +++ b/server/src/vm/emmy.lua @@ -1,15 +1,70 @@ local mt = require 'vm.manager' +function mt:clearEmmy() + self._emmy = nil +end + +function mt:doEmmy(action) + local tp = action.type + if tp == 'emmyClass' then + self:doEmmyClass(action) + elseif tp == 'emmyType' then + self:doEmmyType(action) + elseif tp == 'emmyAlias' then + elseif tp == 'emmyParam' then + elseif tp == 'emmyReturn' then + elseif tp == 'emmyField' then + elseif tp == 'emmyGeneric' then + elseif tp == 'emmyVararg' then + elseif tp == 'emmyLanguage' then + elseif tp == 'emmyArrayType' then + elseif tp == 'emmyTableType' then + elseif tp == 'emmyFunctionType' then + elseif tp == 'emmySee' then + elseif tp == 'emmyIncomplete' then + self:doEmmyIncomplete(action) + end +end + +function mt:getEmmy() + local emmy = self._emmy + self._emmy = nil + return emmy +end + function mt:doEmmyClass(action) + ---@type emmyMgr local emmyMgr = self.emmyMgr self:instantSource(action) + self:instantSource(action[1]) local class = emmyMgr:addClass(action) - self.emmy = class + action:set('target class', class:getName()) + action[1]:set('target class', class:getName()) + local extends = action[2] + if extends then + self:instantSource(extends) + extends:set('target class', extends[1]) + end + self._emmy = class action:set('emmy.class', class) + if self.lsp then + self.lsp.global:markSet(self:getUri()) + end end function mt:doEmmyType(action) + ---@type emmyMgr local emmyMgr = self.emmyMgr + self:instantSource(action) + for _, obj in ipairs(action) do + self:instantSource(obj) + obj:set('target class', obj[1]) + end + local type = emmyMgr:addType(action) + self._emmy = type + if self.lsp then + self.lsp.global:markGet(self:getUri()) + end end function mt:doEmmyIncomplete(action) diff --git a/server/src/vm/local.lua b/server/src/vm/local.lua index e75ed149..c20224de 100644 --- a/server/src/vm/local.lua +++ b/server/src/vm/local.lua @@ -3,6 +3,7 @@ local listMgr = require 'vm.list' local Sort = 0 local Watch = setmetatable({}, {__mode = 'kv'}) +---@class Local local mt = {} mt.__index = mt mt.type = 'local' @@ -111,6 +112,13 @@ function mt:shadow(old) end group[#group+1] = self self._shadow = group + + if not self:getSource() then + log.debug('not self:getSource()', table.dump(self)) + end + if not old.close then + log.debug('not old.close', table.dump(old)) + end old:close(self:getSource().start - 1) end @@ -136,7 +144,6 @@ function mt:setEmmy(emmy) if emmy.type ~= 'emmy.class' and emmy.type ~= 'emmy.type' then return end - self._emmy = emmy if self.value then self.value:setEmmy(emmy) end diff --git a/server/src/vm/value.lua b/server/src/vm/value.lua index 76b173a9..8a0b0861 100644 --- a/server/src/vm/value.lua +++ b/server/src/vm/value.lua @@ -225,10 +225,10 @@ function mt:flushChild() local count = 0 for srcId, info in pairs(infos) do local src = listMgr.get(srcId) - if src - and (info.type == 'set child' or info.type == 'get child') - then - alived[info[1]] = true + if src then + if info.type == 'set child' or info.type == 'get child' then + alived[info[1]] = true + end count = count + 1 else infos[srcId] = nil @@ -322,7 +322,7 @@ function mt:mergeValue(value) if not value then return end - local global = self._global + local global = self._global or value._global local list = {self, value} local pos = 1 while true do @@ -351,13 +351,14 @@ function mt:mergeValue(value) list[#list+1] = bc end end - if global then - bc:markGlobal() - end a._child[k] = bc end end b._child = a._child + if global then + a:markGlobal() + b:markGlobal() + end if b._meta then a._meta = b._meta @@ -528,10 +529,30 @@ function mt:setEmmy(emmy) if not emmy then return end - if emmy.type ~= 'emmy.class' and emmy.type ~= 'emmy.type' then + if emmy.type == 'emmy.class' then + ---@type EmmyClass + local emmyClass = emmy + emmyClass:setValue(self) + emmyClass:eachChild(function (obj) + local value = obj:getValue() + if value then + value:mergeValue(self) + end + end) + elseif emmy.type == 'emmy.type' then + ---@type EmmyType + local emmyType = emmy + emmyType:setValue(self) + emmyType:eachClass(function (class) + if class then + self:mergeValue(class:getValue()) + end + end) + else return end self._emmy = emmy + self:markGlobal() end function mt:getEmmy() diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua index 9ca661bd..a6d5f9ea 100644 --- a/server/src/vm/vm.lua +++ b/server/src/vm/vm.lua @@ -41,12 +41,14 @@ function mt:buildTable(source) end local n = 0 for index, obj in ipairs(source) do + local emmy = self:getEmmy() if obj.type == 'pair' then local value = self:getFirstInMulti(self:getExp(obj[2])) local key = obj[1] self:instantSource(obj) self:instantSource(key) key:bindValue(value, 'set') + value:setEmmy(emmy) if key.type == 'index' then local index = self:getIndex(key) key:set('parent', tbl) @@ -59,6 +61,7 @@ function mt:buildTable(source) end end elseif obj.type:sub(1, 4) == 'emmy' then + self:doEmmy(obj) else local value = self:getExp(obj) if value.type == 'multi' then @@ -779,10 +782,11 @@ function mt:doGoTo(source) end end -function mt:setOne(var, value) +function mt:setOne(var, value, emmy) if not value then value = valueMgr.create('nil', self:getDefaultSource()) end + value:setEmmy(emmy) self:instantSource(var) if var.type == 'name' then self:setName(var[1], var, value) @@ -806,6 +810,7 @@ function mt:setOne(var, value) end function mt:doSet(action) + local emmy = self:getEmmy() if not action[2] then return end @@ -825,11 +830,12 @@ function mt:doSet(action) local i = 0 self:forList(vars, function (var) i = i + 1 - self:setOne(var, values[i]) + self:setOne(var, values[i], emmy) end) end function mt:doLocal(action) + local emmy = self:getEmmy() self:instantSource(action) local vars = action[1] local exps = action[2] @@ -852,9 +858,8 @@ function mt:doLocal(action) if values then value = values[i] end - self:createLocal(key[1], key, value) + self:createLocal(key[1], key, value, emmy) end) - self.emmy = nil end function mt:doIf(action) @@ -934,11 +939,9 @@ function mt:doFunction(action) if source.type == 'index' then local index = self:getIndex(source) parent:setChild(index, value, source[1]) - parent:addInfo('set child', source, index) elseif source.type == 'name' then local index = source[1] parent:setChild(index, value, source) - parent:addInfo('set child', source, index) end source:bindValue(value, 'set') @@ -963,11 +966,9 @@ function mt:doFunction(action) if source.type == 'index' then local index = self:getIndex(source) parent:setChild(index, value, source[1]) - parent:addInfo('set child', source, index) elseif source.type == 'name' then local index = source[1] parent:setChild(index, value, source) - parent:addInfo('set child', source, index) end source:bindValue(value, 'set') end @@ -1011,6 +1012,10 @@ function mt:doAction(action) end end local tp = action.type + if tp:sub(1, 4) == 'emmy' then + self:doEmmy(action) + return + end if tp == 'do' then self:doDo(action) elseif tp == 'break' then @@ -1042,27 +1047,11 @@ function mt:doAction(action) self:doFunction(action) elseif tp == 'localfunction' then self:doLocalFunction(action) - elseif tp == 'emmyClass' then - --self:doEmmyClass(action) - elseif tp == 'emmyType' then - --self:doEmmyType(action) - elseif tp == 'emmyAlias' then - elseif tp == 'emmyParam' then - elseif tp == 'emmyReturn' then - elseif tp == 'emmyField' then - elseif tp == 'emmyGeneric' then - elseif tp == 'emmyVararg' then - elseif tp == 'emmyLanguage' then - elseif tp == 'emmyArrayType' then - elseif tp == 'emmyTableType' then - elseif tp == 'emmyFunctionType' then - elseif tp == 'emmySee' then - elseif tp == 'emmyIncomplete' then - self:doEmmyIncomplete(action) else self:getExp(action) action:set('as action', true) end + self:clearEmmy() end function mt:doActions(actions) @@ -1164,20 +1153,20 @@ function mt:bindLabel(source, label, action) end end -function mt:createLocal(key, source, value) +function mt:createLocal(key, source, value, emmy) local loc = self:bindLocal(source) if not value then value = self:createValue('nil', source) end if loc then loc:setValue(value) - loc:setEmmy(self.emmy) + loc:setEmmy(emmy) self:saveLocal(key, loc) return loc end loc = localMgr.create(key, source, value) - loc:setEmmy(self.emmy) + loc:setEmmy(emmy) self:saveLocal(key, loc) self:bindLocal(source, loc, 'local') value:addInfo('local', source) @@ -1284,6 +1273,7 @@ return function (ast, lsp, uri) main = nil, env = nil, emmy = nil, + ---@type emmyMgr emmyMgr = lsp and lsp.emmy or emmyMgr(), lsp = lsp, uri = uri or '', diff --git a/server/test/completion/init.lua b/server/test/completion/init.lua index 6dc998c7..560f6fa4 100644 --- a/server/test/completion/init.lua +++ b/server/test/completion/init.lua @@ -58,57 +58,16 @@ local function eq(a, b) return a == b end -local function findStartPos(pos, buf) - local res = nil - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c:find '[%w_]' then - res = i - else - break - end - end - if not res then - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c == '.' or c == ':' then - res = i - elseif c:find '[%s%c]' then - else - break - end - end - end - if not res then - return pos - end - return res -end - -local function findWord(position, text) - local word = text - for i = position, 1, -1 do - local c = text:sub(i, i) - if not c:find '[%w_]' then - word = text:sub(i+1, position) - break - end - end - return word:match('^([%w_]*)') -end - rawset(_G, 'TEST', true) function TEST(script) return function (expect) local pos = script:find('$', 1, true) - 1 - local new_script = script:gsub('%$', ' ') + local new_script = script:gsub('%$', '') local ast = parser:ast(new_script, 'lua', 'Lua 5.4') local vm = buildVM(ast) assert(vm) - local word = findWord(pos, new_script) - local startPos = findStartPos(pos, new_script) - local result = core.completion(vm, new_script, startPos, word) + local result = core.completion(vm, new_script, pos) if expect then assert(result) assert(eq(expect, result)) @@ -414,7 +373,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"collect"', }, }, @@ -424,7 +383,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"stop"', }, }, @@ -434,7 +393,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"restart"', }, }, @@ -444,7 +403,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"count"', }, }, @@ -454,7 +413,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"step"', }, }, @@ -464,7 +423,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"setpause"', }, }, @@ -474,7 +433,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"setstepmul"', }, }, @@ -484,7 +443,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"isrunning"', }, }, @@ -536,7 +495,7 @@ self.results.list[#$] kind = CompletionItemKind.Snippet, textEdit = { start = 20, - finish = 21, + finish = 20, newText = 'self.results.list+1] = ', }, }, @@ -551,7 +510,7 @@ self.results.list[#self.re$] kind = CompletionItemKind.Snippet, textEdit = { start = 20, - finish = 28, + finish = 27, newText = 'self.results.list+1] = ', }, }, @@ -570,7 +529,7 @@ fff[#ff$] kind = CompletionItemKind.Snippet, textEdit = { start = 6, - finish = 9, + finish = 8, newText = 'fff+1] = ', }, }, @@ -589,7 +548,7 @@ local _ = fff.kkk[#$] kind = CompletionItemKind.Snippet, textEdit = { start = 20, - finish = 21, + finish = 20, newText = 'fff.kkk]', }, }, @@ -736,25 +695,25 @@ end (nil) require 'config' .config.runtime.version = 'Lua 5.4' -TEST [[ -local *$ -]] -{ - { - label = 'toclose', - kind = CompletionItemKind.Keyword, - } -} - -TEST [[ -local *tocl$ -]] -{ - { - label = 'toclose', - kind = CompletionItemKind.Keyword, - } -} +--TEST [[ +--local *$ +--]] +--{ +-- { +-- label = 'toclose', +-- kind = CompletionItemKind.Keyword, +-- } +--} + +--TEST [[ +--local *tocl$ +--]] +--{ +-- { +-- label = 'toclose', +-- kind = CompletionItemKind.Keyword, +-- } +--} TEST [[ local mt = {} @@ -810,3 +769,18 @@ TEST [[ kind = CompletionItemKind.Keyword } } + +TEST [[ +---@class ABC +---@class BBC : $ +]] +{ + { + label = 'ABC', + kind = CompletionItemKind.Class, + }, + { + label = 'BBC', + kind = CompletionItemKind.Class, + }, +} diff --git a/server/test/crossfile/completion.lua b/server/test/crossfile/completion.lua index c982607b..cc31ed5d 100644 --- a/server/test/crossfile/completion.lua +++ b/server/test/crossfile/completion.lua @@ -61,31 +61,6 @@ local function eq(a, b) return a == b end -local function findStartPos(pos, buf) - local res = nil - for i = pos-1, 1, -1 do - local c = buf:sub(i, i) - if c:find '%a' then - res = i - else - break - end - end - return res -end - -local function findWord(position, text) - local word = text - for i = position-1, 1, -1 do - local c = text:sub(i, i) - if not c:find '[%w_]' then - word = text:sub(i+1, position) - break - end - end - return word:match('^([%w_]*)') -end - function TEST(data) local lsp = service() local ws = workspace(lsp, 'test') @@ -99,7 +74,7 @@ function TEST(data) local uri = ws:uriEncode(fs.path(info.path)) local script = info.content if info.main then - pos = script:find('$', 1, true) + pos = script:find('$', 1, true) - 1 script = script:gsub('%$', '') mainUri = uri mainBuf = script @@ -114,9 +89,7 @@ function TEST(data) local vm = lsp:loadVM(mainUri) assert(vm) - local word = findWord(pos, mainBuf) - local startPos = findStartPos(pos, mainBuf) or pos - local result = core.completion(vm, mainBuf, startPos, word) + local result = core.completion(vm, mainBuf, pos) local expect = data.completion if expect then assert(result) diff --git a/server/test/crossfile/definition.lua b/server/test/crossfile/definition.lua index aac08802..9310c323 100644 --- a/server/test/crossfile/definition.lua +++ b/server/test/crossfile/definition.lua @@ -22,24 +22,53 @@ local function catch_target(script, sep) return new_script, list end +local function founded(targets, results) + if #targets ~= #results then + return false + end + for _, target in ipairs(targets) do + for _, result in ipairs(results) do + if target[1] == result[1] + and target[2] == result[2] + and target[3] == result[3] + then + goto NEXT + end + end + do return false end + ::NEXT:: + end + return true +end + function TEST(datas) local lsp = service() local ws = workspace(lsp, 'test') lsp.workspace = ws local compiled = {} - local targetList, targetUri, sourceList, sourceUri + local targetList = {} + local sourceList, sourceUri for i, data in ipairs(datas) do local uri = ws:uriEncode(fs.path(data.path)) local new, list = catch_target(data.content, '!') if new ~= data.content or data.target then if data.target then - targetList = data.target + targetList[#targetList+1] = { + data.target[1], + data.target[2], + uri + } else - targetList = list[1] + for _, position in ipairs(list) do + targetList[#targetList+1] = { + position[1], + position[2], + uri + } + end end - targetUri = uri data.content = new end new, list = catch_target(data.content, '?') @@ -60,13 +89,12 @@ function TEST(datas) local sourceVM = lsp:getVM(sourceUri) assert(sourceVM) local sourcePos = (sourceList[1][1] + sourceList[1][2]) // 2 - local source = core.findSource(sourceVM, sourcePos) - local positions = core.definition(sourceVM, source, lsp) - assert(positions and positions[1]) - local start, finish, valueUri = positions[1][1], positions[1][2], positions[1][3] - assert(valueUri == targetUri) - assert(start == targetList[1]) - assert(finish == targetList[2]) + local positions = core.definition(sourceVM, sourcePos, 'definition') + if positions then + assert(founded(targetList, positions)) + else + assert(#targetList == 0) + end end TEST { @@ -84,6 +112,17 @@ TEST { TEST { { path = 'a.lua', + content = 'local <!t!> = 1; return <!t!>', + }, + { + path = 'b.lua', + content = 'local <?t?> = require "a"', + }, +} + +TEST { + { + path = 'a.lua', content = '', target = {0, 0}, }, @@ -96,7 +135,7 @@ TEST { TEST { { path = 'a.lua', - content = 'local <!t!> = 1; return t', + content = 'local <!t!> = 1; return <!t!>', }, { path = 'b.lua', @@ -152,7 +191,7 @@ TEST { { path = 'b.lua', content = [[ - local f = require "a" + local <!f!> = require "a" <?f?>() ]], }, @@ -258,3 +297,37 @@ TEST { ]], }, } + +TEST { + { + path = 'a.lua', + content = [[ + ---@class Class + local <!obj!> + ]] + }, + { + path = 'b.lua', + content = [[ + ---@type Class + local <?obj?> + ]] + }, +} + +TEST { + { + path = 'a.lua', + content = [[ + ---@type Class + local <?obj?> + ]] + }, + { + path = 'b.lua', + content = [[ + ---@class Class + local <!obj!> + ]] + }, +} diff --git a/server/test/crossfile/references.lua b/server/test/crossfile/references.lua index 5f29eb25..4163a321 100644 --- a/server/test/crossfile/references.lua +++ b/server/test/crossfile/references.lua @@ -109,7 +109,7 @@ function TEST(data) compileAll(lsp) assert(vm) - local result = core.references(vm, pos, true) + local result = core.definition(vm, pos, 'reference') if expect then assert(result) assert(founded(expect, result)) diff --git a/server/test/definition/bug.lua b/server/test/definition/bug.lua index 1d3ab02c..ee414ef6 100644 --- a/server/test/definition/bug.lua +++ b/server/test/definition/bug.lua @@ -86,5 +86,5 @@ return f(), <?b?> TEST [[ local a = os.clock() -local <?<!b!>?> = os.clock() +local <?b?> = os.clock() ]] diff --git a/server/test/definition/emmy.lua b/server/test/definition/emmy.lua new file mode 100644 index 00000000..82bac7a8 --- /dev/null +++ b/server/test/definition/emmy.lua @@ -0,0 +1,63 @@ +TEST [[ +---@class <!A!> +---@class B : <?A?> +]] + +TEST [[ +---@class <!A!> +---@type B|<?A?> +]] + +TEST [[ +---@class A +local mt = {} +function mt:<!cast!>() +end + +---@type A +local obj +obj:<?cast?>() +]] + +TEST [[ +---@class A +local <!mt!> = {} +function mt:cast() +end + +---@type A +local <!obj!> +<?obj?>:cast() +]] + +TEST [[ +---@type A +local <?obj?> + +---@class A +local <!mt!> +]] + +TEST [[ +---@type A +local obj +obj:<?func?>() + +---@class A +local mt +function mt:<!func!>() +end +]] + +TEST [[ +---@type A +local obj +obj:<?func?>() + +local mt = {} +mt.__index = mt +function mt:<!func!>() +end +---@class A +local obj = setmetatable({}, mt) +]] diff --git a/server/test/definition/function.lua b/server/test/definition/function.lua index aae5786f..ce20f50b 100644 --- a/server/test/definition/function.lua +++ b/server/test/definition/function.lua @@ -18,7 +18,7 @@ end TEST [[ local <!x!> -function x() +function <!x!>() end <?x?>() ]] diff --git a/server/test/definition/init.lua b/server/test/definition/init.lua index e095e474..1ff5881e 100644 --- a/server/test/definition/init.lua +++ b/server/test/definition/init.lua @@ -45,8 +45,7 @@ function TEST(script) local vm = buildVM(ast) assert(vm) - local source = core.findSource(vm, pos) - local positions = core.definition(vm, source, nil) + local positions = core.definition(vm, pos, 'definition') if positions then assert(founded(target, positions)) else @@ -62,3 +61,4 @@ require 'definition.table' require 'definition.method' require 'definition.label' require 'definition.bug' +require 'definition.emmy' diff --git a/server/test/definition/method.lua b/server/test/definition/method.lua index 40c5f127..08b56f61 100644 --- a/server/test/definition/method.lua +++ b/server/test/definition/method.lua @@ -77,6 +77,7 @@ end local obj = setmetatable({}, { __index = mt }) obj.<!init!> = 1 +obj:x() ]] TEST [[ @@ -86,6 +87,7 @@ function mt:x() end local obj = setmetatable({ <!init!> = 1 }, { __index = mt }) +obj:x() ]] TEST [[ @@ -99,6 +101,7 @@ local obj = setmetatable({ <!out!> = 1, } }, { __index = mt }) +obj:x() ]] TEST [[ diff --git a/server/test/definition/set.lua b/server/test/definition/set.lua index 54df1e7a..44277d33 100644 --- a/server/test/definition/set.lua +++ b/server/test/definition/set.lua @@ -23,7 +23,7 @@ x = 1 do local <!x!> = 1 do - x = 2 + <!x!> = 2 end <?x?>() end diff --git a/server/test/definition/table.lua b/server/test/definition/table.lua index 1b6d011e..90e7926f 100644 --- a/server/test/definition/table.lua +++ b/server/test/definition/table.lua @@ -96,19 +96,19 @@ local t = { t.<?insert?>() ]] -TEST[[ -local t = { - <!insert!> = 1, -} -y.<?insert?>() -]] - -TEST[[ -local t = { - <!insert!> = 1, -} -local y = { - insert = 1, -} -t.<?insert?>() -]] +--TEST[[ +--local t = { +-- <!insert!> = 1, +--} +--y.<?insert?>() +--]] + +--TEST[[ +--local t = { +-- <!insert!> = 1, +--} +--local y = { +-- insert = 1, +--} +--t.<?insert?>() +--]] diff --git a/server/test/diagnostics/init.lua b/server/test/diagnostics/init.lua index 7a092803..4b762122 100644 --- a/server/test/diagnostics/init.lua +++ b/server/test/diagnostics/init.lua @@ -334,25 +334,34 @@ local function x() 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 ---]] +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 +]] + +TEST [[ +---@type <!A!> +]] + +TEST [[ +---@class A +---@type A|<!B!>|<!C!> +]] diff --git a/server/test/hover/init.lua b/server/test/hover/init.lua index fbbbeb82..79904e6c 100644 --- a/server/test/hover/init.lua +++ b/server/test/hover/init.lua @@ -465,10 +465,74 @@ function n<next>(table: table [, index: any]) -> key: any, value: any ]] ---TEST[[ ------@class Class ---local <?x?> = class() ---]] ---[[ ---local x: *Class ---]] +TEST[[ +---@class Class +local <?x?> = class() +]] +[[ +local x: *Class {} +]] + +TEST[[ +---@class Class +<?x?> = class() +]] +[[ +global x: *Class {} +]] + +TEST[[ +local t = { + ---@class Class + <?x?> = class() +} +]] +[[ +field x: *Class {} +]] + +TEST[[ +---@type Class +local <?x?> = class() +]] +[[ +local x: *Class {} +]] + +TEST[[ +---@type Class +<?x?> = class() +]] +[[ +global x: *Class {} +]] + +TEST[[ +local t = { + ---@type Class + <?x?> = class() +} +]] +[[ +field x: *Class {} +]] + +TEST[[ +---@type A|B|C +local <?x?> = class() +]] +[[ +local x: *A|B|C {} +]] + +TEST[[ +---@class Class +local <?x?> = { + b = 1 +} +]] +[[ +local x: *Class { + b: number = 1, +} +]] diff --git a/server/test/references/init.lua b/server/test/references/init.lua index e5d0b1cc..d1eab422 100644 --- a/server/test/references/init.lua +++ b/server/test/references/init.lua @@ -43,7 +43,7 @@ function TEST(script) local vm = buildVM(ast) assert(vm) - local positions = core.references(vm, pos, true) + local positions = core.definition(vm, pos, 'reference') if positions then assert(founded(target, positions)) else @@ -52,13 +52,13 @@ function TEST(script) end TEST [[ -local <!a!> = 1 -<?a?> = <?a?> +local <?a?> = 1 +<!a!> = <!a!> ]] TEST [[ -t.<!a!> = 1 -t.<?a?> = t.<?a?> +t.<?a?> = 1 +t.<!a!> = t.<!a!> ]] TEST [[ @@ -68,8 +68,8 @@ goto <?LABEL?> TEST [[ local a = 1 -local <!a!> = 1 -<?a?> = <?a?> +local <?a?> = 1 +<!a!> = <!a!> ]] TEST [[ @@ -100,3 +100,15 @@ table.<!dump!>() function table.<?dump?>() end ]] + +TEST [[ +---@class <!Class!> +---@type <?Class?> +---@type <!Class!> +]] + +TEST [[ +---@class <?Class?> +---@type <!Class!> +---@type <!Class!> +]] |