summaryrefslogtreecommitdiff
path: root/script/core
diff options
context:
space:
mode:
Diffstat (limited to 'script/core')
-rw-r--r--script/core/diagnostics/type-check.lua132
1 files changed, 132 insertions, 0 deletions
diff --git a/script/core/diagnostics/type-check.lua b/script/core/diagnostics/type-check.lua
new file mode 100644
index 00000000..99b40303
--- /dev/null
+++ b/script/core/diagnostics/type-check.lua
@@ -0,0 +1,132 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local vm = require 'vm'
+
+local function hasTypeDoc(obj)
+ if obj.type == 'getlocal'
+ and obj.node
+ and obj.node.type == 'local'
+ and obj.node.bindDocs
+ and obj.node.bindDocs[1]
+ and obj.node.bindDocs[1].type == 'doc.type' then
+ return true
+ end
+ return false
+end
+local function inTypes(param, args)
+ for _, v in ipairs(args.type) do
+ if param[1] == v[1] then
+ return true
+ end
+ end
+ return false
+end
+return function (uri, callback)
+ local ast = files.getState(uri)
+ if not ast then
+ return
+ end
+ guide.eachSourceType(ast.ast, 'call', function (source)
+ if not source.args then
+ return
+ end
+ local callArgs = source.args
+ local callArgsType = {}
+ for _, arg in ipairs(callArgs) do
+ ---检查字面值类型的参数调用
+ if guide.isLiteral(arg) then
+ callArgsType[#callArgsType+1] = {
+ type = {
+ [1] = {
+ [1] = arg.type,
+ ['type'] = arg.type,
+ }
+ },
+ start = arg.start,
+ finish = arg.finish,
+ }
+ ---检查传入参数有完整信息的情况
+ elseif hasTypeDoc(arg) then
+ callArgsType[#callArgsType+1] = {
+ type = arg.node.bindDocs[1].types,
+ start = arg.start,
+ finish = arg.finish,
+ }
+ else
+ return
+ end
+ end
+ local func = source.node
+ local defs = vm.getDefs(func)
+ local funcArgsType = {}
+ ---只检查有emmy注释定义的函数
+ ---获取函数定义的参数信息时,遇到一个定义就停止获取
+ for _, def in ipairs(defs) do
+ if def.value then
+ def = def.value
+ end
+ if def.type == 'function' then
+ if def.args then
+ for _, arg in ipairs(def.args) do
+ if arg.docParam and arg.docParam.extends then
+ ---如果是很复杂的type,比如泛型什么的,先不检查
+ if not arg.docParam.extends.types[1][1]
+ or arg.docParam.extends.types[1].typeGeneric then
+ return
+ end
+ funcArgsType[#funcArgsType+1] = arg.docParam.extends.types
+ else
+ funcArgsType = {}
+ end
+ end
+ end
+ break
+ end
+ end
+ if #funcArgsType == 0 then
+ return
+ end
+ local message = ''
+ ---先遍历实参
+ for i, arg in ipairs(callArgsType) do
+ if not funcArgsType[i] then
+ ---由另一个检查来处理
+ -- message = 'too many call args'
+ -- callback{
+ -- start = arg.start,
+ -- finish = arg.finish,
+ -- message = message
+ -- }
+ return
+ end
+ local flag = ''
+ ---遍历形参
+ for _, tp in ipairs(funcArgsType[i]) do
+ ---如果形参的类型在实参里面
+ if inTypes(tp, arg)
+ or tp[1] == 'any'
+ or arg.type == 'any' then
+ flag = ''
+ break
+ else
+ flag = flag ..' ' .. tp[1]
+ end
+ end
+ if flag ~= '' then
+ local argm = '[ '
+ for _, v in ipairs(arg.type) do
+ argm = argm .. v[1]..' '
+ end
+ argm = argm .. ']'
+ message = 'callArg: '..argm..' has no type belong to ['..flag..' ]'
+ callback{
+ start = arg.start,
+ finish = arg.finish,
+ message = message
+ }
+ return
+ end
+ end
+ end)
+
+end