Skip to content

Q 包混淆类 / Velocity 扩展 / Kotlin 扩展 — 完整反编译分析

目录

  1. Q 包混淆类分析
  2. Velocity 扩展类分析
  3. Kotlin 扩展类分析
  4. 三个子系统之间的交互关系

1. Q 包混淆类分析

Q 包位于 Q/(默认包根目录),包含 3 个混淆类,它们是 iFlyCode 内联代码提示系统的核心数据模型和交互处理类。

1.1 Q.q — CodeTipType 数据模型(CodeEditorInlay 实现)

源文件: cg (混淆前)
完整类名: Q.q
继承关系: public final class Q.q implements com.aicode.service.CodeEditorInlay

字段列表

混淆名类型语义名说明
floatinteditorOffset编辑器中的偏移位置
byteList<String>lines代码提示的文本行列表
enumcom.aicode.enums.CodeTipTypetype代码提示类型

方法列表

方法签名说明
Q.q(CodeTipType, int, List<String>)构造函数,初始化 type/offset/lines
CodeTipType getType()获取提示类型,null 检查后调用 enum()
void setType(CodeTipType)设置提示类型
int getEditorOffset()获取编辑器偏移
void setEditorOffset(int)设置编辑器偏移
List<String> getLines()获取文本行,null 检查后调用 enum()
List<String> ze()获取文本行(混淆名),与 getLines() 逻辑相同
void setLines(List<String>)设置文本行
String toString()格式化输出 type/offset/lines
private static void enum(int)空指针/参数校验失败时的异常生成器

CodeTipType 映射关系

CodeTipType 枚举定义了 3 个值:

CodeTipType.AfterLineEnd  -> ordinal 0
CodeTipType.Block         -> ordinal 1
CodeTipType.Inline        -> ordinal 2

enum(int) 方法中的 tableswitch 使用 0-4 的范围(包含额外占位),但实际只有 3 个枚举值被使用。该方法根据参数值生成不同的混淆错误消息字符串,然后通过 String.format 构造异常消息,最终抛出 IllegalStateExceptionIllegalArgumentException

与 CodeEditorInlay 接口的映射

CodeEditorInlay 接口定义了以下抽象方法,Q.q 全部实现:

接口方法Q.q 实现
List<String> getLines()getLines()
int getEditorOffset()getEditorOffset()
void setEditorOffset(int)setEditorOffset(int)
void setType(CodeTipType)setType(CodeTipType)
void setLines(List<String>)setLines(List<String>)
CodeTipType getType()getType()
boolean isEmptyTip()默认实现(接口 default)

引用方式

  • Q.q 作为 CodeEditorInlay 的唯一实现,被 EditorManagerService 等服务层广泛使用
  • 构造函数中的 null 检查使用混淆字符串,通过 ConditionalActionConfiguration.H()ChatInputController.H() 解码
  • ze() 方法是混淆后的 getter,功能与 getLines() 完全相同

1.2 Q.sa — 内联提示循环动作(抽象 Action)

源文件: dh (混淆前)
完整类名: Q.sa
继承关系: public abstract class Q.sa extends com.aicode.action.click.PluginAnAction

字段列表

无实例字段(继承自 PluginAnAction)。

方法列表

方法签名说明
Q.sa()构造函数,调用 PluginAnAction.<init>()
abstract boolean doCycleAction(Editor)抽象方法,子类实现循环动作逻辑
String getWarningHintText()获取警告提示文本,从 BasicActionsBundle 获取
void actionPerformed(AnActionEvent)动作执行入口,获取 Editor 后调用 doCycleAction
void update(AnActionEvent)更新动作状态,检查 Editor 和 hasTipInlays
private static void Nd(Editor, String)显示错误提示(HintManager.showErrorHint)
private static void enum(int)异常生成器

核心逻辑分析

actionPerformed 流程:

  1. AnActionEvent 获取 Editor 实例(通过 CommonDataKeys.EDITOR
  2. 调用 doCycleAction(editor) — 抽象方法,由子类实现具体循环逻辑
  3. 如果 doCycleAction 返回 false,调用 Nd(editor, getWarningHintText()) 显示错误提示

update 流程:

  1. 获取当前 Editor
  2. 检查 EditorManagerService.getInstance().hasTipInlays(editor) 是否有活动的提示
  3. 根据结果设置 Presentation.setEnabled()

Nd 方法(私有静态):

  • 使用 HintManager.getInstance().showErrorHint() 显示错误提示
  • 参数:errorHintType = 1033hideFlags = 1500
  • 在当前 caret offset 处显示

CodeTipType 映射关系

Q.sa 不直接持有 CodeTipType,但通过 EditorManagerService.hasTipInlays() 间接关联。doCycleAction 的子类实现会操作 Q.q(CodeEditorInlay)实例,其中包含 CodeTipType 类型信息。


1.3 Q.ua — 编辑器动作拦截器(EditorActionHandler 包装器)

源文件: yl (混淆前)
完整类名: Q.ua
继承关系: public class Q.ua extends com.intellij.openapi.editor.actionSystem.EditorActionHandler

字段列表

混淆名类型语义名说明
enumEditorActionHandler (final)delegate被包装的原始动作处理器

方法列表

方法签名说明
Q.ua(EditorActionHandler)构造函数,保存原始 handler
boolean isEnabledForCaret(Editor, Caret, DataContext)判断动作是否启用
void doExecute(Editor, Caret, DataContext)执行动作
boolean executeInCommand(Editor, DataContext)是否在命令中执行
static boolean Yf(Editor)判断编辑器是否有活动的内联提示
private static void enum(int)异常生成器

核心逻辑分析

Yf(Editor) — 关键静态方法:

1. EditorManagerService.getInstance().isAvailable(editor) — 服务是否可用
2. EditorManagerService.getInstance().hasTipInlays(editor) — 是否有提示
3. LookupManager.getActiveLookup(editor) == null — 没有活动的代码补全
4. 三个条件同时满足返回 true

isEnabledForCaret 逻辑:

if (Yf(editor)) {
    return false;  // 有内联提示时,禁用原始动作
} else if (delegate != null && delegate.isEnabled(...)) {
    return true;   // 无提示时,委托给原始 handler
} else {
    return false;
}

doExecute 逻辑:

if (Yf(editor)) {
    // 有内联提示时,执行 EscReject 操作
    EditorManagerService.getInstance().disposeTips(editor, OperateActionEnum.EscReject);
}
// 然后委托给原始 handler 执行(如果存在且 enabled)
if (delegate != null && delegate.isEnabled(...)) {
    delegate.execute(editor, caret, dataContext);
}

OperateActionEnum 映射

Q.ua 使用 OperateActionEnum.EscReject,该枚举完整值:

枚举值说明
Applied用户已应用提示
Typing用户正在输入
IdeCompletionIDE 自动补全
Cycling循环切换提示
SettingsChange设置变更
EscRejectESC 键拒绝提示
UserOperate用户操作
CaretChange光标位置变更
TypingAsSuggested按建议输入

设计模式

Q.ua 实现了 装饰器模式(Decorator Pattern)

  • 包装原始 EditorActionHandler
  • 在有内联提示时拦截动作(如 ESC 键),触发 disposeTips
  • 在无提示时透传给原始 handler
  • ConditionalEditorActionHandler 互补:后者处理条件性按键绑定,前者处理通用编辑器动作拦截

2. Velocity 扩展类分析

iFlyCode 对 Apache Velocity 模板引擎进行了深度定制,包含 5 个扩展类,用于模板配置管理和属性键的废弃迁移。

2.1 DeprecationAwareExtProperties — 废弃键感知属性表

源文件: ia (混淆前)
完整类名: org.apache.velocity.util.DeprecationAwareExtProperties
继承关系: public class DeprecationAwareExtProperties extends Hashtable<String, Object>

字段列表

混淆名类型语义名说明
byteMap<String, String> (static)deprecatedKeyMap废弃键到新键的映射
enumSet&lt;String&gt;warnedKeys已警告过的键集合
loggerLogger (static)loggerSLF4J 日志器

方法列表

方法签名说明
DeprecationAwareExtProperties()构造函数,初始化 warnedKeys HashSet
Object put(Object, Object)代理 put(String, Object)
Object put(String, Object)重写,先 translateKey 再存入 Hashtable
Object get(String)重写,先 translateKey 再从 Hashtable 获取
String translateKey(String)核心方法:将废弃键翻译为新键
boolean containsKey(String)重写,先 translateKey 再检查
void warnDeprecated(String, String)记录废弃警告(仅首次)
static &#123;&#125;静态初始化块

核心逻辑:translateKey

1. 查找 deprecatedKeyMap(byte 字段),如果找到映射,返回新键并警告
2. 检查键是否包含 "." 分隔符(混淆字符串解码后),如果是,取最后一段
3. 检查键是否以特定后缀结尾(22 字符长度),如果是,去掉后缀
4. 都不匹配,返回原始键

静态初始化块逻辑

1. 初始化 logger(通过 LoggerFactory.getLogger)
2. 创建 deprecatedKeyMap(HashMap)
3. 反射读取 DeprecatedRuntimeConstants 的所有字段
4. 验证字段名以 "OLD_" 前缀开头(混淆后为 2 字符前缀)
5. 验证字段类型为 String
6. 验证字段值非空
7. 截取字段名前 4 个字符后的部分
8. 在 RuntimeConstants 中查找对应的新字段
9. 如果新旧值不同,将旧值 -> 新值映射加入 deprecatedKeyMap
10. 任何异常包装为 VelocityException

与模板引擎的集成

DeprecationAwareExtProperties 是 Velocity 配置属性的基础容器,提供透明的键名迁移:

  • 所有属性访问(get/put/containsKey)自动经过 translateKey
  • 废弃键被静默映射到新键,仅首次使用时发出 SLF4J 警告
  • 继承 Hashtable<String, Object>,保持与 Velocity 原生 API 的兼容性

2.2 ExtProperties — 扩展属性配置

源文件: xa (混淆前)
完整类名: org.apache.velocity.util.ExtProperties
继承关系: public class ExtProperties extends DeprecationAwareExtProperties

字段列表

混淆名类型语义名说明
fileSeparatorStringfileSeparator文件路径分隔符
isInitializedbooleanisInitialized是否已初始化
fileStringfile配置文件路径
keysAsListedArrayList&lt;String&gt;keysAsListed按插入顺序排列的键列表
enumExtProperties (private)defaults默认属性集
includeString (static)includeinclude 指令名称
basePathStringbasePath基础路径
END_TOKENString (static final)END_TOKEN变量插值结束标记
START_TOKENString (static final)START_TOKEN变量插值开始标记

方法列表(完整)

方法签名说明
ExtProperties()默认构造
ExtProperties(String)从文件路径构造
ExtProperties(String, String)从文件路径和编码构造
boolean getBoolean(String)获取布尔值
boolean getBoolean(String, boolean)获取布尔值(带默认)
Boolean getBoolean(String, Boolean)获取布尔值(包装类型)
byte getByte(String)获取字节值
byte getByte(String, byte)获取字节值(带默认)
Byte getByte(String, Byte)获取字节值(包装类型)
short getShort(String)获取短整型
short getShort(String, short)获取短整型(带默认)
Short getShort(String, Short)获取短整型(包装类型)
int getInt(String)获取整型
int getInt(String, int)获取整型(带默认)
Integer getInteger(String)获取整型(包装类型)
Integer getInteger(String, Integer)获取整型(包装类型,带默认)
int getInteger(String, int)获取整型(带默认)
long getLong(String)获取长整型
long getLong(String, long)获取长整型(带默认)
Long getLong(String, Long)获取长整型(包装类型)
float getFloat(String)获取浮点型
float getFloat(String, float)获取浮点型(带默认)
Float getFloat(String, Float)获取浮点型(包装类型)
double getDouble(String)获取双精度型
double getDouble(String, double)获取双精度型(带默认)
Double getDouble(String, Double)获取双精度型(包装类型)
String getString(String)获取字符串
String getString(String, String)获取字符串(带默认)
String[] getStringArray(String)获取字符串数组
Vector getVector(String)获取向量
Vector getVector(String, Vector)获取向量(带默认)
List getList(String)获取列表
List getList(String, List)获取列表(带默认)
Properties getProperties(String)获取属性子集
Properties getProperties(String, Properties)获取属性子集(带默认)
Object getProperty(String)获取属性
void setProperty(String, Object)设置属性
void addProperty(String, Object)添加属性
void clearProperty(String)清除属性
void combine(ExtProperties)合并属性
ExtProperties subset(String)获取子集
Iterator&lt;String&gt; getKeys()获取键迭代器
Iterator&lt;String&gt; getKeys(String)获取带前缀的键迭代器
void load(InputStream)从流加载
synchronized void load(InputStream, String)从流加载(带编码)
synchronized void save(OutputStream, String)保存到流
String interpolate(String)变量插值
String interpolateHelper(String, List&lt;String&gt;)插值辅助
void display()显示所有属性
boolean isInitialized()是否已初始化
String getInclude()获取 include 指令名
void setInclude(String)设置 include 指令名
static ExtProperties convertProperties(Map)从 Map 转换
static ExtProperties convertProperties(Properties)从 Properties 转换
private void char()内部初始化
private void int(String, Object)内部属性设置
private void case(String, Object)内部属性处理
private static String catch(String)内部字符串处理
private static String break()内部字符串生成
private static String short(String)内部字符串处理
private static boolean float(String)判断字符串是否为变量引用
private static int long(String, int, char)内部整数解析

模板变量注入机制

ExtProperties 实现了 Velocity 的变量插值系统:

  1. START_TOKEN / END_TOKEN: 定义变量引用的边界标记(如 $&#123;&#125;
  2. interpolate(String): 扫描字符串中的变量引用并替换为实际值
  3. interpolateHelper(String, List<String>): 递归处理嵌套变量引用,防止循环引用
  4. float(String): 检测字符串是否包含变量引用标记
  5. subset(String): 支持命名空间隔离的属性子集

2.3 DeprecatedRuntimeConstants — 废弃运行时常量接口

源文件: u (混淆前)
完整类名: org.apache.velocity.runtime.DeprecatedRuntimeConstants
类型: public interface

常量列表(39 个)

常量名说明
OLD_RUNTIME_LOG_REFERENCE_LOG_INVALID无效引用日志记录
OLD_MAX_NUMBER_LOOPS最大循环次数
OLD_SKIP_INVALID_ITERATOR跳过无效迭代器
OLD_CHECK_EMPTY_OBJECTS检查空对象
OLD_ERRORMSG_START错误消息开始标记
OLD_ERRORMSG_END错误消息结束标记
OLD_PARSE_DIRECTIVE_MAXDEPTH解析指令最大深度
OLD_DEFINE_DIRECTIVE_MAXDEPTH定义指令最大深度
OLD_CUSTOM_DIRECTIVES自定义指令
OLD_RESOURCE_MANAGER_DEFAULTCACHE_SIZE资源管理器默认缓存大小
OLD_RESOURCE_MANAGER_LOGWHENFOUND资源管理器发现时日志
OLD_RESOURCE_LOADERS资源加载器
OLD_FILE_RESOURCE_LOADER_PATH文件资源加载器路径
OLD_FILE_RESOURCE_LOADER_CACHE文件资源加载器缓存
OLD_RESOURCE_LOADER_CHECK_INTERVAL资源加载器检查间隔
OLD_DS_RESOURCE_LOADER_DATASOURCE数据源资源加载器
OLD_DS_RESOURCE_LOADER_KEY_COLUMN数据源键列
OLD_DS_RESOURCE_LOADER_TEMPLATE_COLUMN数据源模板列
OLD_DS_RESOURCE_LOADER_TIMESTAMP_COLUMN数据源时间戳列
OLD_INPUT_ENCODING输入编码
OLD_EVENTHANDLER_REFERENCEINSERTION引用插入事件处理器
OLD_EVENTHANDLER_METHODEXCEPTION方法异常事件处理器
OLD_EVENTHANDLER_INCLUDEInclude 事件处理器
OLD_EVENTHANDLER_INVALIDREFERENCES无效引用事件处理器
OLD_VM_LIBRARYVelocimacro 库
OLD_VM_LIBRARY_DEFAULT默认 Velocimacro 库
OLD_VM_PERM_ALLOW_INLINE允许内联宏
OLD_VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL允许内联宏替换全局
OLD_VM_PERM_INLINE_LOCAL本地内联宏
OLD_VM_MAX_DEPTH宏最大深度
OLD_VM_BODY_REFERENCE宏体引用
OLD_RUNTIME_REFERENCES_STRICT严格引用模式
OLD_RUNTIME_REFERENCES_STRICT_ESCAPE严格引用转义
OLD_UBERSPECT_CLASSNAMEUberspect 类名
OLD_CONVERSION_HANDLER_CLASS转换处理器类
OLD_INTERPOLATE_STRINGLITERALS字符串字面量插值
OLD_STRICT_MATH严格数学模式
OLD_CONTEXT_AUTOREFERENCE_KEY上下文自动引用键
OLD_SPACE_GOBBLING空格吞噬模式
OLD_VM_ENABLE_BC_MODE宏向后兼容模式

初始化机制

所有常量值通过混淆字符串 + 解码函数初始化:

  • 偶数索引常量使用 NewFileUtils.H() 解码
  • 奇数索引常量使用 FontKt.H() 解码
  • 这种交替使用两个不同解码器的模式增加了逆向难度

2.4 ExtProperties$C — 属性键分割器

源文件: xa (与 ExtProperties 同源)
完整类名: org.apache.velocity.util.ExtProperties$C
继承关系: public class ExtProperties$C extends StringTokenizer

字段列表

混淆名类型语义名说明
enumString (static final)delimiter分隔符(解码后为 ",")

方法列表

方法签名说明
ExtProperties$C(String)构造函数,使用分隔符创建 StringTokenizer
boolean hasMoreTokens()是否有更多 token
String nextToken()获取下一个 token,处理转义分隔符

核心逻辑

nextToken() 方法重写了 StringTokenizer 的行为:

  1. 循环读取 token
  2. 如果 token 以转义字符结尾(float() 检测),去掉末尾转义符,追加分隔符,继续读取
  3. 否则直接返回 token
  4. 最终 trim 结果

这允许属性值中包含转义的分隔符(如 value1\,value2 被视为单个值)。


2.5 ExtProperties$L — 属性文件行读取器

源文件: xa (与 ExtProperties 同源)
完整类名: org.apache.velocity.util.ExtProperties$L
继承关系: public class ExtProperties$L extends LineNumberReader

方法列表

方法签名说明
ExtProperties$L(Reader)构造函数,包装 Reader
String false() throws IOException读取逻辑行(合并续行)

核心逻辑

false() 方法(混淆后的方法名,语义为 readLogicalLine):

  1. 创建 StringBuilder
  2. 循环读取物理行
  3. 跳过空行和以 # 开头的注释行
  4. 如果行以续行符结尾(float() 检测),去掉续行符,追加到 StringBuilder,继续读取下一行
  5. 否则直接返回该行
  6. 到达文件末尾返回 null

这实现了属性文件中的续行功能(行末 \ 表示续行)。


3. Kotlin 扩展类分析

iFlyCode 使用 Kotlin 扩展函数为 IntelliJ Platform API 和 Swing 组件添加便利方法。所有扩展类都包含 H(Object) 静态方法,这是混淆字符串解码器。

3.1 EditorKt — Editor 扩展函数集

源文件: vb (混淆前)
完整类名: com.aicode.util.EditorKt

静态字段

字段名类型说明
FILE_LANGMap<String, String>文件扩展名到语言名的映射
categoryRendererCollectionMap<String, InlineChatCategoryPanelRenderer>分类面板渲染器集合
stopRendererCollectionMap<String, InlineChatStopPanelRenderer>停止面板渲染器集合
rendererCollectionMap<String, Object>通用渲染器集合
commentSymbolsMap<String, String>语言到注释符号的映射
inlineChatCacheDataMap<String, InlineChatInfo>内联聊天缓存数据(按文件路径索引)
inlineChatBtnCacheMap<Editor, Inlay<?>>内联聊天按钮缓存(按 Editor 索引)
inlineChatVersionAtomicInteger内联聊天版本计数器
endSymbolsMap<String, String>语言到结束符号的映射

扩展函数列表

函数签名扩展接收者说明
void addInfoByEditor(Editor, InlineChatInfo)Editor按编辑器添加内联聊天信息到缓存
void addCursorListener(Editor, CaretListener)Editor为编辑器添加光标监听器
String getErrorRendererTip(Editor, EditorRequestService)Editor获取错误渲染器提示文本
String getFileType(Editor)Editor获取编辑器当前文件类型(扩展名)
void addSelectionListener(Editor, SelectionListener)Editor为编辑器添加选区监听器
boolean getHasSelection(Editor)Editor检查编辑器是否有选中文本
void closeCategoryPanel(Editor)Editor关闭分类面板
void closeStopPanel(Editor)Editor关闭停止面板
void closeButtonPanel(Editor)Editor关闭按钮面板
VirtualFile getFile(Editor)Editor获取编辑器关联的虚拟文件
InlineChatInfo getInfoByVirtualFile(VirtualFile)VirtualFile按虚拟文件获取内联聊天信息
InlineChatInfo getInfoByEditor(Editor)Editor按编辑器获取内联聊天信息
void removeEditor(Editor)Editor从缓存中移除编辑器
boolean containEditor(Editor)Editor检查编辑器是否在缓存中

功能分析

EditorKt 是内联聊天系统的核心工具类,提供:

  1. 缓存管理: inlineChatCacheDatainlineChatBtnCache 维护编辑器与内联提示的映射关系
  2. 语言支持: FILE_LANGcommentSymbolsendSymbols 提供语言特定的注释和结束符号
  3. 渲染器注册: categoryRendererCollectionstopRendererCollectionrendererCollection 管理不同类型的面板渲染器
  4. 监听器管理: 便捷方法添加光标和选区监听器
  5. 面板控制: 关闭各类内联聊天面板

3.2 FontKt — 字体扩展函数集

源文件: ob (混淆前)
完整类名: com.aicode.ui.FontKt

扩展函数列表

函数签名扩展接收者返回类型说明
italic(JBFont)JBFontJBFont设置字体为斜体(调用 asItalic)
bold(JBFont)JBFontJBFont设置字体为粗体(调用 asBold)
plain(JBFont)JBFontJBFont设置字体为常规(调用 asPlain)
textWidthForFont(String, Font)String + Fontint计算文本在指定字体下的像素宽度
widthForFont(String, Font)String + Fontint计算文本宽度(带 null 检查的包装)
H(Object)String混淆字符串解码器

功能分析

FontKt 提供 IntelliJ 平台字体操作的 Kotlin 扩展:

  1. 字体样式链: italic()bold()plain() 返回 JBFont,支持链式调用
  2. 文本测量: textWidthForFont() 使用 JLabel.getFontMetrics().stringWidth() 精确计算文本像素宽度
  3. 混淆解码器: H(Object) 方法是全局混淆字符串解码器之一,被 DeprecatedRuntimeConstants 等类引用

H() 解码算法

FontKt.H() 实现了与 JComponentKt.H() 类似的解码算法:

  1. 获取调用栈的类名和方法名,拼接为密钥字符串
  2. 对密钥字符串进行位运算变换(位移 + 异或)
  3. 使用变换后的密钥对输入字符串进行 XOR 解码
  4. 双向遍历(从两端向中间)解码字符数组

3.3 JComponentKt — Swing 组件扩展函数集

源文件: rb (混淆前)
完整类名: com.aicode.util.JComponentKt

扩展函数列表

函数签名扩展接收者返回类型说明
font(JComponent, Font)JComponentJComponent设置字体并返回自身(链式调用)
findComponent(JComponent)JComponentT在组件树中查找指定类型子组件
findComponent(KClass&lt;T&gt;, Component)KClass&lt;T&gt; + ComponentT按类型在组件树中查找子组件
isChildFocused(JComponent)JComponentboolean递归检查子组件是否获得焦点
minimumSize(JComponent, int, int)JComponentJComponent设置最小尺寸
minimumSize$default(...)JComponentJComponentminimumSize 默认参数版本
maximumSize(JComponent, int, int)JComponentJComponent设置最大尺寸
maximumSize$default(...)JComponentJComponentmaximumSize 默认参数版本
preferredSize(JComponent, int, int)JComponentJComponent设置首选尺寸
preferredSize$default(...)JComponentJComponentpreferredSize 默认参数版本
opaque(JComponent, boolean)JComponentJComponent设置不透明度
border(JComponent, Border)JComponentJComponent设置边框
removeInsets(JComponent)JComponentJComponent移除内边距
update(JComponent)JComponentJComponent刷新组件 UI
lockMouseInteractions(JComponent)JComponentJComponent锁定鼠标交互
inAllChildren(JComponent, Function1)JComponentvoid递归遍历所有子组件执行操作
H(Object)String混淆字符串解码器

功能分析

JComponentKt 实现了 Kotlin DSL 风格 的 Swing 组件构建器:

  1. 链式配置: 所有 setter 方法返回 JComponent 自身,支持 component.font(f).border(b).opaque(true) 风格
  2. 尺寸快捷方法: minimumSize/maximumSize/preferredSize 封装 Dimension 创建
  3. 组件查找: findComponent 使用 Kotlin 反射按类型递归查找
  4. 递归遍历: inAllChildren 对组件树执行深度优先遍历
  5. 焦点检测: isChildFocused 递归检查焦点状态
  6. 交互锁定: lockMouseInteractions 禁用鼠标事件(用于只读 UI 元素)

3.4 InlineChatStatusServiceKt — 内联聊天状态服务扩展

源文件: hk (混淆前)
完整类名: com.aicode.inline.status.InlineChatStatusServiceKt

扩展函数列表

函数签名说明
InlineChatStatusService InlineChatStatusService()顶级属性访问器,获取 InlineChatStatusService 单例
H(Object)混淆字符串解码器
private enum(int)异常生成器

功能分析

这是一个 Kotlin 顶级属性扩展,提供便捷的服务访问:

kotlin
// Kotlin 源码等价
val InlineChatStatusService: InlineChatStatusService
    get() = InlineChatStatusServiceProvider.INSTANCE.get()
  • 通过 InlineChatStatusServiceProvider 单例获取服务实例
  • 简化其他类对状态服务的访问,避免重复调用 InlineChatStatusServiceProvider.INSTANCE.get()
  • null 安全检查:如果服务为 null,抛出 IllegalStateException

3.5 IdeEditorActionRouterKt — 编辑器动作路由扩展

源文件: ai (混淆前)
完整类名: com.aicode.inline.ide.IdeEditorActionRouterKt

字段列表

混淆名类型语义名说明
enumLogger (private static final)loggerIntelliJ 诊断日志器

扩展函数列表

函数签名说明
void replaceWithConditionalAction(EditorActionManager, String, ConditionalActionConfiguration, InlineChatService)替换编辑器动作为条件动作
private enum(int)异常生成器

核心逻辑:replaceWithConditionalAction

1. 从 ActionManager 获取指定 actionId 的 AnAction
2. 如果 action 不存在,logger.debug 记录并返回
3. 从 EditorActionManager 获取当前 action handler
4. 如果 handler 不存在,logger.warn 记录并返回
5. 创建 ConditionalEditorActionHandler 包装原始 handler
6. 调用 EditorActionManager.setActionHandler() 替换
7. ClassCastException 处理:logger.warn 记录

功能分析

IdeEditorActionRouterKt 是内联聊天系统的 动作拦截注册器

  • 将指定的 IDE 编辑器动作(如 Enter、Tab、Escape)替换为 ConditionalEditorActionHandler
  • ConditionalEditorActionHandler 包装原始 handler,在内联聊天激活时拦截按键
  • Q.ua(通用编辑器动作拦截器)互补:
    • Q.ua 处理所有编辑器动作的通用拦截
    • IdeEditorActionRouterKt 处理特定按键的条件性拦截

4. 三个子系统之间的交互关系

4.1 整体架构

+-------------------------------------------------------+
|                    iFlyCode 插件                        |
|                                                        |
|  +-- Q 包混淆类 (数据模型 + 动作处理) ----------------+ |
|  |                                                     | |
|  |  Q.q (CodeEditorInlay)  <--- 数据模型               | |
|  |  Q.sa (CycleAction)      <--- 用户交互              | |
|  |  Q.ua (ActionHandler)    <--- 动作拦截              | |
|  |                                                     | |
|  +----------------------------------------------------+ |
|                                                        |
|  +-- Velocity 扩展 (模板配置) -------------------------+ |
|  |                                                     | |
|  |  DeprecationAwareExtProperties  <--- 属性基类        | |
|  |  ExtProperties                  <--- 完整属性系统    | |
|  |  DeprecatedRuntimeConstants     <--- 废弃常量定义    | |
|  |  ExtProperties$C                <--- 键分割器        | |
|  |  ExtProperties$L                <--- 行读取器        | |
|  |                                                     | |
|  +----------------------------------------------------+ |
|                                                        |
|  +-- Kotlin 扩展 (便利 API) --------------------------+ |
|  |                                                     | |
|  |  EditorKt                     <--- 编辑器工具       | |
|  |  FontKt                       <--- 字体工具         | |
|  |  JComponentKt                 <--- UI 组件工具      | |
|  |  InlineChatStatusServiceKt    <--- 状态服务访问      | |
|  |  IdeEditorActionRouterKt      <--- 动作路由          | |
|  |                                                     | |
|  +----------------------------------------------------+ |
+-------------------------------------------------------+

4.2 交互关系详解

Q 包 <-> Kotlin 扩展

交互路径说明
Q.q <-> EditorKtEditorKt 管理的 inlineChatCacheData 缓存存储 InlineChatInfo,与 Q.qCodeTipType 类型信息关联
Q.sa <-> EditorKtQ.sa.update() 调用 EditorManagerService.hasTipInlays(),该服务使用 EditorKt 管理的缓存
Q.ua <-> IdeEditorActionRouterKtQ.ua 是通用动作拦截器,IdeEditorActionRouterKt 注册特定条件动作,两者共同构成按键拦截体系
Q.ua <-> EditorKtQ.ua.Yf() 调用 EditorManagerService.isAvailable()hasTipInlays(),依赖 EditorKt 的缓存数据
Q.sa <-> InlineChatStatusServiceKtQ.saupdate() 方法可能通过 InlineChatStatusService 检查内联聊天状态

Velocity 扩展 <-> Kotlin 扩展

交互路径说明
DeprecatedRuntimeConstants <-> FontKt废弃常量的奇数索引值使用 FontKt.H() 解码
DeprecatedRuntimeConstants <-> NewFileUtils废弃常量的偶数索引值使用 NewFileUtils.H() 解码
DeprecationAwareExtProperties <-> GenericUtils属性键翻译中的字符串常量使用 GenericUtils.H() 解码
ExtProperties$C <-> Application.H()分隔符字符串使用 Application.H() 解码

Q 包 <-> Velocity 扩展

交互路径说明
间接关联Velocity 模板系统用于生成代码提示内容,Q.qlines 字段可能包含模板渲染结果
配置驱动Velocity 的 ExtProperties 配置可能影响模板中变量插值的行为,进而影响 Q.q 的内容生成

4.3 混淆字符串解码器网络

三个子系统共享一个混淆字符串解码器网络,每个 H(Object) 方法使用不同的密钥派生算法:

解码器所在类密钥来源被引用者
ConditionalActionConfiguration.H()inline.ide调用栈类名+方法名Q.q, DeprecationAwareExtProperties
ChatInputController.H()inline.controller调用栈类名+方法名Q.q
Application.H()util调用栈类名+方法名Q.sa, ExtProperties$C, FontKt
RequestCancelException.H()exception调用栈类名+方法名Q.sa, FontKt
PropertyUtils.H()util调用栈类名+方法名Q.ua, InlineChatStatusServiceKt
GitReviewService.H()agent.service调用栈类名+方法名Q.ua
GenericUtils.H()diff调用栈类名+方法名DeprecationAwareExtProperties
FontKt.H()ui调用栈类名+方法名DeprecatedRuntimeConstants
NewFileUtils.H()util调用栈类名+方法名DeprecatedRuntimeConstants
Maps.H()util调用栈类名+方法名EditorKt
PositionUtil.H()util调用栈类名+方法名InlineChatStatusServiceKt
FileInfo.H()diff调用栈类名+方法名IdeEditorActionRouterKt
LanguageFileExtensionDetails.H()content.util.file调用栈类名+方法名IdeEditorActionRouterKt
ActionButton.H()ui调用栈类名+方法名ExtProperties$C

4.4 按键拦截体系

Q 包和 Kotlin 扩展共同构建了一个分层的按键拦截体系:

用户按键
    |
    v
EditorActionManager
    |
    +-- IdeEditorActionRouterKt.replaceWithConditionalAction()
    |       |
    |       v
    |   ConditionalEditorActionHandler (特定按键条件拦截)
    |       - 检查 ConditionalActionConfiguration
    |       - 检查 ActionScope
    |       - 检查 KeyStrokeExecutorProvider
    |       |
    |       v
    +-- Q.ua (通用编辑器动作拦截)
    |       |
    |       v
    |   Yf(editor) 检查:
    |       - EditorManagerService.isAvailable()
    |       - EditorManagerService.hasTipInlays()
    |       - LookupManager.getActiveLookup() == null
    |       |
    |       +-- 有内联提示: disposeTips(EscReject)
    |       +-- 无内联提示: 委托给原始 handler
    |
    +-- Q.sa (循环动作)
            |
            v
        doCycleAction(editor)
            |
            +-- 返回 true: 动作已处理
            +-- 返回 false: 显示 HintManager 错误提示

4.5 数据流

Velocity 模板引擎
    |
    v (模板渲染 + 变量插值)
ExtProperties (配置管理)
    |
    v (配置参数)
代码提示生成服务
    |
    v
Q.q (CodeEditorInlay 实现)
    |  - type: CodeTipType (AfterLineEnd/Block/Inline)
    |  - editorOffset: int
    |  - lines: List&lt;String&gt;
    |
    v
EditorKt (缓存管理)
    |  - inlineChatCacheData
    |  - inlineChatBtnCache
    |  - categoryRendererCollection
    |  - stopRendererCollection
    |
    v
渲染器 (InlineChatCategoryPanelRenderer, etc.)
    |
    v
用户界面显示
    |
    v (用户交互)
Q.sa / Q.ua / IdeEditorActionRouterKt (动作处理)
    |
    v
EditorManagerService.disposeTips() / InlineChatStatusService

4.6 关键发现总结

  1. Q 包是内联提示的核心: Q.q 是唯一实现 CodeEditorInlay 接口的类,Q.saQ.ua 分别处理用户交互和动作拦截
  2. Velocity 扩展是配置基础设施: 为模板引擎提供属性管理和废弃键迁移,间接支持代码提示内容生成
  3. Kotlin 扩展是便利层: 提供类型安全的 API 和 DSL 风格的组件构建,简化 Q 包和 Velocity 的使用
  4. 混淆系统是跨子系统的: 三个子系统共享 14+ 个不同的字符串解码器,每个解码器使用调用栈信息派生密钥
  5. 按键拦截是多层协作的: IdeEditorActionRouterKt 注册条件拦截,Q.ua 提供通用拦截,Q.sa 处理循环动作
  6. 缓存管理集中在 EditorKt: 所有编辑器相关的缓存(聊天数据、按钮、渲染器)都由 EditorKt 管理

本项目仅供学习研究,逆向分析内容归原厂商所有。