summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changelog.md17
-rw-r--r--meta/template/math.lua2
-rw-r--r--script/core/completion/postfix.lua15
-rw-r--r--script/core/definition.lua3
-rw-r--r--script/core/diagnostics/unused-function.lua3
-rw-r--r--script/core/infer.lua4
-rw-r--r--script/core/noder.lua136
-rw-r--r--script/core/reference.lua3
-rw-r--r--script/core/searcher.lua58
-rw-r--r--script/encoder/utf16.lua12
-rw-r--r--script/files.lua4
-rw-r--r--script/parser/luadoc.lua8
-rw-r--r--script/parser/newparser.lua80
-rw-r--r--script/provider/diagnostic.lua5
-rw-r--r--script/provider/provider.lua5
-rw-r--r--script/utility.lua3
-rw-r--r--test/completion/common.lua24
-rw-r--r--test/crossfile/hover.lua32
-rw-r--r--test/definition/bug.lua77
-rw-r--r--test/diagnostics/init.lua16
-rw-r--r--test/type_inference/init.lua24
21 files changed, 402 insertions, 129 deletions
diff --git a/changelog.md b/changelog.md
index f1750f28..af0ea081 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,23 @@
# changelog
+## 2.5.2
+`2021-12-2`
+* `FIX` [#815](https://github.com/sumneko/lua-language-server/issues/815)
+* `FIX` [#825](https://github.com/sumneko/lua-language-server/issues/825)
+* `FIX` [#826](https://github.com/sumneko/lua-language-server/issues/826)
+* `FIX` [#827](https://github.com/sumneko/lua-language-server/issues/827)
+* `FIX` [#831](https://github.com/sumneko/lua-language-server/issues/831)
+* `FIX` [#837](https://github.com/sumneko/lua-language-server/issues/837)
+* `FIX` [#838](https://github.com/sumneko/lua-language-server/issues/838)
+* `FIX` postfix
+* `FIX` runtime errors
+
+## 2.5.1
+`2021-11-29`
+* `FIX` incorrect syntax error
+
## 2.5.0
+`2021-11-29`
* `NEW` settings:
+ `Lua.runtime.pathStrict`: not check subdirectories when using `runtime.path`
+ `Lua.hint.await`: display `await` when calling a function marked as async
diff --git a/meta/template/math.lua b/meta/template/math.lua
index 09c75cc6..f987eb0b 100644
--- a/meta/template/math.lua
+++ b/meta/template/math.lua
@@ -184,12 +184,10 @@ function math.random(m, n) end
---#DES 'math.randomseed>5.4'
---@param x? integer
---@param y? integer
----@nodiscard
function math.randomseed(x, y) end
---#else
---#DES 'math.randomseed<5.3'
---@param x integer
----@nodiscard
function math.randomseed(x) end
---#end
diff --git a/script/core/completion/postfix.lua b/script/core/completion/postfix.lua
index 08b3feac..b2b777e7 100644
--- a/script/core/completion/postfix.lua
+++ b/script/core/completion/postfix.lua
@@ -230,9 +230,10 @@ local accepts = {
['table'] = true,
}
-local function checkPostFix(state, word, wordPosition, position, results)
+local function checkPostFix(state, word, wordPosition, position, symbol, results)
local source = guide.eachSourceContain(state.ast, wordPosition, function (source)
- if accepts[source.type] then
+ if accepts[source.type]
+ and source.finish == wordPosition then
return source
end
end)
@@ -249,14 +250,14 @@ local function checkPostFix(state, word, wordPosition, position, results)
: add('lua', newText)
: string(),
textEdit = {
- start = wordPosition + 1,
+ start = wordPosition + #symbol,
finish = position,
newText = newText,
},
additionalTextEdits = {
{
start = source.start,
- finish = wordPosition + 1,
+ finish = wordPosition + #symbol,
newText = '',
},
},
@@ -279,7 +280,7 @@ return function (state, position, results)
local symbol = text:sub(offset, offset)
if symbol == config.get(nil, 'Lua.completion.postfix') then
local wordPosition = guide.offsetToPosition(state, offset - 1)
- checkPostFix(state, word or '', wordPosition, position, results)
+ checkPostFix(state, word or '', wordPosition, position, symbol, results)
return symbol ~= '.' and symbol ~= ':'
end
if not word then
@@ -292,8 +293,8 @@ return function (state, position, results)
offset = offset - 3
end
if word then
- local wordPosition = guide.offsetToPosition(state, offset - 1)
- checkPostFix(state, word or '', wordPosition, position, results)
+ local wordPosition = guide.offsetToPosition(state, offset)
+ checkPostFix(state, word or '', wordPosition, position, '', results)
return true
end
end
diff --git a/script/core/definition.lua b/script/core/definition.lua
index d77ddac1..a1f46afc 100644
--- a/script/core/definition.lua
+++ b/script/core/definition.lua
@@ -155,6 +155,9 @@ return function (uri, offset)
or src.type == 'setindex'
or src.type == 'tableindex' then
src = src.index
+ if not src then
+ goto CONTINUE
+ end
if not guide.isLiteral(src) then
goto CONTINUE
end
diff --git a/script/core/diagnostics/unused-function.lua b/script/core/diagnostics/unused-function.lua
index 0e0c0003..79cb16e2 100644
--- a/script/core/diagnostics/unused-function.lua
+++ b/script/core/diagnostics/unused-function.lua
@@ -28,6 +28,9 @@ return function (uri, callback)
local cache = {}
---@async
local function checkFunction(source)
+ if not source then
+ return
+ end
if cache[source] ~= nil then
return cache[source]
end
diff --git a/script/core/infer.lua b/script/core/infer.lua
index a17d4faa..9166168b 100644
--- a/script/core/infer.lua
+++ b/script/core/infer.lua
@@ -598,6 +598,10 @@ function m.searchAndViewInfers(source, field, mark)
end
local infers = m.searchInfers(source, field, mark)
local view = m.viewInfers(infers)
+ if type(view) == 'boolean' then
+ log.error('Why view is boolean?', util.dump(infers))
+ return 'any'
+ end
return view
end
diff --git a/script/core/noder.lua b/script/core/noder.lua
index 60dc15e6..373644de 100644
--- a/script/core/noder.lua
+++ b/script/core/noder.lua
@@ -27,7 +27,6 @@ local ANY_FIELD_CHAR = '*'
local INDEX_CHAR = '['
local RETURN_INDEX = SPLIT_CHAR .. '#'
local PARAM_INDEX = SPLIT_CHAR .. '&'
-local PARAM_NAME = SPLIT_CHAR .. '$'
local EVENT_ENUM = SPLIT_CHAR .. '>'
local TABLE_KEY = SPLIT_CHAR .. '<'
local WEAK_TABLE_KEY = SPLIT_CHAR .. '<<'
@@ -95,6 +94,10 @@ local INFO_DEEP_AND_DONT_CROSS = {
---@field binfo? table<node.id, node.info>
-- 后退的关联ID与info
---@field backwards table<node.id, node.id[]|table<node.id, node.info>>
+-- 第一个继承
+---@field extend table<node.id, node.id>
+-- 其他继承
+---@field extends table<node.id, node.id[]>
-- 函数调用参数信息(用于泛型)
---@field call table<node.id, parser.guide.object>
---@field require table<node.id, string>
@@ -549,8 +552,8 @@ end
---添加关联的前进ID
---@param noders noders
----@param id string
----@param forwardID string
+---@param id node.id
+---@param forwardID node.id
---@param info? node.info
local function pushForward(noders, id, forwardID, info)
if not id
@@ -581,8 +584,8 @@ end
---添加关联的后退ID
---@param noders noders
----@param id string
----@param backwardID string
+---@param id node.id
+---@param backwardID node.id
---@param info? node.info
local function pushBackward(noders, id, backwardID, info)
if not id
@@ -611,6 +614,36 @@ local function pushBackward(noders, id, backwardID, info)
backwards[#backwards+1] = backwardID
end
+---添加继承的关联ID
+---@param noders noders
+---@param id node.id
+---@param extendID node.id
+local function pushExtend(noders, id, extendID)
+ if not id
+ or not extendID
+ or extendID == ''
+ or id == extendID then
+ return
+ end
+ if not noders.extend[id] then
+ noders.extend[id] = extendID
+ return
+ end
+ if noders.extend[id] == extendID then
+ return
+ end
+ local extends = noders.extends[id]
+ if not extends then
+ extends = {}
+ noders.extends[id] = extends
+ end
+ if extends[extendID] ~= nil then
+ return
+ end
+ extends[extendID] = false
+ extends[#extends+1] = extendID
+end
+
---@class noder
local m = {}
@@ -751,6 +784,31 @@ function m.eachBackward(noders, id)
end
end
+---遍历extend
+---@param noders noders
+---@param id node.id
+---@return fun():string, node.info
+function m.eachExtend(noders, id)
+ local extend = noders.extend[id]
+ if not extend then
+ return DUMMY_FUNCTION
+ end
+ local index
+ local extends = noders.extends[id]
+ return function ()
+ if not index then
+ index = 0
+ return extend
+ end
+ if not extends then
+ return nil
+ end
+ index = index + 1
+ local id = extends[index]
+ return id
+ end
+end
+
local function bindValue(noders, source, id)
local value = source.value
if not value then
@@ -1050,7 +1108,7 @@ compileNodeMap = util.switch()
pushForward(noders, getID(source.class), id)
if source.extends then
for _, ext in ipairs(source.extends) do
- pushForward(noders, id, getID(ext), INFO_CLASS_TO_EXNTENDS)
+ pushExtend(noders, id, getID(ext))
end
end
if source.bindSources then
@@ -1118,14 +1176,12 @@ compileNodeMap = util.switch()
end
if source.bindSources then
for _, src in ipairs(source.bindSources) do
- if src.type == 'function'
- or guide.isSet(src) then
- local paramID = sformat('%s%s%s'
- , getID(src)
- , PARAM_NAME
- , source.param[1]
- )
- pushForward(noders, paramID, id)
+ if src.type == 'function' and src.args then
+ for _, arg in ipairs(src.args) do
+ if arg[1] == source.param[1] then
+ pushForward(noders, getID(arg), id)
+ end
+ end
end
end
end
@@ -1166,12 +1222,6 @@ compileNodeMap = util.switch()
: call(function (noders, id, source)
if source.args then
for index, param in ipairs(source.args) do
- local paramID = sformat('%s%s%s'
- , id
- , PARAM_NAME
- , param.name[1]
- )
- pushForward(noders, paramID, getID(param.extends))
local indexID = sformat('%s%s%s'
, id
, PARAM_INDEX
@@ -1257,32 +1307,7 @@ compileNodeMap = util.switch()
, i
)
pushForward(noders, indexID, getID(arg))
- if arg.type == 'local' then
- pushForward(noders, getID(arg), sformat('%s%s%s'
- , id
- , PARAM_NAME
- , arg[1]
- ))
- if parentID then
- pushForward(noders, getID(arg), sformat('%s%s%s'
- , parentID
- , PARAM_NAME
- , arg[1]
- ))
- end
- else
- pushForward(noders, getID(arg), sformat('%s%s%s'
- , id
- , PARAM_NAME
- , '...'
- ))
- if parentID then
- pushForward(noders, getID(arg), sformat('%s%s%s'
- , parentID
- , PARAM_NAME
- , '...'
- ))
- end
+ if arg.type ~= 'local' then
for j = i + 1, i + 10 do
pushForward(noders, sformat('%s%s%s'
, id
@@ -1341,6 +1366,13 @@ compileNodeMap = util.switch()
pushForward(noders, id, getID(parent))
end
end)
+ : case 'loop'
+ : call(function (noders, id, source)
+ local loc = source.loc
+ if loc then
+ pushForward(noders, getID(loc), 'dn:integer')
+ end
+ end)
: case 'in'
: call(function (noders, id, source)
local keys = source.keys
@@ -1544,6 +1576,11 @@ function m.getLastID(id)
return lastID
end
+function m.getFieldID(id)
+ local fieldID = smatch(id, LAST_REGEX)
+ return fieldID
+end
+
---获取ID的长度
---@param id string
---@return integer
@@ -1569,7 +1606,7 @@ function m.hasField(id)
end
local next2Char = ssub(id, #firstID + 2, #firstID + 2)
if next2Char == RETURN_INDEX
- or next2Char == PARAM_NAME then
+ or next2Char == PARAM_INDEX then
return false
end
return true
@@ -1593,9 +1630,6 @@ function m.isCommonField(field)
if ssub(field, 1, #RETURN_INDEX) == RETURN_INDEX then
return false
end
- if ssub(field, 1, #PARAM_NAME) == PARAM_NAME then
- return false
- end
return true
end
@@ -1671,6 +1705,8 @@ function m.getNoders(source)
backward = {},
binfo = {},
backwards = {},
+ extend = {},
+ extends = {},
call = {},
require = {},
skip = {},
diff --git a/script/core/reference.lua b/script/core/reference.lua
index 067d2e23..5e4a4cbf 100644
--- a/script/core/reference.lua
+++ b/script/core/reference.lua
@@ -111,6 +111,9 @@ return function (uri, position)
elseif src.type == 'table' and src.parent.type ~= 'return' then
goto CONTINUE
end
+ if not src then
+ goto CONTINUE
+ end
results[#results+1] = {
target = src,
uri = root.uri,
diff --git a/script/core/searcher.lua b/script/core/searcher.lua
index 9ddfe6b7..1f4091b3 100644
--- a/script/core/searcher.lua
+++ b/script/core/searcher.lua
@@ -40,6 +40,7 @@ local getHeadID = noder.getHeadID
local eachForward = noder.eachForward
local getUriAndID = noder.getUriAndID
local eachBackward = noder.eachBackward
+local eachExtend = noder.eachExtend
local eachSource = noder.eachSource
local compileAllNodes = noder.compileAllNodes
local compilePartNoders = noder.compilePartNodes
@@ -192,17 +193,17 @@ local pushRefResultsMap = util.switch()
---@param force boolean
local function pushResult(status, mode, source, force)
if not source then
- return
+ return false
end
local results = status.results
local mark = status.rmark
if mark[source] then
- return
+ return true
end
mark[source] = true
if force then
results[#results+1] = source
- return
+ return true
end
if mode == 'def'
@@ -210,7 +211,7 @@ local function pushResult(status, mode, source, force)
local f = pushDefResultsMap[source.type]
if f and f(source, status) then
results[#results+1] = source
- return
+ return true
end
elseif mode == 'ref'
or mode == 'field'
@@ -219,7 +220,7 @@ local function pushResult(status, mode, source, force)
local f = pushRefResultsMap[source.type]
if f and f(source, status) then
results[#results+1] = source
- return
+ return true
end
end
@@ -227,9 +228,11 @@ local function pushResult(status, mode, source, force)
if parent.type == 'return' then
if source ~= status.source then
results[#results+1] = source
- return
+ return true
end
end
+
+ return false
end
---@param obj parser.guide.object
@@ -737,6 +740,46 @@ function m.searchRefsByID(status, suri, expect, mode)
end
end
+ local function checkExtend(uri, id, field)
+ if not field
+ and mode ~= 'field'
+ and mode ~= 'allfield' then
+ return
+ end
+ if field then
+ local results = status.results
+ for i = #results, 1, -1 do
+ local res = results[i]
+ if res.type == 'setfield'
+ or res.type == 'setmethod'
+ or res.type == 'setindex' then
+ local resField = noder.getFieldID(getID(res))
+ if field == resField then
+ return
+ end
+ end
+ if res.type == 'doc.field.name' then
+ local resField = STRING_FIELD .. res[1]
+ if field == resField then
+ return
+ end
+ end
+ end
+ end
+ for extendID in eachExtend(nodersMap[uri], id) do
+ local targetUri, targetID
+
+ targetUri, targetID = getUriAndID(extendID)
+ if targetUri and targetUri ~= uri then
+ if dontCross == 0 then
+ searchID(targetUri, targetID, field, uri)
+ end
+ else
+ searchID(uri, targetID or extendID, field)
+ end
+ end
+ end
+
local function searchSpecial(uri, id, field)
-- Special rule: ('').XX -> stringlib.XX
if id == 'str:'
@@ -892,6 +935,9 @@ function m.searchRefsByID(status, suri, expect, mode)
if noders.backward[id] then
checkBackward(uri, id, field)
end
+ if noders.extend[id] then
+ checkExtend(uri, id, field)
+ end
releaseExpanding(elock, ecall, id, field)
end
diff --git a/script/encoder/utf16.lua b/script/encoder/utf16.lua
index 9e71de68..744da174 100644
--- a/script/encoder/utf16.lua
+++ b/script/encoder/utf16.lua
@@ -86,9 +86,17 @@ local function utf8next(s, n)
return n+1, utf8byte(s, n)
elseif strmatch(s, "^[\xC2-\xDF][\x80-\xBF]", n) then
return n+2, utf8byte(s, n)
- elseif strmatch(s, "^[\xE0-\xEF][\x80-\xBF][\x80-\xBF]", n) then
+ elseif strmatch(s, "^[\xE0][\xA0-\xBF][\x80-\xBF]", n) then
return n+3, utf8byte(s, n)
- elseif strmatch(s, "^[\xF0-\xF4][\x80-\xBF][\x80-\xBF][\x80-\xBF]", n) then
+ elseif strmatch(s, "^[\xE1-\xEC][\x80-\xBF][\x80-\xBF]", n) then
+ return n+3, utf8byte(s, n)
+ elseif strmatch(s, "^[\xED][\x80-\x9F][\x80-\xBF]", n) then
+ return n+3, utf8byte(s, n)
+ elseif strmatch(s, "^[\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]", n) then
+ return n+4, utf8byte(s, n)
+ elseif strmatch(s, "^[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]", n) then
+ return n+4, utf8byte(s, n)
+ elseif strmatch(s, "^[\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF]", n) then
return n+4, utf8byte(s, n)
else
return n+1 --invaild
diff --git a/script/files.lua b/script/files.lua
index ead1ea90..765ac88a 100644
--- a/script/files.lua
+++ b/script/files.lua
@@ -45,7 +45,7 @@ function m.getRealUri(uri)
return uri
end
suc, res = pcall(fs.canonical, path)
- if not suc or res:string() == filename then
+ if not suc or res:string():gsub('/', '\\') == filename then
return uri
end
filename = res:string()
@@ -183,6 +183,7 @@ function m.setText(uri, text, isTrust, version)
local encoding = config.get(nil, 'Lua.runtime.fileEncoding')
text = encoder.decode(encoding, text)
end
+ file.version = version
if file.originText == text then
return
end
@@ -195,7 +196,6 @@ function m.setText(uri, text, isTrust, version)
m.astMap[uri] = nil
file.cache = {}
file.cacheActiveTime = math.huge
- file.version = version
m.globalVersion = m.globalVersion + 1
await.close('files.version')
m.onWatch('version')
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index d206e6d7..bfadcf8a 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -258,15 +258,7 @@ local function parseClass(parent)
end
result.start = getStart()
result.finish = getFinish()
- if not peekToken() then
- return result
- end
if not checkToken('symbol', ':', 1) then
- pushError {
- type = 'LUADOC_MISS_EXTENDS_SYMBOL',
- start = result.finish + 1,
- finish = getStart(),
- }
return result
end
nextToken()
diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua
index 8eb97b17..187de9b3 100644
--- a/script/parser/newparser.lua
+++ b/script/parser/newparser.lua
@@ -367,6 +367,22 @@ local function skipNL()
return false
end
+local function getSavePoint()
+ local index = Index
+ local line = Line
+ local lineOffset = LineOffset
+ local errs = State.errs
+ local errCount = #errs
+ return function ()
+ Index = index
+ Line = line
+ LineOffset = lineOffset
+ for i = errCount + 1, #errs do
+ errs[i] = nil
+ end
+ end
+end
+
local function fastForwardToken(offset)
while true do
local myOffset = Tokens[Index]
@@ -1531,6 +1547,7 @@ local function parseTable()
}
Index = Index + 2
local index = 0
+ local tindex = 0
local wantSep = false
while true do
skipSpace(true)
@@ -1549,39 +1566,34 @@ local function parseTable()
end
local lastRight = lastRightPosition()
- local exp = parseExp(true)
- if exp then
- if wantSep then
- pushError {
- type = 'MISS_SEP_IN_TABLE',
- start = lastRight,
- finish = exp.start,
- }
- end
- wantSep = true
- if exp.type == 'varargs' then
- index = index + 1
- tbl[index] = exp
- exp.parent = tbl
- goto CONTINUE
- end
- if exp.type == 'getlocal'
- or exp.type == 'getglobal' then
+ if peekWord() then
+ local savePoint = getSavePoint()
+ local name = parseName()
+ if name then
skipSpace()
- if expectAssign() then
+ if Tokens[Index + 1] == '=' then
+ Index = Index + 2
+ if wantSep then
+ pushError {
+ type = 'MISS_SEP_IN_TABLE',
+ start = lastRight,
+ finish = getPosition(Tokens[Index], 'left'),
+ }
+ end
+ wantSep = true
local eqRight = lastRightPosition()
skipSpace()
local fvalue = parseExp()
local tfield = {
type = 'tablefield',
- start = exp.start,
+ start = name.start,
finish = fvalue and fvalue.finish or eqRight,
parent = tbl,
- field = exp,
+ field = name,
value = fvalue,
}
- exp.type = 'field'
- exp.parent = tfield
+ name.type = 'field'
+ name.parent = tfield
if fvalue then
fvalue.parent = tfield
else
@@ -1592,12 +1604,32 @@ local function parseTable()
goto CONTINUE
end
end
+ savePoint()
+ end
+
+ local exp = parseExp(true)
+ if exp then
+ if wantSep then
+ pushError {
+ type = 'MISS_SEP_IN_TABLE',
+ start = lastRight,
+ finish = exp.start,
+ }
+ end
+ wantSep = true
+ if exp.type == 'varargs' then
+ index = index + 1
+ tbl[index] = exp
+ exp.parent = tbl
+ goto CONTINUE
+ end
index = index + 1
+ tindex = tindex + 1
local texp = {
type = 'tableexp',
start = exp.start,
finish = exp.finish,
- tindex = index,
+ tindex = tindex,
parent = tbl,
value = exp,
}
diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua
index 5630d44f..a6724a29 100644
--- a/script/provider/diagnostic.lua
+++ b/script/provider/diagnostic.lua
@@ -223,8 +223,6 @@ function m.doDiagnostic(uri)
local version = files.getVersion(uri)
- await.setID('diag:' .. uri)
-
local prog <close> = progress.create(lang.script.WINDOW_DIAGNOSING, 0.5)
prog:setMessage(ws.getRelativePath(uri))
@@ -277,8 +275,9 @@ function m.refresh(uri)
end
await.close('diag:' .. uri)
await.call(function () ---@async
- await.delay()
if uri then
+ await.setID('diag:' .. uri)
+ await.sleep(0.1)
m.clearCache(uri)
xpcall(m.doDiagnostic, log.error, uri)
end
diff --git a/script/provider/provider.lua b/script/provider/provider.lua
index 41338e59..11501b9c 100644
--- a/script/provider/provider.lua
+++ b/script/provider/provider.lua
@@ -215,8 +215,7 @@ m.register 'textDocument/didOpen' {
local uri = files.getRealUri(doc.uri)
workspace.awaitReady(uri)
local text = doc.text
- log.debug('didOpen', uri)
- files.setText(uri, text, true)
+ files.setText(uri, text, true, doc.version)
files.open(uri)
end
}
@@ -244,7 +243,7 @@ m.register 'textDocument/didChange' {
local text = files.getOriginText(uri) or ''
local rows = files.getCachedRows(uri)
text, rows = tm(text, rows, changes)
- files.setText(uri, text, true)
+ files.setText(uri, text, true, doc.version)
files.setCachedRows(uri, rows)
end
}
diff --git a/script/utility.lua b/script/utility.lua
index 85c98cb1..f06dd21e 100644
--- a/script/utility.lua
+++ b/script/utility.lua
@@ -644,6 +644,9 @@ function m.trim(str, mode)
end
function m.expandPath(path)
+ if type(path) ~= 'string' then
+ return nil
+ end
if path:sub(1, 1) == '~' then
local home = getenv('HOME')
if not home then -- has to be Windows
diff --git a/test/completion/common.lua b/test/completion/common.lua
index fad0df8e..94b55514 100644
--- a/test/completion/common.lua
+++ b/test/completion/common.lua
@@ -3013,3 +3013,27 @@ xx++<??>
}
},
}
+
+TEST [[
+fff(function ()
+ xx@xpcall<??>
+end)
+]]
+{
+ [1] = {
+ label = 'xpcall',
+ kind = define.CompletionItemKind.Event,
+ textEdit = {
+ start = 10007,
+ finish = 10013,
+ newText = 'xpcall(xx, ${1:debug.traceback}$2)$0',
+ },
+ additionalTextEdits = {
+ {
+ start = 10004,
+ finish = 10007,
+ newText = '',
+ }
+ }
+ },
+}
diff --git a/test/crossfile/hover.lua b/test/crossfile/hover.lua
index 5c1ad130..86471936 100644
--- a/test/crossfile/hover.lua
+++ b/test/crossfile/hover.lua
@@ -988,22 +988,22 @@ p: T
-- comment 4
```]]}
-TEST {{ path = 'a.lua', content = '', }, {
- path = 'b.lua',
- content = [[
----@param x number # aaa
-local f
-
-function f(<?x?>) end
-]]
-},
-hover = [[
-```lua
-local x: number
-```
-
----
- aaa]]}
+--TEST {{ path = 'a.lua', content = '', }, {
+-- path = 'b.lua',
+-- content = [[
+-----@param x number # aaa
+--local f
+--
+--function f(<?x?>) end
+--]]
+--},
+--hover = [[
+--```lua
+--local x: number
+--```
+--
+-----
+-- aaa]]}
TEST {{ path = 'a.lua', content = '', }, {
path = 'b.lua',
diff --git a/test/definition/bug.lua b/test/definition/bug.lua
index e8733636..4a755170 100644
--- a/test/definition/bug.lua
+++ b/test/definition/bug.lua
@@ -253,3 +253,80 @@ local <!v!> = t[a]
t[a] = <?v?>
]]
+
+TEST [[
+---@class A
+---@field x number
+
+---@class B: A
+---@field <!x!> boolean
+
+---@type B
+local t
+
+local <!<?v?>!> = t.x
+]]
+
+TEST [[
+---@class A
+---@field <!x!> number
+
+---@class B: A
+
+---@type B
+local t
+
+local <!<?v?>!> = t.x
+]]
+
+TEST [[
+---@class A
+local A
+
+function A:x() end
+
+---@class B: A
+local B
+
+function B:<!x!>() end
+
+---@type B
+local t
+
+local <!<?v?>!> = t.x
+]]
+
+TEST [[
+---@class A
+local A
+
+function A:<!x!>() end
+
+---@class B: A
+local B
+
+---@type B
+local t
+
+local <!<?v?>!> = t.x
+]]
+
+-- TODO
+--TEST [[
+-----@class A
+--local A
+--
+-----@return A
+--function A:x() end
+--
+-----@class B: A
+--local <!B!>
+--
+-----@return B
+--function B:x() end
+--
+-----@type B
+--local t
+--
+--local <!<?v?>!> = t.x()
+--]]
diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua
index 3dfd6518..f95c0bad 100644
--- a/test/diagnostics/init.lua
+++ b/test/diagnostics/init.lua
@@ -1506,3 +1506,19 @@ TEST [[
TEST [[
---@type fun(xxx, yyy, ...): boolean
]]
+
+TEST [[
+local <!x!>
+
+return {
+ x = 1,
+}
+]]
+
+TEST [[
+---@class A #1
+]]
+
+TEST [[
+---@class A 1
+]]
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index 284ca023..d62bc607 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -912,12 +912,12 @@ for _, a in ipairs(v) do
end
]]
-TEST 'number' [[
----@param x number
-local f
-
-f = function (<?x?>) end
-]]
+--TEST 'number' [[
+-----@param x number
+--local f
+--
+--f = function (<?x?>) end
+--]]
TEST 'integer' [[
--- @class Emit
@@ -1053,3 +1053,15 @@ f {
}
}
]]
+
+TEST 'integer' [[
+for <?i?> = a, b, c do end
+]]
+
+TEST 'number' [[
+---@param x number
+function F(<?x?>) end
+
+---@param x boolean
+function F(x) end
+]]