summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2021-07-06 19:49:48 +0800
committer最萌小汐 <sumneko@hotmail.com>2021-07-06 19:49:48 +0800
commit7baec4ad875f319ae6076788d656d42c42f47649 (patch)
treef6028803b7b913ffcadb8e6dd729a3540da47c59
parent47f611c9c71bebe0f2ec0b9a52b3c578a1b8e01e (diff)
downloadlua-language-server-7baec4ad875f319ae6076788d656d42c42f47649.zip
fix infer when `__index` is a function
-rw-r--r--script/core/infer.lua11
-rw-r--r--script/core/noder.lua16
-rw-r--r--script/core/searcher.lua102
-rw-r--r--test/type_inference/init.lua4
4 files changed, 116 insertions, 17 deletions
diff --git a/script/core/infer.lua b/script/core/infer.lua
index fc84e597..aa1e1f28 100644
--- a/script/core/infer.lua
+++ b/script/core/infer.lua
@@ -422,7 +422,10 @@ local function searchInfer(source, infers, mark)
end
local value = searcher.getObjectValue(source)
if value then
- searchInferOfValue(value, infers, mark)
+ if value.type ~= 'function'
+ and value.type ~= 'table' then
+ searchInferOfValue(value, infers, mark)
+ end
return
end
-- check LuaDoc
@@ -502,9 +505,13 @@ local function searchLiteral(source, literals, mark)
return
end
mark[source] = true
+ searchLiteralOfValue(source, literals, mark)
local value = searcher.getObjectValue(source)
if value then
- searchLiteralOfValue(value, literals, mark)
+ if value.type ~= 'function'
+ and value.type ~= 'table' then
+ searchLiteralOfValue(value, literals, mark)
+ end
return
end
end
diff --git a/script/core/noder.lua b/script/core/noder.lua
index 49f4613b..c3a9c5bb 100644
--- a/script/core/noder.lua
+++ b/script/core/noder.lua
@@ -43,11 +43,13 @@ local URI_REGEX = URI_CHAR .. '([^' .. URI_CHAR .. ']*)' .. URI_CHAR .. '(.
---@field skip boolean
---@alias noders table<string, node[]>
+---@alias node.filter fun(id: string, field?: string):boolean
---@class node.info
----@field reject? string
----@field deep? boolean
----@field filter? fun(id: string):boolean
+---@field reject? string
+---@field deep? boolean
+---@field filter? node.filter
+---@field filterValid? node.filter
---创建source的链接信息
---@param noders noders
@@ -619,9 +621,15 @@ local function compileCallReturn(noders, call, sourceID, returnIndex)
end
pushForward(noders, sourceID, tblID)
pushForward(noders, sourceID, indexID, {
- filter = function (id)
+ filter = function (id, field)
+ if field then
+ return true
+ end
return id:sub(1, 2) ~= 'f:'
end,
+ filterValid = function (id, field)
+ return not field
+ end
})
pushBackward(noders, tblID, sourceID)
--pushBackward(noders, indexID, callID)
diff --git a/script/core/searcher.lua b/script/core/searcher.lua
index 1d9eff5c..f6146b27 100644
--- a/script/core/searcher.lua
+++ b/script/core/searcher.lua
@@ -436,9 +436,6 @@ function m.searchRefsByID(status, uri, expect, mode)
---@param ward '"forward"'|'"backward"'
---@param info node.info
local function checkThenPushReject(ward, info)
- if not info or info.deep then
- return true
- end
local reject = info.reject
if not reject then
return true
@@ -462,9 +459,6 @@ function m.searchRefsByID(status, uri, expect, mode)
---@param ward '"forward"'|'"backward"'
---@param info node.info
local function popReject(ward, info)
- if not info or info.deep then
- return
- end
local reject = info.reject
if not reject then
return
@@ -478,9 +472,75 @@ function m.searchRefsByID(status, uri, expect, mode)
popTags[reject] = popTags[reject] - 1
end
+ ---@type table<node.filter, integer>
+ local filters = {}
+
+ ---@param id string
+ ---@param info node.info
+ local function pushInfoFilter(id, field, info)
+ local filter = info.filter
+ if not filter then
+ return
+ end
+ local filterValid = info.filterValid
+ if filterValid and not filterValid(id, field) then
+ return
+ end
+ filters[filter] = (filters[filter] or 0) + 1
+ end
+
+ ---@param id string
+ ---@param info node.info
+ local function releaseInfoFilter(id, field, info)
+ local filter = info.filter
+ if not filter then
+ return
+ end
+ local filterValid = info.filterValid
+ if filterValid and not filterValid(id, field) then
+ return
+ end
+ if filters[filter] <= 1 then
+ filters[filter] = nil
+ else
+ filters[filter] = filters[filter] - 1
+ end
+ end
+
+ ---@param id string
+ ---@param info node.info
+ local function checkInfoFilter(id, field, info)
+ for filter in pairs(filters) do
+ if not filter(id, field) then
+ return false
+ end
+ end
+ return true
+ end
+
+ ---@param id string
+ ---@param info node.info
+ local function checkInfoBeforeForward(id, field, info)
+ pushInfoFilter(id, field, info)
+ if not checkThenPushReject('forward', info) then
+ return false
+ end
+ return true
+ end
+
+ ---@param id string
+ ---@param info node.info
+ local function releaseInfoAfterForward(id, field, info)
+ popReject('forward', info)
+ releaseInfoFilter(id, field, info)
+ end
+
local function checkForward(id, node, field)
for forwardID, info in noder.eachForward(node) do
- if info and not checkThenPushReject('forward', info) then
+ if info and not checkInfoBeforeForward(forwardID, field, info) then
+ goto CONTINUE
+ end
+ if not checkInfoFilter(forwardID, field, info) then
goto CONTINUE
end
local targetUri, targetID = noder.getUriAndID(forwardID)
@@ -489,11 +549,29 @@ function m.searchRefsByID(status, uri, expect, mode)
else
searchID(targetID or forwardID, field)
end
- popReject('forward', info)
+ if info then
+ releaseInfoAfterForward(forwardID, field, info)
+ end
::CONTINUE::
end
end
+ local function checkInfoBeforeBackward(id, field, info)
+ if info.deep and mode ~= 'allref' and mode ~= 'alldef' then
+ return false
+ end
+ if not checkThenPushReject('backward', info) then
+ return false
+ end
+ pushInfoFilter(id, field, info)
+ return true
+ end
+
+ local function releaseInfoAfterBackward(id, field, info)
+ popReject('backward', info)
+ releaseInfoFilter(id, field, info)
+ end
+
local function checkBackward(id, node, field)
if ignoredIDs[id] then
return
@@ -502,10 +580,10 @@ function m.searchRefsByID(status, uri, expect, mode)
return
end
for backwardID, info in noder.eachBackward(node) do
- if info and info.deep and mode ~= 'allref' and mode ~= 'alldef' then
+ if info and not checkInfoBeforeBackward(backwardID, field, info) then
goto CONTINUE
end
- if info and not checkThenPushReject('backward', info) then
+ if not checkInfoFilter(backwardID, field, info) then
goto CONTINUE
end
local targetUri, targetID = noder.getUriAndID(backwardID)
@@ -514,7 +592,9 @@ function m.searchRefsByID(status, uri, expect, mode)
else
searchID(targetID or backwardID, field)
end
- popReject('backward', info)
+ if info then
+ releaseInfoAfterBackward(backwardID, field, info)
+ end
::CONTINUE::
end
end
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index 83e73487..c07074f7 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -878,3 +878,7 @@ local t = f('')
print(t.<?x?>)
]]
+
+TEST 'table' [[
+local <?t?> = setmetatable({}, { __index = function () end })
+]]