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 插件进行语境推断.
|
* 标记一个参数的语境类型, 用于帮助编译器和 IntelliJ 插件进行语境推断.
|
||||||
*/
|
*/
|
||||||
@ConsoleExperimentalApi
|
@ConsoleExperimentalApi
|
||||||
@Target(AnnotationTarget.VALUE_PARAMETER,
|
@Target(
|
||||||
|
AnnotationTarget.VALUE_PARAMETER,
|
||||||
AnnotationTarget.PROPERTY,
|
AnnotationTarget.PROPERTY,
|
||||||
AnnotationTarget.FIELD,
|
AnnotationTarget.FIELD,
|
||||||
AnnotationTarget.EXPRESSION)
|
//AnnotationTarget.EXPRESSION
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
public annotation class ResolveContext(
|
public annotation class ResolveContext(
|
||||||
val kind: Kind,
|
val kind: Kind,
|
||||||
) {
|
) {
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
package net.mamoe.mirai.console.plugin.description
|
package net.mamoe.mirai.console.plugin.description
|
||||||
|
|
||||||
import com.vdurmont.semver4j.Semver
|
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
|
import net.mamoe.mirai.console.plugin.Plugin
|
||||||
|
|
||||||
|
|
||||||
@ -46,6 +48,7 @@ public interface PluginDescription {
|
|||||||
* @see ID_REGEX
|
* @see ID_REGEX
|
||||||
* @see FORBIDDEN_ID_NAMES
|
* @see FORBIDDEN_ID_NAMES
|
||||||
*/
|
*/
|
||||||
|
@ResolveContext(PLUGIN_ID)
|
||||||
public val id: String
|
public val id: String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,6 +63,7 @@ public interface PluginDescription {
|
|||||||
*
|
*
|
||||||
* @see FORBIDDEN_ID_NAMES
|
* @see FORBIDDEN_ID_NAMES
|
||||||
*/
|
*/
|
||||||
|
@ResolveContext(PLUGIN_NAME)
|
||||||
public val name: String
|
public val name: String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,6 +92,7 @@ public interface PluginDescription {
|
|||||||
*
|
*
|
||||||
* @see Semver 语义化版本. 允许 [宽松][Semver.SemverType.LOOSE] 类型版本.
|
* @see Semver 语义化版本. 允许 [宽松][Semver.SemverType.LOOSE] 类型版本.
|
||||||
*/
|
*/
|
||||||
|
@ResolveContext(PLUGIN_VERSION)
|
||||||
public val version: Semver
|
public val version: Semver
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
const val core = "1.3.0"
|
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 consoleGraphical = "0.0.7"
|
||||||
const val consoleTerminal = "0.1.0"
|
const val consoleTerminal = "0.1.0"
|
||||||
const val consolePure = console
|
const val consolePure = console
|
||||||
|
@ -16,8 +16,7 @@ import org.jetbrains.kotlin.diagnostics.Errors;
|
|||||||
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
|
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
|
||||||
|
|
||||||
public interface MiraiConsoleErrors {
|
public interface MiraiConsoleErrors {
|
||||||
DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_ID = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_DESCRIPTION = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_NAME = DiagnosticFactory1.create(ERROR);
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
Object _init = new Object() {
|
Object _init = new Object() {
|
||||||
|
@ -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_ID
|
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION
|
||||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_NAME
|
|
||||||
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
|
||||||
@ -18,13 +17,8 @@ import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
|||||||
object MiraiConsoleErrorsRendering : DefaultErrorMessages.Extension {
|
object MiraiConsoleErrorsRendering : DefaultErrorMessages.Extension {
|
||||||
private val MAP = DiagnosticFactoryToRendererMap("MiraiConsole").apply {
|
private val MAP = DiagnosticFactoryToRendererMap("MiraiConsole").apply {
|
||||||
put(
|
put(
|
||||||
ILLEGAL_PLUGIN_ID,
|
ILLEGAL_PLUGIN_DESCRIPTION,
|
||||||
"Illegal plugin id: '{0}'",
|
"{0}",
|
||||||
Renderers.STRING
|
|
||||||
)
|
|
||||||
put(
|
|
||||||
ILLEGAL_PLUGIN_NAME,
|
|
||||||
"Illegal plugin name: '{0}'",
|
|
||||||
Renderers.STRING
|
Renderers.STRING
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
package net.mamoe.mirai.console.compiler.common.resolve
|
package net.mamoe.mirai.console.compiler.common.resolve
|
||||||
|
|
||||||
import net.mamoe.mirai.console.compiler.common.castOrNull
|
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.descriptors.annotations.Annotated
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||||
@ -55,6 +56,6 @@ fun Annotated.isResolveContext(kind: ResolveContextKind) = this.resolveContextKi
|
|||||||
val Annotated.resolveContextKind: ResolveContextKind?
|
val Annotated.resolveContextKind: ResolveContextKind?
|
||||||
get() {
|
get() {
|
||||||
val ann = this.findAnnotation(RESOLVE_CONTEXT_FQ_NAME) ?: return null
|
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())
|
return ResolveContextKind.valueOf(enumEntryName.asString())
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ dependencies {
|
|||||||
compileOnly(kotlin("stdlib-jdk8"))
|
compileOnly(kotlin("stdlib-jdk8"))
|
||||||
|
|
||||||
val core = "1.3.0"
|
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-console:$console")
|
||||||
compileOnly("net.mamoe:mirai-core:$core")
|
compileOnly("net.mamoe:mirai-core:$core")
|
||||||
|
@ -5,15 +5,14 @@ import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
|||||||
|
|
||||||
object MyPluginMain : KotlinPlugin(
|
object MyPluginMain : KotlinPlugin(
|
||||||
JvmPluginDescription(
|
JvmPluginDescription(
|
||||||
"org.example.example-plugin",
|
"net.mamoe.main",
|
||||||
"0.1.0"
|
"0.1.0",
|
||||||
)
|
) {
|
||||||
|
name(".")
|
||||||
|
id("")
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
fun test() {
|
fun test() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PM : KotlinPlugin(
|
|
||||||
|
|
||||||
)
|
|
@ -10,6 +10,7 @@
|
|||||||
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.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.compiler.common.resolve.resolveContextKind
|
import net.mamoe.mirai.console.compiler.common.resolve.resolveContextKind
|
||||||
import net.mamoe.mirai.console.intellij.resolve.findChildren
|
import net.mamoe.mirai.console.intellij.resolve.findChildren
|
||||||
@ -32,15 +33,36 @@ import kotlin.contracts.contract
|
|||||||
*/
|
*/
|
||||||
class PluginDescriptionChecker : DeclarationChecker {
|
class PluginDescriptionChecker : DeclarationChecker {
|
||||||
companion object {
|
companion object {
|
||||||
fun checkPluginName(declaration: KtDeclaration, value: String): Diagnostic? {
|
private val ID_REGEX: Regex = Regex("""([a-zA-Z]+(?:\.[a-zA-Z0-9]+)*)\.([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)""")
|
||||||
return null // TODO: 2020/9/18 checkPluginName
|
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? {
|
fun checkPluginName(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||||
return null // TODO: 2020/9/18 checkPluginId
|
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
|
return null // TODO: 2020/9/18 checkPluginVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,15 +78,14 @@ class PluginDescriptionChecker : DeclarationChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val checkersMap: EnumMap<ResolveContextKind, (declaration: KtDeclaration, value: String) -> Diagnostic?> =
|
private val checkersMap: EnumMap<ResolveContextKind, (declaration: PsiElement, value: String) -> Diagnostic?> =
|
||||||
EnumMap<ResolveContextKind, (declaration: KtDeclaration, value: String) -> Diagnostic?>(ResolveContextKind::class.java).apply {
|
EnumMap<ResolveContextKind, (declaration: PsiElement, value: String) -> Diagnostic?>(ResolveContextKind::class.java).apply {
|
||||||
put(ResolveContextKind.PLUGIN_NAME, ::checkPluginName)
|
put(ResolveContextKind.PLUGIN_NAME, ::checkPluginName)
|
||||||
put(ResolveContextKind.PLUGIN_ID, ::checkPluginId)
|
put(ResolveContextKind.PLUGIN_ID, ::checkPluginId)
|
||||||
put(ResolveContextKind.PLUGIN_VERSION, ::checkPluginVersion)
|
put(ResolveContextKind.PLUGIN_VERSION, ::checkPluginVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun check(
|
fun check(
|
||||||
declaration: KtDeclaration,
|
|
||||||
expression: KtCallExpression,
|
expression: KtCallExpression,
|
||||||
context: DeclarationCheckerContext,
|
context: DeclarationCheckerContext,
|
||||||
) {
|
) {
|
||||||
@ -76,7 +97,7 @@ class PluginDescriptionChecker : DeclarationChecker {
|
|||||||
val value = argument.getArgumentExpression()
|
val value = argument.getArgumentExpression()
|
||||||
?.resolveStringConstantValue(context.bindingContext) ?: continue
|
?.resolveStringConstantValue(context.bindingContext) ?: continue
|
||||||
for ((kind, fn) in checkersMap) {
|
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 -> {
|
is KtObjectDeclaration -> {
|
||||||
// check super type constructor
|
// check super type constructor
|
||||||
val superTypeCallEntry = declaration.findChildren<KtSuperTypeList>()?.findChildren<KtSuperTypeCallEntry>() ?: return
|
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
|
val valueArgumentList = superTypeCallEntry.findChildren<KtValueArgumentList>() ?: return
|
||||||
valueArgumentList.arguments.asSequence().mapNotNull(KtValueArgument::getArgumentExpression).forEach {
|
valueArgumentList.arguments.asSequence().mapNotNull(KtValueArgument::getArgumentExpression).forEach {
|
||||||
if (it.shouldPerformCheck()) {
|
if (it.shouldPerformCheck()) {
|
||||||
check(declaration, it as KtCallExpression, context)
|
check(it as KtCallExpression, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user