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 {
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() {

View File

@ -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

View File

@ -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

View File

@ -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,
)

View File

@ -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())
)
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()
}
}
}
}