KotlinLightClassForExplicitDeclaration: cleanup

This commit is contained in:
Dmitry Jemerov
2015-08-19 13:57:17 +02:00
parent f2ff752dd1
commit 6c32f655f9
@@ -16,12 +16,8 @@
package org.jetbrains.kotlin.asJava package org.jetbrains.kotlin.asJava
import com.google.common.collect.Lists
import com.google.common.collect.Sets
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.openapi.util.NullableLazyValue
import com.intellij.openapi.util.Pair
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.impl.compiled.ClsFileImpl import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
@@ -32,8 +28,6 @@ import com.intellij.psi.search.SearchScope
import com.intellij.psi.stubs.PsiClassHolderFileStub import com.intellij.psi.stubs.PsiClassHolderFileStub
import com.intellij.psi.util.CachedValue import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.ArrayUtil
import com.intellij.util.IncorrectOperationException import com.intellij.util.IncorrectOperationException
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
@@ -43,59 +37,23 @@ import org.jetbrains.kotlin.idea.JetLanguage
import org.jetbrains.kotlin.lexer.JetTokens.* import org.jetbrains.kotlin.lexer.JetTokens.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import javax.swing.Icon import javax.swing.Icon
public open class KotlinLightClassForExplicitDeclaration( public open class KotlinLightClassForExplicitDeclaration(
manager: PsiManager, manager: PsiManager,
private val classFqName: FqName // FqName of (possibly inner) class private val classFqName: FqName, // FqName of (possibly inner) class
,
protected val classOrObject: JetClassOrObject) : KotlinWrappingLightClass(manager), JetJavaMirrorMarker { protected val classOrObject: JetClassOrObject) : KotlinWrappingLightClass(manager), JetJavaMirrorMarker {
private var delegate: PsiClass? = null private var delegate: PsiClass? = null
private val parent = object : NullableLazyValue<PsiElement>() { private fun getLocalClassParent(): PsiElement? {
override fun compute(): PsiElement? { fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? {
if (classOrObject.isLocal()) {
//noinspection unchecked
var declaration: PsiElement? = JetPsiUtil.getTopmostParentOfTypes(
classOrObject,
javaClass<JetNamedFunction>(), javaClass<JetConstructor<*>>(), javaClass<JetProperty>(), javaClass<JetClassInitializer>(), javaClass<JetParameter>())
if (declaration is JetParameter) {
declaration = PsiTreeUtil.getParentOfType(declaration, javaClass<JetNamedDeclaration>())
}
if (declaration is JetFunction) {
return getParentByPsiMethod(LightClassUtil.getLightClassMethod(declaration), declaration.name, false)
}
// Represent the property as a fake method with the same name
if (declaration is JetProperty) {
return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(declaration).getter, declaration.name, true)
}
if (declaration is JetClassInitializer) {
val parent = declaration.parent
val grandparent = parent.parent
if (parent is JetClassBody && grandparent is JetClassOrObject) {
return LightClassUtil.getPsiClass(grandparent)
}
}
if (declaration is JetClass) {
return LightClassUtil.getPsiClass(declaration)
}
}
return if (classOrObject.parent === classOrObject.containingFile) containingFile else containingClass
}
private fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? {
if (method == null || name == null) return null if (method == null || name == null) return null
var containingClass: com.intellij.psi.PsiClass? = method.containingClass ?: return null var containingClass: PsiClass? = method.containingClass ?: return null
val currentFileName = classOrObject.containingFile.name val currentFileName = classOrObject.containingFile.name
@@ -124,23 +82,51 @@ public open class KotlinLightClassForExplicitDeclaration(
return method return method
} }
}
private var modifierList: PsiModifierList? = null var declaration: PsiElement? = JetPsiUtil.getTopmostParentOfTypes(
classOrObject,
javaClass<JetNamedFunction>(), javaClass<JetConstructor<*>>(), javaClass<JetProperty>(), javaClass<JetClassInitializer>(), javaClass<JetParameter>())
private val typeParameterList = object : NullableLazyValue<PsiTypeParameterList>() { if (declaration is JetParameter) {
override fun compute(): PsiTypeParameterList? { declaration = declaration.getStrictParentOfType<JetNamedDeclaration>()
return LightClassUtil.buildLightTypeParameterList(this@KotlinLightClassForExplicitDeclaration, classOrObject)
} }
if (declaration is JetFunction) {
return getParentByPsiMethod(LightClassUtil.getLightClassMethod(declaration), declaration.name, false)
}
// Represent the property as a fake method with the same name
if (declaration is JetProperty) {
return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(declaration).getter, declaration.name, true)
}
if (declaration is JetClassInitializer) {
val parent = declaration.parent
val grandparent = parent.parent
if (parent is JetClassBody && grandparent is JetClassOrObject) {
return LightClassUtil.getPsiClass(grandparent)
}
}
if (declaration is JetClass) {
return LightClassUtil.getPsiClass(declaration)
}
return null
} }
override fun getOrigin(): JetClassOrObject { private val _parent: PsiElement? by lazy {
return classOrObject if (classOrObject.isLocal())
getLocalClassParent()
else if (classOrObject.parent === classOrObject.containingFile)
containingFile
else
containingClass
} }
override fun getFqName(): FqName { override fun getOrigin(): JetClassOrObject = classOrObject
return classFqName
} override fun getFqName(): FqName = classFqName
override fun copy(): PsiElement { override fun copy(): PsiElement {
return KotlinLightClassForExplicitDeclaration(manager, classFqName, classOrObject.copy() as JetClassOrObject) return KotlinLightClassForExplicitDeclaration(manager, classFqName, classOrObject.copy() as JetClassOrObject)
@@ -161,9 +147,7 @@ public open class KotlinLightClassForExplicitDeclaration(
return delegate!! return delegate!!
} }
private fun getJavaFileStub(): PsiJavaFileStub { private fun getJavaFileStub(): PsiJavaFileStub = getLightClassData().javaFileStub
return getLightClassData().javaFileStub
}
protected fun getDescriptor(): ClassDescriptor? { protected fun getDescriptor(): ClassDescriptor? {
val data = getLightClassDataExactly(classOrObject) val data = getLightClassDataExactly(classOrObject)
@@ -174,48 +158,40 @@ public open class KotlinLightClassForExplicitDeclaration(
return getLightClassData(classOrObject) return getLightClassData(classOrObject)
} }
private val _containingFile = object : NullableLazyValue<PsiFile>() { private val _containingFile: PsiFile by lazy {
override fun compute(): PsiFile? { val virtualFile = classOrObject.containingFile.virtualFile
val virtualFile = classOrObject.containingFile.virtualFile assert(virtualFile != null) { "No virtual file for " + classOrObject.text }
assert(virtualFile != null) { "No virtual file for " + classOrObject.text }
return object : ClsFileImpl(ClassFileViewProvider(getManager(), virtualFile)) {
override fun getPackageName(): String {
return classOrObject.getContainingJetFile().packageFqName.asString()
}
override fun getStub(): PsiClassHolderFileStub<PsiJavaFile> { object : ClsFileImpl(ClassFileViewProvider(getManager(), virtualFile)) {
return getJavaFileStub() override fun getPackageName(): String {
} return classOrObject.getContainingJetFile().packageFqName.asString()
}
SuppressWarnings("Contract") override fun getStub(): PsiClassHolderFileStub<PsiJavaFile> = getJavaFileStub()
override fun processDeclarations(
processor: PsiScopeProcessor,
state: ResolveState,
lastParent: PsiElement?,
place: PsiElement): Boolean {
if (!super.processDeclarations(processor, state, lastParent, place)) return false
// We have to explicitly process package declarations if current file belongs to default package override fun processDeclarations(
// so that Java resolve can find classes located in that package processor: PsiScopeProcessor,
val packageName = packageName state: ResolveState,
if (!packageName.isEmpty()) return true lastParent: PsiElement?,
place: PsiElement): Boolean {
if (!super.processDeclarations(processor, state, lastParent, place)) return false
val aPackage = JavaPsiFacade.getInstance(myManager.project).findPackage(packageName) // We have to explicitly process package declarations if current file belongs to default package
if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false // so that Java resolve can find classes located in that package
val packageName = packageName
if (!packageName.isEmpty()) return true
return true val aPackage = JavaPsiFacade.getInstance(myManager.project).findPackage(packageName)
} if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false
return true
} }
} }
} }
override fun getContainingFile(): PsiFile? { override fun getContainingFile(): PsiFile? = _containingFile
return _containingFile.value
}
override fun getNavigationElement(): PsiElement { override fun getNavigationElement(): PsiElement = classOrObject
return classOrObject
}
override fun isEquivalentTo(another: PsiElement?): Boolean { override fun isEquivalentTo(another: PsiElement?): Boolean {
return another is PsiClass && Comparing.equal(another.getQualifiedName(), qualifiedName) return another is PsiClass && Comparing.equal(another.getQualifiedName(), qualifiedName)
@@ -236,61 +212,44 @@ public open class KotlinLightClassForExplicitDeclaration(
return true return true
} }
override fun hashCode(): Int { override fun hashCode(): Int = classFqName.hashCode()
return classFqName.hashCode()
}
override fun getContainingClass(): PsiClass? { override fun getContainingClass(): PsiClass? {
if (classOrObject.parent === classOrObject.containingFile) return null if (classOrObject.parent === classOrObject.containingFile) return null
return super.getContainingClass() return super.getContainingClass()
} }
override fun getParent(): PsiElement? { override fun getParent(): PsiElement? = _parent
return parent.value
override fun getContext(): PsiElement? = getParent()
private val _typeParameterList: PsiTypeParameterList by lazy {
LightClassUtil.buildLightTypeParameterList(this, classOrObject)
} }
override fun getContext(): PsiElement? { override fun getTypeParameterList(): PsiTypeParameterList? = _typeParameterList
return getParent()
}
override fun getTypeParameterList(): PsiTypeParameterList? { override fun getTypeParameters(): Array<PsiTypeParameter> = _typeParameterList.typeParameters
return typeParameterList.value
}
override fun getTypeParameters(): Array<PsiTypeParameter> { override fun getName(): String = classFqName.shortName().asString()
val typeParameterList = getTypeParameterList()
return if (typeParameterList == null) PsiTypeParameter.EMPTY_ARRAY else typeParameterList.typeParameters
}
override fun getName(): String? { override fun getQualifiedName(): String = classFqName.asString()
return classFqName.shortName().asString()
}
override fun getQualifiedName(): String? { private val _modifierList : PsiModifierList by lazy {
return classFqName.asString() object : KotlinLightModifierList(this.manager, computeModifiers()) {
} override fun getDelegate(): PsiModifierList {
return this@KotlinLightClassForExplicitDeclaration.getDelegate().modifierList!!
override fun getModifierList(): PsiModifierList {
if (modifierList == null) {
modifierList = object : KotlinLightModifierList(this.manager, computeModifiers()) {
override fun getDelegate(): PsiModifierList {
return this@KotlinLightClassForExplicitDeclaration.getDelegate().modifierList!!
}
} }
} }
return modifierList!!
} }
override fun getModifierList(): PsiModifierList = _modifierList
private fun computeModifiers(): Array<String> { private fun computeModifiers(): Array<String> {
val psiModifiers = Sets.newHashSet<String>() val psiModifiers = hashSetOf<String>()
// PUBLIC, PROTECTED, PRIVATE, ABSTRACT, FINAL // PUBLIC, PROTECTED, PRIVATE, ABSTRACT, FINAL
//noinspection unchecked //noinspection unchecked
val jetTokenToPsiModifier = Lists.newArrayList(
Pair.create(PUBLIC_KEYWORD, PsiModifier.PUBLIC),
Pair.create(INTERNAL_KEYWORD, PsiModifier.PUBLIC),
Pair.create(PROTECTED_KEYWORD, PsiModifier.PROTECTED),
Pair.create(FINAL_KEYWORD, PsiModifier.FINAL))
for (tokenAndModifier in jetTokenToPsiModifier) { for (tokenAndModifier in jetTokenToPsiModifier) {
if (classOrObject.hasModifier(tokenAndModifier.first)) { if (classOrObject.hasModifier(tokenAndModifier.first)) {
@@ -310,7 +269,7 @@ public open class KotlinLightClassForExplicitDeclaration(
// FINAL // FINAL
if (isAbstract(classOrObject)) { if (isAbstract()) {
psiModifiers.add(PsiModifier.ABSTRACT) psiModifiers.add(PsiModifier.ABSTRACT)
} }
else if (!(classOrObject.hasModifier(OPEN_KEYWORD) || (classOrObject is JetClass && classOrObject.isEnum()))) { else if (!(classOrObject.hasModifier(OPEN_KEYWORD) || (classOrObject is JetClass && classOrObject.isEnum()))) {
@@ -321,16 +280,12 @@ public open class KotlinLightClassForExplicitDeclaration(
psiModifiers.add(PsiModifier.STATIC) psiModifiers.add(PsiModifier.STATIC)
} }
return ArrayUtil.toStringArray(psiModifiers) return psiModifiers.toTypedArray()
} }
private fun isAbstract(`object`: JetClassOrObject): Boolean { private fun isAbstract(): Boolean = classOrObject.hasModifier(ABSTRACT_KEYWORD) || isInterface
return `object`.hasModifier(ABSTRACT_KEYWORD) || isInterface
}
override fun hasModifierProperty(NonNls name: String): Boolean { override fun hasModifierProperty(NonNls name: String): Boolean = getModifierList().hasModifierProperty(name)
return getModifierList().hasModifierProperty(name)
}
override fun isDeprecated(): Boolean { override fun isDeprecated(): Boolean {
val jetModifierList = classOrObject.modifierList ?: return false val jetModifierList = classOrObject.modifierList ?: return false
@@ -357,21 +312,13 @@ public open class KotlinLightClassForExplicitDeclaration(
return classOrObject.isInterface() || classOrObject.isAnnotation() return classOrObject.isInterface() || classOrObject.isAnnotation()
} }
override fun isAnnotationType(): Boolean { override fun isAnnotationType(): Boolean = classOrObject is JetClass && classOrObject.isAnnotation()
return classOrObject is JetClass && classOrObject.isAnnotation()
}
override fun isEnum(): Boolean { override fun isEnum(): Boolean = classOrObject is JetClass && classOrObject.isEnum()
return classOrObject is JetClass && classOrObject.isEnum()
}
override fun hasTypeParameters(): Boolean { override fun hasTypeParameters(): Boolean = classOrObject is JetClass && !classOrObject.typeParameters.isEmpty()
return classOrObject is JetClass && !classOrObject.typeParameters.isEmpty()
}
override fun isValid(): Boolean { override fun isValid(): Boolean = classOrObject.isValid
return classOrObject.isValid
}
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean { override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean {
// Java inheritor check doesn't work when trait (interface in Java) subclasses Java class and for Kotlin local classes // Java inheritor check doesn't work when trait (interface in Java) subclasses Java class and for Kotlin local classes
@@ -417,13 +364,18 @@ public open class KotlinLightClassForExplicitDeclaration(
.filterNotNull() .filterNotNull()
} }
override fun getUseScope(): SearchScope { override fun getUseScope(): SearchScope = getOrigin().useScope
return getOrigin().useScope
}
companion object { companion object {
private val JAVA_API_STUB = Key.create<CachedValue<OutermostKotlinClassLightClassData>>("JAVA_API_STUB") private val JAVA_API_STUB = Key.create<CachedValue<OutermostKotlinClassLightClassData>>("JAVA_API_STUB")
private val jetTokenToPsiModifier = listOf(
PUBLIC_KEYWORD to PsiModifier.PUBLIC,
INTERNAL_KEYWORD to PsiModifier.PUBLIC,
PROTECTED_KEYWORD to PsiModifier.PROTECTED,
FINAL_KEYWORD to PsiModifier.FINAL)
public fun create(manager: PsiManager, classOrObject: JetClassOrObject): KotlinLightClassForExplicitDeclaration? { public fun create(manager: PsiManager, classOrObject: JetClassOrObject): KotlinLightClassForExplicitDeclaration? {
if (LightClassUtil.belongsToKotlinBuiltIns(classOrObject.getContainingJetFile())) { if (LightClassUtil.belongsToKotlinBuiltIns(classOrObject.getContainingJetFile())) {
return null return null
@@ -461,16 +413,13 @@ public open class KotlinLightClassForExplicitDeclaration(
} }
private fun getOutermostClassOrObject(classOrObject: JetClassOrObject): JetClassOrObject { private fun getOutermostClassOrObject(classOrObject: JetClassOrObject): JetClassOrObject {
val outermostClass = JetPsiUtil.getOutermostClassOrObject(classOrObject) val outermostClass = JetPsiUtil.getOutermostClassOrObject(classOrObject) ?:
if (outermostClass == null) {
throw IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.text) throw IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.text)
}
else { return outermostClass
return outermostClass
}
} }
private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean?): Boolean { private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean): Boolean {
if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true
if (qualifiedName == DescriptorUtils.getFqName(classDescriptor).asString()) return true if (qualifiedName == DescriptorUtils.getFqName(classDescriptor).asString()) return true
@@ -481,7 +430,7 @@ public open class KotlinLightClassForExplicitDeclaration(
if (superDescriptor is ClassDescriptor) { if (superDescriptor is ClassDescriptor) {
if (qualifiedName == DescriptorUtils.getFqName(superDescriptor).asString()) return true if (qualifiedName == DescriptorUtils.getFqName(superDescriptor).asString()) return true
if (deep!!) { if (deep) {
if (checkSuperTypeByFQName(superDescriptor, qualifiedName, true)) { if (checkSuperTypeByFQName(superDescriptor, qualifiedName, true)) {
return true return true
} }