summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruhziel <uhziel@gmail.com>2020-12-11 16:12:56 +0800
committeruhziel <uhziel@gmail.com>2020-12-11 16:12:56 +0800
commit93cdf898f5eb8282dba0d684f926e26c6a9f7dbd (patch)
tree1479b7923cf7afdba0b792bda824165d1bfa3fd2
parent64e62cfefbeff094b2d168ed5d0d31d48736c89b (diff)
downloadlua-language-server-93cdf898f5eb8282dba0d684f926e26c6a9f7dbd.zip
通过不向前推断、在vm缓存doc.class查询fields来加快分析速度
-rw-r--r--script/core/diagnostics/undefined-field.lua40
-rw-r--r--script/parser/guide.lua4
-rw-r--r--script/vm/eachField.lua5
-rw-r--r--test/diagnostics/init.lua57
4 files changed, 85 insertions, 21 deletions
diff --git a/script/core/diagnostics/undefined-field.lua b/script/core/diagnostics/undefined-field.lua
index 307182b3..ab707f7c 100644
--- a/script/core/diagnostics/undefined-field.lua
+++ b/script/core/diagnostics/undefined-field.lua
@@ -11,39 +11,37 @@ return function (uri, callback)
return
end
- local function is_G(src)
- if not src then
- return false
- end
- while src.node ~= nil and src.type == 'getfield' and src.field[1] == '_G' do
- src = src.node
+ local function getDocClassFromInfer(src)
+ local infers = vm.getInfers(src, 0)
+
+ if not infers then
+ return nil
end
- return src.type == 'getglobal' and src.special == '_G'
- end
- local function canInfer2Class(src)
- local className = vm.getClass(src, 0)
- if not className then
- local inferType = vm.getInferType(src, 0)
- if inferType ~= 'any' and inferType ~= 'table' then
- className = inferType
+ for i = 1, #infers do
+ local infer = infers[i]
+ if infer.type ~= '_G' then
+ local inferSource = infer.source
+ if inferSource.type == 'doc.class' then
+ return inferSource
+ elseif inferSource.type == 'doc.class.name' then
+ return inferSource.parent
+ end
end
end
- return className and className ~= 'table'
+ return nil
end
local function checkUndefinedField(src)
local fieldName = guide.getKeyName(src)
- if is_G(src)then
- return
- end
- if not canInfer2Class(src.node) then
+ local docClass = getDocClassFromInfer(src.node)
+ if not docClass then
return
end
-
- local refs = vm.getFields(src.node, 0)
+
+ local refs = vm.getFields(docClass)
local fields = {}
local empty = true
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 022be26d..fcf96aa2 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -1242,6 +1242,10 @@ function m.isDoc(source)
return source.type:sub(1, 4) == 'doc.'
end
+function m.isDocClass(source)
+ return source.type == 'doc.class'
+end
+
--- 根据函数的调用参数,获取:调用,参数索引
function m.getCallAndArgIndex(callarg)
local callargs = callarg.parent
diff --git a/script/vm/eachField.lua b/script/vm/eachField.lua
index fabb11c7..19ac77e9 100644
--- a/script/vm/eachField.lua
+++ b/script/vm/eachField.lua
@@ -45,6 +45,11 @@ function vm.getFields(source, deep)
or getFieldsBySource(source, deep)
vm.getCache('eachFieldOfGlobal')[name] = cache
return cache
+ elseif guide.isDocClass(source) then
+ local cache = vm.getCache('eachFieldOfDocClass')[source]
+ or getFieldsBySource(source, deep)
+ vm.getCache('eachFieldOfDocClass')[source] = cache
+ return cache
else
return getFieldsBySource(source, deep)
end
diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua
index 27a7e5f5..b923b8b6 100644
--- a/test/diagnostics/init.lua
+++ b/test/diagnostics/init.lua
@@ -824,6 +824,7 @@ TEST [[
local t
]]
+-- checkUndefinedField 通用
TEST [[
---@class Foo
---@field field1 integer
@@ -865,3 +866,59 @@ local mt3
function mt3:method() return 1 end
print(mt3:method())
]]
+
+-- checkUndefinedField 通过type找到class
+TEST [[
+---@class Foo
+local Foo
+function Foo:method1() end
+
+---@type Foo
+local v
+v:method1()
+<!v:method2!>() -- doc.class.name
+]]
+
+-- checkUndefinedField 通过type找到class,涉及到 class 继承版
+TEST [[
+---@class Foo
+local Foo
+function Foo:method1() end
+---@class Bar: Foo
+local Bar
+function Bar:method3() end
+
+---@type Bar
+local v
+v:method1()
+<!v:method2!>() -- doc.class.name
+v:method3()
+]]
+
+-- checkUndefinedField 类名和类变量同名,类变量被直接使用
+TEST [[
+---@class Foo
+local Foo
+function Foo:method1() end
+<!Foo:method2!>() -- doc.class
+<!Foo:method2!>() -- doc.class
+]]
+
+-- checkUndefinedField 没有@class的不检测
+TEST [[
+local Foo
+function Foo:method1()
+ return Foo:method2() -- table
+end
+]]
+
+-- checkUndefinedField 类名和类变量不同名,类变量被直接使用、使用self
+TEST [[
+---@class Foo
+local mt
+function mt:method1()
+ <!mt.method2!>() -- doc.class
+ self.method1()
+ return <!self.method2!>() -- doc.class.name
+end
+]]