Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

无法识别 Kotlin multiplatform 中非JVM平台源码集中的类 #37

Open
ForteScarlet opened this issue Jun 8, 2024 · 8 comments
Open

Comments

@ForteScarlet
Copy link

ForteScarlet commented Jun 8, 2024

Kotlin多平台项目中无法识别 commonMain 中定义的类型,例如 commonMain 中写的某个数据类。如果点击 Copy JSON 会在粘贴板中得到 null
会考虑支持Kotlin多平台吗?

@ForteScarlet ForteScarlet changed the title 无法识别 Kotlin multiplatform 中非JVM平台源码集中的数据类(例如 commonMain 中) 无法识别 Kotlin multiplatform 中非JVM平台源码集中的类 Jun 8, 2024
@organics2016
Copy link
Owner

我不太了解你说的 Kotlin多平台, 我搜索的信息认为它是一种移动端跨平台的框架, 所以我没明白你的问题, 你应该用代码展示一个例子,, 让我知道你的想法 ..
另外我也不知道你说的 commonMain 是什么? 如果它是一个标准的 Kotlin class 那么应该是支持的.. 插件会检查带有 "class"字段的 Kotlin 文件, 如果你说的 commonMain 可以被定义为一个 Kotlin class 那应该是支持的..

@ForteScarlet
Copy link
Author

ForteScarlet commented Jun 9, 2024

我创建了一个简单的 Kotlin 多平台项目,也许可以用作参考:
kt-multiplatform-example.zip

Kotlin 多平台的源码集大概类似于:

root
   \- src
        \- commonMain  ---> 共享的源码集
        |      \- kotlin 
        |            \- DataCommon.kt
        \- jvmMain  -------> 专供 JVM 平台的源码集
        |      \- kotlin
        |            \--- DataJvm.kt
        \- jsMain  ---------> 专供 JS 平台的源码集
              

其中,commonMain 就是对所有平台都共享的源码集,可以在其他平台中访问、并被编译进对应的平台产物中(比如编译成class文件)
jvmMain 是 JVM 平台的源码集,可以使用 commonMain 中的东西,但是不能使用其他平台的(比如 JS 平台 jsMain 中的类型)

遇到的问题: 在我上面提供的那个简单的项目中,有两个类,分别是定义在 commonMain 中的 DataCommon.ktjvmMain 中的 DataJvm.kt,而对 DataCommon.kt 使用 Copy JSON 只会在粘贴板中得到 nullDataJvm.kt 则是正常的。

这似乎是因为在 commonMain 中的时候,

public void pojo2jsonAction(@NotNull final PsiFile psiFile,
@Nullable final Editor editor,
@Nullable final PsiElement psiElement) {
final Project project = psiFile.getProject();
if (!uastSupported(psiFile)) {
Notifier.notifyWarn("This file can't convert to json.", project);
return;
}
UElement uElement = null;
if (psiElement != null) {
uElement = UastContextKt.toUElement(psiElement, UVariable.class);
}
if (uElement == null) {
if (editor != null) {
PsiElement elementAt = psiFile.findElementAt(editor.getCaretModel().getOffset());
uElement = UastUtils.findContaining(elementAt, UClass.class);
}
}
if (uElement == null) {
String fileText = psiFile.getText();
int offset = fileText.contains("class") ? fileText.indexOf("class") : fileText.indexOf("record");
if (offset < 0) {
Notifier.notifyWarn("Can't find class scope.", project);
return;
}
PsiElement elementAt = psiFile.findElementAt(offset);
uElement = UastUtils.findContaining(elementAt, UClass.class);
}
try {
String json = pojo2JSONParser.uElementToJSONString(uElement);
ClipboardHandler.copyToClipboard(json);
Notifier.notifyInfo("Convert " + psiFile.getName() + " to JSON success, copied to clipboard.", project);
} catch (KnownException ex) {
Notifier.notifyWarn(ex.getMessage(), project);
}
}

POJO2JSONAction.pojo2jsonAction 里准备 uElement 的条件逻辑都没有生效,导致最终 uElement 的值为 null,因此toJson得到了值为 nulljson 并且提示了成功。

String json = pojo2JSONParser.uElementToJSONString(uElement);

逻辑中定位到的 elementAt (例如 PsiElement elementAt = psiFile.findElementAt(offset);)是有值的,但是它们似乎无法被解析为UClass 之类的类型 🤔。

我不太了解插件开发,因此想要尝试自行修复但是没有成功,也无法定位到更根本的原因,还望见谅😢

@organics2016
Copy link
Owner

收到你的回复,,我已经成功复现, 我需要一些时间解决这个BUG

@organics2016
Copy link
Owner

感谢你的回复, 可以确定这是一个BUG, 但遗憾的是短时间无法修复.

uElement = UastUtils.findContaining(elementAt, UClass.class);

问题在这里, 这可能是 jetbrains plugins SDK 的问题, DataCommon.ktDataJvm.kt 格式上没有任何区别, 但却返回两种不同的结果. 准确的说 commonMain 文件夹下的 kt 文件都无法被正确的解析为 UElement 我对此也很懵逼. JB SDK 的抽象语法引擎实现就是一坨....

if (uElement == null) {
String fileText = psiFile.getText();
int offset = fileText.contains("class") ? fileText.indexOf("class") : fileText.indexOf("record");
if (offset < 0) {
Notifier.notifyWarn("Can't find class scope.", project);
return;
}
PsiElement elementAt = psiFile.findElementAt(offset);
uElement = UastUtils.findContaining(elementAt, UClass.class);
}

这段代码逻辑是: 当用户光标在文件没有元素的区域进行 Copy JSON 时, 会自动查找这个文件中 class 关键字 并将这个关键字所在的元素解析为 抽象语法树中的 UElement . 但是对于 commonMain 文件夹下的所有 kt 文件解析结果却是 null.

这个问题我的去 jetbrains plugins SDK 提Issue.. 短时间内应该无法解决.

@ForteScarlet
Copy link
Author

👌🏻已了解

不知道会不会有别的不用 UElement 的实现方法呢?🤔

这方面不太了解,只是随口说说
总而言之辛苦排查了,期待修复的那一天~

@organics2016
Copy link
Owner

目前最有可能的解释是 IDEA 为 commonMainjvmMain 两个文件夹 加载了两种不同的包环境 , 因为环境中的lib不一样 , 导致语法树引擎认为它们不一样... 之前也有类似的情况.
我已经尝试将 UElement 当作原始的 PsiElement 进行处理,结果所有 kt 文件都会失效....情况比现在更差..我暂时也没什么好办法了..

@ForteScarlet
Copy link
Author

好吧,看来需要等待JB对Issue的答复了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants