KtLightClassForSourceDeclaration: use psi based resolve to speedup isInheritor checks
This commit is contained in:
@@ -27,6 +27,4 @@ abstract class KtLazyLightClass(manager: PsiManager) : KtLightClassBase(manager)
|
|||||||
|
|
||||||
override fun getOwnFields() = lightClassData.getOwnFields(this)
|
override fun getOwnFields() = lightClassData.getOwnFields(this)
|
||||||
override fun getOwnMethods() = lightClassData.getOwnMethods(this)
|
override fun getOwnMethods() = lightClassData.getOwnMethods(this)
|
||||||
override fun getSuperTypes() = lightClassData.supertypes
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+71
-6
@@ -17,11 +17,15 @@
|
|||||||
package org.jetbrains.kotlin.asJava.classes
|
package org.jetbrains.kotlin.asJava.classes
|
||||||
|
|
||||||
import com.google.common.collect.Lists
|
import com.google.common.collect.Lists
|
||||||
|
import com.intellij.openapi.components.ServiceManager
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Comparing
|
import com.intellij.openapi.util.Comparing
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.impl.PsiSubstitutorImpl
|
||||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||||
|
import com.intellij.psi.impl.source.PsiImmediateClassType
|
||||||
import com.intellij.psi.scope.PsiScopeProcessor
|
import com.intellij.psi.scope.PsiScopeProcessor
|
||||||
import com.intellij.psi.search.SearchScope
|
import com.intellij.psi.search.SearchScope
|
||||||
import com.intellij.psi.stubs.IStubElementType
|
import com.intellij.psi.stubs.IStubElementType
|
||||||
@@ -31,6 +35,8 @@ import com.intellij.psi.util.CachedValuesManager
|
|||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import com.intellij.util.containers.ContainerUtil
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
|
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
|
||||||
|
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.UNSURE
|
||||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder
|
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder
|
||||||
@@ -174,12 +180,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
|||||||
|
|
||||||
override fun getName(): String? = classOrObject.nameAsName?.asString()
|
override fun getName(): String? = classOrObject.nameAsName?.asString()
|
||||||
|
|
||||||
private val _modifierList: PsiModifierList by lazyPub {
|
private val _modifierList: PsiModifierList by lazyPub { KtLightModifierListWithExplicitModifiers(this@KtLightClassForSourceDeclaration, computeModifiers()) }
|
||||||
object : KtLightModifierListWithExplicitModifiers(this@KtLightClassForSourceDeclaration, computeModifiers()) {
|
|
||||||
override val delegate: PsiAnnotationOwner
|
|
||||||
get() = this@KtLightClassForSourceDeclaration.delegate.modifierList!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getModifierList(): PsiModifierList? = _modifierList
|
override fun getModifierList(): PsiModifierList? = _modifierList
|
||||||
|
|
||||||
@@ -274,6 +275,8 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
|||||||
override fun isValid(): Boolean = classOrObject.isValid
|
override fun isValid(): Boolean = classOrObject.isValid
|
||||||
|
|
||||||
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean {
|
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean {
|
||||||
|
LightClassInheritanceHelper.getService(project).isInheritor(this, baseClass, checkDeep).ifSure { return it }
|
||||||
|
|
||||||
val qualifiedName: String?
|
val qualifiedName: String?
|
||||||
if (baseClass is KtLightClassForSourceDeclaration) {
|
if (baseClass is KtLightClassForSourceDeclaration) {
|
||||||
val baseDescriptor = baseClass.getDescriptor()
|
val baseDescriptor = baseClass.getDescriptor()
|
||||||
@@ -412,6 +415,41 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
|||||||
private val LOG = Logger.getInstance(KtLightClassForSourceDeclaration::class.java)
|
private val LOG = Logger.getInstance(KtLightClassForSourceDeclaration::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getSupers(): Array<PsiClass> {
|
||||||
|
if (classOrObject.superTypeListEntries.isEmpty()) {
|
||||||
|
return getSupertypeByPsi()?.let { arrayOf(it.resolve()!!) } ?: emptyArray()
|
||||||
|
}
|
||||||
|
return clsDelegate.supers
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSuperTypes(): Array<PsiClassType> {
|
||||||
|
if (classOrObject.superTypeListEntries.isEmpty()) {
|
||||||
|
return getSupertypeByPsi()?.let { arrayOf<PsiClassType>(it) } ?: emptyArray()
|
||||||
|
}
|
||||||
|
return clsDelegate.superTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSupertypeByPsi(): PsiImmediateClassType? {
|
||||||
|
return classOrObject.defaultJavaAncestorQualifiedName()?.let {
|
||||||
|
ancestorFqName ->
|
||||||
|
JavaPsiFacade.getInstance(project).findClass(ancestorFqName, resolveScope)?.let {
|
||||||
|
PsiImmediateClassType(it, createSubstitutor(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createSubstitutor(ancestor: PsiClass): PsiSubstitutor {
|
||||||
|
if (ancestor.qualifiedName != CommonClassNames.JAVA_LANG_ENUM) {
|
||||||
|
return PsiSubstitutor.EMPTY
|
||||||
|
}
|
||||||
|
val javaLangEnumsTypeParameter = ancestor.typeParameters.firstOrNull() ?: return PsiSubstitutor.EMPTY
|
||||||
|
return PsiSubstitutorImpl.createSubstitutor(
|
||||||
|
mapOf(
|
||||||
|
javaLangEnumsTypeParameter to PsiImmediateClassType(this, PsiSubstitutor.EMPTY)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override val originKind: LightClassOriginKind
|
override val originKind: LightClassOriginKind
|
||||||
get() = LightClassOriginKind.SOURCE
|
get() = LightClassOriginKind.SOURCE
|
||||||
}
|
}
|
||||||
@@ -423,3 +461,30 @@ fun getOutermostClassOrObject(classOrObject: KtClassOrObject): KtClassOrObject {
|
|||||||
return outermostClass
|
return outermostClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LightClassInheritanceHelper {
|
||||||
|
fun isInheritor(
|
||||||
|
lightClass: KtLightClassForSourceDeclaration,
|
||||||
|
baseClass: PsiClass,
|
||||||
|
checkDeep: Boolean
|
||||||
|
): ImpreciseResolveResult
|
||||||
|
|
||||||
|
object NoHelp : LightClassInheritanceHelper {
|
||||||
|
override fun isInheritor(lightClass: KtLightClassForSourceDeclaration, baseClass: PsiClass, checkDeep: Boolean) = UNSURE
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getService(project: Project): LightClassInheritanceHelper =
|
||||||
|
ServiceManager.getService(project, LightClassInheritanceHelper::class.java) ?: NoHelp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KtClassOrObject.defaultJavaAncestorQualifiedName(): String? {
|
||||||
|
if (this !is KtClass) return CommonClassNames.JAVA_LANG_OBJECT
|
||||||
|
|
||||||
|
return when {
|
||||||
|
isAnnotation() -> CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION
|
||||||
|
isEnum() -> CommonClassNames.JAVA_LANG_ENUM
|
||||||
|
isInterface() -> CommonClassNames.JAVA_LANG_OBJECT // see com.intellij.psi.impl.PsiClassImplUtil.getSuperClass
|
||||||
|
else -> CommonClassNames.JAVA_LANG_OBJECT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.caches.resolve.lightClasses
|
||||||
|
|
||||||
|
import com.intellij.psi.CommonClassNames
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
|
||||||
|
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.*
|
||||||
|
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||||
|
import org.jetbrains.kotlin.asJava.classes.LightClassInheritanceHelper
|
||||||
|
import org.jetbrains.kotlin.asJava.classes.defaultJavaAncestorQualifiedName
|
||||||
|
import org.jetbrains.kotlin.idea.search.PsiBasedClassResolver
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
|
||||||
|
class IdeLightClassInheritanceHelper : LightClassInheritanceHelper {
|
||||||
|
override fun isInheritor(
|
||||||
|
lightClass: KtLightClassForSourceDeclaration,
|
||||||
|
baseClass: PsiClass,
|
||||||
|
checkDeep: Boolean
|
||||||
|
): ImpreciseResolveResult {
|
||||||
|
val classOrObject = lightClass.kotlinOrigin
|
||||||
|
val entries = classOrObject.superTypeListEntries
|
||||||
|
val hasSuperClass = entries.any { it is KtSuperTypeCallEntry }
|
||||||
|
if (baseClass.qualifiedName == classOrObject.defaultJavaAncestorQualifiedName() && (!hasSuperClass || checkDeep)) {
|
||||||
|
return MATCH
|
||||||
|
}
|
||||||
|
if (checkDeep && baseClass.qualifiedName == CommonClassNames.JAVA_LANG_OBJECT) {
|
||||||
|
return MATCH
|
||||||
|
}
|
||||||
|
val amongEntries = isAmongEntries(baseClass, entries)
|
||||||
|
return when {
|
||||||
|
!checkDeep -> amongEntries
|
||||||
|
amongEntries == MATCH -> MATCH
|
||||||
|
else -> UNSURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isAmongEntries(baseClass: PsiClass, entries: List<KtSuperTypeListEntry>): ImpreciseResolveResult {
|
||||||
|
val psiBasedResolver = PsiBasedClassResolver(baseClass)
|
||||||
|
entries@ for (entry in entries) {
|
||||||
|
val reference: KtSimpleNameExpression = entry.typeAsUserType?.referenceExpression ?: continue@entries
|
||||||
|
when (psiBasedResolver.canBeTargetReference(reference)) {
|
||||||
|
MATCH -> return MATCH
|
||||||
|
NO_MATCH -> continue@entries
|
||||||
|
UNSURE -> return UNSURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO_MATCH
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-10
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.caches.resolve.lightClasses
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiClassType
|
|
||||||
import com.intellij.psi.PsiMember
|
import com.intellij.psi.PsiMember
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||||
@@ -65,7 +64,7 @@ sealed class LazyLightClassDataHolder(
|
|||||||
|
|
||||||
// for facade or defaultImpls
|
// for facade or defaultImpls
|
||||||
override fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass): LightClassData =
|
override fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass): LightClassData =
|
||||||
LazyLightClassData(relyOnDummySupertypes = true) { lightClassBuilderResult ->
|
LazyLightClassData { lightClassBuilderResult ->
|
||||||
findDelegate(lightClassBuilderResult.stub)
|
findDelegate(lightClassBuilderResult.stub)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +72,7 @@ sealed class LazyLightClassDataHolder(
|
|||||||
builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider
|
builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider
|
||||||
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForClass {
|
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForClass {
|
||||||
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
|
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
|
||||||
LazyLightClassData(relyOnDummySupertypes = classOrObject.getSuperTypeList() == null) { lightClassBuilderResult ->
|
LazyLightClassData { lightClassBuilderResult ->
|
||||||
lightClassBuilderResult.stub.findDelegate(classOrObject)
|
lightClassBuilderResult.stub.findDelegate(classOrObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,7 +82,6 @@ sealed class LazyLightClassDataHolder(
|
|||||||
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForFacade
|
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForFacade
|
||||||
|
|
||||||
private inner class LazyLightClassData(
|
private inner class LazyLightClassData(
|
||||||
private val relyOnDummySupertypes: Boolean,
|
|
||||||
findDelegate: (LightClassBuilderResult) -> PsiClass
|
findDelegate: (LightClassBuilderResult) -> PsiClass
|
||||||
) : LightClassData {
|
) : LightClassData {
|
||||||
override val clsDelegate: PsiClass by lazyPub { findDelegate(exactResult) }
|
override val clsDelegate: PsiClass by lazyPub { findDelegate(exactResult) }
|
||||||
@@ -133,17 +131,13 @@ sealed class LazyLightClassDataHolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val supertypes: Array<PsiClassType>
|
|
||||||
get() = if (relyOnDummySupertypes && dummyDelegate != null) dummyDelegate!!.superTypes else clsDelegate.superTypes
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : PsiMember> T?.assertMatches(dummyMember: T, containingClass: KtLightClass): T {
|
private fun <T : PsiMember> T?.assertMatches(dummyMember: T, containingClass: KtLightClass): T {
|
||||||
if (this == null) throw LazyLightClassMemberMatchingError.NoMatch(dummyMember, containingClass)
|
if (this == null) throw LazyLightClassMemberMatchingError.NoMatch(dummyMember, containingClass)
|
||||||
|
|
||||||
val parameterCountMatches = (this as? PsiMethod)?.parameterList?.parametersCount ?: 0 ==
|
val parameterCountMatches = (this as? PsiMethod)?.parameterList?.parametersCount ?: 0 ==
|
||||||
(dummyMember as? PsiMethod)?.parameterList?.parametersCount ?: 0
|
(dummyMember as? PsiMethod)?.parameterList?.parametersCount ?: 0
|
||||||
if (this.memberIndex != dummyMember.memberIndex || !parameterCountMatches) {
|
if (this.memberIndex != dummyMember.memberIndex || !parameterCountMatches) {
|
||||||
throw LazyLightClassMemberMatchingError.WrongMatch(this, dummyMember, containingClass)
|
throw LazyLightClassMemberMatchingError.WrongMatch(this, dummyMember, containingClass)
|
||||||
}
|
}
|
||||||
@@ -157,7 +151,6 @@ private fun shouldRollbackOptimization(origin: LightMemberOriginForDeclaration?)
|
|||||||
|
|
||||||
if (!kotlinDeclaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
|
if (!kotlinDeclaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
|
||||||
|
|
||||||
|
|
||||||
val possiblyOverridesInternalMember = kotlinDeclaration.name?.let { anyInternalMembersWithThisName(it, kotlinDeclaration.project) } ?: false
|
val possiblyOverridesInternalMember = kotlinDeclaration.name?.let { anyInternalMembersWithThisName(it, kotlinDeclaration.project) } ?: false
|
||||||
return possiblyOverridesInternalMember
|
return possiblyOverridesInternalMember
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,6 +305,9 @@
|
|||||||
<projectService serviceInterface="org.jetbrains.kotlin.analyzer.LanguageSettingsProvider"
|
<projectService serviceInterface="org.jetbrains.kotlin.analyzer.LanguageSettingsProvider"
|
||||||
serviceImplementation="org.jetbrains.kotlin.idea.compiler.LanguageVersionSettingsProviderImpl"/>
|
serviceImplementation="org.jetbrains.kotlin.idea.compiler.LanguageVersionSettingsProviderImpl"/>
|
||||||
|
|
||||||
|
<projectService serviceInterface="org.jetbrains.kotlin.asJava.classes.LightClassInheritanceHelper"
|
||||||
|
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.lightClasses.IdeLightClassInheritanceHelper"/>
|
||||||
|
|
||||||
<projectService serviceInterface="org.jetbrains.kotlin.config.KotlinFacetSettingsProvider"
|
<projectService serviceInterface="org.jetbrains.kotlin.config.KotlinFacetSettingsProvider"
|
||||||
serviceImplementation="org.jetbrains.kotlin.idea.facet.KotlinFacetSettingsProviderImpl"/>
|
serviceImplementation="org.jetbrains.kotlin.idea.facet.KotlinFacetSettingsProviderImpl"/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user