From 19db4304bd616cbc9b3abfdc60fbead6f04d7826 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 25 May 2017 17:31:01 +0300 Subject: [PATCH] Use clsDelegate to calculate hasModifierProperty("final") for light psi AllOpen plugin can make some changes and we don't have the tools to make correct decision based on psi #KT-17857 Fixed --- .../KtLightClassForSourceDeclaration.kt | 26 ++++++++++++++++--- .../asJava/elements/KtLightMemberImpl.kt | 4 +++ .../AllOpenAnnotatedClasses.java | 25 ++++++++++++++++++ .../ideRegression/AllOpenAnnotatedClasses.kt | 26 +++++++++++++++++++ .../resolve/IdeLightClassTestGenerated.java | 6 +++++ 5 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.java create mode 100644 compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.kt diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index 50c7a35332a..f6f87cf30b6 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -44,8 +44,8 @@ import org.jetbrains.kotlin.asJava.builder.LightClassData import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForClassOrObject import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass -import org.jetbrains.kotlin.asJava.elements.KtLightSimpleModifierList import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +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.KotlinBuiltIns @@ -180,7 +180,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC override fun getName(): String? = classOrObject.nameAsName?.asString() - private val _modifierList: PsiModifierList by lazyPub { KtLightSimpleModifierList(this@KtLightClassForSourceDeclaration, computeModifiers()) } + private val _modifierList: PsiModifierList by lazyPub { KtLightClassModifierList(this) } override fun getModifierList(): PsiModifierList? = _modifierList @@ -452,8 +452,28 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC override val originKind: LightClassOriginKind get() = LightClassOriginKind.SOURCE + + private class KtLightClassModifierList(containingClass: KtLightClassForSourceDeclaration) + : KtLightModifierList(containingClass) { + + private val modifiers by lazyPub { containingClass.computeModifiers() } + + override fun hasModifierProperty(name: String): Boolean { + if (name != PsiModifier.FINAL) { + return name in modifiers + } + + val isFinalByPsi = PsiModifier.FINAL in modifiers + // annotations can make class open via 'allopen' plugin + if (!owner.isPossiblyAffectedByAllOpen() || !isFinalByPsi) return isFinalByPsi + + return clsDelegate.hasModifierProperty(PsiModifier.FINAL) + } + } } +fun KtLightClassForSourceDeclaration.isPossiblyAffectedByAllOpen() = !isAnnotationType && !isInterface && kotlinOrigin.annotationEntries.isNotEmpty() + fun getOutermostClassOrObject(classOrObject: KtClassOrObject): KtClassOrObject { val outermostClass = KtPsiUtil.getOutermostClassOrObject(classOrObject) ?: throw IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.text) @@ -487,4 +507,4 @@ fun KtClassOrObject.defaultJavaAncestorQualifiedName(): String? { isInterface() -> CommonClassNames.JAVA_LANG_OBJECT // see com.intellij.psi.impl.PsiClassImplUtil.getSuperClass else -> CommonClassNames.JAVA_LANG_OBJECT } -} +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt index c7f8a13d9f6..d913a071b54 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt @@ -24,6 +24,8 @@ import org.jetbrains.kotlin.asJava.builder.LightElementOrigin import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration +import org.jetbrains.kotlin.asJava.classes.isPossiblyAffectedByAllOpen import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtDeclaration @@ -81,6 +83,8 @@ private class KtLightMemberModifierList( name == PsiModifier.ABSTRACT && isImplementationInInterface() -> false // pretend this method behaves like a default method name == PsiModifier.DEFAULT && isImplementationInInterface() -> true + name == PsiModifier.FINAL && ((owner.containingClass as? KtLightClassForSourceDeclaration)?.isPossiblyAffectedByAllOpen() ?: false) -> + clsDelegate.hasModifierProperty(name) dummyDelegate != null -> { when { name in visibilityModifiers && isMethodOverride() -> diff --git a/compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.java b/compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.java new file mode 100644 index 00000000000..e11ea9960a4 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.java @@ -0,0 +1,25 @@ +@test.AllOpen +public class C { + private final int p; + + public void f() { /* compiled code */ } + + public void g() { /* compiled code */ } + + public int getP() { /* compiled code */ } + + public C() { /* compiled code */ } + + public static final class D { + public final void z() { /* compiled code */ } + + public D() { /* compiled code */ } + } + + @test.AllOpen + public static class H { + public void j() { /* compiled code */ } + + public H() { /* compiled code */ } + } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.kt b/compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.kt new file mode 100644 index 00000000000..c7217cf8456 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.kt @@ -0,0 +1,26 @@ +// test.C +package test + +annotation class AllOpen + +@AllOpen +class C { + fun f() {} + + fun g() {} + + val p: Int + + class D { + fun z() { + + } + } + + @AllOpen + class H { + fun j() {} + } +} + +// LAZINESS:NoLaziness \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java index 0acdb4964e8..3064c928bb6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java @@ -236,6 +236,12 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/ideRegression"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("AllOpenAnnotatedClasses.kt") + public void testAllOpenAnnotatedClasses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.kt"); + doTest(fileName); + } + @TestMetadata("ImplementingCharSequenceAndNumber.kt") public void testImplementingCharSequenceAndNumber() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/ideRegression/ImplementingCharSequenceAndNumber.kt");