12 KiB
12 KiB
kotlin-language-server 使用指南
通过 Serena MCP 工具调用 kotlin-language-server 进行 Kotlin/Android 代码分析
前置条件
1. 确保 kotlin-language-server 已安装
kotlin-language-server 可通过以下方式安装:
# 通过 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
激活项目
# Step 1: 激活 Kotlin/Android 项目
tool: mcp__serena__activate_project
params:
project: "/path/to/android/project"
# 返回: 项目已激活,kotlin-language-server 已初始化
验证配置
# 检查当前配置
tool: mcp__serena__get_current_config
# 确认输出包含:
# - active_project: /path/to/android/project
# - language_server: kotlin-language-server
符号提取操作
获取文件符号概览
# 获取单个文件的符号列表(不含代码体)
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]
查找符号
# 按名称模式查找符号
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" -> 匹配类中的方法
获取符号详情(含代码体)
# 获取完整的符号定义(含代码)
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 注释
# - 完整方法体
# - 行号范围
引用分析操作
查找符号引用
# 查找某个符号被哪些地方引用
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)
# 当 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 特有关键字与结构
# 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 架构层识别
# 根据命名约定和基类识别架构层
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 识别
# 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 识别
# 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 模式
# 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 映射
# 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 调用链
# 伪代码: 构建 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 调用链
# 实际操作步骤
# 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
最佳实践
- 按架构层分析 - 先识别 MVVM 各层文件,再逐层深入
- Repository 是关键 - Repository 层连接 ViewModel 和 API,是分析重点
- 注解驱动识别 - 利用 @Composable, @GET/@POST 等注解快速分类
- 命名约定优先 - Kotlin/Android 项目通常遵循严格命名约定 (*Vm, *Repository, *Activity)
- 结合 Gradle 分析 - 通过 build.gradle.kts 了解依赖和模块结构
- 注意扩展函数 - Kotlin 扩展函数可能分散在不同文件中
项目特定模式 (chefu_driver_app_android)
该项目使用的技术栈和模式:
架构模式: 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/ # 通用类