2
0
Эх сурвалжийг харах

Support UNSERIALIZABLE_TYPE for detecting `@Serializable` annotations

Him188 5 жил өмнө
parent
commit
39145634e6

+ 1 - 0
tools/compiler-common/src/main/java/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrors.java

@@ -18,6 +18,7 @@ import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
 public interface MiraiConsoleErrors {
     DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_DESCRIPTION = DiagnosticFactory1.create(ERROR);
     DiagnosticFactory1<PsiElement, String> NOT_CONSTRUCTABLE_TYPE = DiagnosticFactory1.create(ERROR);
+    DiagnosticFactory1<PsiElement, String> UNSERIALIZABLE_TYPE = DiagnosticFactory1.create(ERROR);
 
     @Deprecated
     Object _init = new Object() {

+ 7 - 2
tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrorsRendering.kt

@@ -9,8 +9,7 @@
 
 package net.mamoe.mirai.console.compiler.common.diagnostics
 
-import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION
-import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE
+import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.*
 import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
 import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap
 import org.jetbrains.kotlin.diagnostics.rendering.Renderers
@@ -28,6 +27,12 @@ object MiraiConsoleErrorsRendering : DefaultErrorMessages.Extension {
             "类型 {0} 无法通过反射直接构造, 需要提供默认值.",
             Renderers.STRING
         )
+
+        put(
+            UNSERIALIZABLE_TYPE,
+            "类型 {0} 无法被自动序列化, 需要添加序列化器",
+            Renderers.STRING
+        )
     }
 
     override fun getMap() = MAP

+ 2 - 0
tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/utilCommon.kt

@@ -9,8 +9,10 @@
 
 package net.mamoe.mirai.console.compiler.common
 
+import org.jetbrains.kotlin.name.FqName
 import kotlin.contracts.contract
 
+val SERIALIZABLE_FQ_NAME = FqName("kotlinx.serialization.Serializable")
 
 fun <K, V> Map<K, V>.firstValue(): V = this.entries.first().value
 fun <K, V> Map<K, V>.firstKey(): K = this.entries.first().key

+ 2 - 0
tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt

@@ -1,5 +1,6 @@
 package org.example.myplugin
 
+import kotlinx.serialization.Serializable
 import net.mamoe.mirai.console.data.AutoSavePluginConfig
 import net.mamoe.mirai.console.data.value
 import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
@@ -26,6 +27,7 @@ object DataTest : AutoSavePluginConfig() {
     val pp by value<NoDefaultValue>()
 }
 
+@Serializable
 data class HasDefaultValue(
     val x: Int = 0,
 )

+ 17 - 18
tools/intellij-plugin/src/main/kotlin/net/mamoe/mirai/console/intellij/diagnostics/PluginDataValuesChecker.kt

@@ -10,12 +10,10 @@
 package net.mamoe.mirai.console.intellij.diagnostics
 
 import com.intellij.psi.PsiElement
+import net.mamoe.mirai.console.compiler.common.SERIALIZABLE_FQ_NAME
 import net.mamoe.mirai.console.compiler.common.castOrNull
 import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors
-import net.mamoe.mirai.console.compiler.common.resolve.PLUGIN_DATA_VALUE_FUNCTIONS_FQ_FQ_NAME
-import net.mamoe.mirai.console.compiler.common.resolve.ResolveContextKind
-import net.mamoe.mirai.console.compiler.common.resolve.hasNoArgConstructor
-import net.mamoe.mirai.console.compiler.common.resolve.resolveContextKind
+import net.mamoe.mirai.console.compiler.common.resolve.*
 import net.mamoe.mirai.console.intellij.resolve.resolveAllCallsWithElement
 import org.jetbrains.kotlin.descriptors.ClassDescriptor
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -41,24 +39,25 @@ class PluginDataValuesChecker : DeclarationChecker {
                 (p.isReified || p.resolveContextKind == ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR)
                     && t is SimpleType
             }.forEach { (e, callExpr) ->
-                val (_, t) = e
-                val classDescriptor = t.constructor.declarationDescriptor?.castOrNull<ClassDescriptor>()
+                val (_, type) = e
+                val classDescriptor = type.constructor.declarationDescriptor?.castOrNull<ClassDescriptor>()
 
-                fun getInspectionTarget(): PsiElement {
-                    return callExpr.typeArguments.find { it.references.firstOrNull()?.canonicalText == t.fqName?.toString() } ?: callExpr
+                val inspectionTarget: PsiElement by lazy {
+                    callExpr.typeArguments.find { it.references.firstOrNull()?.canonicalText == type.fqName?.toString() } ?: callExpr
                 }
 
-                fun reportInspection() {
-                    context.report(MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE.on(
-                        getInspectionTarget(),
-                        t.fqName?.asString().toString())
-                    )
-                }
+                if (classDescriptor == null
+                    || !classDescriptor.hasNoArgConstructor()
+                ) return@forEach context.report(MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE.on(
+                    inspectionTarget,
+                    type.fqName?.asString().toString())
+                )
 
-                when {
-                    classDescriptor == null -> reportInspection()
-                    !classDescriptor.hasNoArgConstructor() -> reportInspection()
-                }
+                if (!classDescriptor.hasAnnotation(SERIALIZABLE_FQ_NAME)) // TODO: 2020/9/18 external serializers
+                    return@forEach context.report(MiraiConsoleErrors.UNSERIALIZABLE_TYPE.on(
+                        inspectionTarget,
+                        type.fqName?.asString().toString())
+                    )
             }
     }
 }