mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Support checking plugin name and plugin id (ILLEGAL_PLUGIN_DESCRIPTION)
This commit is contained in:
parent
3fc2d7f5c1
commit
5dbf596582
@ -17,11 +17,13 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
||||
* 标记一个参数的语境类型, 用于帮助编译器和 IntelliJ 插件进行语境推断.
|
||||
*/
|
||||
@ConsoleExperimentalApi
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER,
|
||||
@Target(
|
||||
AnnotationTarget.VALUE_PARAMETER,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.FIELD,
|
||||
AnnotationTarget.EXPRESSION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
//AnnotationTarget.EXPRESSION
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
public annotation class ResolveContext(
|
||||
val kind: Kind,
|
||||
) {
|
||||
|
@ -10,6 +10,8 @@
|
||||
package net.mamoe.mirai.console.plugin.description
|
||||
|
||||
import com.vdurmont.semver4j.Semver
|
||||
import net.mamoe.mirai.console.compiler.common.ResolveContext
|
||||
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.*
|
||||
import net.mamoe.mirai.console.plugin.Plugin
|
||||
|
||||
|
||||
@ -46,6 +48,7 @@ public interface PluginDescription {
|
||||
* @see ID_REGEX
|
||||
* @see FORBIDDEN_ID_NAMES
|
||||
*/
|
||||
@ResolveContext(PLUGIN_ID)
|
||||
public val id: String
|
||||
|
||||
/**
|
||||
@ -60,6 +63,7 @@ public interface PluginDescription {
|
||||
*
|
||||
* @see FORBIDDEN_ID_NAMES
|
||||
*/
|
||||
@ResolveContext(PLUGIN_NAME)
|
||||
public val name: String
|
||||
|
||||
/**
|
||||
@ -88,6 +92,7 @@ public interface PluginDescription {
|
||||
*
|
||||
* @see Semver 语义化版本. 允许 [宽松][Semver.SemverType.LOOSE] 类型版本.
|
||||
*/
|
||||
@ResolveContext(PLUGIN_VERSION)
|
||||
public val version: Semver
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
object Versions {
|
||||
const val core = "1.3.0"
|
||||
const val console = "1.0-RC-dev-1"
|
||||
const val console = "1.0-RC-dev-2"
|
||||
const val consoleGraphical = "0.0.7"
|
||||
const val consoleTerminal = "0.1.0"
|
||||
const val consolePure = console
|
||||
|
@ -16,8 +16,7 @@ import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
|
||||
|
||||
public interface MiraiConsoleErrors {
|
||||
DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_ID = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_NAME = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_DESCRIPTION = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
@Deprecated
|
||||
Object _init = new Object() {
|
||||
|
@ -9,8 +9,7 @@
|
||||
|
||||
package net.mamoe.mirai.console.compiler.common.diagnostics
|
||||
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_ID
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_NAME
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
@ -18,13 +17,8 @@ import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
object MiraiConsoleErrorsRendering : DefaultErrorMessages.Extension {
|
||||
private val MAP = DiagnosticFactoryToRendererMap("MiraiConsole").apply {
|
||||
put(
|
||||
ILLEGAL_PLUGIN_ID,
|
||||
"Illegal plugin id: '{0}'",
|
||||
Renderers.STRING
|
||||
)
|
||||
put(
|
||||
ILLEGAL_PLUGIN_NAME,
|
||||
"Illegal plugin name: '{0}'",
|
||||
ILLEGAL_PLUGIN_DESCRIPTION,
|
||||
"{0}",
|
||||
Renderers.STRING
|
||||
)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
package net.mamoe.mirai.console.compiler.common.resolve
|
||||
|
||||
import net.mamoe.mirai.console.compiler.common.castOrNull
|
||||
import net.mamoe.mirai.console.compiler.common.firstValue
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
@ -55,6 +56,6 @@ fun Annotated.isResolveContext(kind: ResolveContextKind) = this.resolveContextKi
|
||||
val Annotated.resolveContextKind: ResolveContextKind?
|
||||
get() {
|
||||
val ann = this.findAnnotation(RESOLVE_CONTEXT_FQ_NAME) ?: return null
|
||||
val (_, enumEntryName) = ann.allValueArguments.castOrNull<EnumValue>()?.value ?: return null // undetermined kind
|
||||
val (_, enumEntryName) = ann.allValueArguments.firstValue().castOrNull<EnumValue>()?.value ?: return null // undetermined kind
|
||||
return ResolveContextKind.valueOf(enumEntryName.asString())
|
||||
}
|
@ -22,7 +22,7 @@ dependencies {
|
||||
compileOnly(kotlin("stdlib-jdk8"))
|
||||
|
||||
val core = "1.3.0"
|
||||
val console = "1.0-RC-dev-1"
|
||||
val console = "1.0-RC-dev-2"
|
||||
|
||||
compileOnly("net.mamoe:mirai-console:$console")
|
||||
compileOnly("net.mamoe:mirai-core:$core")
|
||||
|
@ -5,15 +5,14 @@ import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
||||
|
||||
object MyPluginMain : KotlinPlugin(
|
||||
JvmPluginDescription(
|
||||
"org.example.example-plugin",
|
||||
"0.1.0"
|
||||
)
|
||||
"net.mamoe.main",
|
||||
"0.1.0",
|
||||
) {
|
||||
name(".")
|
||||
id("")
|
||||
}
|
||||
) {
|
||||
fun test() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class PM : KotlinPlugin(
|
||||
|
||||
)
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
package net.mamoe.mirai.console.intellij.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.ResolveContextKind
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.resolveContextKind
|
||||
import net.mamoe.mirai.console.intellij.resolve.findChildren
|
||||
@ -32,15 +33,36 @@ import kotlin.contracts.contract
|
||||
*/
|
||||
class PluginDescriptionChecker : DeclarationChecker {
|
||||
companion object {
|
||||
fun checkPluginName(declaration: KtDeclaration, value: String): Diagnostic? {
|
||||
return null // TODO: 2020/9/18 checkPluginName
|
||||
private val ID_REGEX: Regex = Regex("""([a-zA-Z]+(?:\.[a-zA-Z0-9]+)*)\.([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)""")
|
||||
private val FORBIDDEN_ID_NAMES: Array<String> = arrayOf("main", "console", "plugin", "config", "data")
|
||||
|
||||
fun checkPluginId(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
if (value.isBlank()) return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "Plugin id cannot be blank")
|
||||
if (value.none { it == '.' }) return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget,
|
||||
"'$value' is illegal. Plugin id must consist of both domain and name. ")
|
||||
|
||||
val lowercaseId = value.toLowerCase()
|
||||
|
||||
if (ID_REGEX.matchEntire(value) == null) {
|
||||
return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "Plugin does not match regex '${ID_REGEX.pattern}'.")
|
||||
}
|
||||
|
||||
FORBIDDEN_ID_NAMES.firstOrNull { it == lowercaseId }?.let { illegal ->
|
||||
return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "Plugin id contains illegal word: '$illegal'.")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkPluginId(declaration: KtDeclaration, value: String): Diagnostic? {
|
||||
return null // TODO: 2020/9/18 checkPluginId
|
||||
fun checkPluginName(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
if (value.isBlank()) return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "Plugin name cannot be blank")
|
||||
val lowercaseName = value.toLowerCase()
|
||||
FORBIDDEN_ID_NAMES.firstOrNull { it == lowercaseName }?.let { illegal ->
|
||||
return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "Plugin name is illegal: '$illegal'.")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkPluginVersion(declaration: KtDeclaration, value: String): Diagnostic? {
|
||||
fun checkPluginVersion(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
return null // TODO: 2020/9/18 checkPluginVersion
|
||||
}
|
||||
}
|
||||
@ -56,15 +78,14 @@ class PluginDescriptionChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private val checkersMap: EnumMap<ResolveContextKind, (declaration: KtDeclaration, value: String) -> Diagnostic?> =
|
||||
EnumMap<ResolveContextKind, (declaration: KtDeclaration, value: String) -> Diagnostic?>(ResolveContextKind::class.java).apply {
|
||||
private val checkersMap: EnumMap<ResolveContextKind, (declaration: PsiElement, value: String) -> Diagnostic?> =
|
||||
EnumMap<ResolveContextKind, (declaration: PsiElement, value: String) -> Diagnostic?>(ResolveContextKind::class.java).apply {
|
||||
put(ResolveContextKind.PLUGIN_NAME, ::checkPluginName)
|
||||
put(ResolveContextKind.PLUGIN_ID, ::checkPluginId)
|
||||
put(ResolveContextKind.PLUGIN_VERSION, ::checkPluginVersion)
|
||||
}
|
||||
|
||||
fun check(
|
||||
declaration: KtDeclaration,
|
||||
expression: KtCallExpression,
|
||||
context: DeclarationCheckerContext,
|
||||
) {
|
||||
@ -76,7 +97,7 @@ class PluginDescriptionChecker : DeclarationChecker {
|
||||
val value = argument.getArgumentExpression()
|
||||
?.resolveStringConstantValue(context.bindingContext) ?: continue
|
||||
for ((kind, fn) in checkersMap) {
|
||||
if (parameterContextKind == kind) fn(declaration, value)?.let { context.report(it) }
|
||||
if (parameterContextKind == kind) fn(argument.asElement(), value)?.let { context.report(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,11 +114,11 @@ class PluginDescriptionChecker : DeclarationChecker {
|
||||
is KtObjectDeclaration -> {
|
||||
// check super type constructor
|
||||
val superTypeCallEntry = declaration.findChildren<KtSuperTypeList>()?.findChildren<KtSuperTypeCallEntry>() ?: return
|
||||
val constructorCall = superTypeCallEntry.findChildren<KtConstructorCalleeExpression>()?.resolveToCall() ?: return
|
||||
// val constructorCall = superTypeCallEntry.findChildren<KtConstructorCalleeExpression>()?.resolveToCall() ?: return
|
||||
val valueArgumentList = superTypeCallEntry.findChildren<KtValueArgumentList>() ?: return
|
||||
valueArgumentList.arguments.asSequence().mapNotNull(KtValueArgument::getArgumentExpression).forEach {
|
||||
if (it.shouldPerformCheck()) {
|
||||
check(declaration, it as KtCallExpression, context)
|
||||
check(it as KtCallExpression, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user