✨ feat(vscode): 代码阅读的调用与构造:跨多行写的调用排成「新建 / 调用 名字 · N 个参数」一行,实参摊成参数 / 值表;Python 查被调用名字的定义分新建和调用,查到后刷新

This commit is contained in:
cruldra committed 2026-09-27 22:08:16 +08:00
1 parent ebf228cdc7
commit ecc415d763
30 files changed
+1033 -157

No files matched your search

+84
View File
@@ -0,0 +1,84 @@
import type { BlockKind, CallFacts, Node } from './contract'
import { describe, expect, it, vi } from 'vitest'
import { DocumentCallees } from './calleeKinds'
/** 一次调用:只用到被调用的表达式原文,和最后那个名字的下标。 */
function call(callee: string, nameAt?: number): CallFacts {
const facts = { callee: { text: callee } as Node, argumentList: {} as Node, arguments: [] }
return nameAt === undefined ? facts : { ...facts, name: { startIndex: nameAt } as Node }
}
/** 各下标处名字的定义是哪种块(语言扩展答的;没有的是没答);记下问了哪些下标。 */
function source(kinds: Record<number, BlockKind | null>): { asked: number[], kindOf: (offset: number) => Promise<BlockKind | null | undefined> } {
const asked: number[] = []
return {
asked,
kindOf: async (offset) => {
asked.push(offset)
return kinds[offset]
},
}
}
describe('调用的名字定义成哪种块(DocumentCallees)', () => {
it('第一遍当没查到,按被调用的表达式原文记下问了什么(写法一样的按一处问);查到后叫宿主重排,再排时交出来', async () => {
let changed = 0
const callees = new DocumentCallees(() => changed++, [])
const first = callees.session()
expect(first.calleeKind(call('UserDetailResponse', 40))).toBeUndefined()
expect(first.calleeKind(call('UserDetailResponse', 90))).toBeUndefined()
expect(first.calleeKind(call('user_service.update_user', 120))).toBeUndefined()
expect(first.requests()).toEqual([{ callee: 'UserDetailResponse', offset: 40 }, { callee: 'user_service.update_user', offset: 120 }])
const from = source({ 40: 'class', 120: 'function' })
callees.resolve(1, first.requests(), from.kindOf)
await vi.waitFor(() => expect(changed).toBe(1))
const second = callees.session()
expect(second.calleeKind(call('UserDetailResponse', 12))).toBe('class')
expect(second.calleeKind(call('user_service.update_user', 7))).toBe('function')
// 同一版本再发一遍:问过的不再查
callees.resolve(1, first.requests(), from.kindOf)
await Promise.resolve()
expect(from.asked).toEqual([40, 120])
})
it('被调用的不是名字(没有 name)不问;查了没有(null)不算变了', async () => {
let changed = 0
const callees = new DocumentCallees(() => changed++, [])
const session = callees.session()
expect(session.calleeKind(call('handlers[k]'))).toBeUndefined()
session.calleeKind(call('build', 5))
expect(session.requests()).toEqual([{ callee: 'build', offset: 5 }])
const from = source({ 5: null })
callees.resolve(1, session.requests(), from.kindOf)
await vi.waitFor(() => expect(from.asked).toEqual([5]))
await Promise.resolve()
expect(changed).toBe(0)
})
it('语言扩展还没起来(没答):隔一会儿只再查没答的,查到了再叫重排', async () => {
let changed = 0
const pending: (() => void)[] = []
const scheduled: number[] = []
const callees = new DocumentCallees(() => changed++, [5, 10], (task, ms) => {
scheduled.push(ms)
pending.push(task)
return setTimeout(() => {}, 0)
})
const session = callees.session()
session.calleeKind(call('Detail', 40))
session.calleeKind(call('run', 60))
const kinds: Record<number, BlockKind | null> = { 60: 'function' }
const from = source(kinds)
callees.resolve(1, session.requests(), from.kindOf)
await vi.waitFor(() => expect(scheduled).toEqual([5]))
expect(changed).toBe(1)
kinds[40] = 'class'
pending.shift()?.()
await vi.waitFor(() => expect(changed).toBe(2))
expect(from.asked).toEqual([40, 60, 40])
expect(callees.session().calleeKind(call('Detail', 40))).toBe('class')
})
})