VS Code 中的跳转到定义

Alpha 版 VS Code 扩展中的 C# 定义导航。

跳转到定义

SharpLsp 正在基于 Roslyn sidecar 构建 LSP 定义导航请求家族。当前扩展展示 VS Code 工作流,边界情况仍在继续加固。

导航方法

LSP 方法 快捷键(VS Code) 描述
textDocument/definition F12 导航到符号的声明
textDocument/typeDefinition Ctrl+F12 导航到符号的类型
textDocument/declaration 导航到接口/抽象声明
textDocument/implementation Ctrl+Shift+F12 导航到所有具体实现

定义导航是 SharpLsp 的发布阻断领域。Alpha 阶段请针对你依赖的具体操作和项目结构验证行为。

C# 导航(Roslyn)

textDocument/definition

Roslyn 通过 SemanticModel.GetSymbolInfo() 解析符号,并从 ISymbol.Locations 返回源位置。

textDocument/implementation

使用 SymbolFinder.FindImplementationsAsync() 在整个解决方案中定位所有具体实现。当存在多个实现时(例如,有十个实现类的接口),返回 Location[]

特殊情况

符号 definition typeDefinition declaration implementation
变量(var x = new Foo() 变量声明 Foo 与 definition 相同
方法调用(bar.Baz() 方法体 返回类型 接口/抽象方法 所有重写
接口成员 接口声明 成员返回类型 相同 所有实现类
重写方法 重写位置 返回类型 基虚拟/抽象方法 所有同级重写
构造函数(new Foo() 构造函数声明 Foo 相同
分部类/方法 第一个 partial 声明 类型 定义分部 所有分部

反编译源码导航

当符号定义在引用的程序集(NuGet 包、BCL)中时,SharpLsp 使用 ICSharpCode.Decompiler 按需反编译包含类型。反编译的源码在只读缓冲区中打开,即使对框架内部也能完整导航。

// Ctrl+单击 List<T>.Add() 导航到反编译内容:
// public void Add(T item) {
//     if (_size == _items.Length) EnsureCapacity(_size + 1);
//     _items[_size++] = item;
//     _version++;
// }

缓存

所有定义结果通过 salsa 以键 (document_uri, version, position, method) 缓存。缓存命中在 1ms 内返回。method 组件区分同一位置的 definitiontypeDefinitiondeclarationimplementation

性能目标

指标 目标
定义延迟(p50) <100ms
定义延迟(p95) <250ms
缓存定义 <1ms
查找实现(100 个实现) <500ms