Move AllOpen UL support to separate extension

This commit is contained in:
Igor Yakovlev
2019-10-17 23:28:44 +03:00
parent 58b8d8868a
commit 8c65a9a2aa
10 changed files with 100 additions and 25 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.asJava
import com.intellij.psi.PsiModifier
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
@@ -32,4 +33,10 @@ interface UltraLightClassModifierExtension {
containingDeclaration: KtUltraLightClass,
fieldsList: MutableList<KtLightField>
) = Unit
fun interceptModalityBuilding(
declaration: KtDeclaration,
descriptor: Lazy<DeclarationDescriptor?>,
modifier: String
) = modifier
}
@@ -42,10 +42,7 @@ import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
import org.jetbrains.kotlin.asJava.elements.KtLightPsiReferenceList
import org.jetbrains.kotlin.asJava.hasInterfaceDefaultImpls
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.name.FqNameUnsafe
@@ -230,10 +227,12 @@ abstract class KtLightClassForSourceDeclaration(
if (isAbstract() || isSealed()) {
psiModifiers.add(PsiModifier.ABSTRACT)
} else if (!(classOrObject.hasModifier(OPEN_KEYWORD) || (classOrObject is KtClass && classOrObject.isEnum()))) {
// AllOpen can affect on modality of the member. We ought to check if the extension could override the modality
// Resolver will produce correct descriptor corresponding to modality from AllOpen.
// The easiest way to get new modality is to resolve the descriptor
if (!kotlinOrigin.isOrdinaryClass || getDescriptor()?.modality != Modality.OPEN) {
val descriptor = lazy { getDescriptor() }
var modifier = PsiModifier.FINAL
project.applyCompilerPlugins {
modifier = it.interceptModalityBuilding(kotlinOrigin, descriptor, modifier)
}
if (modifier == PsiModifier.FINAL) {
psiModifiers.add(PsiModifier.FINAL)
}
}
@@ -197,7 +197,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
fun ArrayList<KtLightField>.updateWithCompilerPlugins() = also {
val lazyDescriptor = lazy { getDescriptor() }
applyCompilerPlugins {
project.applyCompilerPlugins {
it.interceptFieldsBuilding(
declaration = kotlinOrigin,
descriptor = lazyDescriptor,
@@ -309,7 +309,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
addDelegatesToInterfaceMethods(result)
val lazyDescriptor = lazy { getDescriptor() }
applyCompilerPlugins {
project.applyCompilerPlugins {
it.interceptMethodsBuilding(
declaration = kotlinOrigin,
descriptor = lazyDescriptor,
@@ -321,10 +321,6 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
return result
}
private inline fun applyCompilerPlugins(body: (UltraLightClassModifierExtension) -> Unit) {
UltraLightClassModifierExtension.getInstances(project).forEach { body(it) }
}
private val _ownMethods: CachedValue<List<KtLightMethod>> = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result.create(
@@ -246,14 +246,15 @@ internal class UltraLightMembersCreator(
override fun hasModifierProperty(name: String): Boolean {
val modifierResult = hasModifier(name)
if (name != PsiModifier.FINAL || !outerDeclaration.isOrdinaryClass) return hasModifier(name)
//AllOpen can affect on modality of the member. We ought to check if the extension could override the modality
if (name != PsiModifier.FINAL) return modifierResult
if (!outerDeclaration.isOrdinaryClass) return modifierResult
// Resolver will produce correct descriptor corresponding to modality from AllOpen.
// The easiest way to get new modality is to resolve the descriptor
return (declaration.resolve() as? CallableMemberDescriptor)?.modality == Modality.FINAL
val descriptor = lazy { declaration.resolve() }
var modifier = PsiModifier.FINAL
project.applyCompilerPlugins {
modifier = it.interceptModalityBuilding(declaration, descriptor, modifier)
}
return modifier == PsiModifier.FINAL
}
private fun hasModifier(name: String): Boolean {
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.asJava.classes
import com.google.common.collect.Lists
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.impl.cache.ModifierFlags
import com.intellij.psi.impl.cache.TypeInfo
@@ -16,6 +17,7 @@ import com.intellij.psi.impl.light.*
import com.intellij.util.BitUtil.isSet
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
@@ -390,5 +392,9 @@ fun KotlinType.tryResolveMarkerInterfaceFQName(): String? {
return null
}
internal inline fun Project.applyCompilerPlugins(body: (UltraLightClassModifierExtension) -> Unit) {
UltraLightClassModifierExtension.getInstances(this).forEach { body(it) }
}
internal fun <L : Any> L.invalidAccess(): Nothing =
error("Cls delegate shouldn't be loaded for not too complex ultra-light classes! Qualified name: ${javaClass.name}")
+1
View File
@@ -198,6 +198,7 @@
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.samWithReceiver.ide.IdeSamWithReceiverComponentContributor"/>
<declarationAttributeAltererExtension implementation="org.jetbrains.kotlin.allopen.ide.IdeAllOpenDeclarationAttributeAltererExtension"/>
<ultraLightClassModifierExtension implementation="org.jetbrains.kotlin.allopen.ide.AllOpenUltraLightClassModifierExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgComponentContainerContributor"/>
<expressionCodegenExtension implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgExpressionCodegenExtension"/>
+1
View File
@@ -198,6 +198,7 @@
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.samWithReceiver.ide.IdeSamWithReceiverComponentContributor"/>
<declarationAttributeAltererExtension implementation="org.jetbrains.kotlin.allopen.ide.IdeAllOpenDeclarationAttributeAltererExtension"/>
<ultraLightClassModifierExtension implementation="org.jetbrains.kotlin.allopen.ide.AllOpenUltraLightClassModifierExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgComponentContainerContributor"/>
<expressionCodegenExtension implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgExpressionCodegenExtension"/>
@@ -43,6 +43,7 @@ dependencies {
testRuntimeOnly(intellijDep())
Platform[192].orHigher {
compileOnly(intellijPluginDep("java"))
testCompileOnly(intellijPluginDep("java"))
testRuntimeOnly(intellijPluginDep("java"))
}
@@ -0,0 +1,67 @@
/*
* 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.allopen.ide
import org.jetbrains.kotlin.descriptors.*
/*
* 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.
*/
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiModifier
import org.jetbrains.kotlin.annotation.plugin.ide.CachedAnnotationNames
import org.jetbrains.kotlin.annotation.plugin.ide.getAnnotationNames
import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension
import org.jetbrains.kotlin.extensions.AnnotationBasedExtension
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
import org.jetbrains.kotlin.util.isAnnotated
import org.jetbrains.kotlin.util.isOrdinaryClass
class AllOpenUltraLightClassModifierExtension(project: Project) :
AnnotationBasedExtension,
UltraLightClassModifierExtension {
private val cachedAnnotationsNames = CachedAnnotationNames(project, ALL_OPEN_ANNOTATION_OPTION_PREFIX)
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List<String> =
cachedAnnotationsNames.getAnnotationNames(modifierListOwner)
private val KtDeclaration.isMethodOrProperty get() = this is KtProperty || this is KtPropertyAccessor || this is KtFunction || (this is KtParameter && this.isPropertyParameter())
private fun isSuitableDeclaration(declaration: KtDeclaration): Boolean {
if (getAnnotationFqNames(declaration).isEmpty()) return false
val declarationToCheck = if (declaration.isMethodOrProperty) declaration.containingClass() else declaration
declarationToCheck ?: return false
if (!declarationToCheck.isOrdinaryClass || declarationToCheck !is KtClassOrObject) return false
if (declarationToCheck.superTypeListEntries.isEmpty() && !declarationToCheck.isAnnotated) return false
return true
}
override fun interceptModalityBuilding(
declaration: KtDeclaration,
descriptor: Lazy<DeclarationDescriptor?>,
modifier: String
): String {
//Final can be altered to Open only
if (modifier != PsiModifier.FINAL) return modifier
if (!isSuitableDeclaration(declaration)) return modifier
// Resolver will produce correct descriptor corresponding to modality from AllOpen.
// The easiest way to get new modality is to resolve the descriptor
return if ((descriptor.value as? MemberDescriptor)?.modality == Modality.OPEN) PsiModifier.OPEN else modifier
}
}
@@ -3,11 +3,10 @@
* 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.noarg
package org.jetbrains.kotlin.allopen
import com.intellij.lang.jvm.JvmModifier
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.allopen.AbstractAllOpenDeclarationAttributeAltererExtension
import org.jetbrains.kotlin.allopen.ide.ALL_OPEN_ANNOTATION_OPTION_PREFIX
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.idea.facet.KotlinFacet
@@ -17,11 +16,8 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class TestNoArgForLightClass : KotlinLightCodeInsightFixtureTestCase() {
class TestAllOpenForLightClass : KotlinLightCodeInsightFixtureTestCase() {
companion object {
val allOpenAnnotationName = AbstractAllOpenDeclarationAttributeAltererExtension.ANNOTATIONS_FOR_TESTS.first()