Add CodegenApplicabilityCheckerExtension and use it to fallback to Heavy LigthClasses
+ Fixed #KT-33584
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.annotation.plugin.ide
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.extensions.AnnotationBasedExtension
|
||||
import org.jetbrains.kotlin.extensions.LightClassApplicabilityCheckExtension
|
||||
import org.jetbrains.kotlin.extensions.LightClassApplicabilityType
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
|
||||
abstract class AnnotationBasedLightClassApplicabilityExtension(project: Project, annotationOptionPrefix: String) :
|
||||
LightClassApplicabilityCheckExtension,
|
||||
AnnotationBasedExtension
|
||||
{
|
||||
private val cachedAnnotationsNames = CachedAnnotationNames(project, annotationOptionPrefix)
|
||||
|
||||
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List<String> =
|
||||
cachedAnnotationsNames.getAnnotationNames(modifierListOwner)
|
||||
|
||||
override fun checkApplicabilityType(declaration: KtDeclaration, descriptor: Lazy<DeclarationDescriptor?>): LightClassApplicabilityType {
|
||||
if (!declaration.isOrdinaryClass || !declaration.isAnnotated) return LightClassApplicabilityType.UltraLightClass
|
||||
|
||||
if (cachedAnnotationsNames.getAnnotationNames(declaration).isEmpty()) return LightClassApplicabilityType.UltraLightClass
|
||||
|
||||
val descriptorValue = descriptor.value ?: return LightClassApplicabilityType.UltraLightClass
|
||||
|
||||
val classDescriptor = (descriptorValue as? ClassDescriptor)
|
||||
?: descriptorValue.containingDeclaration as? ClassDescriptor
|
||||
?: return LightClassApplicabilityType.UltraLightClass
|
||||
|
||||
val hasSpecialAnnotation = run { classDescriptor.hasSpecialAnnotation(declaration) }
|
||||
|
||||
return if (hasSpecialAnnotation) LightClassApplicabilityType.LightClass else LightClassApplicabilityType.UltraLightClass
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.annotation.plugin.ide
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||
import com.intellij.psi.util.CachedValue
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
fun CachedAnnotationNames.getAnnotationNames(element: KtElement?): List<String> {
|
||||
if (element === null) return emptyList()
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return emptyList()
|
||||
return getNamesForModule(module)
|
||||
}
|
||||
|
||||
class CachedAnnotationNames(project: Project, private val annotationOptionPrefix: String) {
|
||||
|
||||
private val cache: CachedValue<ConcurrentMap<Module, List<String>>> = cachedValue(project) {
|
||||
CachedValueProvider.Result.create(
|
||||
ContainerUtil.createConcurrentWeakMap<Module, List<String>>(),
|
||||
ProjectRootModificationTracker.getInstance(project)
|
||||
)
|
||||
}
|
||||
|
||||
fun getNamesForModule(module: Module): List<String> {
|
||||
return cache.value.getOrPut(module) { module.getSpecialAnnotations(annotationOptionPrefix) }
|
||||
}
|
||||
|
||||
private fun <T> cachedValue(project: Project, result: () -> CachedValueProvider.Result<T>): CachedValue<T> {
|
||||
return CachedValuesManager.getManager(project).createCachedValue(result, false)
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@ package org.jetbrains.kotlin.annotation.plugin.ide
|
||||
import com.intellij.openapi.module.Module
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import java.io.File
|
||||
|
||||
fun Module.getSpecialAnnotations(prefix: String): List<String> {
|
||||
@@ -26,9 +29,9 @@ fun Module.getSpecialAnnotations(prefix: String): List<String> {
|
||||
val commonArgs = kotlinFacet.configuration.settings.compilerArguments ?: return emptyList()
|
||||
|
||||
return commonArgs.pluginOptions
|
||||
?.filter { it.startsWith(prefix) }
|
||||
?.map { it.substring(prefix.length) }
|
||||
?: emptyList()
|
||||
?.filter { it.startsWith(prefix) }
|
||||
?.map { it.substring(prefix.length) }
|
||||
?: emptyList()
|
||||
}
|
||||
|
||||
class AnnotationBasedCompilerPluginSetup(val options: List<PluginOption>, val classpath: List<String>) {
|
||||
@@ -36,10 +39,10 @@ class AnnotationBasedCompilerPluginSetup(val options: List<PluginOption>, val cl
|
||||
}
|
||||
|
||||
internal fun modifyCompilerArgumentsForPlugin(
|
||||
facet: KotlinFacet,
|
||||
setup: AnnotationBasedCompilerPluginSetup?,
|
||||
compilerPluginId: String,
|
||||
pluginName: String
|
||||
facet: KotlinFacet,
|
||||
setup: AnnotationBasedCompilerPluginSetup?,
|
||||
compilerPluginId: String,
|
||||
pluginName: String
|
||||
) {
|
||||
val facetSettings = facet.configuration.settings
|
||||
|
||||
@@ -49,7 +52,8 @@ internal fun modifyCompilerArgumentsForPlugin(
|
||||
/** See [CommonCompilerArguments.PLUGIN_OPTION_FORMAT] **/
|
||||
val newOptionsForPlugin = setup?.options?.map { "plugin:$compilerPluginId:${it.key}=${it.value}" } ?: emptyList()
|
||||
|
||||
val oldAllPluginOptions = (commonArguments.pluginOptions ?: emptyArray()).filterTo(mutableListOf()) { !it.startsWith("plugin:$compilerPluginId:") }
|
||||
val oldAllPluginOptions =
|
||||
(commonArguments.pluginOptions ?: emptyArray()).filterTo(mutableListOf()) { !it.startsWith("plugin:$compilerPluginId:") }
|
||||
val newAllPluginOptions = oldAllPluginOptions + newOptionsForPlugin
|
||||
|
||||
val oldPluginClasspaths = (commonArguments.pluginClasspaths ?: emptyArray()).filterTo(mutableListOf()) {
|
||||
@@ -66,4 +70,12 @@ internal fun modifyCompilerArgumentsForPlugin(
|
||||
commonArguments.pluginClasspaths = newPluginClasspaths.toTypedArray()
|
||||
|
||||
facetSettings.compilerArguments = commonArguments
|
||||
}
|
||||
}
|
||||
|
||||
val KtDeclaration.isOrdinaryClass
|
||||
get() = this is KtClass &&
|
||||
!this.hasModifier(KtTokens.INLINE_KEYWORD) &&
|
||||
!this.isAnnotation() &&
|
||||
!this.isInterface()
|
||||
|
||||
val KtDeclaration.isAnnotated get() = this.annotationEntries.isNotEmpty()
|
||||
|
||||
Reference in New Issue
Block a user