mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-31 11:50:09 +08:00
Improve performance of IDEA plugin
This commit is contained in:
parent
aa915085b8
commit
92465c3213
@ -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
|
// 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 yamlkt = "0.10.2"
|
||||||
const val intellijGradlePlugin = "1.1"
|
const val intellijGradlePlugin = "1.3.0"
|
||||||
const val kotlinIntellijPlugin = "211-1.5.20-release-284-IJ7442.40" // keep to newest as kotlinCompiler
|
// 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 intellij = "2021.3" // don't update easily unless you want your disk space -= 500MB
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ object MiraiConsoleErrors {
|
|||||||
val ILLEGAL_COMMAND_REGISTER_USE = create<PsiElement, KtNamedDeclaration, String>(ERROR)
|
val ILLEGAL_COMMAND_REGISTER_USE = create<PsiElement, KtNamedDeclaration, String>(ERROR)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val RESTRICTED_CONSOLE_COMMAND_OWNER = create<KtElement>(WARNING)
|
val RESTRICTED_CONSOLE_COMMAND_OWNER = create<PsiElement>(WARNING)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val ILLEGAL_COMMAND_DECLARATION_RECEIVER = create<KtTypeReference>(ERROR)
|
val ILLEGAL_COMMAND_DECLARATION_RECEIVER = create<KtTypeReference>(ERROR)
|
||||||
|
@ -24,11 +24,6 @@ repositories {
|
|||||||
version = Versions.console
|
version = Versions.console
|
||||||
description = "IntelliJ plugin for Mirai 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/
|
// See https://github.com/JetBrains/gradle-intellij-plugin/
|
||||||
intellij {
|
intellij {
|
||||||
version.set(Versions.intellij)
|
version.set(Versions.intellij)
|
||||||
@ -39,9 +34,10 @@ intellij {
|
|||||||
|
|
||||||
plugins.set(
|
plugins.set(
|
||||||
listOf(
|
listOf(
|
||||||
"org.jetbrains.kotlin:${Versions.kotlinIntellijPlugin}", // @eap
|
// "org.jetbrains.kotlin:${Versions.kotlinIntellijPlugin}", // @eap
|
||||||
"java",
|
"java",
|
||||||
"gradle"
|
"gradle",
|
||||||
|
"org.jetbrains.kotlin"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -68,8 +64,6 @@ fun File.resolveMkdir(relative: String): File {
|
|||||||
|
|
||||||
kotlin.target.compilations.all {
|
kotlin.target.compilations.all {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
apiVersion = "1.4"
|
|
||||||
languageVersion = "1.4"
|
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +77,7 @@ tasks.withType<org.jetbrains.intellij.tasks.PatchPluginXmlTask> {
|
|||||||
|
|
||||||
<h3>Features</h3>
|
<h3>Features</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Inspections for plugin properties, for example, checking PluginDescription.</li>
|
<li>Inspections for plugin properties.</li>
|
||||||
<li>Inspections for illegal calls.</li>
|
<li>Inspections for illegal calls.</li>
|
||||||
<li>Intentions for resolving serialization problems.</li>
|
<li>Intentions for resolving serialization problems.</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -103,13 +97,6 @@ dependencies {
|
|||||||
|
|
||||||
api(project(":mirai-console-compiler-common"))
|
api(project(":mirai-console-compiler-common"))
|
||||||
|
|
||||||
compileOnly(`kotlin-stdlib-jdk8`)
|
implementation(`kotlin-stdlib-jdk8`)
|
||||||
// compileOnly("com.jetbrains:ideaIC:${Versions.intellij}")
|
implementation(`kotlin-reflect`)
|
||||||
// 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`)
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.4.20"
|
kotlin("jvm") version "1.6.0"
|
||||||
kotlin("plugin.serialization") version "1.4.20"
|
kotlin("plugin.serialization") version "1.6.0"
|
||||||
id("net.mamoe.mirai-console") version "2.4-M1"
|
id("net.mamoe.mirai-console") version "2.9.0-M1"
|
||||||
java
|
java
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ object MyPluginMain : KotlinPlugin(
|
|||||||
PermissionService.INSTANCE.register(permissionId("dvs"), "ok")
|
PermissionService.INSTANCE.register(permissionId("dvs"), "ok")
|
||||||
PermissionService.INSTANCE.register(permissionId("perm with space"), "error")
|
PermissionService.INSTANCE.register(permissionId("perm with space"), "error")
|
||||||
PermissionId("Namespace with space", "Name with space")
|
PermissionId("Namespace with space", "Name with space")
|
||||||
SemVersion.parseRangeRequirement("")
|
SemVersion.parseRangeRequirement("1.0")
|
||||||
SemVersion.parseRangeRequirement("<br/>")
|
SemVersion.parseRangeRequirement("<br/>")
|
||||||
SemVersion.parseRangeRequirement("SB YELLOW")
|
SemVersion.parseRangeRequirement("SB YELLOW")
|
||||||
SemVersion.parseRangeRequirement("1.0.0 || 2.0.0 || ")
|
SemVersion.parseRangeRequirement("1.0.0 || 2.0.0 || ")
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
package org.example.myplugin
|
package org.example.myplugin
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
|
import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
|
||||||
import net.mamoe.mirai.console.data.value
|
import net.mamoe.mirai.console.data.value
|
||||||
import org.example.myplugin.DataTest1.provideDelegate
|
import org.example.myplugin.DataTest1.provideDelegate
|
||||||
@ -16,5 +17,8 @@ import org.example.myplugin.DataTest1.provideDelegate
|
|||||||
|
|
||||||
object DataTest2 : ReadOnlyPluginConfig("data") {
|
object DataTest2 : ReadOnlyPluginConfig("data") {
|
||||||
var pp by value<String>()
|
var pp by value<String>()
|
||||||
|
val x by value<V>(V(""))
|
||||||
// var should be reported
|
// var should be reported
|
||||||
|
|
||||||
|
class V constructor(val s: String)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.intellij
|
package net.mamoe.mirai.console.intellij
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import net.mamoe.mirai.console.compiler.common.castOrNull
|
import net.mamoe.mirai.console.compiler.common.castOrNull
|
||||||
import net.mamoe.mirai.console.intellij.diagnostics.CommandDeclarationChecker
|
import net.mamoe.mirai.console.intellij.diagnostics.CommandDeclarationChecker
|
||||||
import net.mamoe.mirai.console.intellij.diagnostics.ContextualParametersChecker
|
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.core.unwrapModuleSourceInfo
|
||||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
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.DeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -37,7 +41,8 @@ class IDEContainerContributor : StorageComponentContainerContributor {
|
|||||||
) {
|
) {
|
||||||
if (moduleDescriptor.hasMiraiConsoleDependency()) {
|
if (moduleDescriptor.hasMiraiConsoleDependency()) {
|
||||||
container.useInstance(ContextualParametersChecker().wrapIgnoringExceptionIfNotDebug())
|
container.useInstance(ContextualParametersChecker().wrapIgnoringExceptionIfNotDebug())
|
||||||
container.useInstance(PluginDataValuesChecker().wrapIgnoringExceptionIfNotDebug())
|
container.useInstance((PluginDataValuesChecker() as CallChecker).wrapIgnoringExceptionIfNotDebug())
|
||||||
|
container.useInstance((PluginDataValuesChecker() as DeclarationChecker).wrapIgnoringExceptionIfNotDebug())
|
||||||
container.useInstance(CommandDeclarationChecker().wrapIgnoringExceptionIfNotDebug())
|
container.useInstance(CommandDeclarationChecker().wrapIgnoringExceptionIfNotDebug())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +54,22 @@ class IDEContainerContributor : StorageComponentContainerContributor {
|
|||||||
return DeclarationCheckerIgnoringExceptions(this)
|
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(
|
class DeclarationCheckerIgnoringExceptions(
|
||||||
private val delegate: DeclarationChecker
|
private val delegate: DeclarationChecker
|
||||||
) : DeclarationChecker {
|
) : DeclarationChecker {
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.intellij.diagnostics
|
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.CheckerConstants
|
||||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_COMMAND_NAME
|
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_COMMAND_NAME
|
||||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.ILLEGAL_PERMISSION_ID
|
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.CONSOLE_COMMAND_OWNER_FQ_NAME
|
||||||
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.resolveContextKinds
|
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.resolve.resolveStringConstantValues
|
||||||
import net.mamoe.mirai.console.intellij.util.RequirementHelper
|
import net.mamoe.mirai.console.intellij.util.RequirementHelper
|
||||||
import net.mamoe.mirai.console.intellij.util.RequirementParser
|
import net.mamoe.mirai.console.intellij.util.RequirementParser
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.inspections.collections.isCalling
|
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.KtElement
|
||||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.reflect.KFunction2
|
import kotlin.reflect.KFunction2
|
||||||
|
|
||||||
|
val CallCheckerContext.bindingContext get() = trace.bindingContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks parameters with [ResolveContextKind]
|
* Checks parameters with [ResolveContextKind]
|
||||||
*/
|
*/
|
||||||
class ContextualParametersChecker : DeclarationChecker {
|
class ContextualParametersChecker : CallChecker {
|
||||||
override fun check(
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
declaration: KtDeclaration,
|
for ((parameter, resolvedArgument) in resolvedCall.valueArguments) {
|
||||||
descriptor: DeclarationDescriptor,
|
for (valueArgument in resolvedArgument.arguments) {
|
||||||
context: DeclarationCheckerContext,
|
checkArgument(parameter, valueArgument, context, valueArgument.asElement())
|
||||||
) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// 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(
|
private fun checkArgument(
|
||||||
parameter: ValueParameterDescriptor,
|
parameter: ValueParameterDescriptor,
|
||||||
argument: ValueArgument,
|
argument: ValueArgument,
|
||||||
context: DeclarationCheckerContext,
|
context: CallCheckerContext,
|
||||||
|
inspectionTarget: PsiElement,
|
||||||
) {
|
) {
|
||||||
val elementCheckers = parameter.resolveContextKinds?.mapNotNull(checkersMap::get) ?: return
|
val elementCheckers = parameter.resolveContextKinds?.mapNotNull(checkersMap::get) ?: return
|
||||||
if (elementCheckers.isEmpty()) return
|
if (elementCheckers.isEmpty()) return
|
||||||
@ -69,15 +80,15 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
|
|
||||||
for (elementChecker in elementCheckers) {
|
for (elementChecker in elementCheckers) {
|
||||||
if (resolvedConstants.isEmpty()) {
|
if (resolvedConstants.isEmpty()) {
|
||||||
elementChecker(context, argument.asElement(), argument, null)?.let { context.report(it) }
|
elementChecker(context, inspectionTarget, argument, null)?.let { context.trace.report(it) }
|
||||||
} else {
|
} else {
|
||||||
for (resolvedConstant in resolvedConstants) {
|
for (resolvedConstant in resolvedConstants) {
|
||||||
elementChecker(
|
elementChecker(
|
||||||
context,
|
context,
|
||||||
argument.asElement(),
|
inspectionTarget,
|
||||||
argument,
|
argument,
|
||||||
resolvedConstant
|
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)
|
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.isBlank()) return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件 Id 不能为空. \n插件 Id$syntax")
|
||||||
if (value.none { it == '.' }) return ILLEGAL_PLUGIN_DESCRIPTION.on(
|
if (value.none { it == '.' }) return ILLEGAL_PLUGIN_DESCRIPTION.on(
|
||||||
inspectionTarget,
|
inspectionTarget,
|
||||||
"插件 Id '$value' 无效. 插件 Id 必须同时包含 groupId 和插件名称. $syntax"
|
"插件 Id '$value' 无效. 插件 Id 必须同时包含 groupId 和插件名称. $syntax"
|
||||||
)
|
)
|
||||||
|
|
||||||
val lowercaseId = value.toLowerCase()
|
val lowercaseId = value.lowercase()
|
||||||
|
|
||||||
if (ID_REGEX.matchEntire(value) == null) {
|
if (ID_REGEX.matchEntire(value) == null) {
|
||||||
return ILLEGAL_PLUGIN_DESCRIPTION.on(
|
return ILLEGAL_PLUGIN_DESCRIPTION.on(
|
||||||
@ -120,16 +131,16 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
return null
|
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, "插件名不能为空")
|
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 ->
|
FORBIDDEN_ID_NAMES.firstOrNull { it == lowercaseName }?.let { illegal ->
|
||||||
return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "'$illegal' 不允许作为插件名. 确保插件名不完全是这个名称")
|
return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "'$illegal' 不允许作为插件名. 确保插件名不完全是这个名称")
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkPluginVersion(inspectionTarget: KtElement, value: String): Diagnostic? {
|
fun checkPluginVersion(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||||
if (!SEMANTIC_VERSIONING_REGEX.matches(value)) {
|
if (!SEMANTIC_VERSIONING_REGEX.matches(value)) {
|
||||||
return ILLEGAL_PLUGIN_DESCRIPTION.on(
|
return ILLEGAL_PLUGIN_DESCRIPTION.on(
|
||||||
inspectionTarget,
|
inspectionTarget,
|
||||||
@ -139,7 +150,7 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkCommandName(inspectionTarget: KtElement, value: String): Diagnostic? {
|
fun checkCommandName(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||||
return when {
|
return when {
|
||||||
value.isBlank() -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "指令名不能为空")
|
value.isBlank() -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "指令名不能为空")
|
||||||
value.any { it.isWhitespace() } -> 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 {
|
return when {
|
||||||
value.isBlank() -> ILLEGAL_PERMISSION_NAMESPACE.on(inspectionTarget, value, "权限命名空间不能为空")
|
value.isBlank() -> ILLEGAL_PERMISSION_NAMESPACE.on(inspectionTarget, value, "权限命名空间不能为空")
|
||||||
value.any { it.isWhitespace() } -> ILLEGAL_PERMISSION_NAMESPACE.on(
|
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 {
|
return when {
|
||||||
value.isBlank() -> ILLEGAL_PERMISSION_NAME.on(inspectionTarget, value, "权限名称不能为空")
|
value.isBlank() -> ILLEGAL_PERMISSION_NAME.on(inspectionTarget, value, "权限名称不能为空")
|
||||||
value.any { it.isWhitespace() } -> 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 {
|
return when {
|
||||||
value.isBlank() -> ILLEGAL_PERMISSION_ID.on(inspectionTarget, value, "权限 Id 不能为空")
|
value.isBlank() -> ILLEGAL_PERMISSION_ID.on(inspectionTarget, value, "权限 Id 不能为空")
|
||||||
value.any { it.isWhitespace() } -> 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")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun checkVersionRequirement(inspectionTarget: KtElement, value: String): Diagnostic? {
|
fun checkVersionRequirement(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||||
return try {
|
return try {
|
||||||
RequirementHelper.RequirementChecker.processLine(RequirementParser.TokenReader(value))
|
RequirementHelper.RequirementChecker.processLine(RequirementParser.TokenReader(value))
|
||||||
null
|
null
|
||||||
@ -195,14 +206,14 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun checkConsoleCommandOwner(
|
fun checkConsoleCommandOwner(
|
||||||
context: DeclarationCheckerContext,
|
context: CallCheckerContext,
|
||||||
inspectionTarget: KtElement,
|
inspectionTarget: PsiElement,
|
||||||
argument: ValueArgument
|
argument: ValueArgument
|
||||||
): Diagnostic? {
|
): Diagnostic? {
|
||||||
val expr = argument.getArgumentExpression() ?: return null
|
val expr = argument.getArgumentExpression() ?: return null
|
||||||
|
|
||||||
if (expr is KtReferenceExpression) {
|
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)
|
return RESTRICTED_CONSOLE_COMMAND_OWNER.on(inspectionTarget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,8 +224,8 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
|
|
||||||
fun interface ElementChecker {
|
fun interface ElementChecker {
|
||||||
operator fun invoke(
|
operator fun invoke(
|
||||||
context: DeclarationCheckerContext,
|
context: CallCheckerContext,
|
||||||
declaration: KtElement,
|
declaration: PsiElement,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
value: String?
|
value: String?
|
||||||
): Diagnostic?
|
): Diagnostic?
|
||||||
@ -224,7 +235,7 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
private val checkersMap: EnumMap<ResolveContextKind, ElementChecker> =
|
private val checkersMap: EnumMap<ResolveContextKind, ElementChecker> =
|
||||||
EnumMap<ResolveContextKind, ElementChecker>(ResolveContextKind::class.java).apply {
|
EnumMap<ResolveContextKind, ElementChecker>(ResolveContextKind::class.java).apply {
|
||||||
|
|
||||||
fun put(key: ResolveContextKind, value: KFunction2<KtElement, String, Diagnostic?>): ElementChecker? {
|
fun put(key: ResolveContextKind, value: KFunction2<PsiElement, String, Diagnostic?>): ElementChecker? {
|
||||||
return put(key) { _, d, _, v ->
|
return put(key) { _, d, _, v ->
|
||||||
if (v != null) value(d, v)
|
if (v != null) value(d, v)
|
||||||
else null
|
else null
|
||||||
@ -233,7 +244,7 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
|
|
||||||
fun put(
|
fun put(
|
||||||
key: ResolveContextKind,
|
key: ResolveContextKind,
|
||||||
value: KFunction2<KtElement, ValueArgument, Diagnostic?>
|
value: KFunction2<PsiElement, ValueArgument, Diagnostic?>
|
||||||
): ElementChecker? {
|
): ElementChecker? {
|
||||||
return put(key) { _, d, v, _ ->
|
return put(key) { _, d, v, _ ->
|
||||||
value(d, v)
|
value(d, v)
|
||||||
@ -242,7 +253,7 @@ class ContextualParametersChecker : DeclarationChecker {
|
|||||||
|
|
||||||
fun put(
|
fun put(
|
||||||
key: ResolveContextKind,
|
key: ResolveContextKind,
|
||||||
value: (DeclarationCheckerContext, KtElement, ValueArgument) -> Diagnostic?
|
value: (CallCheckerContext, PsiElement, ValueArgument) -> Diagnostic?
|
||||||
): ElementChecker? {
|
): ElementChecker? {
|
||||||
return put(key) { c, d, v, _ ->
|
return put(key) { c, d, v, _ ->
|
||||||
value(c, d, v)
|
value(c, d, v)
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.intellij.diagnostics
|
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.SERIALIZABLE_FQ_NAME
|
||||||
import net.mamoe.mirai.console.compiler.common.castOrNull
|
import net.mamoe.mirai.console.compiler.common.castOrNull
|
||||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors
|
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors
|
||||||
import net.mamoe.mirai.console.compiler.common.resolve.*
|
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 net.mamoe.mirai.console.intellij.resolve.hasSuperType
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
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.js.descriptorUtils.getJetTypeFqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
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.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
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.KotlinType
|
||||||
import org.jetbrains.kotlin.types.SimpleType
|
import org.jetbrains.kotlin.types.SimpleType
|
||||||
|
|
||||||
class PluginDataValuesChecker : DeclarationChecker {
|
class PluginDataValuesChecker : CallChecker, DeclarationChecker {
|
||||||
/**
|
|
||||||
* [KtObjectDeclaration], [KtParameter], [KtPrimaryConstructor], [KtClass], [KtNamedFunction], [KtProperty]
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
*/
|
check(
|
||||||
|
resolvedCall as ResolvedCall<out CallableDescriptor>,
|
||||||
|
resolvedCall.call.callElement as? KtExpression ?: return,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun check(
|
override fun check(
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
context: DeclarationCheckerContext
|
context: DeclarationCheckerContext
|
||||||
) {
|
) {
|
||||||
val bindingContext = context.bindingContext
|
|
||||||
|
|
||||||
//println(declaration::class.qualifiedName + "\t:" + declaration.text.take(10))
|
|
||||||
|
|
||||||
if (declaration is KtProperty) {
|
if (declaration is KtProperty) {
|
||||||
checkReadOnly(declaration, context)
|
checkReadOnly(declaration, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
val calls = declaration.bodyCalls(bindingContext) ?: return
|
|
||||||
|
|
||||||
for ((call, expr) in calls) {
|
|
||||||
check(call, expr, context)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check `PluginData.value` calls
|
* Check `PluginData.value` calls
|
||||||
*/
|
*/
|
||||||
fun check(call: ResolvedCall<out CallableDescriptor>, expr: KtExpression, context: DeclarationCheckerContext) {
|
fun check(call: ResolvedCall<out CallableDescriptor>, expr: KtExpression, context: CallCheckerContext) {
|
||||||
if (!call.isCalling(PLUGIN_DATA_VALUE_FUNCTIONS_FQ_FQ_NAME)) return
|
if (!call.isCalling(PLUGIN_DATA_VALUE_FUNCTIONS_FQ_FQ_NAME)) return
|
||||||
|
|
||||||
if (expr is KtCallExpression)
|
if (expr is KtCallExpression)
|
||||||
@ -87,25 +85,28 @@ class PluginDataValuesChecker : DeclarationChecker {
|
|||||||
private fun checkConstructableAndSerializable(
|
private fun checkConstructableAndSerializable(
|
||||||
call: ResolvedCall<out CallableDescriptor>,
|
call: ResolvedCall<out CallableDescriptor>,
|
||||||
expr: KtCallExpression,
|
expr: KtCallExpression,
|
||||||
context: DeclarationCheckerContext
|
context: CallCheckerContext
|
||||||
) {
|
) {
|
||||||
if (call.resultingDescriptor.resolveContextKinds?.contains(ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR) != true) return
|
if (call.resultingDescriptor.resolveContextKinds?.contains(ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR) != true) return
|
||||||
|
|
||||||
for ((typeParameterDescriptor, kotlinType) in call.typeArguments.entries) {
|
for ((entry, argument) in call.typeArguments.entries.zip(expr.typeArguments)) {
|
||||||
if ((typeParameterDescriptor.isReified || typeParameterDescriptor.resolveContextKinds?.contains(
|
val (parameter, kotlinType) = entry
|
||||||
ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR
|
if ((parameter.isReified
|
||||||
) == true)
|
|| parameter.resolveContextKinds?.contains(ResolveContextKind.RESTRICTED_NO_ARG_CONSTRUCTOR) == true)
|
||||||
&& kotlinType is SimpleType
|
&& kotlinType is SimpleType
|
||||||
) {
|
) {
|
||||||
|
checkConstructableAndSerializable(kotlinType, expr, argument, context)
|
||||||
checkConstructableAndSerializable(kotlinType, expr, context)
|
checkFixType(kotlinType, expr, argument, context)
|
||||||
checkFixType(kotlinType, expr, context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkFixType(type: KotlinType, callExpr: KtCallExpression, context: DeclarationCheckerContext) {
|
private fun checkFixType(
|
||||||
val inspectionTarget = retrieveInspectionTarget(type, callExpr) ?: return
|
type: KotlinType,
|
||||||
|
callExpr: KtCallExpression,
|
||||||
|
inspectionTarget: KtTypeProjection,
|
||||||
|
context: CallCheckerContext
|
||||||
|
) {
|
||||||
val classDescriptor = type.classDescriptor() ?: return
|
val classDescriptor = type.classDescriptor() ?: return
|
||||||
val jetTypeFqn = type.getJetTypeFqName(false)
|
val jetTypeFqn = type.getJetTypeFqName(false)
|
||||||
|
|
||||||
@ -132,22 +133,21 @@ class PluginDataValuesChecker : DeclarationChecker {
|
|||||||
else -> return
|
else -> return
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
context.report(factory.on(inspectionTarget, callExpr, jetTypeFqn.substringAfterLast('.')))
|
context.trace.report(factory.on(inspectionTarget, callExpr, jetTypeFqn.substringAfterLast('.')))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkConstructableAndSerializable(
|
private fun checkConstructableAndSerializable(
|
||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
callExpr: KtCallExpression,
|
callExpr: KtCallExpression,
|
||||||
context: DeclarationCheckerContext
|
inspectionTarget: KtTypeProjection,
|
||||||
|
context: CallCheckerContext
|
||||||
) {
|
) {
|
||||||
val classDescriptor = type.classDescriptor() ?: return
|
val classDescriptor = type.classDescriptor() ?: return
|
||||||
|
|
||||||
if (canBeSerializedInternally(classDescriptor)) return
|
if (canBeSerializedInternally(classDescriptor)) return
|
||||||
|
|
||||||
val inspectionTarget = retrieveInspectionTarget(type, callExpr) ?: return
|
|
||||||
|
|
||||||
if (!classDescriptor.hasNoArgConstructor())
|
if (!classDescriptor.hasNoArgConstructor())
|
||||||
return context.report(
|
return context.trace.report(
|
||||||
MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE.on(
|
MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE.on(
|
||||||
inspectionTarget,
|
inspectionTarget,
|
||||||
callExpr,
|
callExpr,
|
||||||
@ -156,7 +156,7 @@ class PluginDataValuesChecker : DeclarationChecker {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!classDescriptor.hasAnnotation(SERIALIZABLE_FQ_NAME))
|
if (!classDescriptor.hasAnnotation(SERIALIZABLE_FQ_NAME))
|
||||||
return context.report(
|
return context.trace.report(
|
||||||
MiraiConsoleErrors.UNSERIALIZABLE_TYPE.on(
|
MiraiConsoleErrors.UNSERIALIZABLE_TYPE.on(
|
||||||
inspectionTarget,
|
inspectionTarget,
|
||||||
classDescriptor
|
classDescriptor
|
||||||
|
@ -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.AbstractKotlinInspection
|
||||||
import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
|
import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinCrossLanguageQuickFixAction
|
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.search.usagesSearch.descriptor
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
@ -17,7 +17,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference
|
||||||
import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
|
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.name.FqName
|
||||||
import org.jetbrains.kotlin.nj2k.postProcessing.type
|
import org.jetbrains.kotlin.nj2k.postProcessing.type
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
@ -160,57 +160,6 @@ val KtAnnotationEntry.annotationClass: KtClass?
|
|||||||
fun KtAnnotated.hasAnnotation(fqName: FqName): Boolean =
|
fun KtAnnotated.hasAnnotation(fqName: FqName): Boolean =
|
||||||
this.annotationEntries.any { it.annotationClass?.getKotlinFqName() == fqName }
|
this.annotationEntries.any { it.annotationClass?.getKotlinFqName() == fqName }
|
||||||
|
|
||||||
fun KtElement.resolveAllCalls(bindingContext: BindingContext): Sequence<ResolvedCall<*>> {
|
|
||||||
return allChildrenWithSelfSequence
|
|
||||||
.filterIsInstance<KtElement>()
|
|
||||||
.mapNotNull { it.getResolvedCall(bindingContext) }
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ResolvedCallWithExpr<C : CallableDescriptor, E : KtExpression>(
|
|
||||||
val call: ResolvedCall<C>,
|
|
||||||
val expr: E
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只解决一层
|
|
||||||
*/
|
|
||||||
fun KtDeclaration.bodyCalls(bindingContext: BindingContext): Sequence<ResolvedCallWithExpr<out CallableDescriptor, KtExpression>>? {
|
|
||||||
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<ResolvedCallWithExpr<out CallableDescriptor, KtExpression>> {
|
|
||||||
return (if (recursive) allChildrenWithSelfSequence else childrenWithSelf.asSequence())
|
|
||||||
.filterIsInstance<KtExpression>()
|
|
||||||
.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<String>? {
|
fun ValueArgument.resolveStringConstantValues(bindingContext: BindingContext): Sequence<String>? {
|
||||||
return this.getArgumentExpression()?.resolveStringConstantValues(bindingContext)
|
return this.getArgumentExpression()?.resolveStringConstantValues(bindingContext)
|
||||||
}
|
}
|
||||||
@ -234,7 +183,7 @@ fun KtReferenceExpression.typeFqName() = type()?.fqName
|
|||||||
fun KtExpression.typeFqName() = referenceExpression()?.typeFqName()
|
fun KtExpression.typeFqName() = referenceExpression()?.typeFqName()
|
||||||
|
|
||||||
fun KtElement.getResolvedCall(
|
fun KtElement.getResolvedCall(
|
||||||
context: BindingContext = analyze(BodyResolveMode.PARTIAL),
|
context: BindingContext,
|
||||||
): ResolvedCall<out CallableDescriptor>? {
|
): ResolvedCall<out CallableDescriptor>? {
|
||||||
return this.getCall(context)?.getResolvedCall(context)
|
return this.getCall(context)?.getResolvedCall(context)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user