UltraLight implementation for local and anonymous declarations

This commit is contained in:
Igor Yakovlev
2019-07-08 21:27:18 +03:00
parent d6c54b845b
commit 79a603768a
18 changed files with 389 additions and 178 deletions
@@ -1,31 +1,20 @@
/*
* Copyright 2010-2016 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.
* 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.asJava.classes
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.*
import com.intellij.psi.impl.InheritanceImplUtil
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.reference.SoftReference
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.DescriptorUtils
internal open class KtLightClassForAnonymousDeclaration(classOrObject: KtClassOrObject) :
KtLightClassForLocalDeclaration(classOrObject), PsiAnonymousClass {
KtLightClassForLocalDeclaration(classOrObject), PsiAnonymousClass {
private var cachedBaseType: SoftReference<PsiClassType>? = null
@@ -33,33 +22,13 @@ internal open class KtLightClassForAnonymousDeclaration(classOrObject: KtClassOr
return JavaPsiFacade.getElementFactory(classOrObject.project).createReferenceElementByType(baseClassType)
}
private val firstSupertypeFQName: String
get() {
val descriptor = getDescriptor() ?: return CommonClassNames.JAVA_LANG_OBJECT
val superTypes = descriptor.typeConstructor.supertypes
if (superTypes.isEmpty()) return CommonClassNames.JAVA_LANG_OBJECT
val superType = superTypes.iterator().next()
val superClassDescriptor = superType.constructor.declarationDescriptor
if (superClassDescriptor == null) {
LOG.error("No declaration descriptor for supertype " + superType + " of " + getDescriptor())
// return java.lang.Object for recovery
return CommonClassNames.JAVA_LANG_OBJECT
}
return DescriptorUtils.getFqName(superClassDescriptor).asString()
}
@Synchronized override fun getBaseClassType(): PsiClassType {
@Synchronized
override fun getBaseClassType(): PsiClassType {
var type: PsiClassType? = null
if (cachedBaseType != null) type = cachedBaseType!!.get()
if (type != null && type.isValid) return type
val firstSupertypeFQName = firstSupertypeFQName
val firstSupertypeFQName = getFirstSupertypeFQNameForAnonymousDeclaration()
for (superType in superTypes) {
val superClass = superType.resolve()
if (superClass != null && firstSupertypeFQName == superClass.qualifiedName) {
@@ -106,20 +75,36 @@ internal open class KtLightClassForAnonymousDeclaration(classOrObject: KtClassOr
return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep)
}
override fun getNameIdentifier() = null
override fun getNameIdentifier(): KtLightIdentifier? = null
override fun getModifierList(): PsiModifierList? = null
override fun hasModifierProperty(name: String): Boolean = name == PsiModifier.FINAL
override fun getExtendsList() = null
override fun getImplementsList() = null
override fun getExtendsList(): PsiReferenceList? = null
override fun getImplementsList(): PsiReferenceList? = null
override fun getContainingClass(): PsiClass? = null
override fun isInterface() = false
override fun isAnnotationType() = false
override fun getTypeParameterList() = null
override fun getTypeParameterList(): PsiTypeParameterList? = null
override fun isEnum() = false
override fun copy(): PsiElement = KtLightClassForAnonymousDeclaration(classOrObject)
companion object {
private val LOG = Logger.getInstance(KtLightClassForAnonymousDeclaration::class.java)
fun KtLightClassForSourceDeclaration.getFirstSupertypeFQNameForAnonymousDeclaration(): String {
val descriptor = getDescriptor() ?: return CommonClassNames.JAVA_LANG_OBJECT
val superTypes = descriptor.typeConstructor.supertypes
if (superTypes.isEmpty()) return CommonClassNames.JAVA_LANG_OBJECT
val superType = superTypes.iterator().next()
val superClassDescriptor = superType.constructor.declarationDescriptor
if (superClassDescriptor === null) {
// return java.lang.Object for recovery
return CommonClassNames.JAVA_LANG_OBJECT
}
return DescriptorUtils.getFqName(superClassDescriptor).asString()
}
}
}
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2016 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.
* 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.asJava.classes
@@ -22,14 +11,16 @@ import com.intellij.psi.PsiMethod
import com.intellij.psi.impl.light.LightClass
import com.intellij.psi.impl.light.LightMethod
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
open class KtLightClassForLocalDeclaration(
classOrObject: KtClassOrObject
classOrObject: KtClassOrObject
) : KtLightClassForSourceDeclaration(classOrObject) {
override val myInnersCache: KotlinClassInnerStuffCache =
KotlinClassInnerStuffCache(
@@ -45,80 +36,82 @@ open class KtLightClassForLocalDeclaration(
)
override fun copy(): PsiElement = KtLightClassForLocalDeclaration(classOrObject.copy() as KtClassOrObject)
override fun getQualifiedName(): String? = null
override fun getParent() = _parent
private val _parent: PsiElement? by lazyPub(this::computeParent)
private val _parent: PsiElement? by lazyPub { getParentForLocalDeclaration(classOrObject) }
private fun computeParent(): PsiElement? {
fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? {
if (method == null || name == null) return null
companion object {
fun getParentForLocalDeclaration(classOrObject: KtClassOrObject): PsiElement? {
var containingClass: PsiClass? = method.containingClass ?: return null
fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? {
if (method == null || name == null) return null
val currentFileName = classOrObject.containingFile.name
var containingClass: PsiClass? = method.containingClass ?: return null
var createWrapper = forceMethodWrapping
// Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views
if (containingClass is KtLightClassForFacade) {
containingClass = object : LightClass(containingClass as KtLightClassForFacade, KotlinLanguage.INSTANCE) {
override fun getName(): String? {
return currentFileName
val currentFileName = classOrObject.containingFile.name
var createWrapper = forceMethodWrapping
// Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views
if (containingClass is KtLightClassForFacade) {
containingClass = object : LightClass(containingClass as KtLightClassForFacade, KotlinLanguage.INSTANCE) {
override fun getName(): String? = currentFileName
}
createWrapper = true
}
if (createWrapper) {
return object : LightMethod(classOrObject.manager, method, containingClass!!, KotlinLanguage.INSTANCE) {
override fun getParent(): PsiElement = getContainingClass()
override fun getName(): String = name
}
}
createWrapper = true
return method
}
if (createWrapper) {
return object : LightMethod(myManager, method, containingClass!!, KotlinLanguage.INSTANCE) {
override fun getParent(): PsiElement {
return getContainingClass()
}
override fun getName(): String {
return name
}
}
}
return method
}
var declaration: PsiElement? = KtPsiUtil.getTopmostParentOfTypes(
var declaration: PsiElement? = KtPsiUtil.getTopmostParentOfTypes(
classOrObject,
KtNamedFunction::class.java,
KtConstructor::class.java,
KtProperty::class.java,
KtAnonymousInitializer::class.java,
KtParameter::class.java)
KtParameter::class.java
)
if (declaration is KtParameter) {
declaration = declaration.getStrictParentOfType<KtNamedDeclaration>()
}
if (declaration is KtFunction) {
return getParentByPsiMethod(LightClassUtil.getLightClassMethod(declaration), declaration.name, false)
}
// Represent the property as a fake method with the same name
if (declaration is KtProperty) {
return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(declaration).getter, declaration.name, true)
}
if (declaration is KtAnonymousInitializer) {
val parent = declaration.parent
val grandparent = parent.parent
if (parent is KtClassBody && grandparent is KtClassOrObject) {
return grandparent.toLightClass()
if (declaration is KtParameter) {
declaration = declaration.getStrictParentOfType<KtNamedDeclaration>()
}
}
if (declaration is KtClass) {
return declaration.toLightClass()
if (declaration is KtFunction) {
return getParentByPsiMethod(
LightClassUtil.getLightClassMethod(declaration),
declaration.name,
forceMethodWrapping = false
)
}
// Represent the property as a fake method with the same name
if (declaration is KtProperty) {
return getParentByPsiMethod(
LightClassUtil.getLightClassPropertyMethods(declaration).getter,
declaration.name,
forceMethodWrapping = true
)
}
if (declaration is KtAnonymousInitializer) {
val parent = declaration.parent
val grandparent = parent.parent
if (parent is KtClassBody && grandparent is KtClassOrObject) {
return grandparent.toLightClass()
}
}
return if (declaration is KtClass) declaration.toLightClass() else null
}
return null
}
}
@@ -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.asJava.classes
import com.intellij.psi.*
import com.intellij.psi.impl.InheritanceImplUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClassForAnonymousDeclaration.Companion.getFirstSupertypeFQNameForAnonymousDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.psi.KtClassOrObject
open class KtUltraLightClassForAnonymousDeclaration(classOrObject: KtClassOrObject, support: KtUltraLightSupport) :
KtUltraLightClassForLocalDeclaration(classOrObject, support), PsiAnonymousClass {
override fun getBaseClassReference() =
JavaPsiFacade.getElementFactory(classOrObject.project).createReferenceElementByType(baseClassType)
private val _baseClassType by lazyPub {
val firstSupertypeFQName = getFirstSupertypeFQNameForAnonymousDeclaration()
if (firstSupertypeFQName == CommonClassNames.JAVA_LANG_OBJECT) {
return@lazyPub PsiType.getJavaLangObject(kotlinOrigin.manager, resolveScope)
}
extendsListTypes.find { it.resolve()?.qualifiedName == firstSupertypeFQName }?.let { return@lazyPub it }
implementsListTypes.find { it.resolve()?.qualifiedName == firstSupertypeFQName }?.let { return@lazyPub it }
PsiType.getJavaLangObject(kotlinOrigin.manager, resolveScope)
}
override fun getBaseClassType(): PsiClassType = _baseClassType
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
val aClass = other as KtUltraLightClassForAnonymousDeclaration
return classOrObject == aClass.classOrObject
}
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean {
if (baseClass is KtLightClassForSourceDeclaration) {
return super.isInheritor(baseClass, checkDeep)
}
return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep)
}
override fun hashCode(): Int = classOrObject.hashCode()
override fun getArgumentList(): PsiExpressionList? = null
override fun isInQualifiedNew(): Boolean = false
override fun getName(): String? = null
override fun getNameIdentifier(): KtLightIdentifier? = null
override fun getModifierList(): PsiModifierList? = null
override fun hasModifierProperty(name: String): Boolean = name == PsiModifier.FINAL
override fun getContainingClass(): PsiClass? = null
override fun isInterface() = false
override fun isAnnotationType() = false
override fun getTypeParameterList(): PsiTypeParameterList? = null
override fun isEnum() = false
override fun copy() = KtUltraLightClassForAnonymousDeclaration(classOrObject, support)
}
@@ -0,0 +1,24 @@
/*
* 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.asJava.classes
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration.Companion.getParentForLocalDeclaration
import org.jetbrains.kotlin.psi.KtClassOrObject
open class KtUltraLightClassForLocalDeclaration(
classOrObject: KtClassOrObject,
support: KtUltraLightSupport
) : KtUltraLightClass(classOrObject, support) {
private val _parent: PsiElement? by lazyPub { getParentForLocalDeclaration(classOrObject) }
override fun copy() = KtUltraLightClassForLocalDeclaration(classOrObject.copy() as KtClassOrObject, support)
override fun getQualifiedName(): String? = null
override fun getParent() = _parent
}
@@ -157,8 +157,7 @@ internal class UltraLightMembersCreator(
): KtLightMethod {
val isConstructor = ktFunction is KtConstructor<*>
val name =
if (isConstructor)
containingClass.name
if (isConstructor) containingClass.name
else computeMethodName(ktFunction, ktFunction.name ?: SpecialNames.NO_NAME_PROVIDED.asString(), MethodType.REGULAR)
val method = lightMethod(name.orEmpty(), ktFunction, forceStatic, forcePrivate)
@@ -12,9 +12,7 @@ import com.intellij.psi.impl.cache.TypeInfo
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
import com.intellij.psi.impl.compiled.SignatureParsing
import com.intellij.psi.impl.compiled.StubBuildingVisitor
import com.intellij.psi.impl.light.LightMethodBuilder
import com.intellij.psi.impl.light.LightModifierList
import com.intellij.psi.impl.light.LightParameterListBuilder
import com.intellij.psi.impl.light.*
import com.intellij.util.BitUtil.isSet
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
@@ -29,9 +27,10 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -40,6 +39,7 @@ import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.replace
@@ -177,6 +177,15 @@ fun createTypeFromCanonicalText(
return type
}
fun tryGetPredefinedName(klass: ClassDescriptor): String? {
val sourceClass = (klass.source as? KotlinSourceElement)?.psi as? KtClassOrObject
return if (sourceClass?.isLocal == true)
(sourceClass.nameAsName ?: SpecialNames.NO_NAME_PROVIDED).asString()
else null
}
// Returns null when type is unchanged
fun KotlinType.cleanFromAnonymousTypes(): KotlinType? {
val returnTypeClass = constructor.declarationDescriptor as? ClassDescriptor ?: return null
@@ -309,7 +318,8 @@ internal fun KtModifierListOwner.isHiddenByDeprecation(support: KtUltraLightSupp
return (deprecated?.argumentValue("level") as? EnumValue)?.enumEntryName?.asString() == "HIDDEN"
}
internal fun KtAnnotated.isJvmStatic(support: KtUltraLightSupport): Boolean = support.findAnnotation(this, JVM_STATIC_ANNOTATION_FQ_NAME) !== null
internal fun KtAnnotated.isJvmStatic(support: KtUltraLightSupport): Boolean =
support.findAnnotation(this, JVM_STATIC_ANNOTATION_FQ_NAME) !== null
internal fun KtDeclaration.simpleVisibility(): String = when {
hasModifier(KtTokens.PRIVATE_KEYWORD) -> PsiModifier.PRIVATE
@@ -351,4 +361,4 @@ private fun toQualifiedName(userType: KtUserType): FqName? {
}
return FqName.fromSegments(ContainerUtil.reverse(reversedNames))
}
}