Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inspection for usages of abstract message keys in restricted areas #1759

Merged
merged 4 commits into from
Dec 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .run/Publish local artifacts.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!--
~ Copyright 2019-2021 Mamoe Technologies and contributors.
~
~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
~
~ https://github.com/mamoe/mirai/blob/dev/LICENSE
-->

<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Publish local artifacts" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="mirai.build.project.version" value="2.99.0-local" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="publishToMavenLocal" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>
32 changes: 32 additions & 0 deletions .run/Run IDE.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--
~ Copyright 2019-2021 Mamoe Technologies and contributors.
~
~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
~
~ https://github.com/mamoe/mirai/blob/dev/LICENSE
-->

<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run IDE" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>
8 changes: 4 additions & 4 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import org.gradle.kotlin.dsl.exclude
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler

object Versions {
const val project = "2.10.0-RC"
val project = System.getenv("mirai.build.project.version") ?: "2.10.0-RC"

const val core = project
const val console = project
const val consoleTerminal = project
val core = project
val console = project
val consoleTerminal = project

const val kotlinCompiler = "1.6.0"
const val kotlinStdlib = kotlinCompiler
Expand Down
17 changes: 14 additions & 3 deletions mirai-console/tools/compiler-annotations/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@

@file:Suppress("UnusedImport")

import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType

plugins {
kotlin("jvm")
id("java")
kotlin("multiplatform")
`maven-publish`
}

Expand All @@ -20,6 +21,16 @@ description = "Mirai Console compiler annotations"

kotlin {
explicitApi()

jvm("android") {
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.androidJvm)
}

jvm("common") {
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
}

jvm("jvm")
}

configurePublishing("mirai-console-compiler-annotations")
configureMppPublishing()
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ public annotation class ResolveContext(
*/
RESTRICTED_NO_ARG_CONSTRUCTOR, // NOT_CONSTRUCTABLE_TYPE

RESTRICTED_CONSOLE_COMMAND_OWNER, ;
RESTRICTED_CONSOLE_COMMAND_OWNER,

RESTRICTED_ABSTRACT_MESSAGE_KEYS;

public companion object
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ object MiraiConsoleErrors {
@JvmField
val RESTRICTED_CONSOLE_COMMAND_OWNER = create<PsiElement>(WARNING)

@JvmField
val PROHIBITED_ABSTRACT_MESSAGE_KEYS = create<PsiElement>(WARNING)

@JvmField
val ILLEGAL_COMMAND_DECLARATION_RECEIVER = create<KtTypeReference>(ERROR)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.IL
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_VERSION_REQUIREMENT
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.PROHIBITED_ABSTRACT_MESSAGE_KEYS
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.READ_ONLY_VALUE_CANNOT_BE_VAR
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.RESTRICTED_CONSOLE_COMMAND_OWNER
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.UNSERIALIZABLE_TYPE
Expand Down Expand Up @@ -114,6 +115,11 @@ object MiraiConsoleErrorsRendering : DefaultErrorMessages.Extension {
"插件不允许使用 ConsoleCommandOwner 构造指令, 请使用插件主类作为 CommandOwner",
)

put(
PROHIBITED_ABSTRACT_MESSAGE_KEYS,
"使用 MessageContent.Key 等抽象消息类型的 Key 没有意义",
)

put(
READ_ONLY_VALUE_CANNOT_BE_VAR,
"在 ReadOnlyPluginData 中不可定义 'var' by value",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ val READ_ONLY_PLUGIN_DATA_FQ_NAME = FqName("net.mamoe.mirai.console.data.ReadOnl

val RESOLVE_CONTEXT_FQ_NAME = FqName("net.mamoe.mirai.console.compiler.common.ResolveContext")

val PROHIBITED_MESSAGE_KEYS = arrayOf(
FqName("net.mamoe.mirai.message.data.MessageContent.Key")
)

/**
* net.mamoe.mirai.console.compiler.common.ResolveContext.Kind
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
kotlin("jvm") version "1.6.0"
kotlin("plugin.serialization") version "1.6.0"
id("net.mamoe.mirai-console") version "2.9.0-M1"
id("net.mamoe.mirai-console") version "2.99.0-local"
java
}

Expand All @@ -13,6 +13,6 @@ dependencies {
}

repositories {
jcenter()
mavenCentral()
mavenLocal()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/

package org.example.myplugin

import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.messageChainOf

fun main() {
val chain = messageChainOf()
chain[MessageContent]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.IL
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PERMISSION_NAMESPACE
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_VERSION_REQUIREMENT
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.PROHIBITED_ABSTRACT_MESSAGE_KEYS
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.RESTRICTED_CONSOLE_COMMAND_OWNER
import net.mamoe.mirai.console.compiler.common.resolve.CONSOLE_COMMAND_OWNER_FQ_NAME
import net.mamoe.mirai.console.compiler.common.resolve.PROHIBITED_MESSAGE_KEYS
import net.mamoe.mirai.console.compiler.common.resolve.ResolveContextKind
import net.mamoe.mirai.console.compiler.common.resolve.resolveContextKinds
import net.mamoe.mirai.console.intellij.resolve.getResolvedCall
Expand All @@ -30,6 +32,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.inspections.collections.isCalling
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
Expand Down Expand Up @@ -219,6 +222,23 @@ class ContextualParametersChecker : CallChecker {

return null
}

fun checkAbstractMessageKeys(
context: CallCheckerContext,
inspectionTarget: PsiElement,
argument: ValueArgument
): Diagnostic? {
val expr = argument.getArgumentExpression() ?: return null

if (expr is KtReferenceExpression) {
val call = expr.getResolvedCall(context.bindingContext) ?: return null
if (PROHIBITED_MESSAGE_KEYS.any { call.isCalling(it) }) {
return PROHIBITED_ABSTRACT_MESSAGE_KEYS.on(inspectionTarget)
}
}

return null
}
}

fun interface ElementChecker {
Expand Down Expand Up @@ -268,6 +288,7 @@ class ContextualParametersChecker : CallChecker {
put(ResolveContextKind.PERMISSION_ID, ::checkPermissionId)
put(ResolveContextKind.VERSION_REQUIREMENT, ::checkVersionRequirement)
put(ResolveContextKind.RESTRICTED_CONSOLE_COMMAND_OWNER, ::checkConsoleCommandOwner)
put(ResolveContextKind.RESTRICTED_ABSTRACT_MESSAGE_KEYS, ::checkAbstractMessageKeys)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/

package net.mamoe.mirai.console.intellij.diagnostics

import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.inspections.collections.isCalling
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall

class MessageChainGetCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
// if (resolvedCall.isCalling())
}

}
1 change: 1 addition & 0 deletions mirai-core-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ kotlin {
api(`ktor-client-okhttp`)

implementation(project(":mirai-core-utils"))
implementation(project(":mirai-console-compiler-annotations"))
implementation(`kotlinx-serialization-protobuf-jvm`)
implementation(`jetbrains-annotations`)
implementation(`log4j-api`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.message.MessageSerializers
Expand All @@ -38,6 +39,7 @@ import net.mamoe.mirai.utils.safeCast
import java.util.stream.Stream
import kotlin.reflect.KProperty
import kotlin.streams.asSequence
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.RESTRICTED_ABSTRACT_MESSAGE_KEYS as RAMK

/**
* 消息链, `List<SingleMessage>`, 即 [单个消息元素][SingleMessage] 的有序集合.
Expand Down Expand Up @@ -211,7 +213,7 @@ public sealed interface MessageChain :
*
* @see MessageChain.getOrFail 在找不到此类型的元素时抛出 [NoSuchElementException]
*/
public operator fun <M : SingleMessage> get(key: MessageKey<M>): M? {
public operator fun <M : SingleMessage> get(@ResolveContext(RAMK) key: MessageKey<M>): M? {
@Suppress("UNCHECKED_CAST")
return firstOrNull { key.safeCast.invoke(it) != null } as M?
}
Expand Down Expand Up @@ -242,7 +244,7 @@ public sealed interface MessageChain :
*
* @see MessageChain.getOrFail 在找不到此类型的元素时抛出 [NoSuchElementException]
*/
public operator fun <M : SingleMessage> contains(key: MessageKey<M>): Boolean =
public operator fun <M : SingleMessage> contains(@ResolveContext(RAMK) key: MessageKey<M>): Boolean =
any { key.safeCast.invoke(it) != null }

@MiraiExperimentalApi
Expand Down Expand Up @@ -381,7 +383,7 @@ public object EmptyMessageChain : MessageChain, List<SingleMessage> by emptyList
*/
@JvmSynthetic
public inline fun <M : SingleMessage> MessageChain.getOrFail(
key: MessageKey<M>,
@ResolveContext(RAMK) key: MessageKey<M>,
crossinline lazyMessage: (key: MessageKey<M>) -> String = { key.toString() }
): M = get(key) ?: throw NoSuchElementException(lazyMessage(key))

Expand Down