org.jetbrains.kotlin.asJava.classes.KtLightClassForFacadeBase.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2023 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.util.TextRange
import com.intellij.psi.*
import com.intellij.psi.impl.PsiSuperMethodImplUtil
import com.intellij.psi.impl.light.LightEmptyImplementsList
import com.intellij.psi.impl.light.LightModifierList
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.isJvmMultifileClassFile
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.JvmNames.JVM_NAME_SHORT
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.psi.psiUtil.siblings
import javax.swing.Icon
abstract class KtLightClassForFacadeBase(
override val facadeClassFqName: FqName,
final override val files: Collection
) : KtLightClassBase(files.first().manager), KtLightClassForFacade {
private val firstFileInFacade by lazyPub { files.first() }
override val multiFileClass: Boolean by lazyPub {
files.size > 1 || firstFileInFacade.isJvmMultifileClassFile
}
private val _modifierList: PsiModifierList by lazyPub {
if (multiFileClass)
LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
else
createModifierListForSimpleFacade()
}
private val _implementsList: LightEmptyImplementsList by lazyPub {
LightEmptyImplementsList(manager)
}
private val packageClsFile by lazyPub {
FakeFileForLightClass(
firstFileInFacade,
lightClass = this,
packageFqName = facadeClassFqName.parent()
)
}
private val _ownMethods: List by lazyPub {
createOwnMethods()
}
private val _ownFields: List by lazyPub {
createOwnFields()
}
abstract fun createOwnMethods(): List
abstract fun createOwnFields(): List
abstract fun createModifierListForSimpleFacade(): PsiModifierList
override fun getParent(): PsiElement = containingFile
override val kotlinOrigin: KtClassOrObject? get() = null
val fqName: FqName
get() = facadeClassFqName
override fun getModifierList() = _modifierList
override fun hasModifierProperty(@NonNls name: String) = modifierList.hasModifierProperty(name)
override fun getExtendsList(): PsiReferenceList? = null
override fun isDeprecated() = false
override fun isInterface() = false
override fun isAnnotationType() = false
override fun isEnum() = false
override fun getContainingClass(): PsiClass? = null
override fun getContainingFile() = packageClsFile
override fun hasTypeParameters() = false
override fun getTypeParameters(): Array = PsiTypeParameter.EMPTY_ARRAY
override fun getTypeParameterList(): PsiTypeParameterList? = null
override fun getDocComment(): Nothing? = null
override fun getImplementsList() = _implementsList
override fun getImplementsListTypes(): Array = PsiClassType.EMPTY_ARRAY
override fun getInterfaces(): Array = PsiClass.EMPTY_ARRAY
override fun getInnerClasses(): Array = PsiClass.EMPTY_ARRAY
override fun getOwnInnerClasses(): List = listOf()
override fun getAllInnerClasses(): Array = PsiClass.EMPTY_ARRAY
override fun getInitializers(): Array = PsiClassInitializer.EMPTY_ARRAY
override fun findInnerClassByName(@NonNls name: String, checkBases: Boolean): PsiClass? = null
override fun isInheritorDeep(baseClass: PsiClass?, classToByPass: PsiClass?): Boolean = false
override fun getLBrace(): PsiElement? = null
override fun getRBrace(): PsiElement? = null
override fun getName() = super.getName()
override fun setName(name: String): PsiElement? {
for (file in files) {
val jvmNameEntry = JvmFileClassUtil.findAnnotationEntryOnFileNoResolve(file, JVM_NAME_SHORT)
if (PackagePartClassUtils.getFilePartShortName(file.name) == name) {
jvmNameEntry?.delete()
continue
}
if (jvmNameEntry == null) {
val newFileName = PackagePartClassUtils.getFileNameByFacadeName(name)
val facadeDir = file.parent
if (newFileName != null && facadeDir != null && facadeDir.findFile(newFileName) == null) {
file.name = newFileName
continue
}
val psiFactory = KtPsiFactory(project)
val annotationText = "${JVM_NAME_SHORT}(\"$name\")"
val newFileAnnotationList = psiFactory.createFileAnnotationListWithAnnotation(annotationText)
val annotationList = file.fileAnnotationList
if (annotationList != null) {
annotationList.add(newFileAnnotationList.annotationEntries.first())
} else {
val anchor = file.firstChild.siblings().firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
file.addBefore(newFileAnnotationList, anchor)
}
continue
}
val jvmNameExpression = jvmNameEntry.valueArguments.firstOrNull()?.getArgumentExpression() as? KtStringTemplateExpression
?: continue
ElementManipulators.handleContentChange(jvmNameExpression, name)
}
return this
}
override fun getQualifiedName() = facadeClassFqName.asString()
override fun getNameIdentifier(): PsiIdentifier? = null
override fun isValid() = files.all { it.isValid && it.hasTopLevelCallables() && facadeClassFqName == it.javaFileFacadeFqName }
abstract override fun copy(): KtLightClassForFacade
override fun getNavigationElement() = firstFileInFacade
override fun isEquivalentTo(another: PsiElement?): Boolean =
equals(another) ||
(another is KtLightClassForFacade && another.facadeClassFqName == facadeClassFqName)
override fun getElementIcon(flags: Int): Icon? = throw UnsupportedOperationException("This should be done by KotlinIconProvider")
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean {
return baseClass.qualifiedName == CommonClassNames.JAVA_LANG_OBJECT
}
override fun getSuperClass(): PsiClass? {
return JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope)
}
override fun getSupers(): Array {
return superClass?.let { arrayOf(it) } ?: arrayOf()
}
override fun getSuperTypes(): Array {
return arrayOf(PsiType.getJavaLangObject(manager, resolveScope))
}
override fun hashCode() = facadeClassFqName.hashCode()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) {
return false
}
val lightClass = other as KtLightClassForFacadeBase
if (facadeClassFqName != lightClass.facadeClassFqName) return false
if (files != lightClass.files) return false
return true
}
override fun toString() = "${KtLightClassForFacadeBase::class.java.simpleName}:$facadeClassFqName"
override val originKind: LightClassOriginKind
get() = LightClassOriginKind.SOURCE
override fun getText() = firstFileInFacade.text ?: ""
override fun getTextRange(): TextRange = firstFileInFacade.textRange ?: TextRange.EMPTY_RANGE
override fun getTextOffset() = firstFileInFacade.textOffset
override fun getStartOffsetInParent() = firstFileInFacade.startOffsetInParent
override fun isWritable() = files.all { it.isWritable }
override fun getOwnFields() = _ownFields
override fun getOwnMethods() = _ownMethods
override fun getVisibleSignatures(): MutableCollection = PsiSuperMethodImplUtil.getVisibleSignatures(this)
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy