mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-25 15:40:28 +08:00
New inspection: ILLEGAL_COMMAND_DECLARATION_RECEIVER, close #174
This commit is contained in:
parent
062227e072
commit
bc290f63bb
@ -10,6 +10,7 @@ package net.mamoe.mirai.console.compiler.common.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0.create
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1.create
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2.create
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
@ -17,6 +18,7 @@ import org.jetbrains.kotlin.diagnostics.Severity.ERROR
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtTypeProjection
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
|
||||
/**
|
||||
* 如何增加一个错误:
|
||||
@ -54,6 +56,12 @@ object MiraiConsoleErrors {
|
||||
@JvmField
|
||||
val ILLEGAL_VERSION_REQUIREMENT = create<PsiElement, String, String>(ERROR)
|
||||
|
||||
// @JvmField
|
||||
// val INAPPLICABLE_COMMAND_ANNOTATION = create<PsiElement, String>(ERROR)
|
||||
|
||||
@JvmField
|
||||
val ILLEGAL_COMMAND_DECLARATION_RECEIVER = create<KtTypeReference>(ERROR)
|
||||
|
||||
@Suppress("ObjectPropertyName", "unused")
|
||||
@JvmField
|
||||
@Deprecated("", level = DeprecationLevel.ERROR)
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
package net.mamoe.mirai.console.compiler.common.diagnostics
|
||||
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_COMMAND_DECLARATION_RECEIVER
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_COMMAND_NAME
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_COMMAND_REGISTER_USE
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PERMISSION_ID
|
||||
@ -95,6 +96,17 @@ object MiraiConsoleErrorsRendering : DefaultErrorMessages.Extension {
|
||||
Renderers.STRING,
|
||||
Renderers.STRING
|
||||
)
|
||||
|
||||
put(
|
||||
ILLEGAL_COMMAND_DECLARATION_RECEIVER,
|
||||
"指令函数的接收者参数必须为 CommandSender 及其子类或无接收者.",
|
||||
)
|
||||
|
||||
// put(
|
||||
// INAPPLICABLE_COMMAND_ANNOTATION,
|
||||
// "''{0}'' 无法在顶层函数使用.",
|
||||
// Renderers.STRING,
|
||||
// )
|
||||
}
|
||||
|
||||
override fun getMap() = MAP
|
||||
|
@ -32,6 +32,7 @@ val AUTO_SERVICE = FqName("com.google.auto.service.AutoService")
|
||||
|
||||
val COMPOSITE_COMMAND_SUB_COMMAND_FQ_NAME = FqName("net.mamoe.mirai.console.command.CompositeCommand.SubCommand")
|
||||
val SIMPLE_COMMAND_HANDLER_COMMAND_FQ_NAME = FqName("net.mamoe.mirai.console.command.SimpleCommand.Handler")
|
||||
val COMMAND_SENDER_FQ_NAME = FqName("net.mamoe.mirai.console.command.CommandSender")
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Plugin
|
||||
|
@ -17,7 +17,7 @@ object MySimpleCommand000 : SimpleCommand(
|
||||
}
|
||||
|
||||
object DataTest : AutoSavePluginConfig("data") {
|
||||
val pp by value<NoDefaultValue>(NoDefaultValue(1))
|
||||
val pp by value(NoDefaultValue(1))
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
package net.mamoe.mirai.console.intellij
|
||||
|
||||
import net.mamoe.mirai.console.intellij.diagnostics.CommandDeclarationChecker
|
||||
import net.mamoe.mirai.console.intellij.diagnostics.ContextualParametersChecker
|
||||
import net.mamoe.mirai.console.intellij.diagnostics.PluginDataValuesChecker
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
@ -24,5 +25,6 @@ class IDEContainerContributor : StorageComponentContainerContributor {
|
||||
) {
|
||||
container.useInstance(ContextualParametersChecker())
|
||||
container.useInstance(PluginDataValuesChecker())
|
||||
container.useInstance(CommandDeclarationChecker())
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package net.mamoe.mirai.console.intellij.diagnostics
|
||||
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_COMMAND_DECLARATION_RECEIVER
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.COMMAND_SENDER_FQ_NAME
|
||||
import net.mamoe.mirai.console.intellij.resolve.hasSuperType
|
||||
import net.mamoe.mirai.console.intellij.resolve.isCompositeCommandSubCommand
|
||||
import net.mamoe.mirai.console.intellij.resolve.isSimpleCommandHandler
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
|
||||
class CommandDeclarationChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (declaration !is KtNamedFunction) return
|
||||
|
||||
// exclusive checks
|
||||
when {
|
||||
declaration.isSimpleCommandHandler() -> {
|
||||
}
|
||||
|
||||
declaration.isCompositeCommandSubCommand() -> {
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
|
||||
// common checks
|
||||
checkCommandReceiverParameter(declaration)?.let { context.report(it) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun checkCommandReceiverParameter(declaration: KtNamedFunction): Diagnostic? {
|
||||
val receiverTypeRef = declaration.receiverTypeReference ?: return null // no receiver, accept.
|
||||
val receiver = receiverTypeRef.resolveReferencedType() ?: return null // unresolved type
|
||||
if (!receiver.hasSuperType(COMMAND_SENDER_FQ_NAME)) {
|
||||
return ILLEGAL_COMMAND_DECLARATION_RECEIVER.on(receiverTypeRef)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
|
||||
package net.mamoe.mirai.console.intellij.resolve
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiDeclarationStatement
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.parentsWithSelf
|
||||
@ -60,6 +61,19 @@ val KtPureClassOrObject.allSuperTypes: Sequence<KtSuperTypeListEntry>
|
||||
}
|
||||
}
|
||||
|
||||
val PsiClass.allSuperTypes: Sequence<PsiClass>
|
||||
get() = sequence {
|
||||
interfaces.forEach {
|
||||
yield(it)
|
||||
yieldAll(it.allSuperTypes)
|
||||
}
|
||||
val superClass = superClass
|
||||
if (superClass != null) {
|
||||
yield(superClass)
|
||||
yieldAll(superClass.allSuperTypes)
|
||||
}
|
||||
}
|
||||
|
||||
fun KtConstructorCalleeExpression.getTypeAsUserType(): KtUserType? {
|
||||
val reference = typeReference
|
||||
if (reference != null) {
|
||||
@ -71,7 +85,26 @@ fun KtConstructorCalleeExpression.getTypeAsUserType(): KtUserType? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun KtClassOrObject.hasSuperType(fqName: FqName): Boolean = allSuperNames.contains(fqName)
|
||||
fun KtClass.hasSuperType(fqName: FqName): Boolean = allSuperNames.contains(fqName)
|
||||
|
||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||
@kotlin.internal.LowPriorityInOverloadResolution
|
||||
fun PsiElement.hasSuperType(fqName: FqName): Boolean = allSuperNames.contains(fqName)
|
||||
|
||||
val KtClassOrObject.allSuperNames: Sequence<FqName> get() = allSuperTypes.mapNotNull { it.getKotlinFqName() }
|
||||
val PsiClass.allSuperNames: Sequence<FqName> get() = allSuperTypes.mapNotNull { clazz -> clazz.qualifiedName?.let { FqName(it) } }
|
||||
|
||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||
@kotlin.internal.LowPriorityInOverloadResolution
|
||||
val PsiElement.allSuperNames: Sequence<FqName>
|
||||
get() {
|
||||
return when (this) {
|
||||
is KtClassOrObject -> allSuperNames
|
||||
is PsiClass -> allSuperNames
|
||||
else -> emptySequence()
|
||||
}
|
||||
}
|
||||
|
||||
fun getElementForLineMark(callElement: PsiElement): PsiElement =
|
||||
when (callElement) {
|
||||
|
Loading…
Reference in New Issue
Block a user