summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/core/completion/completion.lua2
-rw-r--r--script/core/diagnostics/deprecated.lua34
-rw-r--r--script/core/diagnostics/type-check.lua458
-rw-r--r--script/core/diagnostics/undefined-global.lua35
-rw-r--r--script/core/reference.lua1
-rw-r--r--script/vm/doc.lua2
-rw-r--r--script/vm/manager.lua2
-rw-r--r--test/crossfile/completion.lua2
-rw-r--r--test/crossfile/hover.lua2
-rw-r--r--test/crossfile/references.lua1
-rw-r--r--test/references/init.lua1
11 files changed, 33 insertions, 507 deletions
diff --git a/script/core/completion/completion.lua b/script/core/completion/completion.lua
index 8e1ef696..edbb2673 100644
--- a/script/core/completion/completion.lua
+++ b/script/core/completion/completion.lua
@@ -205,7 +205,7 @@ local function getSnip(source)
if context <= 0 then
return nil
end
- local defs = vm.getRefs(source)
+ local defs = vm.getDefs(source)
for _, def in ipairs(defs) do
def = vm.getObjectValue(def) or def
if def ~= source and def.type == 'function' then
diff --git a/script/core/diagnostics/deprecated.lua b/script/core/diagnostics/deprecated.lua
index bd2a95b0..a5d623d2 100644
--- a/script/core/diagnostics/deprecated.lua
+++ b/script/core/diagnostics/deprecated.lua
@@ -14,7 +14,9 @@ return function (uri, callback)
return
end
- local cache = {}
+ local dglobals = config.get(uri, 'Lua.diagnostics.globals')
+ local rspecial = config.get(uri, 'Lua.runtime.special')
+ local cache = {}
guide.eachSourceTypes(ast.ast, types, function (src) ---@async
if src.type == 'getglobal' then
@@ -22,37 +24,17 @@ return function (uri, callback)
if not key then
return
end
- if config.get(uri, 'Lua.diagnostics.globals')[key] then
+ if dglobals[key] then
return
end
- if config.get(uri, 'Lua.runtime.special')[key] then
+ if rspecial[key] then
return
end
end
- local id = noder.getID(src)
- if not id then
- return
- end
-
- if cache[id] == false then
- return
- end
-
- if cache[id] then
- callback {
- start = src.start,
- finish = src.finish,
- tags = { define.DiagnosticTag.Deprecated },
- message = cache[id].message,
- data = cache[id].data,
- }
- end
-
await.delay()
if not vm.isDeprecated(src, true) then
- cache[id] = false
return
end
@@ -89,12 +71,6 @@ return function (uri, callback)
)
end
end
- cache[id] = {
- message = message,
- data = {
- versions = versions,
- },
- }
callback {
start = src.start,
diff --git a/script/core/diagnostics/type-check.lua b/script/core/diagnostics/type-check.lua
index 931e1cf6..cc2b3228 100644
--- a/script/core/diagnostics/type-check.lua
+++ b/script/core/diagnostics/type-check.lua
@@ -1,461 +1,3 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local vm = require 'vm'
-local infer = require 'vm.infer'
-local await = require 'await'
-local hasVarargs, errType
-
-local tableMap = {
- ['table'] = true,
- ['array'] = true,
- ['ltable'] = true,
- ['[]'] = true,
-}
-
-local typeNameMap = {
- ['doc.extends.name'] = true,
- ['doc.class.name'] = true,
- ['doc.alias.name'] = true,
- ['doc.type.name'] = true,
- ['doc.type.string'] = true,
- ['doc.type.integer'] = true,
-
-}
-
-local function isTable(name)
- if type(name) ~= 'string' then
- return
- end
- if tableMap[name]
- ---table<K: number, V: string> table
- or tableMap[name:sub(1, 5)]
- ---string[]
- or tableMap[name:sub(-2, -1)] then
- return true
- end
- return false
-end
-
-local function isUserDefineClass(uri, name)
- if guide.isBasicType(name) then
- return false
- else
- local defs = vm.getDocSets(uri, name)
- for _, v in ipairs(defs) do
- if v.type == 'doc.class.name' then
- return true
- end
- end
- end
- return false
-end
-
-local function isClassOralias(typeName)
- if not typeName then
- return false
- elseif typeNameMap[typeName]
- or guide.isBasicType(typeName) then
- return true
- else
- return false
- end
-end
-
-local function isGeneric(type)
- if type.typeGeneric then
- return true
- end
- return false
-end
-
-local function compatibleType(param, args)
- if string.sub(param.type, 1, 9) == 'doc.type.'
- and not param[1] then
- param[1] = string.sub(param.type, 10)
- end
- for _, v in ipairs(args) do
- if v[1] == 'any' then
- return true
- elseif param[1] == v[1] then
- return true
- elseif (param[1] == 'number' or param[1] == 'integer')
- and (v[1] == 'integer' or v[1] == 'number') then
- return true
- elseif v[1] == 'string' then
- ---处理alias
- --@alias searchmode '"ref"'|'"def"'
- if param[1] and param[1]:sub(1, 1) == '"' then
- return true
- end
- elseif (isTable(v.type) or isTable(v[1]))
- and (isTable(param[1]) or isTable(param.type)) then
- return true
- end
- end
- return false
-end
-
--- local function addFatherClass(types, type)
--- if not type[1] then
--- return
--- end
--- local docDefs = vm.getDocSets(type[1])
--- for _, doc in ipairs(docDefs) do
--- if doc.parent
--- and doc.parent.type == 'doc.class'
--- and doc.parent.extends then
--- for _, tp in ipairs(doc.parent.extends) do
--- if tp.type == 'doc.extends.name' then
--- types[#types+1] = {
--- [1] = tp[1],
--- type = 'doc.class.name'
--- }
--- end
--- end
--- end
--- end
--- end
-
-local function addFatherClass(uri, infers)
- for k in pairs(infers) do
- if type(k) == 'string' then
- local docDefs = vm.getDocSets(uri, k)
- for _, doc in ipairs(docDefs) do
- if doc.parent
- and doc.parent.type == 'doc.class'
- and doc.parent.extends then
- for _, tp in ipairs(doc.parent.extends) do
- if tp.type == 'doc.extends.name' then
- infers[tp[1]] = true
- end
- end
- end
- end
- end
- end
-end
-
-local function getParamTypes(arg)
- if not arg then
- return false
- end
- local types
- if arg.type == 'doc.type.arg' then
- ---处理doc.type.function
- if arg.name and arg.name[1] == '...' then
- types = {
- [1] = {
- [1] = '...',
- type = 'varargs'
- }
- }
- return true, types
- end
- types = arg.extends.types
- return true, types
- elseif arg.type == 'local' then
- ---处理function
- local argDefs = vm.getDefs(arg)
- if #argDefs == 0 then
- return false
- end
- types = {}
- if arg.tag == 'self' then
- ---method, 如果self没有定义为一个class或者type,则认为它为any
- for _, argDef in ipairs(argDefs) do
- if argDef.type == 'doc.class.name'
- or argDef.type == 'doc.type.name'
- or argDef.type == 'doc.type.string'
- or argDef.type == 'doc.type.ltable' then
- types[#types+1] = argDef
- end
- end
- if #types == 0 then
- return false
- end
- return true, types
- else
- for _, argDef in ipairs(argDefs) do
- if argDef.type == 'doc.param' and argDef.extends then
- types = argDef.extends.types
- if argDef.optional then
- types[#types+1] = {
- [1] = 'nil',
- type = 'nil'
- }
- end
- elseif argDef.type == 'doc.type.string'
- or argDef.type == 'doc.type.ltable' then
- types[#types+1] = argDef
- ---变长参数
- elseif argDef.name and argDef.name[1] == '...' then
- types = {
- [1] = {
- [1] = '...',
- type = 'varargs'
- }
- }
- break
- end
- end
- if #types == 0 then
- return false
- else
- return true, types
- end
- end
- elseif arg.type == '...' then
- ---处理只有一个可变参数
- types = {
- [1] = {
- [1] = '...',
- type = 'varargs'
- }
- }
- return true, types
- end
-end
-
-local function getInfoFromDefs(defs)
- local paramsTypes = {}
- local funcArgsType
- local mark = {}
- for _, def in ipairs(defs) do
- funcArgsType = {}
- if def.value then
- def = def.value
- end
- if not mark[def] then
- mark[def] = true
- if def.type == 'function'
- or def.type == 'doc.type.function' then
- if def.args then
- for _, arg in ipairs(def.args) do
- local suc, types = getParamTypes(arg)
- if suc then
- local plusAlias = {}
- for i, tp in ipairs(types) do
- local aliasDefs = vm.getDefs(tp)
- for _, v in ipairs(aliasDefs) do
- ---TODO(arthur)
- -- if not v.type then
- -- end
- if v[1] ~= tp[1]
- and isClassOralias(v.type) then
- plusAlias[#plusAlias+1] = v
- end
- end
- plusAlias[#plusAlias+1] = types[i]
- end
- funcArgsType[#funcArgsType+1] = plusAlias
- else
- ---如果有一个参数没有定义type,都会跳过检查
- funcArgsType = {}
- break
- end
- end
- end
- if #funcArgsType > 0 then
- paramsTypes[#paramsTypes+1] = funcArgsType
- end
- end
- end
- end
- return paramsTypes
-end
-
-local function getArgsInfo(uri, callArgs)
- local callArgsType = {}
- for _, arg in ipairs(callArgs) do
- -- local defs = vm.getDefs(arg)
- local infers = infer.searchInfers(arg)
- if infers['_G'] or infer['_ENV'] then
- infers['_G'] = nil
- infers['_ENV'] = nil
- infers['table'] = true
- end
- local hasAny = infers['any']
- ---处理继承
- addFatherClass(uri, infers)
- if not hasAny then
- infers['any'] = nil
- infers['unknown'] = nil
- end
- local types = {}
- if not infers['table'] then
- for k in pairs(infers) do
- if not vm.isBuiltinType(k)
- and isUserDefineClass(uri, k) then
- infers['table'] = true
- break
- end
- end
- end
- for k in pairs(infers) do
- if k then
- types[#types+1] = {
- [1] = k,
- type = k
- }
- end
- end
- if #types < 1 then
- return false
- end
- types.start = arg.start
- types.finish = arg.finish
- callArgsType[#callArgsType+1] = types
- -- local defs = vm.getDefs(arg)
- -- local types = {}
- -- types.typeMap = {}
- -- for _, def in ipairs(defs) do
- -- if vm.isBuiltinType(def.type) then
- -- types[#types+1] = {
- -- [1] = def.type,
- -- type = def.type
- -- }
- -- elseif def.type == 'doc.class.name'
- -- or def.type == 'doc.type.name'
- -- or def.type == 'doc.type.string'
- -- or def.type == 'doc.type.ltable' then
- -- if def[1] then
- -- if not types.typeMap[def[1]] then
- -- types[#types+1] = def
- -- types.typeMap[def[1]] = true
- -- end
- -- else
- -- types[#types+1] = def
- -- end
- -- elseif def.type == 'doc.type' then
- -- print(1)
- -- elseif def.type == 'doc.type.arg' then
- -- for _, tp in ipairs(arg.extends.types) do
- -- types[#types+1] = arg.extends.types[1]
- -- end
- -- elseif def.type == 'doc.param' then
- -- for i, tp in ipairs(def.extends.types) do
- -- types[#types+1] = def.extends.types[i]
- -- end
- -- if def.optional then
- -- types[#types+1] = {
- -- [1] = 'nil',
- -- type = 'nil'
- -- }
- -- end
- -- end
- -- end
- -- for _, tp in ipairs(types) do
- -- if not vm.isBuiltinType(tp.type) then
- -- addFatherClass(types, tp)
- -- end
- -- end
- -- types.start = arg.start
- -- types.finish = arg.finish
- -- if #types == 0 then
- -- types = {
- -- [1] = {
- -- [1] = 'any',
- -- type = 'any',
- -- }
- -- }
- -- end
- -- callArgsType[#callArgsType+1] = types
- end
- return true, callArgsType
-end
-
-local function matchParams(paramsTypes, i, arg)
- local flag = ''
- local messages = {}
- ---paramsTypes 存的是多个定义的参数信息
- ---paramTypes 存的是单独一个定义的参数信息
- ---param 是某一个定义中的第i个参数的信息
- for _, paramTypes in ipairs(paramsTypes) do
- if not paramTypes[i] then
- goto CONTINUE
- end
- flag = ''
- for _, param in ipairs(paramTypes[i]) do
- if param[1] == '...' then
- hasVarargs = true
- return true
- elseif compatibleType(param, arg)
- or param[1] == 'any' then
- ---如果形参的类型在实参里面
- flag = ''
- return true
- elseif isGeneric(param) then
- ---如果是泛型,不检查
- return true
- else
- if param[1] and not errType[param[1]] then
- ---TODO(arthur) 什么时候param[1]是nil?
- errType[param[1]] = true
- flag = flag .. ' ' .. (param[1] or '')
- end
- end
- end
- if flag ~= '' then
- local argm = '[ '
- for _, v in ipairs(arg) do
- argm = argm .. v[1] .. ' '
- end
- argm = argm .. ']'
- local message = 'Argument of type in '
- .. argm
- .. ' is not assignable to parameter of type in ['
- .. flag
- .. ' ]'
- if not messages[message] then
- messages[message] = true
- messages[#messages+1] = message
- end
- end
- ::CONTINUE::
- end
- return false, messages
-end
-
---@async
return function(uri, callback)
- local ast = files.getState(uri)
- if not ast then
- return
- end
- guide.eachSourceType(ast.ast, 'call', function(source) ---@async
- if not source.args then
- return
- end
- await.delay()
- local callArgs = source.args
- local suc, callArgsType = getArgsInfo(uri, callArgs)
- if not suc then
- return
- end
- local func = source.node
- local defs = vm.getDefs(func)
- ---只检查有emmy注释定义的函数
- local paramsTypes = getInfoFromDefs(defs)
- ---遍历实参
- for i, arg in ipairs(callArgsType) do
- ---遍历形参
- hasVarargs = false
- errType = {}
- local match, messages = matchParams(paramsTypes, i, arg)
- if hasVarargs then
- return
- end
- ---都不匹配
- if not match then
- if #messages > 0 then
- callback {
- start = arg.start,
- finish = arg.finish,
- message = table.concat(messages, '\n')
- }
- end
- end
- end
- ---所有参数都匹配了
- end)
end
diff --git a/script/core/diagnostics/undefined-global.lua b/script/core/diagnostics/undefined-global.lua
index cf31ec4e..139fa74f 100644
--- a/script/core/diagnostics/undefined-global.lua
+++ b/script/core/diagnostics/undefined-global.lua
@@ -3,8 +3,8 @@ local vm = require 'vm'
local lang = require 'language'
local config = require 'config'
local guide = require 'parser.guide'
-local collector = require 'core.collector' 'searcher'
local await = require 'await'
+local globalMgr = require 'vm.global-manager'
local requireLike = {
['include'] = true,
@@ -20,35 +20,40 @@ return function (uri, callback)
return
end
+ local dglobals = config.get(uri, 'Lua.diagnostics.globals')
+ local rspecial = config.get(uri, 'Lua.runtime.special')
+ local cache = {}
+
-- 遍历全局变量,检查所有没有 set 模式的全局变量
guide.eachSourceType(ast.ast, 'getglobal', function (src) ---@async
local key = src[1]
if not key then
return
end
- if config.get(uri, 'Lua.diagnostics.globals')[key] then
+ if dglobals[key] then
return
end
- if config.get(uri, 'Lua.runtime.special')[key] then
+ if rspecial[key] then
return
end
local node = src.node
if node.tag ~= '_ENV' then
return
end
- await.delay()
- local id = 'def:' .. noder.getID(src)
- if not collector:has(uri, id) then
- local message = lang.script('DIAG_UNDEF_GLOBAL', key)
- if requireLike[key:lower()] then
- message = ('%s(%s)'):format(message, lang.script('DIAG_REQUIRE_LIKE', key))
- end
- callback {
- start = src.start,
- finish = src.finish,
- message = message,
- }
+ if cache[key] == nil then
+ cache[key] = globalMgr.hasGlobalSets(uri, 'variable', key)
+ end
+ if cache[key] then
return
end
+ local message = lang.script('DIAG_UNDEF_GLOBAL', key)
+ if requireLike[key:lower()] then
+ message = ('%s(%s)'):format(message, lang.script('DIAG_REQUIRE_LIKE', key))
+ end
+ callback {
+ start = src.start,
+ finish = src.finish,
+ message = message,
+ }
end)
end
diff --git a/script/core/reference.lua b/script/core/reference.lua
index c7fa7782..c3ce2716 100644
--- a/script/core/reference.lua
+++ b/script/core/reference.lua
@@ -51,6 +51,7 @@ local accept = {
['doc.alias.name'] = true,
}
+---@async
return function (uri, position)
local ast = files.getState(uri)
if not ast then
diff --git a/script/vm/doc.lua b/script/vm/doc.lua
index e52712d2..16ac0778 100644
--- a/script/vm/doc.lua
+++ b/script/vm/doc.lua
@@ -3,8 +3,6 @@ local guide = require 'parser.guide'
---@class vm
local vm = require 'vm.vm'
local config = require 'config'
-local collector = require 'core.collector' 'searcher'
-local define = require 'proto.define'
local globalMgr = require 'vm.global-manager'
---获取class与alias
diff --git a/script/vm/manager.lua b/script/vm/manager.lua
index 2068507f..67e8cc38 100644
--- a/script/vm/manager.lua
+++ b/script/vm/manager.lua
@@ -14,6 +14,8 @@ end
files.watch(function (ev, uri)
if ev == 'update' then
+ globalManager.dropUri(uri)
+ localManager.dropUri(uri)
local state = files.getState(uri)
if state then
globalManager.compileAst(state.ast)
diff --git a/test/crossfile/completion.lua b/test/crossfile/completion.lua
index c271f598..79762646 100644
--- a/test/crossfile/completion.lua
+++ b/test/crossfile/completion.lua
@@ -837,7 +837,7 @@ TEST {
kind = CompletionItemKind.Variable,
description = [[
```lua
-local z: {}
+local z: table
```]]
},
}
diff --git a/test/crossfile/hover.lua b/test/crossfile/hover.lua
index b0cc8c7d..4461e775 100644
--- a/test/crossfile/hover.lua
+++ b/test/crossfile/hover.lua
@@ -280,7 +280,7 @@ TEST {
hover = [[
```lua
global t: {
- [1]: integer = 1|2,
+ [1]: integer = 2,
}
```]],
}
diff --git a/test/crossfile/references.lua b/test/crossfile/references.lua
index 9e55c77a..5ab6a18f 100644
--- a/test/crossfile/references.lua
+++ b/test/crossfile/references.lua
@@ -1,3 +1,4 @@
+---@diagnostic disable: await-in-sync
local files = require 'files'
local furi = require 'file-uri'
local core = require 'core.reference'
diff --git a/test/references/init.lua b/test/references/init.lua
index ed324d36..c8391769 100644
--- a/test/references/init.lua
+++ b/test/references/init.lua
@@ -1,3 +1,4 @@
+---@diagnostic disable: await-in-sync
local core = require 'core.reference'
local files = require 'files'
local catch = require 'catch'