diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2021-07-06 19:49:48 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2021-07-06 19:49:48 +0800 |
commit | 7baec4ad875f319ae6076788d656d42c42f47649 (patch) | |
tree | f6028803b7b913ffcadb8e6dd729a3540da47c59 | |
parent | 47f611c9c71bebe0f2ec0b9a52b3c578a1b8e01e (diff) | |
download | lua-language-server-7baec4ad875f319ae6076788d656d42c42f47649.zip |
fix infer when `__index` is a function
-rw-r--r-- | script/core/infer.lua | 11 | ||||
-rw-r--r-- | script/core/noder.lua | 16 | ||||
-rw-r--r-- | script/core/searcher.lua | 102 | ||||
-rw-r--r-- | test/type_inference/init.lua | 4 |
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 }) +]] |