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

549 lines
12 KiB
Markdown
Raw 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.
# 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<BaseResponse<OrderDetailBean>>
#
# 提取:
# method: GET
# path: /client-driver/v2/order/getOrderDetail
# params: [{name: orderId, type: Long?, annotation: @Query}]
# return_type: Observable<BaseResponse<OrderDetailBean>>
```
### 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<BaseResponse<HomePolymerizationBean>>
```
---
## 常见问题
### 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<BaseResponse<T>>
UI 层:
传统: XML + ViewBinding
新版: Jetpack Compose (myCompose/ 目录)
状态管理:
ViewModel: MutableLiveData<T>
Compose: mutableStateOf, remember
目录结构:
app/src/main/java/com/dezhong/driverandroid/
ui/ # 传统 UI (Activity + Fragment + ViewModel)
myCompose/ # Compose UI
net/ # 网络层
base/ # 基类
service/ # 后台服务
common/ # 通用类
```