Files

881 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# sourcekit-lsp 使用指南
> 通过 Serena MCP 工具调用 sourcekit-lsp 进行 Swift/iOS 代码分析
## 前置条件
### 1. 确保 sourcekit-lsp 已安装
sourcekit-lsp 随 Xcode 一起安装,位于 Xcode 工具链中:
```bash
# 验证 sourcekit-lsp 是否可用
xcrun sourcekit-lsp --version
# 或者直接定位
xcrun --find sourcekit-lsp
# 输出示例:
# /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp
```
### 2. 项目结构要求
sourcekit-lsp 需要以下文件来识别 iOS/Swift 项目:
- Xcode 项目: `*.xcodeproj` 或 `*.xcworkspace`
- Swift Package: `Package.swift`
- CocoaPods: `Podfile` + `*.xcworkspace`
- Carthage: `Cartfile`
**注意**: 对于使用 CocoaPods 的项目,必须先执行 `pod install` 生成 workspace。
---
## 通过 Serena 使用 sourcekit-lsp
### 激活项目
```yaml
# Step 1: 激活 Swift/iOS 项目
tool: mcp__serena__activate_project
params:
project: "/path/to/ios/project"
# 返回: 项目已激活,sourcekit-lsp 已初始化
```
### 验证配置
```yaml
# 检查当前配置
tool: mcp__serena__get_current_config
# 确认输出包含:
# - active_project: /path/to/ios/project
# - language_server: sourcekit-lsp
```
---
## 符号提取操作
### 获取文件符号概览
```yaml
# 获取单个文件的符号列表(不含代码体)
tool: mcp__serena__get_symbols_overview
params:
relative_path: "MyApp/ViewModels/HomeViewModel.swift"
depth: 1 # 0=仅顶层, 1=含直接成员, 2=含嵌套成员
# 返回示例:
# Classes:
# - HomeViewModel (class) [12-187]
# Structs:
# - Input (struct) [15-25]
# - Output (struct) [27-40]
# Properties:
# - disposeBag (property) [14-14]
# - userService (property) [13-13]
# Methods:
# - transform(input:) (method) [42-120]
# - fetchUserData() (method) [122-150]
```
### 查找符号
```yaml
# 按名称模式查找符号
tool: mcp__serena__find_symbol
params:
name_path_pattern: "HomeViewModel"
relative_path: "MyApp/ViewModels/"
include_body: false
include_info: true
depth: 1
# 名称模式规则:
# - "HomeViewModel" -> 匹配任何包含此名称的符号
# - "ViewModels/HomeViewModel" -> 匹配此路径后缀
# - "/MyApp.HomeViewModel" -> 精确匹配完整路径
# - "HomeViewModel/transform" -> 匹配类中的方法
```
### 获取符号详情(含代码体)
```yaml
# 获取完整的符号定义(含代码)
tool: mcp__serena__find_symbol
params:
name_path_pattern: "HomeViewModel/fetchUserData"
relative_path: "MyApp/ViewModels/HomeViewModel.swift"
include_body: true
depth: 0
# 返回包含:
# - 方法签名
# - 文档注释
# - 完整方法体
# - 行号范围
```
---
## 引用分析操作
### 查找符号引用
```yaml
# 查找某个符号被哪些地方引用
tool: mcp__serena__find_referencing_symbols
params:
name_path: "UserService/fetchUser"
relative_path: "MyApp/Services/UserService.swift"
include_info: true
# 返回示例:
# References (3 found):
# - HomeViewModel.fetchUserData [45:12-45:35]
# snippet: "userService.fetchUser()"
# - ProfileViewModel.loadProfile [67:8-67:31]
# snippet: "userService.fetchUser()"
```
### 模式搜索(补充 LSP)
```yaml
# 当 LSP 无法找到时,使用模式搜索
tool: mcp__serena__search_for_pattern
params:
substring_pattern: "\.subscribe\(onNext:"
paths_include_glob: "**/*.swift"
restrict_search_to_code_files: true
context_lines_before: 2
context_lines_after: 2
# 适用场景:
# - RxSwift 订阅链
# - Protocol extension 方法
# - 动态类型调用
```
---
## Swift 特有处理
### Swift 特有关键字与结构
```yaml
# Swift 特有符号类型
struct:
pattern: "struct \\w+"
description: "Swift 结构体,值类型"
class:
pattern: "class \\w+"
description: "Swift 类,引用类型"
enum:
pattern: "enum \\w+"
description: "Swift 枚举,支持关联值"
protocol:
pattern: "protocol \\w+"
description: "Swift 协议,类似接口"
extension:
pattern: "extension \\w+"
description: "Swift 扩展,为类型添加功能"
typealias:
pattern: "typealias \\w+"
description: "类型别名"
@propertyWrapper:
pattern: "@\\w+\\s+(var|let)"
description: "属性包装器"
computed_property:
pattern: "var \\w+: \\w+ \\{"
description: "计算属性"
lazy_property:
pattern: "lazy var \\w+"
description: "延迟初始化属性"
```
### iOS MVVM 架构层识别
```yaml
# 根据命名约定和基类识别架构层
ViewController 层:
naming: "*ViewController.swift", "*VC.swift"
base_classes:
- "UIViewController"
- "BaseViewController"
- "UITableViewController"
- "UICollectionViewController"
key_elements:
- "viewDidLoad()"
- "viewWillAppear(_:)"
- "IBOutlet"
- "IBAction"
ViewModel 层:
naming: "*ViewModel.swift", "*VM.swift"
protocols:
- "ViewModelProtocol"
- "ViewModelType"
key_elements:
- "struct Input"
- "struct Output"
- "func transform(input:)"
- "DisposeBag"
Service 层:
naming: "*Service.swift", "*Manager.swift"
patterns:
- "static let shared"
- "func fetch"
- "func request"
key_elements:
- "Observable<"
- "Single<"
- "Completable"
Model 层:
naming: "*Model.swift", "*Entity.swift", "*Response.swift"
markers:
- ": Codable"
- ": Decodable"
- ": Encodable"
key_elements:
- "enum CodingKeys"
- "init(from decoder:)"
Network 层:
naming: "*API.swift", "*Router.swift", "*Target.swift"
protocols:
- "TargetType"
- "URLRequestConvertible"
key_elements:
- "var baseURL: URL"
- "var path: String"
- "var method: Moya.Method"
Coordinator 层:
naming: "*Coordinator.swift", "*Navigator.swift"
protocols:
- "Coordinator"
- "CoordinatorType"
key_elements:
- "var childCoordinators"
- "func start()"
- "weak var parentCoordinator"
Extension 层:
naming: "*+*.swift"
description: "Swift extension 文件 (e.g., String+Extensions.swift)"
patterns:
- "extension \\w+ \\{"
- "extension \\w+: \\w+ \\{"
```
### Moya API 识别
```yaml
# Moya TargetType 枚举识别
TargetType 协议:
description: "Moya 网络请求定义协议"
required_properties:
- "baseURL: URL"
- "path: String"
- "method: Moya.Method"
- "task: Task"
- "headers: [String: String]?"
# 提取示例
tool: mcp__serena__search_for_pattern
params:
substring_pattern: "case\\s+\\w+.*\\n.*var path"
paths_include_glob: "**/*API.swift"
multiline: true
# 解析 Moya Target
# enum UserAPI: TargetType {
# case login(phone: String, code: String)
# case fetchProfile(userId: Int)
#
# var path: String {
# switch self {
# case .login:
# return "/api/v1/user/login"
# case .fetchProfile(let userId):
# return "/api/v1/user/\(userId)"
# }
# }
# }
#
# 提取:
# - case: login
# path: /api/v1/user/login
# method: POST (从 method 属性推断)
# params: [phone: String, code: String]
#
# - case: fetchProfile
# path: /api/v1/user/{userId}
# method: GET
# params: [userId: Int]
```
### Alamofire 请求识别
```yaml
# Alamofire 请求模式
AF.request:
description: "Alamofire 5.x 请求"
pattern: "AF\\.request\\("
example: |
AF.request("https://api.example.com/users",
method: .get,
parameters: params,
encoding: URLEncoding.default)
.responseDecodable(of: UserResponse.self) { response in
// handle response
}
session.request:
description: "Session 实例请求"
pattern: "session\\.request\\("
URLRequestConvertible:
description: "自定义请求构建器"
protocol: "URLRequestConvertible"
method: "asURLRequest() throws -> URLRequest"
```
### RxSwift/RxCocoa 模式
```yaml
# RxSwift 核心类型
rx_types:
Observable:
description: "可观察序列,核心类型"
operators: ["map", "flatMap", "filter", "subscribe"]
Single:
description: "单值序列,成功或失败"
operators: ["subscribe", "map", "flatMap"]
Completable:
description: "无值序列,仅完成或失败"
operators: ["subscribe", "andThen"]
Maybe:
description: "可选单值序列"
operators: ["subscribe", "map"]
Driver:
description: "UI 绑定专用,主线程、无错误、共享"
from: "asDriver()"
Signal:
description: "类似 Driver,但不重放"
from: "asSignal()"
# RxSwift Subject 类型
rx_subjects:
PublishSubject:
description: "无初始值,只发送新事件"
usage: "事件总线"
BehaviorSubject:
description: "有初始值,发送最新值"
usage: "状态管理"
ReplaySubject:
description: "缓存指定数量事件"
usage: "历史事件回放"
PublishRelay:
description: "PublishSubject 无 error/complete"
usage: "UI 事件转发"
BehaviorRelay:
description: "BehaviorSubject 无 error/complete"
usage: "状态绑定"
# 常用操作符
rx_operators:
transformation:
- "map"
- "flatMap"
- "flatMapLatest"
- "compactMap"
- "scan"
filtering:
- "filter"
- "distinctUntilChanged"
- "debounce"
- "throttle"
- "skip"
- "take"
combining:
- "merge"
- "combineLatest"
- "zip"
- "withLatestFrom"
- "concat"
error_handling:
- "catchError"
- "catchErrorJustReturn"
- "retry"
- "retryWhen"
utility:
- "do(onNext:)"
- "delay"
- "observeOn"
- "subscribeOn"
- "share"
- "replay"
# 提取 RxSwift 模式
tool: mcp__serena__search_for_pattern
params:
substring_pattern: "\\.(map|flatMap|filter|subscribe)\\s*\\{"
paths_include_glob: "**/*.swift"
```
### Combine 模式(Swift 原生响应式)
```yaml
# Combine 核心类型
combine_types:
Publisher:
description: "发布者协议"
operators: ["map", "flatMap", "sink", "assign"]
AnyPublisher:
description: "类型擦除发布者"
usage: "API 返回类型"
PassthroughSubject:
description: "类似 PublishSubject"
usage: "事件发送"
CurrentValueSubject:
description: "类似 BehaviorSubject"
usage: "状态管理"
@Published:
description: "属性包装器,自动发布变化"
usage: "SwiftUI/Combine 状态"
AnyCancellable:
description: "订阅句柄"
usage: "生命周期管理"
# 识别 Combine 使用
tool: mcp__serena__search_for_pattern
params:
substring_pattern: "@Published|PassthroughSubject|CurrentValueSubject|\\.sink\\("
paths_include_glob: "**/*.swift"
```
---
## LSP SymbolKind 映射
```yaml
# sourcekit-lsp 返回的 SymbolKind 数值对照
1: File
2: Module
3: Namespace # extension
4: Package
5: Class # class
6: Method # func (instance)
7: Property # var/let (instance)
8: Field
9: Constructor # init
10: Enum # enum
11: Interface # protocol
12: Function # func (top-level/static)
13: Variable # var/let (local)
14: Constant # let (constant)
15: String
16: Number
17: Boolean
18: Array
19: Object
20: Key
21: Null
22: EnumMember # enum case
23: Struct # struct
24: Event
25: Operator
26: TypeParameter # associated type / generic
```
---
## 调用链构建
### ViewController -> ViewModel 调用链
```python
# 伪代码: 构建 MVVM 调用链
def build_mvvm_chain(viewcontroller_path):
# Step 1: 获取 ViewController 符号
vc_symbols = get_symbols_overview(viewcontroller_path, depth=2)
# Step 2: 识别 ViewModel 依赖
# 查找类似: private let viewModel = HomeViewModel()
# 或: private var viewModel: HomeViewModelType!
vm_deps = extract_viewmodel_deps(vc_symbols)
# Step 3: 追踪 ViewModel 绑定
for vm in vm_deps:
# 获取 ViewModel 定义
vm_symbols = get_symbols_overview(vm.file_path, depth=2)
# 查找 Input/Output 模式
if has_input_output_pattern(vm_symbols):
input_struct = find_symbol("Input", vm.file_path)
output_struct = find_symbol("Output", vm.file_path)
transform_method = find_symbol("transform", vm.file_path, include_body=True)
# 追踪 Service 调用
service_calls = extract_service_calls(transform_method.body)
return chain
```
### ViewModel -> Service -> API 调用链
```yaml
# 实际操作步骤
# 1. 获取 ViewModel 方法
tool: mcp__serena__find_symbol
params:
name_path_pattern: "HomeViewModel/fetchUserData"
relative_path: "MyApp/ViewModels/"
include_body: true
# 2. 分析方法体中的 Service 调用
# 从返回的 body 中提取: userService.fetchUser()
# 3. 定位 Service 方法
tool: mcp__serena__find_symbol
params:
name_path_pattern: "UserService/fetchUser"
relative_path: "MyApp/Services/"
include_body: true
# 4. 分析 Service 中的 API 调用
# 从返回的 body 中提取: provider.request(.fetchProfile(userId))
# 5. 定位 Moya Target
tool: mcp__serena__search_for_pattern
params:
substring_pattern: "case fetchProfile"
paths_include_glob: "**/*API.swift"
context_lines_after: 10
# 6. 提取端点信息
# case fetchProfile(userId: Int)
# path: "/api/v1/user/\(userId)"
# method: .get
```
---
## 大规模项目处理
### 项目规模评估
```bash
# 评估 Swift 项目规模
find /path/to/project -name "*.swift" -not -path "*/Pods/*" -not -path "*/Carthage/*" | wc -l
# 输出: 3602 (文件数)
find /path/to/project -name "*.swift" -not -path "*/Pods/*" -not -path "*/Carthage/*" -exec wc -l {} + | tail -1
# 输出: 424000 (总行数)
```
### 分批处理策略
```yaml
# 大规模项目(424K 行)处理策略
batch_processing:
description: "按模块分批处理,避免内存溢出"
# Step 1: 按目录分组
grouping:
- "AppDelegate.swift" # 入口点优先
- "**/Coordinator/**/*.swift" # 导航层
- "**/ViewModel/**/*.swift" # ViewModel 层
- "**/Service/**/*.swift" # Service 层
- "**/Network/**/*.swift" # Network 层
- "**/Model/**/*.swift" # Model 层
- "**/View/**/*.swift" # View 层
- "**/Extension/**/*.swift" # Extension 层
- "**/*.swift" # 其他
# Step 2: 批次配置
batch_config:
batch_size: 100 # 每批 100 个文件
parallel_batches: 3 # 最多 3 个并行批次
checkpoint_interval: 50 # 每 50 个文件保存检查点
# Step 3: 内存管理
memory_management:
release_after_batch: true # 每批处理后释放内存
stream_output: true # 流式写入输出文件
# 处理流程
procedure:
- step: "scan_and_group"
description: "扫描文件并按层分组"
- step: "process_core_first"
description: "优先处理核心文件"
files:
- "AppDelegate.swift"
- "SceneDelegate.swift"
- "*Coordinator.swift"
- step: "batch_process"
description: "分批处理各层"
for_each_batch: "grouped_files | batch(100)"
actions:
- "extract_symbols"
- "analyze_layer"
- "save_checkpoint"
- step: "merge_results"
description: "合并所有批次结果"
```
### Pod 模块边界识别
```yaml
# 分析 Podfile 识别模块边界
# Step 1: 读取 Podfile
tool: Read
params:
file_path: "/path/to/project/Podfile"
# Step 2: 提取 Pod 依赖
patterns:
- "pod '([^']+)'(?:,\\s*'([^']+)')?"
- "pod \"([^\"]+)\"(?:,\\s*\"([^\"]+)\")?"
# Step 3: 分类 Pod
categories:
networking:
- "Alamofire"
- "Moya"
- "AFNetworking"
- "Kingfisher"
- "SDWebImage"
reactive:
- "RxSwift"
- "RxCocoa"
- "RxRelay"
- "RxDataSources"
- "RxGesture"
ui:
- "SnapKit"
- "Masonry"
- "MBProgressHUD"
- "SVProgressHUD"
- "MJRefresh"
database:
- "Realm"
- "FMDB"
- "GRDB"
- "CoreStore"
analytics:
- "Firebase"
- "Bugly"
- "UMAnalytics"
testing:
- "Quick"
- "Nimble"
- "RxTest"
- "RxBlocking"
# Step 4: 分析模块边界
module_boundaries:
description: "识别 Pod 模块边界"
analysis:
- "哪些模块依赖 RxSwift"
- "网络层使用哪个库"
- "UI 组件库选型"
```
---
## 常见问题
### Q: sourcekit-lsp 启动慢
```
A: sourcekit-lsp 首次索引项目可能较慢:
- 大型项目(3600+ 文件)可能需要几分钟
- 确保 Xcode 和 Command Line Tools 已安装
建议: 先执行 xcodebuild 构建项目预热索引
# 预热命令
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Debug build
```
### Q: 找不到 Swift 符号
```
A: 可能原因:
1. 项目未正确配置(缺少 xcworkspace)
2. CocoaPods 未安装(先执行 pod install)
3. 符号在 Pods 目录中(被排除)
4. Swift Package 未解析
解决:
1. 确保使用 .xcworkspace 而非 .xcodeproj
2. 执行 pod install 生成 workspace
3. 使用 search_for_pattern 作为备选
4. 对于 SPM 项目,确保 Package.resolved 存在
```
### Q: RxSwift 调用追踪不完整
```
A: RxSwift 的链式调用使得静态分析困难:
1. 操作符链可能跨越多行
2. 闭包中的调用难以追踪
3. 协议扩展方法无法直接定位
解决:
使用 search_for_pattern 搜索特定操作符模式
结合 Input/Output 模式分析 ViewModel
追踪 DisposeBag 的使用位置
```
### Q: Extension 方法找不到
```
A: Swift extension 方法分散在多个文件中:
1. extension 文件通常命名为 Type+Category.swift
2. 同一类型可能有多个 extension 文件
3. Protocol extension 更难追踪
解决:
1. 先搜索 extension TypeName 识别所有扩展
2. 使用 Glob 匹配 *+*.swift 文件
3. 分析 Protocol extension 时搜索协议名
```
### Q: Moya Target 解析
```
A: Moya TargetType 是 enum,需要特殊处理:
1. case 定义了 API 端点
2. path/method/task 等属性需要配合分析
3. switch self 模式匹配需要解析
解决:
1. 先提取所有 case 定义
2. 分析 path 属性的 switch 语句
3. 匹配 case 与 path 的对应关系
# 示例搜索
mcp__serena__search_for_pattern(
substring_pattern="case \\w+.*\\n.*path:",
paths_include_glob="**/*API.swift",
multiline=True,
context_lines_after=5
)
```
---
## 最佳实践
1. **按架构层分析** - 先识别 MVVM 各层文件,再逐层深入
2. **ViewModel 是关键** - ViewModel 层连接 ViewController 和 Service,是分析重点
3. **Input/Output 模式** - 识别 RxSwift MVVM 的标准模式
4. **Pod 依赖优先** - 通过 Podfile 快速了解项目技术栈
5. **Extension 归类** - 将 extension 文件与原类型关联
6. **分批处理大项目** - 424K 行项目必须分批处理
---
## 项目特定模式(示例:chefu_driver_app_ios)
该项目使用的技术栈和模式:
```yaml
架构模式: MVVM + Coordinator
ViewController: *ViewController.swift
ViewModel: *ViewModel.swift (Input/Output 模式)
Service: *Service.swift (单例模式)
Coordinator: *Coordinator.swift
网络层: Moya + RxSwift
API 定义: *API.swift (TargetType enum)
Provider: MoyaProvider<API>
响应类型: Observable<Response>
响应式框架: RxSwift + RxCocoa
ViewModel: Observable/Driver
ViewController: DisposeBag, bind/drive
UI 框架:
布局: SnapKit
图片: Kingfisher
刷新: MJRefresh
项目规模:
文件数: 3,602 Swift 文件
代码行数: 约 424,000 行
Pod 依赖: 50+ 个 Pod
目录结构:
MyApp/
AppDelegate.swift
Coordinator/ # 导航协调器
Modules/ # 按功能模块划分
Home/
ViewController/
ViewModel/
View/
Model/
Order/
...
Services/ # 业务服务
Network/ # 网络层
API/
Model/
Common/ # 公共组件
Base/
Extension/
Utils/
```