diff options
| author | 2026-10-15 10:11:56 +0330 | |
|---|---|---|
| committer | 2026-10-15 10:11:56 +0330 | |
| commit | e1e0a265e931637f452ac05bb7d912e07bcee574 (patch) | |
| tree | 60289bb1fc3d812dfc576f01e0f8a83091a495c1 /tests/drivers/ext_cache_test.js | |
| parent | analyzer: check borrow returns of forward-called functions at the unit's end;... (diff) | |
lsp: borrow errors ranged on the use, with related information for where the owner ended and was declared; vscode client passes relatedInformation through
Diffstat (limited to 'tests/drivers/ext_cache_test.js')
| -rw-r--r-- | tests/drivers/ext_cache_test.js | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/tests/drivers/ext_cache_test.js b/tests/drivers/ext_cache_test.js index 93caf94..9bd3e3a 100644 --- a/tests/drivers/ext_cache_test.js +++ b/tests/drivers/ext_cache_test.js @@ -31,6 +31,8 @@ const stub = { EventEmitter: class { constructor() { this.event = () => ({ dispose() {} }); } fire() {} }, Diagnostic: class { constructor(range, message, severity) { Object.assign(this, { range, message, severity }); } }, Range: class { constructor(a, b, c, d) { Object.assign(this, { start: { line: a, character: b }, end: { line: c, character: d } }); } }, + Location: class { constructor(uri, range) { Object.assign(this, { uri, range }); } }, + DiagnosticRelatedInformation: class { constructor(location, message) { Object.assign(this, { location, message }); } }, DiagnosticSeverity: { Error: 0, Warning: 1, Information: 2, Hint: 3 }, SemanticTokensLegend: class { constructor(t, m) { this.tokenTypes = t; this.tokenModifiers = m; } }, SemanticTokensBuilder: class { constructor() {} push() {} build() { return null; } }, @@ -177,6 +179,17 @@ const mainUri = 'file://' + main; const expiredList = await world.completion.provideCompletionItems(expiredDoc, { line: 3, character: 1 }, { isCancellationRequested: false }); const expiredItem = expiredList && expiredList.items.find(c => c.label === 'used'); check('completion maps consumed lifetimes to the editor strikethrough tag', expiredItem && expiredItem.tags?.[0] === stub.CompletionItemTag.Deprecated && /lifetime ended/.test(expiredItem.documentation?.value)); + // a borrow error keeps the server's related information: where the owner ended and where it was declared + const borrowPath = path.join(root, 'borrow.zc'); + const borrowDoc = doc(borrowPath, 'include rt;\nfn main() {\n\tchar* t = rt.new(4); t[0] = 65;\n\tchar* r = t + 1;\n\trt.free(t);\n\treturn r[0];\n}\n'); + fs.writeFileSync(borrowPath, borrowDoc.text); + world.textDocuments.push(borrowDoc); + if (world.listeners.onDidOpenTextDocument) world.listeners.onDidOpenTextDocument(borrowDoc); + await until(() => world.sets.some(s => s.uri === 'file://' + borrowPath && s.list.length)); + const borrowSet = world.sets.filter(s => s.uri === 'file://' + borrowPath).pop(); + const borrowDiag = borrowSet && borrowSet.list.find(d => /r borrows t/.test(d.message)); + const related = borrowDiag && borrowDiag.relatedInformation; + check('borrow diagnostics pass related information through to the editor', related && related.length === 2 && related[0] instanceof stub.DiagnosticRelatedInformation && related[0].message === 'owner t was freed here' && related[0].location.range.start.line === 4 && related[1].message === 'owner t is declared here', JSON.stringify(borrowSet && borrowSet.list)); const actionDoc = doc(path.join(root, 'imports.zc'), 'fn main() { rt.put_n(7); }'); const actions = await world.actions.provideCodeActions(actionDoc, new stub.Range(0, 15, 0, 15), {}, { isCancellationRequested: false }); check('quick fixes reach the editor as workspace edits', actions.some(a => a.kind === 'quickfix' && a.edit.edits.some(e => e.newText === 'include rt;\n'))); |
