mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-25 15:40:28 +08:00
Support PluginMainServiceNotConfiguredInspection and ConfigurePluginMainServiceFix
This commit is contained in:
parent
e37ac17b82
commit
0c3a4c735d
@ -19,10 +19,11 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Serializer
|
||||
// OTHERS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
val SERIALIZABLE_FQ_NAME = FqName("kotlinx.serialization.Serializable")
|
||||
val AUTO_SERVICE = FqName("com.google.auto.service.AutoService")
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -32,6 +32,12 @@
|
||||
<codeInsight.lineMarkerProvider language="kotlin"
|
||||
implementationClass="net.mamoe.mirai.console.intellij.line.marker.CommandDeclarationLineMarkerProvider"/>
|
||||
|
||||
<localInspection groupPath="Mirai console" language="kotlin" shortName="PluginMainServiceNotConfigured"
|
||||
bundle="messages.InspectionGadgetsBundle"
|
||||
key="plugin.service.not.configured.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.plugin.service.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="net.mamoe.mirai.console.intellij.diagnostics.PluginMainServiceNotConfiguredInspection"/>
|
||||
|
||||
<!--
|
||||
<intentionAction>
|
||||
<className>net.mamoe.mirai.console.intellij.diagnostics.fix.AbuseYellowIntention</className>
|
||||
|
@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
#
|
||||
# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
# Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found through the following link.
|
||||
#
|
||||
# https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
#
|
||||
plugin.service.not.configured.display.name=Plugin main not configured
|
@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
#
|
||||
# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
# Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found through the following link.
|
||||
#
|
||||
# https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
#
|
||||
group.names.plugin.service.issues=Plugin main class issues
|
@ -29,6 +29,3 @@ object MyPluginMain : KotlinPlugin(
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val y = "傻逼 yellow"
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.intellij.diagnostics
|
||||
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.AUTO_SERVICE
|
||||
import net.mamoe.mirai.console.intellij.diagnostics.fix.ConfigurePluginMainServiceFix
|
||||
import net.mamoe.mirai.console.intellij.resolve.hasAnnotation
|
||||
import org.jetbrains.kotlin.idea.debugger.readAction
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.idea.util.rootManager
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.referenceExpressionVisitor
|
||||
import java.util.*
|
||||
|
||||
/*
|
||||
private val bundle by lazy {
|
||||
BundleUtil.loadLanguageBundle(PluginMainServiceNotConfiguredInspection::class.java.classLoader, "messages.InspectionGadgetsBundle")!!
|
||||
}*/
|
||||
|
||||
class PluginMainServiceNotConfiguredInspection : AbstractKotlinInspection() {
|
||||
companion object {
|
||||
private val SERVICE_FILE_NAMES = arrayOf(
|
||||
"net.mamoe.mirai.console.plugin.jvm.JvmPlugin",
|
||||
"net.mamoe.mirai.console.plugin.jvm.KotlinPlugin",
|
||||
"net.mamoe.mirai.console.plugin.jvm.JavaPlugin",
|
||||
)
|
||||
}
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
return referenceExpressionVisitor visitor@{ referenceExpr ->
|
||||
val ktClass = referenceExpr.resolveMiraiPluginDeclaration() ?: return@visitor
|
||||
val fqName = ktClass.fqName?.asString() ?: return@visitor
|
||||
|
||||
val found = isServiceConfiguredWithAutoService(ktClass)
|
||||
|| isServiceConfiguredWithResource(ktClass, fqName)
|
||||
|
||||
if (!found) {
|
||||
holder.registerProblem(
|
||||
ktClass.nameIdentifier ?: ktClass.identifyingElement ?: ktClass,
|
||||
"插件主类服务未配置",
|
||||
ProblemHighlightType.WARNING,
|
||||
ConfigurePluginMainServiceFix(ktClass)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isServiceConfiguredWithAutoService(
|
||||
ktClass: KtClassOrObject,
|
||||
): Boolean = ktClass.hasAnnotation(AUTO_SERVICE)
|
||||
|
||||
private fun isServiceConfiguredWithResource(
|
||||
ktClass: KtClassOrObject,
|
||||
fqName: String,
|
||||
): Boolean {
|
||||
val sourceRoots = ktClass.module?.rootManager?.sourceRoots ?: return false
|
||||
val services = sourceRoots.asSequence().flatMap { file ->
|
||||
SERVICE_FILE_NAMES.asSequence().mapNotNull { serviceFileName ->
|
||||
file.findFileByRelativePath("META-INF/services/$serviceFileName")
|
||||
}
|
||||
}
|
||||
return services.any { serviceFile ->
|
||||
serviceFile.readAction { f -> f.inputStream.bufferedReader().use { it.readLine() }.trim() == fqName }
|
||||
}
|
||||
}
|
||||
}
|
@ -9,16 +9,19 @@
|
||||
|
||||
package net.mamoe.mirai.console.intellij.diagnostics
|
||||
|
||||
import com.intellij.util.castSafelyTo
|
||||
import net.mamoe.mirai.console.compiler.common.castOrNull
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.PLUGIN_FQ_NAME
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.parents
|
||||
import net.mamoe.mirai.console.intellij.resolve.allSuperNames
|
||||
import net.mamoe.mirai.console.intellij.resolve.getResolvedCall
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.psi.KtUserType
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.resolve
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
|
||||
@ -40,4 +43,13 @@ fun KtTypeReference.isReferencing(fqName: FqName): Boolean {
|
||||
|
||||
val KtTypeReference.referencedUserType: KtUserType? get() = this.typeElement.castOrNull()
|
||||
|
||||
fun KtTypeReference.resolveReferencedType() = referencedUserType?.referenceExpression?.mainReference?.resolve()
|
||||
fun KtTypeReference.resolveReferencedType() = referencedUserType?.referenceExpression?.mainReference?.resolve()
|
||||
|
||||
fun KtReferenceExpression.resolveMiraiPluginDeclaration(): KtClassOrObject? {
|
||||
val main =
|
||||
parents.filterIsInstance<KtClassOrObject>().firstOrNull() ?: return null
|
||||
val kotlinPluginClass =
|
||||
resolve().castSafelyTo<KtConstructor<*>>()?.parent?.castSafelyTo<KtClass>() ?: return null
|
||||
if (kotlinPluginClass.allSuperNames.none { it == PLUGIN_FQ_NAME }) return null
|
||||
return main
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.intellij.diagnostics.fix
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.testFramework.writeChild
|
||||
import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinCrossLanguageQuickFixAction
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
|
||||
class ConfigurePluginMainServiceFix(
|
||||
element: KtClassOrObject,
|
||||
) : KotlinCrossLanguageQuickFixAction<KtClassOrObject>(element), KotlinUniversalQuickFix, LocalQuickFix {
|
||||
|
||||
override fun getFamilyName(): String = "Mirai Console"
|
||||
override fun getText(): String = "配置插件主类服务"
|
||||
|
||||
override fun invokeImpl(project: Project, editor: Editor?, file: PsiFile) {
|
||||
val elementFqName = element?.fqName ?: return
|
||||
val sourceRoots = file.module?.rootManager?.sourceRoots ?: return
|
||||
|
||||
val sourceRoot = sourceRoots.find { it.name.endsWith("resources") }
|
||||
?: sourceRoots.find { it.name.contains("resources") }
|
||||
?: sourceRoots.last()
|
||||
|
||||
project.executeWriteCommand(name) {
|
||||
sourceRoot.writeChild("META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin", elementFqName.asString().toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
@ -15,27 +15,16 @@ import com.intellij.codeInsight.daemon.LineMarkerProvider
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.castSafelyTo
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.PLUGIN_FQ_NAME
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.parents
|
||||
import net.mamoe.mirai.console.intellij.Icons
|
||||
import net.mamoe.mirai.console.intellij.resolve.allSuperNames
|
||||
import net.mamoe.mirai.console.intellij.diagnostics.resolveMiraiPluginDeclaration
|
||||
import net.mamoe.mirai.console.intellij.resolve.getElementForLineMark
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.resolve
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtConstructor
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
|
||||
class PluginMainLineMarkerProvider : LineMarkerProvider {
|
||||
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
|
||||
if (element !is KtReferenceExpression) return null
|
||||
val objectDeclaration =
|
||||
element.parents.filterIsInstance<KtObjectDeclaration>().firstOrNull() ?: return null
|
||||
val kotlinPluginClass =
|
||||
element.resolve().castSafelyTo<KtConstructor<*>>()?.parent?.castSafelyTo<KtClass>() ?: return null
|
||||
if (kotlinPluginClass.allSuperNames.none { it == PLUGIN_FQ_NAME }) return null
|
||||
return Info(getElementForLineMark(objectDeclaration))
|
||||
val main = element.resolveMiraiPluginDeclaration() ?: return null
|
||||
return Info(getElementForLineMark(main))
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
|
@ -11,6 +11,7 @@ package net.mamoe.mirai.console.intellij.resolve
|
||||
|
||||
import com.intellij.psi.PsiDeclarationStatement
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.parentsWithSelf
|
||||
import net.mamoe.mirai.console.compiler.common.castOrNull
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.COMPOSITE_COMMAND_SUB_COMMAND_FQ_NAME
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.SIMPLE_COMMAND_HANDLER_COMMAND_FQ_NAME
|
||||
@ -19,9 +20,9 @@ import net.mamoe.mirai.console.compiler.common.resolve.findParent
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.resolve
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@ -32,6 +33,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
|
||||
@ -53,7 +55,8 @@ val KtPureClassOrObject.allSuperTypes: Sequence<KtSuperTypeListEntry>
|
||||
get() = sequence {
|
||||
yieldAll(superTypeListEntries)
|
||||
for (list in superTypeListEntries.asSequence()) {
|
||||
yieldAll((list.typeAsUserType?.referenceExpression?.resolve() as? KtClass)?.allSuperTypes.orEmpty())
|
||||
yieldAll((list.typeAsUserType?.referenceExpression?.resolve()?.parentsWithSelf?.filterIsInstance<KtClass>()
|
||||
?.firstOrNull())?.allSuperTypes.orEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +148,7 @@ fun KtExpression.resolveStringConstantValues(): Sequence<String> {
|
||||
is KtNameReferenceExpression -> {
|
||||
when (val reference = references.firstIsInstance<KtSimpleNameReference>().resolve()) {
|
||||
is KtDeclaration -> {
|
||||
val descriptor = reference.descriptor.castOrNull<VariableDescriptor>() ?: return emptySequence()
|
||||
val descriptor = reference.resolveToDescriptorIfAny(BodyResolveMode.FULL).castOrNull<VariableDescriptor>() ?: return emptySequence()
|
||||
val compileTimeConstant = descriptor.compileTimeInitializer ?: return emptySequence()
|
||||
return compileTimeConstant.selfOrChildrenConstantStrings()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user