Support UNSERIALIZABLE_TYPE for detecting @Serializable annotations

This commit is contained in:
Him188 2020-09-18 20:00:47 +08:00
parent 7244cb76c4
commit 39145634e6
5 changed files with 29 additions and 20 deletions

View File

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

View File

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

View File

@ -9,8 +9,10 @@
package net.mamoe.mirai.console.compiler.common package net.mamoe.mirai.console.compiler.common
import org.jetbrains.kotlin.name.FqName
import kotlin.contracts.contract 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>.firstValue(): V = this.entries.first().value
fun <K, V> Map<K, V>.firstKey(): K = this.entries.first().key fun <K, V> Map<K, V>.firstKey(): K = this.entries.first().key

View File

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

View File

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