diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/compiler/common/ResolveContext.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/compiler/common/ResolveContext.kt index b020dbd7c..fc41edc14 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/compiler/common/ResolveContext.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/compiler/common/ResolveContext.kt @@ -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, ) { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt index e9af5a3b1..85c199628 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt @@ -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 /** diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index e61e28505..3349612e6 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -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 diff --git a/tools/compiler-common/src/main/java/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrors.java b/tools/compiler-common/src/main/java/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrors.java index 2b65a3bd8..b8e6b9be8 100644 --- a/tools/compiler-common/src/main/java/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrors.java +++ b/tools/compiler-common/src/main/java/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrors.java @@ -16,8 +16,7 @@ import org.jetbrains.kotlin.diagnostics.Errors; import static org.jetbrains.kotlin.diagnostics.Severity.ERROR; public interface MiraiConsoleErrors { - DiagnosticFactory1 ILLEGAL_PLUGIN_ID = DiagnosticFactory1.create(ERROR); - DiagnosticFactory1 ILLEGAL_PLUGIN_NAME = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 ILLEGAL_PLUGIN_DESCRIPTION = DiagnosticFactory1.create(ERROR); @Deprecated Object _init = new Object() { diff --git a/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrorsRendering.kt b/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrorsRendering.kt index 8eb25bc37..a8af96814 100644 --- a/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrorsRendering.kt +++ b/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/diagnostics/MiraiConsoleErrorsRendering.kt @@ -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 ) } diff --git a/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/resolve/MiraiConsoleTypes.kt b/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/resolve/MiraiConsoleTypes.kt index 48ba53148..fa59374bd 100644 --- a/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/resolve/MiraiConsoleTypes.kt +++ b/tools/compiler-common/src/main/kotlin/net/mamoe/mirai/console/compiler/common/resolve/MiraiConsoleTypes.kt @@ -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()?.value ?: return null // undetermined kind + val (_, enumEntryName) = ann.allValueArguments.firstValue().castOrNull()?.value ?: return null // undetermined kind return ResolveContextKind.valueOf(enumEntryName.asString()) } \ No newline at end of file diff --git a/tools/intellij-plugin/run/projects/test-project/build.gradle.kts b/tools/intellij-plugin/run/projects/test-project/build.gradle.kts index b247cee62..d26b54d1d 100644 --- a/tools/intellij-plugin/run/projects/test-project/build.gradle.kts +++ b/tools/intellij-plugin/run/projects/test-project/build.gradle.kts @@ -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") diff --git a/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt b/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt index 9ee5ff208..7abb6a55c 100644 --- a/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt +++ b/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt @@ -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( - -) \ No newline at end of file +} \ No newline at end of file diff --git a/tools/intellij-plugin/src/main/kotlin/net/mamoe/mirai/console/intellij/diagnostics/PluginDescriptionChecker.kt b/tools/intellij-plugin/src/main/kotlin/net/mamoe/mirai/console/intellij/diagnostics/PluginDescriptionChecker.kt index 6b5841e8e..5f8c0b64a 100644 --- a/tools/intellij-plugin/src/main/kotlin/net/mamoe/mirai/console/intellij/diagnostics/PluginDescriptionChecker.kt +++ b/tools/intellij-plugin/src/main/kotlin/net/mamoe/mirai/console/intellij/diagnostics/PluginDescriptionChecker.kt @@ -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 = 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 Diagnostic?> = - EnumMap Diagnostic?>(ResolveContextKind::class.java).apply { + private val checkersMap: EnumMap Diagnostic?> = + EnumMap 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()?.findChildren() ?: return - val constructorCall = superTypeCallEntry.findChildren()?.resolveToCall() ?: return + // val constructorCall = superTypeCallEntry.findChildren()?.resolveToCall() ?: return val valueArgumentList = superTypeCallEntry.findChildren() ?: return valueArgumentList.arguments.asSequence().mapNotNull(KtValueArgument::getArgumentExpression).forEach { if (it.shouldPerformCheck()) { - check(declaration, it as KtCallExpression, context) + check(it as KtCallExpression, context) } }