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
This commit is contained in:
Pavel V. Talanov
2017-05-25 17:31:01 +03:00
parent f3f2379e5a
commit 19db4304bd
5 changed files with 84 additions and 3 deletions
@@ -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<KtLightClassForSourceDeclaration>(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
}
}
}
@@ -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() ->
@@ -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 */ }
}
}
@@ -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
@@ -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");