Files
zentao-flow/.agents/skills/codemap/guides/lsp-swift.md
T

20 KiB
Raw Blame History

sourcekit-lsp 使用指南

通过 Serena MCP 工具调用 sourcekit-lsp 进行 Swift/iOS 代码分析

前置条件

1. 确保 sourcekit-lsp 已安装

sourcekit-lsp 随 Xcode 一起安装,位于 Xcode 工具链中:

# 验证 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

激活项目

# Step 1: 激活 Swift/iOS 项目
tool: mcp__serena__activate_project
params:
  project: "/path/to/ios/project"

# 返回: 项目已激活,sourcekit-lsp 已初始化

验证配置

# 检查当前配置
tool: mcp__serena__get_current_config

# 确认输出包含:
# - active_project: /path/to/ios/project
# - language_server: sourcekit-lsp

符号提取操作

获取文件符号概览

# 获取单个文件的符号列表(不含代码体)
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]

查找符号

# 按名称模式查找符号
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"    -> 匹配类中的方法

获取符号详情(含代码体)

# 获取完整的符号定义(含代码)
tool: mcp__serena__find_symbol
params:
  name_path_pattern: "HomeViewModel/fetchUserData"
  relative_path: "MyApp/ViewModels/HomeViewModel.swift"
  include_body: true
  depth: 0

# 返回包含:
# - 方法签名
# - 文档注释
# - 完整方法体
# - 行号范围

引用分析操作

查找符号引用

# 查找某个符号被哪些地方引用
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)

# 当 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 特有关键字与结构

# 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 架构层识别

# 根据命名约定和基类识别架构层

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 识别

# 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 请求识别

# 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 模式

# 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 原生响应式)

# 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 映射

# 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 调用链

# 伪代码: 构建 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 调用链

# 实际操作步骤

# 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

大规模项目处理

项目规模评估

# 评估 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 (总行数)

分批处理策略

# 大规模项目(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 模块边界识别

# 分析 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)

该项目使用的技术栈和模式:

架构模式: 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/