diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 33d2f2788..1018cc6da 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -54,9 +54,9 @@ object Versions { // If you the versions below, you need to sync changes to mirai-console/buildSrc/src/main/kotlin/Versions.kt const val yamlkt = "0.10.2" - const val intellijGradlePlugin = "1.1" - const val kotlinIntellijPlugin = "211-1.5.20-release-284-IJ7442.40" // keep to newest as kotlinCompiler - const val intellij = "2021.1.3" // don't update easily unless you want your disk space -= 500MB + const val intellijGradlePlugin = "1.3.0" +// const val kotlinIntellijPlugin = "211-1.5.20-release-284-IJ7442.40" // keep to newest as kotlinCompiler + const val intellij = "2021.3" // don't update easily unless you want your disk space -= 500MB } diff --git a/mirai-console/tools/compiler-common/src/diagnostics/MiraiConsoleErrors.kt b/mirai-console/tools/compiler-common/src/diagnostics/MiraiConsoleErrors.kt index c80ad2d7c..c0d1caa47 100644 --- a/mirai-console/tools/compiler-common/src/diagnostics/MiraiConsoleErrors.kt +++ b/mirai-console/tools/compiler-common/src/diagnostics/MiraiConsoleErrors.kt @@ -67,7 +67,7 @@ object MiraiConsoleErrors { val ILLEGAL_COMMAND_REGISTER_USE = create(ERROR) @JvmField - val RESTRICTED_CONSOLE_COMMAND_OWNER = create(WARNING) + val RESTRICTED_CONSOLE_COMMAND_OWNER = create(WARNING) @JvmField val ILLEGAL_COMMAND_DECLARATION_RECEIVER = create(ERROR) diff --git a/mirai-console/tools/intellij-plugin/build.gradle.kts b/mirai-console/tools/intellij-plugin/build.gradle.kts index 1d3b218ef..f6dedd2b0 100644 --- a/mirai-console/tools/intellij-plugin/build.gradle.kts +++ b/mirai-console/tools/intellij-plugin/build.gradle.kts @@ -24,11 +24,6 @@ repositories { version = Versions.console description = "IntelliJ plugin for Mirai Console" -// JVM fails to compile -kotlin.target.compilations.forEach { kotlinCompilation -> - kotlinCompilation.kotlinOptions.freeCompilerArgs += "-Xuse-ir" -} // don't use `useIr()`, compatibility with mirai-console dedicated builds - // See https://github.com/JetBrains/gradle-intellij-plugin/ intellij { version.set(Versions.intellij) @@ -39,9 +34,10 @@ intellij { plugins.set( listOf( - "org.jetbrains.kotlin:${Versions.kotlinIntellijPlugin}", // @eap +// "org.jetbrains.kotlin:${Versions.kotlinIntellijPlugin}", // @eap "java", - "gradle" + "gradle", + "org.jetbrains.kotlin" ) ) } @@ -68,8 +64,6 @@ fun File.resolveMkdir(relative: String): File { kotlin.target.compilations.all { kotlinOptions { - apiVersion = "1.4" - languageVersion = "1.4" jvmTarget = "11" } } @@ -83,7 +77,7 @@ tasks.withType {

Features

    -
  • Inspections for plugin properties, for example, checking PluginDescription.
  • +
  • Inspections for plugin properties.
  • Inspections for illegal calls.
  • Intentions for resolving serialization problems.
@@ -103,13 +97,6 @@ dependencies { api(project(":mirai-console-compiler-common")) - compileOnly(`kotlin-stdlib-jdk8`) -// compileOnly("com.jetbrains:ideaIC:${Versions.intellij}") - // compileOnly(`kotlin-compiler`) - -// compileOnly(files("libs/ide-common.jar")) - compileOnly(fileTree("run/idea-sandbox/plugins/Kotlin/lib").filter { - !it.name.contains("stdlib") && !it.name.contains("coroutines") - }) - compileOnly(`kotlin-reflect`) + implementation(`kotlin-stdlib-jdk8`) + implementation(`kotlin-reflect`) } diff --git a/mirai-console/tools/intellij-plugin/run/projects/test-project/build.gradle.kts b/mirai-console/tools/intellij-plugin/run/projects/test-project/build.gradle.kts index 3188dee80..2bc148209 100644 --- a/mirai-console/tools/intellij-plugin/run/projects/test-project/build.gradle.kts +++ b/mirai-console/tools/intellij-plugin/run/projects/test-project/build.gradle.kts @@ -1,7 +1,7 @@ plugins { - kotlin("jvm") version "1.4.20" - kotlin("plugin.serialization") version "1.4.20" - id("net.mamoe.mirai-console") version "2.4-M1" + kotlin("jvm") version "1.6.0" + kotlin("plugin.serialization") version "1.6.0" + id("net.mamoe.mirai-console") version "2.9.0-M1" java } diff --git a/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt b/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt index 64c9095ad..ce4891d25 100644 --- a/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt +++ b/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/MyPluginMain.kt @@ -25,7 +25,7 @@ object MyPluginMain : KotlinPlugin( PermissionService.INSTANCE.register(permissionId("dvs"), "ok") PermissionService.INSTANCE.register(permissionId("perm with space"), "error") PermissionId("Namespace with space", "Name with space") - SemVersion.parseRangeRequirement("") + SemVersion.parseRangeRequirement("1.0") SemVersion.parseRangeRequirement("
") SemVersion.parseRangeRequirement("SB YELLOW") SemVersion.parseRangeRequirement("1.0.0 || 2.0.0 || ") diff --git a/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/ReadOnlyPluginDataVar.kt b/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/ReadOnlyPluginDataVar.kt index 3c8990c78..4ed8c90db 100644 --- a/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/ReadOnlyPluginDataVar.kt +++ b/mirai-console/tools/intellij-plugin/run/projects/test-project/src/main/kotlin/org/example/myplugin/ReadOnlyPluginDataVar.kt @@ -9,6 +9,7 @@ package org.example.myplugin +import kotlinx.serialization.Serializable import net.mamoe.mirai.console.data.ReadOnlyPluginConfig import net.mamoe.mirai.console.data.value import org.example.myplugin.DataTest1.provideDelegate @@ -16,5 +17,8 @@ import org.example.myplugin.DataTest1.provideDelegate object DataTest2 : ReadOnlyPluginConfig("data") { var pp by value() + val x by value(V("")) // var should be reported + + class V constructor(val s: String) } diff --git a/mirai-console/tools/intellij-plugin/src/IDEContainerContributor.kt b/mirai-console/tools/intellij-plugin/src/IDEContainerContributor.kt index 21ced0078..a9d852cce 100644 --- a/mirai-console/tools/intellij-plugin/src/IDEContainerContributor.kt +++ b/mirai-console/tools/intellij-plugin/src/IDEContainerContributor.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.console.intellij +import com.intellij.psi.PsiElement import net.mamoe.mirai.console.compiler.common.castOrNull import net.mamoe.mirai.console.intellij.diagnostics.CommandDeclarationChecker import net.mamoe.mirai.console.intellij.diagnostics.ContextualParametersChecker @@ -25,6 +26,9 @@ import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.idea.core.unwrapModuleSourceInfo import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import java.io.File @@ -37,7 +41,8 @@ class IDEContainerContributor : StorageComponentContainerContributor { ) { if (moduleDescriptor.hasMiraiConsoleDependency()) { container.useInstance(ContextualParametersChecker().wrapIgnoringExceptionIfNotDebug()) - container.useInstance(PluginDataValuesChecker().wrapIgnoringExceptionIfNotDebug()) + container.useInstance((PluginDataValuesChecker() as CallChecker).wrapIgnoringExceptionIfNotDebug()) + container.useInstance((PluginDataValuesChecker() as DeclarationChecker).wrapIgnoringExceptionIfNotDebug()) container.useInstance(CommandDeclarationChecker().wrapIgnoringExceptionIfNotDebug()) } } @@ -49,6 +54,22 @@ class IDEContainerContributor : StorageComponentContainerContributor { return DeclarationCheckerIgnoringExceptions(this) } + private fun CallChecker.wrapIgnoringExceptionIfNotDebug(): CallChecker { + if (DEBUG_ENABLED) { + return this + } + return CallCheckerIgnoringExceptions(this) + } + + class CallCheckerIgnoringExceptions( + private val delegate: CallChecker + ) : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + runIgnoringErrors { delegate.check(resolvedCall, reportOn, context) } + } + + } + class DeclarationCheckerIgnoringExceptions( private val delegate: DeclarationChecker ) : DeclarationChecker { diff --git a/mirai-console/tools/intellij-plugin/src/diagnostics/ContextualParametersChecker.kt b/mirai-console/tools/intellij-plugin/src/diagnostics/ContextualParametersChecker.kt index 04c29d37b..aaceef753 100644 --- a/mirai-console/tools/intellij-plugin/src/diagnostics/ContextualParametersChecker.kt +++ b/mirai-console/tools/intellij-plugin/src/diagnostics/ContextualParametersChecker.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.console.intellij.diagnostics +import com.intellij.psi.PsiElement import net.mamoe.mirai.console.compiler.common.CheckerConstants import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_COMMAND_NAME import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PERMISSION_ID @@ -20,47 +21,57 @@ import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.RE import net.mamoe.mirai.console.compiler.common.resolve.CONSOLE_COMMAND_OWNER_FQ_NAME 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.bodyCalls +import net.mamoe.mirai.console.intellij.resolve.getResolvedCall import net.mamoe.mirai.console.intellij.resolve.resolveStringConstantValues import net.mamoe.mirai.console.intellij.util.RequirementHelper import net.mamoe.mirai.console.intellij.util.RequirementParser -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.idea.inspections.collections.isCalling -import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtReferenceExpression import org.jetbrains.kotlin.psi.ValueArgument -import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker -import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import java.util.* import kotlin.reflect.KFunction2 +val CallCheckerContext.bindingContext get() = trace.bindingContext + /** * Checks parameters with [ResolveContextKind] */ -class ContextualParametersChecker : DeclarationChecker { - override fun check( - declaration: KtDeclaration, - descriptor: DeclarationDescriptor, - context: DeclarationCheckerContext, - ) { - val calls = declaration.bodyCalls(context.bindingContext) ?: return - - for ((call, _) in calls) { - for ((parameter, resolvedArgument) in call.valueArguments) { - for (valueArgument in resolvedArgument.arguments) { - checkArgument(parameter, valueArgument, context) - } +class ContextualParametersChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + for ((parameter, resolvedArgument) in resolvedCall.valueArguments) { + for (valueArgument in resolvedArgument.arguments) { + checkArgument(parameter, valueArgument, context, valueArgument.asElement()) } } } +// +// override fun check( +// declaration: KtDeclaration, +// descriptor: DeclarationDescriptor, +// context: DeclarationCheckerContext, +// ) { +// val calls = declaration.bodyCalls(context.bindingContext) ?: return +// +// for ((call, _) in calls) { +// for ((parameter, resolvedArgument) in call.valueArguments) { +// for (valueArgument in resolvedArgument.arguments) { +// checkArgument(parameter, valueArgument, context) +// } +// } +// } +// } private fun checkArgument( parameter: ValueParameterDescriptor, argument: ValueArgument, - context: DeclarationCheckerContext, + context: CallCheckerContext, + inspectionTarget: PsiElement, ) { val elementCheckers = parameter.resolveContextKinds?.mapNotNull(checkersMap::get) ?: return if (elementCheckers.isEmpty()) return @@ -69,15 +80,15 @@ class ContextualParametersChecker : DeclarationChecker { for (elementChecker in elementCheckers) { if (resolvedConstants.isEmpty()) { - elementChecker(context, argument.asElement(), argument, null)?.let { context.report(it) } + elementChecker(context, inspectionTarget, argument, null)?.let { context.trace.report(it) } } else { for (resolvedConstant in resolvedConstants) { elementChecker( context, - argument.asElement(), + inspectionTarget, argument, resolvedConstant - )?.let { context.report(it) } + )?.let { context.trace.report(it) } } } } @@ -98,14 +109,14 @@ class ContextualParametersChecker : DeclarationChecker { */ private val SEMANTIC_VERSIONING_REGEX = Regex(SEMANTIC_VERSIONING_PATTERN) - fun checkPluginId(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkPluginId(inspectionTarget: PsiElement, value: String): Diagnostic? { if (value.isBlank()) return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件 Id 不能为空. \n插件 Id$syntax") if (value.none { it == '.' }) return ILLEGAL_PLUGIN_DESCRIPTION.on( inspectionTarget, "插件 Id '$value' 无效. 插件 Id 必须同时包含 groupId 和插件名称. $syntax" ) - val lowercaseId = value.toLowerCase() + val lowercaseId = value.lowercase() if (ID_REGEX.matchEntire(value) == null) { return ILLEGAL_PLUGIN_DESCRIPTION.on( @@ -120,16 +131,16 @@ class ContextualParametersChecker : DeclarationChecker { return null } - fun checkPluginName(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkPluginName(inspectionTarget: PsiElement, value: String): Diagnostic? { if (value.isBlank()) return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件名不能为空") - val lowercaseName = value.toLowerCase() + val lowercaseName = value.lowercase() FORBIDDEN_ID_NAMES.firstOrNull { it == lowercaseName }?.let { illegal -> return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "'$illegal' 不允许作为插件名. 确保插件名不完全是这个名称") } return null } - fun checkPluginVersion(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkPluginVersion(inspectionTarget: PsiElement, value: String): Diagnostic? { if (!SEMANTIC_VERSIONING_REGEX.matches(value)) { return ILLEGAL_PLUGIN_DESCRIPTION.on( inspectionTarget, @@ -139,7 +150,7 @@ class ContextualParametersChecker : DeclarationChecker { return null } - fun checkCommandName(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkCommandName(inspectionTarget: PsiElement, value: String): Diagnostic? { return when { value.isBlank() -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "指令名不能为空") value.any { it.isWhitespace() } -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "暂时不允许指令名中存在空格") @@ -149,7 +160,7 @@ class ContextualParametersChecker : DeclarationChecker { } } - fun checkPermissionNamespace(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkPermissionNamespace(inspectionTarget: PsiElement, value: String): Diagnostic? { return when { value.isBlank() -> ILLEGAL_PERMISSION_NAMESPACE.on(inspectionTarget, value, "权限命名空间不能为空") value.any { it.isWhitespace() } -> ILLEGAL_PERMISSION_NAMESPACE.on( @@ -162,7 +173,7 @@ class ContextualParametersChecker : DeclarationChecker { } } - fun checkPermissionName(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkPermissionName(inspectionTarget: PsiElement, value: String): Diagnostic? { return when { value.isBlank() -> ILLEGAL_PERMISSION_NAME.on(inspectionTarget, value, "权限名称不能为空") value.any { it.isWhitespace() } -> ILLEGAL_PERMISSION_NAME.on(inspectionTarget, value, "不允许权限名称中存在空格") @@ -171,7 +182,7 @@ class ContextualParametersChecker : DeclarationChecker { } } - fun checkPermissionId(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkPermissionId(inspectionTarget: PsiElement, value: String): Diagnostic? { return when { value.isBlank() -> ILLEGAL_PERMISSION_ID.on(inspectionTarget, value, "权限 Id 不能为空") value.any { it.isWhitespace() } -> ILLEGAL_PERMISSION_ID.on(inspectionTarget, value, "暂时不允许权限 Id 中存在空格") @@ -185,7 +196,7 @@ class ContextualParametersChecker : DeclarationChecker { } @Suppress("UNUSED_PARAMETER") - fun checkVersionRequirement(inspectionTarget: KtElement, value: String): Diagnostic? { + fun checkVersionRequirement(inspectionTarget: PsiElement, value: String): Diagnostic? { return try { RequirementHelper.RequirementChecker.processLine(RequirementParser.TokenReader(value)) null @@ -195,14 +206,14 @@ class ContextualParametersChecker : DeclarationChecker { } fun checkConsoleCommandOwner( - context: DeclarationCheckerContext, - inspectionTarget: KtElement, + context: CallCheckerContext, + inspectionTarget: PsiElement, argument: ValueArgument ): Diagnostic? { val expr = argument.getArgumentExpression() ?: return null if (expr is KtReferenceExpression) { - if (expr.getResolvedCall(context)?.isCalling(CONSOLE_COMMAND_OWNER_FQ_NAME) == true) { + if (expr.getResolvedCall(context.bindingContext)?.isCalling(CONSOLE_COMMAND_OWNER_FQ_NAME) == true) { return RESTRICTED_CONSOLE_COMMAND_OWNER.on(inspectionTarget) } } @@ -213,8 +224,8 @@ class ContextualParametersChecker : DeclarationChecker { fun interface ElementChecker { operator fun invoke( - context: DeclarationCheckerContext, - declaration: KtElement, + context: CallCheckerContext, + declaration: PsiElement, valueArgument: ValueArgument, value: String? ): Diagnostic? @@ -224,7 +235,7 @@ class ContextualParametersChecker : DeclarationChecker { private val checkersMap: EnumMap = EnumMap(ResolveContextKind::class.java).apply { - fun put(key: ResolveContextKind, value: KFunction2): ElementChecker? { + fun put(key: ResolveContextKind, value: KFunction2): ElementChecker? { return put(key) { _, d, _, v -> if (v != null) value(d, v) else null @@ -233,7 +244,7 @@ class ContextualParametersChecker : DeclarationChecker { fun put( key: ResolveContextKind, - value: KFunction2 + value: KFunction2 ): ElementChecker? { return put(key) { _, d, v, _ -> value(d, v) @@ -242,7 +253,7 @@ class ContextualParametersChecker : DeclarationChecker { fun put( key: ResolveContextKind, - value: (DeclarationCheckerContext, KtElement, ValueArgument) -> Diagnostic? + value: (CallCheckerContext, PsiElement, ValueArgument) -> Diagnostic? ): ElementChecker? { return put(key) { c, d, v, _ -> value(c, d, v) diff --git a/mirai-console/tools/intellij-plugin/src/diagnostics/PluginDataValuesChecker.kt b/mirai-console/tools/intellij-plugin/src/diagnostics/PluginDataValuesChecker.kt index f8609513f..c12edee57 100644 --- a/mirai-console/tools/intellij-plugin/src/diagnostics/PluginDataValuesChecker.kt +++ b/mirai-console/tools/intellij-plugin/src/diagnostics/PluginDataValuesChecker.kt @@ -11,11 +11,11 @@ package net.mamoe.mirai.console.intellij.diagnostics +import com.intellij.psi.PsiElement import net.mamoe.mirai.console.compiler.common.SERIALIZABLE_FQ_NAME import net.mamoe.mirai.console.compiler.common.castOrNull import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors import net.mamoe.mirai.console.compiler.common.resolve.* -import net.mamoe.mirai.console.intellij.resolve.bodyCalls import net.mamoe.mirai.console.intellij.resolve.hasSuperType import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor @@ -26,6 +26,8 @@ import org.jetbrains.kotlin.idea.refactoring.fqName.fqName import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext @@ -33,34 +35,30 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.SimpleType -class PluginDataValuesChecker : DeclarationChecker { - /** - * [KtObjectDeclaration], [KtParameter], [KtPrimaryConstructor], [KtClass], [KtNamedFunction], [KtProperty] - */ +class PluginDataValuesChecker : CallChecker, DeclarationChecker { + + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + check( + resolvedCall as ResolvedCall, + resolvedCall.call.callElement as? KtExpression ?: return, + context + ) + } + override fun check( declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext ) { - val bindingContext = context.bindingContext - - //println(declaration::class.qualifiedName + "\t:" + declaration.text.take(10)) - if (declaration is KtProperty) { checkReadOnly(declaration, context) } - - val calls = declaration.bodyCalls(bindingContext) ?: return - - for ((call, expr) in calls) { - check(call, expr, context) - } } /** * Check `PluginData.value` calls */ - fun check(call: ResolvedCall, expr: KtExpression, context: DeclarationCheckerContext) { + fun check(call: ResolvedCall, expr: KtExpression, context: CallCheckerContext) { if (!call.isCalling(PLUGIN_DATA_VALUE_FUNCTIONS_FQ_FQ_NAME)) return if (expr is KtCallExpression) @@ -87,25 +85,28 @@ class PluginDataValuesChecker : DeclarationChecker { private fun checkConstructableAndSerializable( call: ResolvedCall, expr: KtCallExpression, - context: DeclarationCheckerContext + context: CallCheckerContext ) { if (call.resultingDescriptor.resolveContextKinds?.contains(ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR) != true) return - for ((typeParameterDescriptor, kotlinType) in call.typeArguments.entries) { - if ((typeParameterDescriptor.isReified || typeParameterDescriptor.resolveContextKinds?.contains( - ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR - ) == true) + for ((entry, argument) in call.typeArguments.entries.zip(expr.typeArguments)) { + val (parameter, kotlinType) = entry + if ((parameter.isReified + || parameter.resolveContextKinds?.contains(ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR) == true) && kotlinType is SimpleType ) { - - checkConstructableAndSerializable(kotlinType, expr, context) - checkFixType(kotlinType, expr, context) + checkConstructableAndSerializable(kotlinType, expr, argument, context) + checkFixType(kotlinType, expr, argument, context) } } } - private fun checkFixType(type: KotlinType, callExpr: KtCallExpression, context: DeclarationCheckerContext) { - val inspectionTarget = retrieveInspectionTarget(type, callExpr) ?: return + private fun checkFixType( + type: KotlinType, + callExpr: KtCallExpression, + inspectionTarget: KtTypeProjection, + context: CallCheckerContext + ) { val classDescriptor = type.classDescriptor() ?: return val jetTypeFqn = type.getJetTypeFqName(false) @@ -132,22 +133,21 @@ class PluginDataValuesChecker : DeclarationChecker { else -> return } ?: return - context.report(factory.on(inspectionTarget, callExpr, jetTypeFqn.substringAfterLast('.'))) + context.trace.report(factory.on(inspectionTarget, callExpr, jetTypeFqn.substringAfterLast('.'))) } private fun checkConstructableAndSerializable( type: KotlinType, callExpr: KtCallExpression, - context: DeclarationCheckerContext + inspectionTarget: KtTypeProjection, + context: CallCheckerContext ) { val classDescriptor = type.classDescriptor() ?: return if (canBeSerializedInternally(classDescriptor)) return - val inspectionTarget = retrieveInspectionTarget(type, callExpr) ?: return - if (!classDescriptor.hasNoArgConstructor()) - return context.report( + return context.trace.report( MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE.on( inspectionTarget, callExpr, @@ -156,7 +156,7 @@ class PluginDataValuesChecker : DeclarationChecker { ) if (!classDescriptor.hasAnnotation(SERIALIZABLE_FQ_NAME)) - return context.report( + return context.trace.report( MiraiConsoleErrors.UNSERIALIZABLE_TYPE.on( inspectionTarget, classDescriptor diff --git a/mirai-console/tools/intellij-plugin/src/diagnostics/ResourceNotClosedInspection.kt b/mirai-console/tools/intellij-plugin/src/diagnostics/ResourceNotClosedInspection.kt index a6056de5d..144f403de 100644 --- a/mirai-console/tools/intellij-plugin/src/diagnostics/ResourceNotClosedInspection.kt +++ b/mirai-console/tools/intellij-plugin/src/diagnostics/ResourceNotClosedInspection.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix import org.jetbrains.kotlin.idea.quickfix.KotlinCrossLanguageQuickFixAction -import org.jetbrains.kotlin.idea.search.getKotlinFqName +import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.name.FqName diff --git a/mirai-console/tools/intellij-plugin/src/resolve/FunctionSignature.kt b/mirai-console/tools/intellij-plugin/src/resolve/FunctionSignature.kt index 84be5c9d2..49cb223ea 100644 --- a/mirai-console/tools/intellij-plugin/src/resolve/FunctionSignature.kt +++ b/mirai-console/tools/intellij-plugin/src/resolve/FunctionSignature.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference import org.jetbrains.kotlin.idea.refactoring.fqName.fqName -import org.jetbrains.kotlin.idea.search.getKotlinFqName +import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.nj2k.postProcessing.type import org.jetbrains.kotlin.psi.KtExpression diff --git a/mirai-console/tools/intellij-plugin/src/resolve/resolveIdea.kt b/mirai-console/tools/intellij-plugin/src/resolve/resolveIdea.kt index 0192be79b..a6c75d67c 100644 --- a/mirai-console/tools/intellij-plugin/src/resolve/resolveIdea.kt +++ b/mirai-console/tools/intellij-plugin/src/resolve/resolveIdea.kt @@ -160,57 +160,6 @@ val KtAnnotationEntry.annotationClass: KtClass? fun KtAnnotated.hasAnnotation(fqName: FqName): Boolean = this.annotationEntries.any { it.annotationClass?.getKotlinFqName() == fqName } -fun KtElement.resolveAllCalls(bindingContext: BindingContext): Sequence> { - return allChildrenWithSelfSequence - .filterIsInstance() - .mapNotNull { it.getResolvedCall(bindingContext) } -} - -data class ResolvedCallWithExpr( - val call: ResolvedCall, - val expr: E -) - -/** - * 只解决一层 - */ -fun KtDeclaration.bodyCalls(bindingContext: BindingContext): Sequence>? { - return when (val declaration = this) { - is KtClassOrObject -> { - declaration.superTypeListEntries.asSequence().flatMap { - it.resolveAllCallsWithElement(bindingContext, true) - } - } - is KtDeclarationWithBody -> { - declaration.bodyExpression?.resolveAllCallsWithElement(bindingContext, false) ?: return null - } - is KtCallExpression -> { - val call = declaration.getResolvedCall(bindingContext) ?: return null - sequenceOf(ResolvedCallWithExpr(call, declaration)) - } - is KtProperty -> { - val expr = declaration.delegateExpression ?: return null - val call = expr.getResolvedCall(bindingContext) ?: return null - sequenceOf(ResolvedCallWithExpr(call, expr)) - } - else -> return null - } -} - -fun KtElement.resolveAllCallsWithElement( - bindingContext: BindingContext, - recursive: Boolean = true -): Sequence> { - return (if (recursive) allChildrenWithSelfSequence else childrenWithSelf.asSequence()) - .filterIsInstance() - .mapNotNull { expr -> - val callee = expr.getCalleeExpressionIfAny() ?: return@mapNotNull null - val resolved = callee.getResolvedCall(bindingContext) ?: return@mapNotNull null - - ResolvedCallWithExpr(resolved, expr) - } -} - fun ValueArgument.resolveStringConstantValues(bindingContext: BindingContext): Sequence? { return this.getArgumentExpression()?.resolveStringConstantValues(bindingContext) } @@ -234,7 +183,7 @@ fun KtReferenceExpression.typeFqName() = type()?.fqName fun KtExpression.typeFqName() = referenceExpression()?.typeFqName() fun KtElement.getResolvedCall( - context: BindingContext = analyze(BodyResolveMode.PARTIAL), + context: BindingContext, ): ResolvedCall? { return this.getCall(context)?.getResolvedCall(context) }