# kotlin-language-server 使用指南 > 通过 Serena MCP 工具调用 kotlin-language-server 进行 Kotlin/Android 代码分析 ## 前置条件 ### 1. 确保 kotlin-language-server 已安装 kotlin-language-server 可通过以下方式安装: ```bash # 通过 Homebrew (macOS) brew install kotlin-language-server # 或通过 VS Code Kotlin 扩展 # 扩展会自动安装 language server ``` ### 2. 项目结构要求 kotlin-language-server 需要以下文件来识别 Android/Kotlin 项目: - Gradle: `build.gradle` 或 `build.gradle.kts` - Settings: `settings.gradle` 或 `settings.gradle.kts` - Android: `app/build.gradle.kts` (通常包含 android {} 配置) --- ## 通过 Serena 使用 kotlin-language-server ### 激活项目 ```yaml # Step 1: 激活 Kotlin/Android 项目 tool: mcp__serena__activate_project params: project: "/path/to/android/project" # 返回: 项目已激活,kotlin-language-server 已初始化 ``` ### 验证配置 ```yaml # 检查当前配置 tool: mcp__serena__get_current_config # 确认输出包含: # - active_project: /path/to/android/project # - language_server: kotlin-language-server ``` --- ## 符号提取操作 ### 获取文件符号概览 ```yaml # 获取单个文件的符号列表(不含代码体) tool: mcp__serena__get_symbols_overview params: relative_path: "app/src/main/java/com/example/ui/home/HomeVm.kt" depth: 1 # 0=仅顶层, 1=含直接成员, 2=含嵌套成员 # 返回示例: # Classes: # - HomeVm (class) [28-307] # Properties: # - repository (property) [29-29] # - listeningState (property) [34-34] # - homePolymerization (property) [39-39] # Methods: # - getListeningState (method) [59-74] # - changeListeningState (method) [76-102] # - getHomeInfoData (method) [116-142] ``` ### 查找符号 ```yaml # 按名称模式查找符号 tool: mcp__serena__find_symbol params: name_path_pattern: "HomeVm" relative_path: "app/src/main/java/" include_body: false include_info: true depth: 1 # 名称模式规则 (与 Java 相同): # - "HomeVm" -> 匹配任何包含此名称的符号 # - "home/HomeVm" -> 匹配此路径后缀 # - "/com.example.HomeVm" -> 精确匹配完整路径 # - "HomeVm/getListeningState" -> 匹配类中的方法 ``` ### 获取符号详情(含代码体) ```yaml # 获取完整的符号定义(含代码) tool: mcp__serena__find_symbol params: name_path_pattern: "HomeRepository/getHomeInfoData" relative_path: "app/src/main/java/com/example/ui/home/HomeRepository.kt" include_body: true depth: 0 # 返回包含: # - 方法签名 # - KDoc 注释 # - 完整方法体 # - 行号范围 ``` --- ## 引用分析操作 ### 查找符号引用 ```yaml # 查找某个符号被哪些地方引用 tool: mcp__serena__find_referencing_symbols params: name_path: "HomeRepository/getHomeInfoData" relative_path: "app/src/main/java/com/example/ui/home/HomeRepository.kt" include_info: true # 返回示例: # References (2 found): # - HomeVm.getHomeInfoData [117:12-117:42] # snippet: "repository.getHomeInfoData()" ``` ### 模式搜索(补充 LSP) ```yaml # 当 LSP 无法找到时,使用模式搜索 tool: mcp__serena__search_for_pattern params: substring_pattern: "repository\\.get" paths_include_glob: "**/*.kt" restrict_search_to_code_files: true context_lines_before: 2 context_lines_after: 2 # 适用场景: # - 协程调用 (withContext, launch) # - 扩展函数调用 # - 动态代理 ``` --- ## Kotlin 特有处理 ### Kotlin 特有关键字与结构 ```yaml # Kotlin 特有符号类型 data class: pattern: "data class \\w+" description: "Kotlin 数据类,自动生成 equals/hashCode/copy" sealed class: pattern: "sealed class \\w+" description: "密封类,限制继承的类型" object: pattern: "object \\w+" description: "单例对象声明" companion object: pattern: "companion object" description: "伴生对象,类似静态成员" suspend fun: pattern: "suspend fun \\w+" description: "协程挂起函数" extension function: pattern: "fun \\w+\\.\\w+" description: "扩展函数" ``` ### Android MVVM 架构层识别 ```yaml # 根据命名约定和基类识别架构层 ViewModel 层: naming: "*Vm.kt", "*ViewModel.kt" base_classes: - "ViewModel" - "AndroidViewModel" - "BaseViewModel" annotations: - "@HiltViewModel" key_elements: - "MutableLiveData" - "MutableStateFlow" - "viewModelScope" Repository 层: naming: "*Repository.kt" base_classes: - "BaseRepository" key_elements: - "suspend fun" - "Flow<>" - "RetrofitHelper" Activity 层: naming: "*Activity.kt" base_classes: - "AppCompatActivity" - "ComponentActivity" - "BaseActivity" key_elements: - "setContentView" - "ViewBinding" Fragment 层: naming: "*Fragment.kt" base_classes: - "Fragment" - "DialogFragment" - "BaseFragment" key_elements: - "onCreateView" - "ViewBinding" Compose UI: naming: "*Page.kt", "*Compose.kt", "*Screen.kt" annotations: - "@Composable" key_elements: - "remember" - "LaunchedEffect" - "collectAsState" Adapter 层: naming: "*Adapter.kt" base_classes: - "RecyclerView.Adapter" - "ListAdapter" - "BaseAdapter" key_elements: - "onCreateViewHolder" - "onBindViewHolder" ``` ### Retrofit API 识别 ```yaml # Retrofit 注解识别 HTTP 方法注解: - "@GET": GET 请求 - "@POST": POST 请求 - "@PUT": PUT 请求 - "@DELETE": DELETE 请求 - "@PATCH": PATCH 请求 - "@HEAD": HEAD 请求 - "@OPTIONS": OPTIONS 请求 参数注解: - "@Path": 路径参数 - "@Query": 查询参数 - "@QueryMap": 查询参数 Map - "@Body": 请求体 - "@Field": 表单字段 - "@FieldMap": 表单字段 Map - "@Part": Multipart 部分 - "@Header": 请求头 - "@HeaderMap": 请求头 Map - "@Url": 动态 URL # 提取示例 tool: mcp__serena__search_for_pattern params: substring_pattern: "@(GET|POST|PUT|DELETE|PATCH)\\s*\\([^)]*\\)" paths_include_glob: "**/*Service.kt" # 解析端点 # @GET("/client-driver/v2/order/getOrderDetail") # fun getOrderDetail(@Query("orderId") orderId: Long?): Observable> # # 提取: # method: GET # path: /client-driver/v2/order/getOrderDetail # params: [{name: orderId, type: Long?, annotation: @Query}] # return_type: Observable> ``` ### Jetpack Compose 识别 ```yaml # Compose 注解和模式 @Composable: description: "可组合函数,Compose UI 构建块" pattern: "@Composable\\s+(fun|private fun|internal fun)" @Preview: description: "预览注解,用于 Android Studio 预览" State 管理: patterns: - "remember\\s*\\{" - "mutableStateOf" - "collectAsState" - "LaunchedEffect" - "SideEffect" - "DisposableEffect" # 提取 Composable 函数 tool: mcp__serena__search_for_pattern params: substring_pattern: "@Composable\\s+fun\\s+\\w+" paths_include_glob: "**/*.kt" ``` ### RxJava/Coroutines 模式 ```yaml # RxJava 模式(该项目使用) rx_patterns: - "Observable<" - "subscribeOn" - "observeOn" - "subscribe" - "Schedulers.io()" - "AndroidSchedulers.mainThread()" # Coroutines 模式 coroutine_patterns: - "suspend fun" - "viewModelScope.launch" - "lifecycleScope.launch" - "withContext" - "async" - "await" - "Flow<" - "StateFlow<" - "SharedFlow<" - "collect" - "collectLatest" ``` --- ## LSP SymbolKind 映射 ```yaml # kotlin-language-server 返回的 SymbolKind 数值对照 1: File 2: Module 3: Namespace 4: Package 5: Class # 类、object 6: Method # 方法 7: Property # 属性 8: Field # 字段 9: Constructor # 构造函数 10: Enum # 枚举 11: Interface # 接口 12: Function # 顶层函数 13: Variable # 变量 14: Constant # 常量 (val) 15: String 16: Number 17: Boolean 18: Array 19: Object # object 声明 20: Key 21: Null 22: EnumMember # 枚举值 23: Struct 24: Event 25: Operator 26: TypeParameter # 泛型参数 ``` --- ## 调用链构建 ### ViewModel -> Repository 调用链 ```python # 伪代码: 构建 MVVM 调用链 def build_mvvm_chain(viewmodel_path): # Step 1: 获取 ViewModel 符号 vm_symbols = get_symbols_overview(viewmodel_path, depth=2) # Step 2: 识别 Repository 依赖 # 查找类似: private val repository = HomeRepository() repo_deps = extract_repository_deps(vm_symbols) # Step 3: 追踪 Repository 方法调用 for method in vm_symbols.methods: # 获取方法体 method_body = find_symbol(method.name, include_body=True) # 查找 repository.xxx() 调用 repo_calls = extract_repo_calls(method_body) for call in repo_calls: # 跟踪到 Repository 方法 repo_method = find_symbol(f"{repo_deps}/{call.method_name}") # Repository 通常调用 RetrofitHelper api_calls = extract_api_calls(repo_method.body) return chain ``` ### Repository -> API Service 调用链 ```yaml # 实际操作步骤 # 1. 获取 Repository 方法 tool: mcp__serena__find_symbol params: name_path_pattern: "HomeRepository/getHomeInfoData" relative_path: "app/src/main/java/" include_body: true # 2. 分析方法体中的 API 调用 # 从返回的 body 中提取: RetrofitHelper.getDefaultService().getHomeInfoData() # 3. 定位 API 接口定义 tool: mcp__serena__search_for_pattern params: substring_pattern: "fun getHomeInfoData" paths_include_glob: "**/*Service.kt" # 4. 提取端点信息 # @GET("/client-driver/v3/info/getHomeInfoData") # fun getHomeInfoData(): Observable> ``` --- ## 常见问题 ### Q: kotlin-language-server 启动慢 ``` A: 首次打开项目时,需要构建 Gradle 项目并索引。 - 大型 Android 项目可能需要几分钟 - 确保 Gradle Daemon 正在运行 建议: 先执行 ./gradlew build 预热项目 ``` ### Q: 找不到 Kotlin 符号 ``` A: 可能原因: 1. Gradle 配置未正确解析 2. 使用了 Kotlin DSL 但 settings.gradle.kts 缺失 3. 符号在 generated 目录中 4. 项目使用 Kotlin Multiplatform 解决: 1. 确保项目可以正常 Gradle 编译 2. 使用 search_for_pattern 作为备选 3. 检查 exclude_patterns 配置 ``` ### Q: 协程/Flow 调用追踪不完整 ``` A: 协程的异步特性使得静态分析困难: 1. viewModelScope.launch {} 内部调用难以追踪 2. Flow 的 collect 在不同协程作用域 3. 挂起函数的调用栈可能中断 解决: 使用 search_for_pattern 搜索特定调用模式 结合 @Composable 中的 LaunchedEffect 分析 ``` ### Q: Compose 函数调用关系 ``` A: Compose 函数组合特殊: 1. @Composable 函数只能被其他 @Composable 调用 2. 状态提升模式使数据流向不明显 3. remember/LaunchedEffect 的依赖追踪 解决: 1. 先识别所有 @Composable 函数 2. 分析函数参数中的回调 lambda 3. 追踪 ViewModel 的 StateFlow/LiveData ``` --- ## 最佳实践 1. **按架构层分析** - 先识别 MVVM 各层文件,再逐层深入 2. **Repository 是关键** - Repository 层连接 ViewModel 和 API,是分析重点 3. **注解驱动识别** - 利用 @Composable, @GET/@POST 等注解快速分类 4. **命名约定优先** - Kotlin/Android 项目通常遵循严格命名约定 (*Vm, *Repository, *Activity) 5. **结合 Gradle 分析** - 通过 build.gradle.kts 了解依赖和模块结构 6. **注意扩展函数** - Kotlin 扩展函数可能分散在不同文件中 --- ## 项目特定模式 (chefu_driver_app_android) 该项目使用的技术栈和模式: ```yaml 架构模式: MVVM ViewModel: *Vm.kt (如 HomeVm, LoginViewMode) Repository: *Repository.kt (如 HomeRepository) Activity: *Activity.kt (如 HomeActivity) Fragment: *Fragment.kt (如 RankDetailFragment) 网络层: Retrofit + RxJava3 ApiService: com.dezhong.driverandroid.net.ApiService Helper: RetrofitHelper.getDefaultService() 响应类型: Observable> UI 层: 传统: XML + ViewBinding 新版: Jetpack Compose (myCompose/ 目录) 状态管理: ViewModel: MutableLiveData Compose: mutableStateOf, remember 目录结构: app/src/main/java/com/dezhong/driverandroid/ ui/ # 传统 UI (Activity + Fragment + ViewModel) myCompose/ # Compose UI net/ # 网络层 base/ # 基类 service/ # 后台服务 common/ # 通用类 ```