[FIR IDE] Initial FIR LightClass implementation

This commit is contained in:
Igor Yakovlev
2020-09-22 16:21:30 +03:00
committed by Ilya Kirillov
parent c881cf7af6
commit b742a475ff
38 changed files with 2774 additions and 49 deletions
@@ -550,11 +550,17 @@ fun KtClassOrObject.defaultJavaAncestorQualifiedName(): String? {
}
fun KtClassOrObject.shouldNotBeVisibleAsLightClass(): Boolean {
if (containingFile is KtCodeFragment) {
// Avoid building light classes for code fragments
return true
}
if (parentsWithSelf.filterIsInstance<KtClassOrObject>().any { it.hasExpectModifier() }) {
return true
}
if (safeIsLocal()) {
if (isLocal) {
if (containingFile.virtualFile == null) return true
if (hasParseErrorsAround(this) || PsiUtilCore.hasErrorElementChild(this)) return true
}
@@ -50,9 +50,9 @@ fun PsiReferenceList.addSuperTypeEntry(
}
}
internal fun KtClassOrObject.getExternalDependencies(): List<ModificationTracker> {
fun KtClassOrObject.getExternalDependencies(): List<ModificationTracker> {
return with(KotlinModificationTrackerService.getInstance(project)) {
if (!safeIsLocal()) return listOf(outOfBlockModificationTracker)
if (!this@getExternalDependencies.isLocal) return listOf(outOfBlockModificationTracker)
else when (val file = containingFile) {
is KtFile -> listOf(outOfBlockModificationTracker, fileModificationTracker(file))
else -> listOf(outOfBlockModificationTracker)
@@ -32,13 +32,13 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.types.RawType
internal const val METHOD_INDEX_FOR_GETTER = 1
internal const val METHOD_INDEX_FOR_SETTER = 2
internal const val METHOD_INDEX_FOR_DEFAULT_CTOR = 3
internal const val METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR = 4
internal const val METHOD_INDEX_FOR_NON_ORIGIN_METHOD = 5
internal const val METHOD_INDEX_FOR_SCRIPT_MAIN = 6
internal const val METHOD_INDEX_BASE = 7
const val METHOD_INDEX_FOR_GETTER = 1
const val METHOD_INDEX_FOR_SETTER = 2
const val METHOD_INDEX_FOR_DEFAULT_CTOR = 3
const val METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR = 4
const val METHOD_INDEX_FOR_NON_ORIGIN_METHOD = 5
const val METHOD_INDEX_FOR_SCRIPT_MAIN = 6
const val METHOD_INDEX_BASE = 7
internal abstract class KtUltraLightMethod(
internal val delegate: PsiMethod,
@@ -26,7 +26,6 @@ import com.intellij.psi.util.PsiUtilCore
import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.isValidJavaFqName
@@ -73,7 +72,7 @@ class JavaElementFinder(
for (declaration in classOrObjectDeclarations) {
if (declaration !is KtEnumEntry) {
val lightClass = declaration.toLightClass()
val lightClass = kotlinAsJavaSupport.getLightClass(declaration)
if (lightClass != null) {
answer.add(lightClass)
}
@@ -90,7 +89,7 @@ class JavaElementFinder(
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
//NOTE: can't filter out more interfaces right away because decompiled declarations do not have member bodies
if (classOrObject is KtClass && classOrObject.isInterface()) {
val interfaceClass = classOrObject.toLightClass() ?: continue
val interfaceClass = kotlinAsJavaSupport.getLightClass(classOrObject) ?: continue
val implsClass = interfaceClass.findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false) ?: continue
answer.add(implsClass)
}
@@ -141,7 +140,7 @@ class JavaElementFinder(
val declarations = kotlinAsJavaSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope)
for (declaration in declarations) {
val aClass = declaration.toLightClass() ?: continue
val aClass = kotlinAsJavaSupport.getLightClass(declaration) ?: continue
answer.add(aClass)
}
@@ -36,9 +36,21 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.utils.sure
class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport() {
open class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport() {
private val psiManager: PsiManager = PsiManager.getInstance(project)
protected open fun createLightClassForSourceDeclaration(classOrObject: KtClassOrObject): KtLightClass? =
KtLightClassForSourceDeclaration.create(classOrObject)
protected open fun createLightClassForScript(script: KtScript): KtLightClass? =
KtLightClassForScript.create(script)
protected open fun createLightClassForFacade(
manager: PsiManager,
facadeClassFqName: FqName,
searchScope: GlobalSearchScope
): KtLightClass? = KtLightClassForFacade.createForFacade(psiManager, facadeClassFqName, searchScope)
override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection<String> {
val facadeFilesInPackage = project.runReadActionInSmartMode {
KotlinFileFacadeClassByPackageIndex.getInstance().get(packageFqName.asString(), project, scope)
@@ -139,7 +151,7 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport
if (virtualFile != null) {
when {
ProjectRootsUtil.isProjectSourceFile(project, virtualFile) ->
return KtLightClassForSourceDeclaration.create(classOrObject)
return createLightClassForSourceDeclaration(classOrObject)
ProjectRootsUtil.isLibraryClassFile(project, virtualFile) ->
return getLightClassForDecompiledClassOrObject(classOrObject)
ProjectRootsUtil.isLibrarySourceFile(project, virtualFile) ->
@@ -152,17 +164,17 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport
classOrObject.containingFile.originalFile.virtualFile != null
) {
// explicit request to create light class from dummy.kt
return KtLightClassForSourceDeclaration.create(classOrObject)
return createLightClassForSourceDeclaration(classOrObject)
}
return null
}
override fun getLightClassForScript(script: KtScript): KtLightClassForScript? {
override fun getLightClassForScript(script: KtScript): KtLightClass? {
if (!script.isValid) {
return null
}
return KtLightClassForScript.create(script)
return createLightClassForScript(script)
}
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
@@ -229,7 +241,7 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport
private fun tryCreateFacadesForSourceFiles(moduleInfo: IdeaModuleInfo, facadeFqName: FqName): PsiClass? {
if (moduleInfo !is ModuleSourceInfo && moduleInfo !is PlatformModuleInfo) return null
return KtLightClassForFacade.createForFacade(psiManager, facadeFqName, moduleInfo.contentScope())
return createLightClassForFacade(psiManager, facadeFqName, moduleInfo.contentScope())
}
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile> {
@@ -0,0 +1,60 @@
/*
* Copyright 2000-2018 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.idea.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass
import org.jetbrains.kotlin.idea.asJava.FirLightClassForFacade
import org.jetbrains.kotlin.idea.asJava.FirLightClassForSymbol
import org.jetbrains.kotlin.idea.frontend.api.analyze
import org.jetbrains.kotlin.idea.util.ifTrue
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScript
class IDEKotlinAsJavaFirSupport(project: Project) : IDEKotlinAsJavaSupport(project) {
//TODO Make caching
override fun createLightClassForFacade(manager: PsiManager, facadeClassFqName: FqName, searchScope: GlobalSearchScope): KtLightClass? {
val sources = findFilesForFacade(facadeClassFqName, searchScope)
.filterNot { it.isCompiled }
if (sources.isEmpty()) return null
return FirLightClassForFacade(manager, facadeClassFqName, sources)
}
override fun createLightClassForScript(script: KtScript): KtLightClass? = null
private fun KtClassOrObject.isSupportedByFitLightClasses() =
containingFile.let { it is KtFile && !it.isCompiled } &&
!isLocal /*TODO*/ &&
this !is KtEnumEntry /*TODO*/ &&
!shouldNotBeVisibleAsLightClass()
override fun createLightClassForSourceDeclaration(classOrObject: KtClassOrObject): KtLightClass? =
classOrObject.isSupportedByFitLightClasses().ifTrue {
CachedValuesManager.getCachedValue(classOrObject) {
CachedValueProvider.Result
.create(
FirLightClassForSymbol(
analyze(classOrObject) { classOrObject.getClassOrObjectSymbol() },
classOrObject.manager
),
KotlinModificationTrackerService.getInstance(classOrObject.project).outOfBlockModificationTracker
)
}
}
}
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveState
import com.intellij.psi.scope.PsiScopeProcessor
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.psi.KtClassOrObject
class FirFakeFileImpl(private val classOrObject: KtClassOrObject, ktClass: KtLightClass) : FakeFileForLightClass(
classOrObject.containingKtFile,
{ if (classOrObject.isTopLevel()) ktClass else FirLightClassForSymbol.create(getOutermostClassOrObject(classOrObject))!! },
{ null }
) {
override fun findReferenceAt(offset: Int) = ktFile.findReferenceAt(offset)
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
// so that Java resolve can find classes located in that package
val packageName = packageName
if (packageName.isNotEmpty()) return true
val aPackage = JavaPsiFacade.getInstance(classOrObject.project).findPackage(packageName)
if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false
return true
}
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiIdentifier
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.javadoc.PsiDocComment
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration
internal abstract class FirLightMemberImpl<T : PsiMember>(
override val lightMemberOrigin: LightMemberOrigin?,
private val containingClass: KtLightClass,
) : KtLightElementBase(containingClass), PsiMember, KtLightMember<T> {
override val clsDelegate: T
get() = invalidAccess()
private val lightIdentifier by lazyPub { KtLightIdentifier(this, kotlinOrigin as? KtNamedDeclaration) }
override fun hasModifierProperty(name: String): Boolean = modifierList?.hasModifierProperty(name) ?: false
override fun toString(): String = "${this::class.java.simpleName}:$name"
override fun getContainingClass() = containingClass
override fun getNameIdentifier(): PsiIdentifier = lightIdentifier
override val kotlinOrigin: KtDeclaration? get() = lightMemberOrigin?.originalElement
override fun getDocComment(): PsiDocComment? = null //TODO()
override fun isDeprecated(): Boolean = false //TODO()
abstract override fun getName(): String
override fun isValid(): Boolean =
parent.isValid && lightMemberOrigin?.isValid() != false
override fun isEquivalentTo(another: PsiElement?): Boolean =
basicIsEquivalentTo(this, another as? PsiMethod)
abstract override fun hashCode(): Int
abstract override fun equals(other: Any?): Boolean
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.idea.asJava
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.psi.*
@@ -14,33 +15,26 @@ class LightClassProviderFirImpl : LightClassProvider {
return null
}
override fun getLightClassMethods(function: KtFunction): List<PsiMethod> {
return emptyList()
}
override fun getLightClassMethods(function: KtFunction): List<PsiMethod> =
LightClassUtil.getLightClassMethods(function)
override fun getLightClassParameterDeclarations(parameter: KtParameter): List<PsiNamedElement> {
return emptyList()
}
override fun getLightClassParameterDeclarations(parameter: KtParameter): List<PsiNamedElement> =
LightClassUtil.getLightClassPropertyMethods(parameter).allDeclarations
override fun getLightClassPropertyDeclarations(property: KtProperty): List<PsiNamedElement> {
return emptyList()
}
override fun getLightClassPropertyDeclarations(property: KtProperty): List<PsiNamedElement> =
LightClassUtil.getLightClassPropertyMethods(property).allDeclarations
override fun toLightClassWithBuiltinMapping(classOrObject: KtClassOrObject): PsiClass? {
return null
}
override fun toLightClassWithBuiltinMapping(classOrObject: KtClassOrObject): PsiClass? =
null
override fun toLightMethods(psiElement: PsiElement): List<PsiMethod> {
return emptyList()
}
override fun toLightMethods(psiElement: PsiElement): List<PsiMethod> =
psiElement.toLightMethods()
override fun toLightClass(classOrObject: KtClassOrObject): KtLightClass? {
return null
}
override fun toLightClass(classOrObject: KtClassOrObject): KtLightClass? =
classOrObject.toLightClass()
override fun toLightElements(ktElement: KtElement): List<PsiNamedElement> {
return emptyList()
}
override fun toLightElements(ktElement: KtElement): List<PsiNamedElement> =
ktElement.toLightElements()
override fun createKtFakeLightClass(kotlinOrigin: KtClassOrObject): PsiClass? {
return null
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightIdentifier
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedConstantValue
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue
import org.jetbrains.kotlin.psi.KtElement
internal class FirAnnotationParameterList(
parent: FirLightAbstractAnnotation,
private val annotationCall: KtAnnotationCall,
) : KtLightElementBase(parent), PsiAnnotationParameterList {
private val _attributes: Array<PsiNameValuePair> by lazyPub {
annotationCall.arguments.map {
FirNameValuePairForAnnotationArgument(it, this)
}.toTypedArray()
}
override fun getAttributes(): Array<PsiNameValuePair> = _attributes
override val kotlinOrigin: KtElement? get() = null
//TODO: EQ GHC EQIV
}
private class FirNameValuePairForAnnotationArgument(
private val constantValue: KtNamedConstantValue,
parent: PsiElement
) : KtLightElementBase(parent), PsiNameValuePair {
override val kotlinOrigin: KtElement? get() = null
private val _value by lazyPub {
(constantValue.expression as? KtSimpleConstantValue<*>)?.createPsiLiteral(this)
}
override fun setValue(p0: PsiAnnotationMemberValue) = cannotModify()
private val _nameIdentifier: PsiIdentifier by lazyPub {
LightIdentifier(parent.manager, constantValue.name)
}
override fun getNameIdentifier(): PsiIdentifier = _nameIdentifier
override fun getValue(): PsiAnnotationMemberValue? = _value
override fun getLiteralValue(): String? = (value as? PsiLiteralExpression)?.value?.toString()
override fun getName(): String = constantValue.name
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import com.intellij.psi.impl.PsiImplUtil
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.psi.*
internal abstract class FirLightAbstractAnnotation(parent: PsiElement) :
KtLightElementBase(parent), PsiAnnotation, KtLightElement<KtCallElement, PsiAnnotation> {
override val clsDelegate: PsiAnnotation
get() = invalidAccess()
override fun getOwner() = parent as? PsiAnnotationOwner
private val KtExpression.nameReference: KtNameReferenceExpression?
get() = when (this) {
is KtConstructorCalleeExpression -> constructorReferenceExpression as? KtNameReferenceExpression
else -> this as? KtNameReferenceExpression
}
private val _nameReferenceElement: PsiJavaCodeReferenceElement by lazyPub {
val ktElement = kotlinOrigin?.navigationElement ?: this
val reference = (kotlinOrigin as? KtAnnotationEntry)?.typeReference?.reference
?: (kotlinOrigin?.calleeExpression?.nameReference)?.references?.firstOrNull()
if (reference != null) FirLightPsiJavaCodeReferenceElementWithReference(ktElement, reference)
else FirLightPsiJavaCodeReferenceElementWithNoReference(ktElement)
}
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement = _nameReferenceElement
private class FirAnnotationParameterList(parent: PsiAnnotation) : KtLightElementBase(parent), PsiAnnotationParameterList {
override val kotlinOrigin: KtElement? = null
override fun getAttributes(): Array<PsiNameValuePair> = emptyArray() //TODO()
}
private val annotationParameterList: PsiAnnotationParameterList = FirAnnotationParameterList(this)
override fun getParameterList(): PsiAnnotationParameterList = annotationParameterList
override fun delete() {
kotlinOrigin?.delete()
}
override fun toString() = "@$qualifiedName"
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
}
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import com.intellij.psi.impl.PsiImplUtil
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.classes.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue
import org.jetbrains.kotlin.psi.KtCallElement
internal class FirLightAnnotationForAnnotationCall(
private val annotationCall: KtAnnotationCall,
parent: PsiElement,
) : FirLightAbstractAnnotation(parent) {
override fun findAttributeValue(attributeName: String?): PsiAnnotationMemberValue? =
PsiImplUtil.findAttributeValue(this, attributeName)
override fun findDeclaredAttributeValue(attributeName: String?) =
PsiImplUtil.findDeclaredAttributeValue(this, attributeName)
private val _parameterList: PsiAnnotationParameterList by lazyPub {
FirAnnotationParameterList(this@FirLightAnnotationForAnnotationCall, annotationCall)
}
override fun getParameterList(): PsiAnnotationParameterList = _parameterList
override val kotlinOrigin: KtCallElement? = annotationCall.psi
override fun getQualifiedName(): String? = annotationCall.classId?.asSingleFqName()?.asString()
override fun getName(): String? = qualifiedName
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightAnnotationForAnnotationCall &&
kotlinOrigin == other.kotlinOrigin &&
annotationCall == other.annotationCall)
override fun hashCode(): Int = kotlinOrigin.hashCode()
override fun isEquivalentTo(another: PsiElement?): Boolean =
basicIsEquivalentTo(this, another as? PsiAnnotation)
}
private fun escapeString(str: String): String = buildString {
str.forEach { char ->
val escaped = when (char) {
'\n' -> "\\n"
'\r' -> "\\r"
'\t' -> "\\t"
'\"' -> "\\\""
'\\' -> "\\\\"
else -> "$char"
}
append(escaped)
}
}
private fun KtSimpleConstantValue<*>.asStringForPsiLiteral(parent: PsiElement): String =
when (val value = this.constant) {
is String -> "\"${escapeString(value)}\""
is Long -> "${value}L"
is Float -> "${value}f"
else -> value?.toString() ?: "null"
}
internal fun KtSimpleConstantValue<*>.createPsiLiteral(parent: PsiElement): PsiExpression? {
val asString = asStringForPsiLiteral(parent)
val instance = PsiElementFactory.getInstance(parent.project)
return try {
instance.createExpressionFromText(asString, parent)
} catch (_: IncorrectOperationException) {
null
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiAnnotationMemberValue
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.PsiImplUtil
import org.jetbrains.kotlin.psi.KtCallElement
internal class FirLightSimpleAnnotation(
private val fqName: String?,
parent: PsiElement
) : FirLightAbstractAnnotation(parent) {
override val kotlinOrigin: KtCallElement? = null
override fun getQualifiedName(): String? = fqName
override fun getName(): String? = fqName
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightSimpleAnnotation && fqName == other.fqName && parent == other.parent)
override fun hashCode(): Int = fqName.hashCode()
override fun findAttributeValue(attributeName: String?): PsiAnnotationMemberValue? = null
override fun findDeclaredAttributeValue(attributeName: String?): PsiAnnotationMemberValue? = null
}
@@ -0,0 +1,118 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiElement
import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirAnnotationCall
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.mapAnnotationParameters
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue
internal fun KtAnnotatedSymbol.hasJvmSyntheticAnnotation(annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean =
hasAnnotation("kotlin/jvm/JvmSynthetic", annotationUseSiteTarget)
internal fun KtAnnotatedSymbol.getJvmNameFromAnnotation(annotationUseSiteTarget: AnnotationUseSiteTarget? = null): String? {
val annotation = annotations.firstOrNull {
val siteTarget = it.useSiteTarget
(siteTarget == null || siteTarget == annotationUseSiteTarget) &&
it.classId?.asString() == "kotlin/jvm/JvmName"
}
return annotation?.let {
(it.arguments.firstOrNull()?.expression as? KtSimpleConstantValue<*>)?.constant as? String
}
}
internal fun KtAnnotatedSymbol.isHiddenByDeprecation(annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean {
//TODO Move it to HL API
require(this is KtFirSymbol<*>)
return this.firRef.withFir(FirResolvePhase.TYPES) {
if (it !is FirAnnotatedDeclaration) return@withFir false
val deprecatedAnnotationCall = it.annotations.firstOrNull { annotationCall ->
val siteTarget = annotationCall.useSiteTarget
(siteTarget == null || siteTarget == annotationUseSiteTarget) &&
annotationCall.classId?.asString() == "kotlin/Deprecated"
} ?: return@withFir false
val qualifiedExpression = mapAnnotationParameters(deprecatedAnnotationCall, it.session)["level"] as? FirQualifiedAccessExpression
?: return@withFir false
val calleeReference = (qualifiedExpression.calleeReference as? FirNamedReference)?.name?.asString()
calleeReference == "HIDDEN"
}
}
internal fun KtAnnotatedSymbol.hasJvmFieldAnnotation(): Boolean =
hasAnnotation("kotlin/jvm/JvmField", null)
internal fun KtAnnotatedSymbol.hasJvmOverloadsAnnotation(): Boolean =
hasAnnotation("kotlin/jvm/JvmOverloads", null)
internal fun KtAnnotatedSymbol.hasJvmStaticAnnotation(): Boolean =
hasAnnotation("kotlin/jvm/JvmStatic", null)
internal fun KtAnnotatedSymbol.hasInlineOnlyAnnotation(): Boolean =
hasAnnotation("kotlin/internal/InlineOnly", null)
internal fun KtAnnotatedSymbol.hasAnnotation(classIdString: String, annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean =
annotations.any {
val siteTarget = it.useSiteTarget
(siteTarget == null || siteTarget == annotationUseSiteTarget) && it.classId?.asString() == classIdString
}
internal fun KtAnnotatedSymbol.computeAnnotations(
parent: PsiElement,
nullability: NullabilityType,
annotationUseSiteTarget: AnnotationUseSiteTarget?
): List<PsiAnnotation> {
if (nullability == NullabilityType.Unknown && annotations.isEmpty()) return emptyList()
val nullabilityAnnotation = when (nullability) {
NullabilityType.NotNull -> NotNull::class.java
NullabilityType.Nullable -> Nullable::class.java
else -> null
}?.let {
FirLightSimpleAnnotation(it.name, parent)
}
if (annotations.isEmpty()) {
return if (nullabilityAnnotation != null) listOf(nullabilityAnnotation) else emptyList()
}
val result = mutableListOf<PsiAnnotation>()
for (annotation in annotations) {
val siteTarget = annotation.useSiteTarget
if (siteTarget == null || siteTarget == annotationUseSiteTarget) {
result.add(FirLightAnnotationForAnnotationCall(annotation, parent))
}
}
if (nullabilityAnnotation != null) {
result.add(nullabilityAnnotation)
}
return result
}
@@ -0,0 +1,267 @@
/*
* 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.
*/
package org.jetbrains.kotlin.idea.asJava
import com.intellij.navigation.ItemPresentation
import com.intellij.navigation.ItemPresentationProviders
import com.intellij.openapi.util.Pair
import com.intellij.psi.*
import com.intellij.psi.impl.PsiClassImplUtil
import com.intellij.psi.impl.PsiImplUtil
import com.intellij.psi.impl.light.LightElement
import com.intellij.psi.impl.source.PsiExtensibleClass
import com.intellij.psi.javadoc.PsiDocComment
import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.psi.util.PsiUtil
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.asJava.classes.KotlinClassInnerStuffCache
import org.jetbrains.kotlin.asJava.classes.KotlinClassInnerStuffCache.Companion.processDeclarationsInEnum
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_BASE
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol
import java.util.*
abstract class FirLightClassBase protected constructor(manager: PsiManager) : LightElement(manager, KotlinLanguage.INSTANCE), PsiClass,
KtLightClass, PsiExtensibleClass {
override val clsDelegate: PsiClass
get() = invalidAccess()
protected open val myInnersCache = KotlinClassInnerStuffCache(
myClass = this,
externalDependencies = listOf(KotlinModificationTrackerService.getInstance(manager.project).outOfBlockModificationTracker)
)
override fun getFields(): Array<PsiField> = myInnersCache.fields
override fun getMethods(): Array<PsiMethod> = myInnersCache.methods
override fun getConstructors(): Array<PsiMethod> = myInnersCache.constructors
override fun getInnerClasses(): Array<out PsiClass> = myInnersCache.innerClasses
override fun getAllFields(): Array<PsiField> = PsiClassImplUtil.getAllFields(this)
override fun getAllMethods(): Array<PsiMethod> = PsiClassImplUtil.getAllMethods(this)
override fun getAllInnerClasses(): Array<PsiClass> = PsiClassImplUtil.getAllInnerClasses(this)
override fun findFieldByName(name: String, checkBases: Boolean) =
myInnersCache.findFieldByName(name, checkBases)
override fun findMethodsByName(name: String, checkBases: Boolean): Array<PsiMethod> =
myInnersCache.findMethodsByName(name, checkBases)
override fun findInnerClassByName(name: String, checkBases: Boolean): PsiClass? =
myInnersCache.findInnerClassByName(name, checkBases)
override fun processDeclarations(
processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement
): Boolean {
if (isEnum && !processDeclarationsInEnum(processor, state, myInnersCache)) return false
return PsiClassImplUtil.processDeclarationsInClass(
this,
processor,
state,
null,
lastParent,
place,
PsiUtil.getLanguageLevel(place),
false
)
}
override fun getText(): String = kotlinOrigin?.text ?: ""
override fun getLanguage(): KotlinLanguage = KotlinLanguage.INSTANCE
override fun getPresentation(): ItemPresentation? =
ItemPresentationProviders.getItemPresentation(this)
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
override fun getContext(): PsiElement = parent
override fun isEquivalentTo(another: PsiElement?): Boolean =
PsiClassImplUtil.isClassEquivalentTo(this, another)
override fun getDocComment(): PsiDocComment? = null
override fun hasTypeParameters(): Boolean = PsiImplUtil.hasTypeParameters(this)
override fun getExtendsListTypes(): Array<PsiClassType?> =
PsiClassImplUtil.getExtendsListTypes(this)
override fun getImplementsListTypes(): Array<PsiClassType?> =
PsiClassImplUtil.getImplementsListTypes(this)
override fun findMethodBySignature(patternMethod: PsiMethod?, checkBases: Boolean): PsiMethod? =
patternMethod?.let { PsiClassImplUtil.findMethodBySignature(this, it, checkBases) }
override fun findMethodsBySignature(patternMethod: PsiMethod?, checkBases: Boolean): Array<PsiMethod?> =
patternMethod?.let { PsiClassImplUtil.findMethodsBySignature(this, it, checkBases) } ?: emptyArray()
override fun findMethodsAndTheirSubstitutorsByName(
@NonNls name: String?,
checkBases: Boolean
): List<Pair<PsiMethod?, PsiSubstitutor?>?> =
PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases)
override fun getAllMethodsAndTheirSubstitutors(): List<Pair<PsiMethod?, PsiSubstitutor?>?> {
return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD)
}
abstract override fun copy(): PsiElement
override fun accept(visitor: PsiElementVisitor) {
if (visitor is JavaElementVisitor) {
visitor.visitClass(this)
} else {
visitor.visitElement(this)
}
}
protected fun createMethods(declarations: Sequence<KtCallableSymbol>, isTopLevel: Boolean, result: MutableList<KtLightMethod>) {
var methodIndex = METHOD_INDEX_BASE
for (declaration in declarations) {
if (declaration is KtFunctionSymbol && declaration.isInline) continue
if (declaration is KtAnnotatedSymbol && declaration.hasJvmSyntheticAnnotation(annotationUseSiteTarget = null)) continue
if (declaration is KtAnnotatedSymbol && declaration.isHiddenByDeprecation(annotationUseSiteTarget = null)) continue
when (declaration) {
is KtFunctionSymbol -> {
result.add(
FirLightSimpleMethodForSymbol(
functionSymbol = declaration,
lightMemberOrigin = null,
containingClass = this@FirLightClassBase,
isTopLevel = isTopLevel,
methodIndex = methodIndex++
)
)
if (declaration.hasJvmOverloadsAnnotation()) {
val skipMask = BitSet(declaration.valueParameters.size)
for (i in declaration.valueParameters.size - 1 downTo 0) {
if (!declaration.valueParameters[i].hasDefaultValue) continue
skipMask.set(i)
result.add(
FirLightSimpleMethodForSymbol(
functionSymbol = declaration,
lightMemberOrigin = null,
containingClass = this@FirLightClassBase,
isTopLevel = isTopLevel,
methodIndex = methodIndex++,
argumentsSkipMask = skipMask
)
)
}
}
}
is KtConstructorSymbol -> {
result.add(
FirLightConstructorForSymbol(
constructorSymbol = declaration,
lightMemberOrigin = null,
containingClass = this@FirLightClassBase,
methodIndex++
)
)
}
is KtPropertySymbol -> {
if (declaration.hasJvmFieldAnnotation()) continue
val getter = declaration.getter?.takeIf {
!declaration.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.PROPERTY_GETTER) &&
!it.isInline &&
!declaration.isHiddenByDeprecation(AnnotationUseSiteTarget.PROPERTY_GETTER)
}
if (getter != null) {
result.add(
FirLightAccessorMethodForSymbol(
propertyAccessorSymbol = getter,
containingPropertySymbol = declaration,
lightMemberOrigin = null,
containingClass = this@FirLightClassBase,
isTopLevel = isTopLevel
)
)
}
val setter = declaration.setter?.takeIf {
!declaration.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.PROPERTY_SETTER) &&
!it.isInline &&
!declaration.isHiddenByDeprecation(AnnotationUseSiteTarget.PROPERTY_GETTER)
}
if (setter != null) {
result.add(
FirLightAccessorMethodForSymbol(
propertyAccessorSymbol = setter,
containingPropertySymbol = declaration,
lightMemberOrigin = null,
containingClass = this@FirLightClassBase,
isTopLevel = isTopLevel
)
)
}
}
}
}
}
protected fun createFields(declarations: Sequence<KtCallableSymbol>, isTopLevel: Boolean, result: MutableList<KtLightField>) {
//TODO isHiddenByDeprecation
for (declaration in declarations) {
if (declaration !is KtPropertySymbol) continue
if (!declaration.hasBackingField) continue
if (declaration.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.FIELD)) continue
result.add(
FirLightFieldForPropertySymbol(
propertySymbol = declaration,
containingClass = this@FirLightClassBase,
lightMemberOrigin = null,
isTopLevel = isTopLevel
)
)
}
}
}
@@ -0,0 +1,281 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.openapi.util.Comparing
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.classes.*
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.types.ConeNullability
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacade
import org.jetbrains.kotlin.idea.frontend.api.analyze
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
import javax.swing.Icon
class FirLightClassForFacade(
manager: PsiManager,
private val facadeClassFqName: FqName,
private val files: Collection<KtFile>
) : FirLightClassBase(manager) {
override val clsDelegate: PsiClass get() = invalidAccess()
private val isMultiFileClass: Boolean by lazyPub {
files.size > 1 || files.any {
JvmFileClassUtil.findAnnotationEntryOnFileNoResolve(
file = it,
shortName = JvmFileClassUtil.JVM_MULTIFILE_CLASS_SHORT
) != null
}
}
private val _modifierList: PsiModifierList by lazyPub {
if (isMultiFileClass)
return@lazyPub LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
val modifiers = setOf(PsiModifier.PUBLIC, PsiModifier.FINAL)
// val annotations = files.flatMap { file ->
// file.withFir<FirFile, List<PsiAnnotation>> {
// computeAnnotations(
// parent = this@FirLightClassForFacade,
// nullability = ConeNullability.UNKNOWN,
// annotationUseSiteTarget = AnnotationUseSiteTarget.FILE
// )
// }
// }
val annotations = emptyList<PsiAnnotation>() //TODO
FirLightClassModifierList(this@FirLightClassForFacade, modifiers, annotations)
}
override fun getModifierList(): PsiModifierList = _modifierList
override fun getScope(): PsiElement? = parent
private inline fun <reified T : FirDeclaration, K> KtFile.withFir(body: T.() -> K): K {
val resolveState = LowLevelFirApiFacade.getResolveStateFor(this)
return LowLevelFirApiFacade.withFirFile(this, resolveState) {
require(it is T)
it.body()
}
}
private fun loadMethodsFromFile(
file: KtFile,
result: MutableList<KtLightMethod>
) {
//it.isHiddenByDeprecation(support)
val declarations = file.declarations
.filterIsInstance<KtNamedDeclaration>()
.filterNot { multiFileClass && it.isPrivate() }
if (declarations.isEmpty()) return
val symbols = analyze(file) {
declarations.mapNotNull {
it.getSymbol() as? KtCallableSymbol
}
}
createMethods(symbols.asSequence(), isTopLevel = true, result)
}
private val _ownMethods: List<KtLightMethod> by lazyPub {
val result = mutableListOf<KtLightMethod>()
for (file in files) {
loadMethodsFromFile(file, result)
}
result
}
private val multiFileClass: Boolean by lazyPub {
false //TODO
// files.any {
// it.withFir<FirFile, Boolean> {
// this.hasAnnotation(JvmFileClassUtil.JVM_MULTIFILE_CLASS.asString())
// }
// }
}
private fun loadFieldsFromFile(
file: KtFile,
result: MutableList<KtLightField>
) {
//it.isHiddenByDeprecation(support)
val declarations = file.declarations
.filterIsInstance<KtNamedDeclaration>()
.filterNot { multiFileClass && it is FirProperty && it.isConst }
if (declarations.isEmpty()) return
val symbols = analyze(file) {
declarations.mapNotNull {
it.getSymbol() as? KtCallableSymbol
}
}
createFields(symbols.asSequence(), isTopLevel = true, result)
}
private val _ownFields: List<KtLightField> by lazyPub {
val result = mutableListOf<KtLightField>()
for (file in files) {
loadFieldsFromFile(file, result)
}
result
}
override fun getOwnFields() = _ownFields
override fun getOwnMethods() = _ownMethods
override fun copy(): FirLightClassForFacade =
FirLightClassForFacade(manager, facadeClassFqName, files)
private val firstFileInFacade by lazyPub { files.iterator().next() }
private val packageFqName: FqName =
facadeClassFqName.parent()
private val modifierList: PsiModifierList =
LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
private val implementsList: LightEmptyImplementsList =
LightEmptyImplementsList(manager)
private val packageClsFile = FakeFileForLightClass(
firstFileInFacade,
lightClass = { this },
stub = { null },
packageFqName = packageFqName
)
override fun getParent(): PsiElement = containingFile
override val kotlinOrigin: KtClassOrObject? get() = null
val fqName: FqName
get() = facadeClassFqName
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<out PsiTypeParameter> = PsiTypeParameter.EMPTY_ARRAY
override fun getTypeParameterList(): PsiTypeParameterList? = null
override fun getImplementsList() = implementsList
override fun getInterfaces(): Array<out PsiClass> = PsiClass.EMPTY_ARRAY
override fun getInnerClasses(): Array<out PsiClass> = PsiClass.EMPTY_ARRAY
override fun getOwnInnerClasses(): List<PsiClass> = listOf()
override fun getAllInnerClasses(): Array<PsiClass> = PsiClass.EMPTY_ARRAY
override fun getInitializers(): Array<out PsiClassInitializer> = 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(): String = facadeClassFqName.shortName().asString()
override fun setName(name: String): PsiElement? = cannotModify()
override fun getQualifiedName() = facadeClassFqName.asString()
override fun getNameIdentifier(): PsiIdentifier? = null
override fun isValid() = files.all { it.isValid && it.hasTopLevelCallables() && facadeClassFqName == it.javaFileFacadeFqName }
override fun getNavigationElement() = firstFileInFacade
override fun isEquivalentTo(another: PsiElement?): Boolean =
equals(another) || another is FirLightClassForFacade && Comparing.equal(another.qualifiedName, qualifiedName)
override fun getElementIcon(flags: Int): Icon? = throw UnsupportedOperationException("This should be done by JetIconProvider")
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<PsiClass> =
superClass?.let { arrayOf(it) } ?: arrayOf()
override fun getSuperTypes(): Array<PsiClassType> =
arrayOf(PsiType.getJavaLangObject(manager, resolveScope))
override fun equals(other: Any?): Boolean {
if (other !is FirLightClassForFacade) return false
if (this === other) return true
if (this.hashCode() != other.hashCode()) return false
if (manager != other.manager) return false
if (facadeClassFqName != other.facadeClassFqName) return false
return true
}
override fun hashCode() = facadeClassFqName.hashCode()
override fun toString() = "${KtLightClassForFacade::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 getVisibleSignatures(): MutableCollection<HierarchicalMethodSignature> = PsiSuperMethodImplUtil.getVisibleSignatures(this)
}
@@ -0,0 +1,350 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.openapi.util.Comparing
import com.intellij.psi.*
import com.intellij.psi.impl.InheritanceImplUtil
import com.intellij.psi.impl.PsiClassImplUtil
import com.intellij.psi.impl.PsiSuperMethodImplUtil
import com.intellij.psi.search.SearchScope
import com.intellij.psi.stubs.IStubElementType
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.util.IncorrectOperationException
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.asJava.classes.*
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.idea.frontend.api.analyze
import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility
import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType
import org.jetbrains.kotlin.idea.util.ifFalse
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.debugText.getDebugText
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub
import javax.swing.Icon
import kotlin.collections.ArrayList
class FirLightClassForSymbol(
private val classOrObjectSymbol: KtClassOrObjectSymbol,
manager: PsiManager
) :
FirLightClassBase(manager),
StubBasedPsiElement<KotlinClassOrObjectStub<out KtClassOrObject>> {
private val isTopLevel: Boolean = classOrObjectSymbol.symbolKind == KtSymbolKind.TOP_LEVEL
private val _modifierList: PsiModifierList? by lazyPub {
val modifiers = mutableSetOf(classOrObjectSymbol.computeVisibility(isTopLevel))
classOrObjectSymbol.computeSimpleModality()?.run {
modifiers.add(this)
}
if (!isTopLevel && !classOrObjectSymbol.isInner) {
modifiers.add(PsiModifier.STATIC)
}
val annotations = classOrObjectSymbol.computeAnnotations(
parent = this@FirLightClassForSymbol,
nullability = NullabilityType.Unknown,
annotationUseSiteTarget = null,
)
FirLightClassModifierList(this@FirLightClassForSymbol, modifiers, annotations)
}
override fun getModifierList(): PsiModifierList? = _modifierList
override fun getOwnFields(): List<KtLightField> = _ownFields
override fun getOwnMethods(): List<PsiMethod> = _ownMethods
override fun isDeprecated(): Boolean = false //TODO()
override fun getNameIdentifier(): KtLightIdentifier? = null //TODO()
override fun getExtendsList(): PsiReferenceList? = _extendsList
override fun getImplementsList(): PsiReferenceList? = _implementsList
override fun getTypeParameterList(): PsiTypeParameterList? = null //TODO()
override fun getTypeParameters(): Array<PsiTypeParameter> = emptyArray() //TODO()
override fun getOwnInnerClasses(): List<PsiClass> {
val result = ArrayList<PsiClass>()
// workaround for ClassInnerStuffCache not supporting classes with null names, see KT-13927
// inner classes with null names can't be searched for and can't be used from java anyway
// we can't prohibit creating light classes with null names either since they can contain members
analyzeWithSymbolAsContext(classOrObjectSymbol) {
classOrObjectSymbol.getDeclaredMemberScope().getAllSymbols().filterIsInstance<KtClassOrObjectSymbol>().mapTo(result) {
FirLightClassForSymbol(it, manager)
}
}
//TODO
//if (classOrObject.hasInterfaceDefaultImpls) {
// result.add(KtLightClassForInterfaceDefaultImpls(classOrObject))
//}
return result
}
override fun getTextOffset(): Int = kotlinOrigin?.textOffset ?: 0
override fun getStartOffsetInParent(): Int = kotlinOrigin?.startOffsetInParent ?: 0
override fun isWritable() = kotlinOrigin?.isWritable ?: false
override val kotlinOrigin: KtClassOrObject? = classOrObjectSymbol.psi as? KtClassOrObject
private val _extendsList by lazyPub { createInheritanceList(forExtendsList = true) }
private val _implementsList by lazyPub { createInheritanceList(forExtendsList = false) }
private fun KtClassType.isTypeForInheritanceList(forExtendsList: Boolean): Boolean {
// Do not add redundant "extends java.lang.Object" anywhere
if (classId == StandardClassIds.Any) return false
// We don't have Enum among enums supertype in sources neither we do for decompiled class-files and light-classes
if (isEnum && classId == StandardClassIds.Enum) return false
// Interfaces have only extends lists
if (isInterface) return forExtendsList
val isInterface = (this.classSymbol as? KtClassOrObjectSymbol)?.classKind == KtClassKind.INTERFACE
return forExtendsList == !isInterface
}
private fun createInheritanceList(forExtendsList: Boolean): PsiReferenceList? {
val role = if (forExtendsList) PsiReferenceList.Role.EXTENDS_LIST else PsiReferenceList.Role.IMPLEMENTS_LIST
if (isAnnotationType) return KotlinLightReferenceListBuilder(manager, language, role)
val listBuilder = KotlinSuperTypeListBuilder(
kotlinOrigin = kotlinOrigin?.getSuperTypeList(),
manager = manager,
language = language,
role = role
)
//TODO Add support for kotlin.collections.
classOrObjectSymbol.superTypes.map { type ->
if (type is KtClassType && type.isTypeForInheritanceList(forExtendsList)) {
type.mapSupertype(this, kotlinCollectionAsIs = true)?.run {
listBuilder.addReference(this)
}
}
}
return listBuilder
}
private val _ownMethods: List<KtLightMethod> by lazyPub {
val result = mutableListOf<KtLightMethod>()
analyzeWithSymbolAsContext(classOrObjectSymbol) {
//TODO filterNot { it.isHiddenByDeprecation(support) }
val callableSymbols = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols()
val visibleDeclarations = callableSymbols.filterNot {
isInterface && it is KtFunctionSymbol && it.visibility == KtSymbolVisibility.PRIVATE
}
createMethods(visibleDeclarations, isTopLevel = false, result)
}
if (result.none { it.isConstructor }) {
classOrObjectSymbol.primaryConstructor?.let {
result.add(
FirLightConstructorForSymbol(
constructorSymbol = it,
lightMemberOrigin = null,
containingClass = this,
methodIndex = METHOD_INDEX_FOR_DEFAULT_CTOR
)
)
}
}
result
}
private val _ownFields: List<KtLightField> by lazyPub {
val result = mutableListOf<KtLightField>()
classOrObjectSymbol.companionObject?.run {
result.add(FirLightFieldForObjectSymbol(this, this@FirLightClassForSymbol, null))
if (!isInterface) {
analyzeWithSymbolAsContext(this) {
getDeclaredMemberScope().getCallableSymbols()
.filterIsInstance<KtPropertySymbol>()
.filter { it.hasJvmFieldAnnotation() || it.isConst }
.mapTo(result) {
FirLightFieldForPropertySymbol(
propertySymbol = it,
containingClass = this@FirLightClassForSymbol,
lightMemberOrigin = null,
isTopLevel = false,
forceStatic = true
)
}
}
}
}
val isNamedObject = classOrObjectSymbol.classKind == KtClassKind.OBJECT
if (isNamedObject && classOrObjectSymbol.symbolKind != KtSymbolKind.LOCAL) {
result.add(FirLightFieldForObjectSymbol(classOrObjectSymbol, this@FirLightClassForSymbol, null))
}
analyzeWithSymbolAsContext(classOrObjectSymbol) {
val callableSymbols = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols()
.filterIsInstance<KtPropertySymbol>()
.applyIf(classOrObjectSymbol.classKind == KtClassKind.COMPANION_OBJECT) {
filter { it.hasJvmFieldAnnotation() || it.isConst }
}
createFields(callableSymbols, isTopLevel = false, result)
}
result
}
private val _containingFile: PsiFile? by lazyPub {
val kotlinOrigin = kotlinOrigin ?: return@lazyPub null
val containingClass = isTopLevel.ifFalse { create(getOutermostClassOrObject(kotlinOrigin)) } ?: this
FirFakeFileImpl(kotlinOrigin, containingClass)
}
override fun getContainingFile(): PsiFile? = _containingFile
override fun getNavigationElement(): PsiElement = kotlinOrigin ?: this
override fun isEquivalentTo(another: PsiElement?): Boolean =
basicIsEquivalentTo(this, another) ||
another is PsiClass && qualifiedName != null && Comparing.equal(another.qualifiedName, qualifiedName)
override fun getElementIcon(flags: Int): Icon? =
throw UnsupportedOperationException("This should be done by JetIconProvider")
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightClassForSymbol && kotlinOrigin == other.kotlinOrigin && classOrObjectSymbol == other.classOrObjectSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
override fun getName(): String = classOrObjectSymbol.name.asString()
override fun hasModifierProperty(@NonNls name: String): Boolean = modifierList?.hasModifierProperty(name) ?: false
override fun isInterface(): Boolean =
classOrObjectSymbol.classKind == KtClassKind.INTERFACE || classOrObjectSymbol.classKind == KtClassKind.ANNOTATION_CLASS
override fun isAnnotationType(): Boolean =
classOrObjectSymbol.classKind == KtClassKind.ANNOTATION_CLASS
override fun isEnum(): Boolean =
classOrObjectSymbol.classKind == KtClassKind.ENUM_CLASS
override fun hasTypeParameters(): Boolean =
classOrObjectSymbol is KtClass && classOrObjectSymbol.typeParameters.isNotEmpty()
override fun isValid(): Boolean = kotlinOrigin?.isValid ?: true
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean =
InheritanceImplUtil.isInheritor(this, baseClass, checkDeep)
@Throws(IncorrectOperationException::class)
override fun setName(@NonNls name: String): PsiElement =
throw IncorrectOperationException()
override fun toString() =
"${this::class.java.simpleName}:${kotlinOrigin?.getDebugText()}"
override fun getUseScope(): SearchScope = kotlinOrigin?.useScope ?: TODO()
override fun getElementType(): IStubElementType<out StubElement<*>, *>? = kotlinOrigin?.elementType
override fun getStub(): KotlinClassOrObjectStub<out KtClassOrObject>? = kotlinOrigin?.stub
override val originKind: LightClassOriginKind
get() = LightClassOriginKind.SOURCE
override fun getQualifiedName() = kotlinOrigin?.fqName?.asString()
override fun getInterfaces(): Array<PsiClass> = PsiClassImplUtil.getInterfaces(this)
override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this)
override fun getSupers(): Array<PsiClass> = PsiClassImplUtil.getSupers(this)
override fun getSuperTypes(): Array<PsiClassType> = PsiClassImplUtil.getSuperTypes(this)
override fun getVisibleSignatures(): MutableCollection<HierarchicalMethodSignature> = PsiSuperMethodImplUtil.getVisibleSignatures(this)
override fun getRBrace(): PsiElement? = null
override fun getLBrace(): PsiElement? = null
override fun getInitializers(): Array<PsiClassInitializer> = emptyArray()
override fun getContainingClass(): PsiClass? {
val containingBody = kotlinOrigin?.parent as? KtClassBody
val containingClass = containingBody?.parent as? KtClassOrObject
containingClass?.let { return create(it) }
val containingBlock = kotlinOrigin?.parent as? KtBlockExpression
// val containingScript = containingBlock?.parent as? KtScript
// containingScript?.let { return KtLightClassForScript.create(it) }
return null
}
override fun getParent(): PsiElement? = containingClass ?: containingFile
override fun getScope(): PsiElement? = parent
override fun isInheritorDeep(baseClass: PsiClass?, classToByPass: PsiClass?): Boolean =
baseClass?.let { InheritanceImplUtil.isInheritorDeep(this, it, classToByPass) } ?: false
override fun copy(): FirLightClassForSymbol =
FirLightClassForSymbol(classOrObjectSymbol, manager)
companion object {
fun create(classOrObject: KtClassOrObject): FirLightClassForSymbol? =
CachedValuesManager.getCachedValue(classOrObject) {
CachedValueProvider.Result
.create(
createNoCache(classOrObject),
KotlinModificationTrackerService.getInstance(classOrObject.project).outOfBlockModificationTracker
)
}
fun createNoCache(classOrObject: KtClassOrObject): FirLightClassForSymbol? {
val containingFile = classOrObject.containingFile
if (containingFile is KtCodeFragment) {
// Avoid building light classes for code fragments
return null
}
if (classOrObject.shouldNotBeVisibleAsLightClass()) {
return null
}
return when {
classOrObject.isObjectLiteral() -> return null //TODO
classOrObject.safeIsLocal() -> return null //TODO
classOrObject.hasModifier(KtTokens.INLINE_KEYWORD) -> return null //TODO
else -> FirLightClassForSymbol(
analyze(classOrObject) { classOrObject.getClassOrObjectSymbol() },
manager = classOrObject.manager
)
}
}
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import com.intellij.psi.scope.PsiScopeProcessor
internal abstract class FirLightPsiJavaCodeReferenceElementBase(private val ktElement: PsiElement) :
PsiElement by ktElement,
PsiJavaCodeReferenceElement {
override fun multiResolve(incompleteCode: Boolean): Array<JavaResolveResult> = emptyArray()
override fun processVariants(processor: PsiScopeProcessor) { }
override fun advancedResolve(incompleteCode: Boolean): JavaResolveResult =
JavaResolveResult.EMPTY
override fun getQualifier(): PsiElement? = null
override fun getReferenceName(): String? = null
override fun getReferenceNameElement(): PsiElement? = null
override fun getParameterList(): PsiReferenceParameterList? = null
override fun getTypeParameters(): Array<PsiType> = emptyArray()
override fun isQualified(): Boolean = false
override fun getQualifiedName(): String? = null
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.util.IncorrectOperationException
internal class FirLightPsiJavaCodeReferenceElementWithNoReference(private val ktElement: PsiElement):
FirLightPsiJavaCodeReferenceElementBase(ktElement),
PsiReference {
override fun getElement(): PsiElement = ktElement
override fun getRangeInElement(): TextRange = ktElement.textRange
override fun resolve(): PsiElement? = null
override fun getCanonicalText(): String = "<no-text>"
override fun handleElementRename(newElementName: String): PsiElement = element
@Throws(IncorrectOperationException::class)
override fun bindToElement(element: PsiElement): PsiElement =
throw IncorrectOperationException("can't rename FirLightPsiJavaCodeReferenceElementWithNoReference")
override fun isReferenceTo(element: PsiElement): Boolean = false
override fun isSoft(): Boolean = false
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.openapi.util.TextRange
import com.intellij.psi.*
import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.util.IncorrectOperationException
internal class FirLightPsiJavaCodeReferenceElementWithReference(private val ktElement: PsiElement, reference: PsiReference):
FirLightPsiJavaCodeReferenceElementBase(ktElement),
PsiReference by reference {
override fun getElement(): PsiElement = ktElement
}
@@ -0,0 +1,83 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.lang.Language
import com.intellij.psi.*
import com.intellij.psi.impl.ElementPresentationUtil
import com.intellij.ui.IconManager
import com.intellij.util.IncorrectOperationException
import com.intellij.util.PlatformIcons
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import javax.swing.Icon
internal abstract class FirLightField protected constructor(
private val containingClass: KtLightClass,
lightMemberOrigin: LightMemberOrigin?,
) : FirLightMemberImpl<PsiField>(lightMemberOrigin, containingClass), KtLightField {
override val clsDelegate: PsiField get() = invalidAccess()
override fun setInitializer(initializer: PsiExpression?) = cannotModify()
override fun isEquivalentTo(another: PsiElement?): Boolean =
basicIsEquivalentTo(this, another as? PsiField)
override fun getLanguage(): Language = KotlinLanguage.INSTANCE
override fun getParent() = containingClass
override fun getContainingClass() = containingClass
override fun getContainingFile(): PsiFile? = containingClass.containingFile
override fun hasInitializer(): Boolean = initializer !== null
override fun computeConstantValue(): Any? = null //TODO _constantInitializer?.value
override fun computeConstantValue(visitedVars: MutableSet<PsiVariable>?): Any? = computeConstantValue()
override fun setName(@NonNls name: String): PsiElement {
(kotlinOrigin as? KtNamedDeclaration)?.setName(name)
return this
}
override fun toString(): String = "KtLightField:$name"
override fun getTypeElement(): PsiTypeElement? = null
@Throws(IncorrectOperationException::class)
override fun normalizeDeclaration() {
}
override fun isVisibilitySupported(): Boolean = true
override fun getElementIcon(flags: Int): Icon? {
val baseIcon = IconManager.getInstance().createLayeredIcon(
this,
PlatformIcons.VARIABLE_ICON, ElementPresentationUtil.getFlags(
this,
false
)
)
return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon)
}
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
override fun accept(visitor: PsiElementVisitor) {
if (visitor is JavaElementVisitor) {
visitor.visitField(this)
} else {
visitor.visitElement(this)
}
}
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiExpression
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassKind
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.psi.KtDeclaration
internal class FirLightFieldForObjectSymbol(
private val objectSymbol: KtClassOrObjectSymbol,
containingClass: KtLightClass,
lightMemberOrigin: LightMemberOrigin?,
) : FirLightField(containingClass, lightMemberOrigin) {
override val kotlinOrigin: KtDeclaration? = objectSymbol.psi as? KtDeclaration
private val _name = if (objectSymbol.classKind == KtClassKind.COMPANION_OBJECT) objectSymbol.name.asString() else "INSTANCE"
override fun getName(): String = _name
private val _modifierList: PsiModifierList by lazyPub {
val modifiers = setOf(objectSymbol.computeVisibility(isTopLevel = false), PsiModifier.STATIC, PsiModifier.FINAL)
val notNullAnnotation = FirLightSimpleAnnotation("org.jetbrains.annotations.NotNull", this)
FirLightClassModifierList(this, modifiers, listOf(notNullAnnotation))
}
override fun getModifierList(): PsiModifierList? = _modifierList
private val _type: PsiType by lazyPub {
objectSymbol.typeForClassSymbol(this@FirLightFieldForObjectSymbol)
}
override fun getType(): PsiType = _type
override fun getInitializer(): PsiExpression? = null //TODO
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightFieldForObjectSymbol &&
kotlinOrigin == other.kotlinOrigin &&
objectSymbol == other.objectSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
}
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiExpression
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertyGetterSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol
import org.jetbrains.kotlin.psi.KtDeclaration
internal class FirLightFieldForPropertySymbol(
private val propertySymbol: KtPropertySymbol,
containingClass: FirLightClassBase,
lightMemberOrigin: LightMemberOrigin?,
isTopLevel: Boolean,
forceStatic: Boolean = false
) : FirLightField(containingClass, lightMemberOrigin) {
override val kotlinOrigin: KtDeclaration? = propertySymbol.psi as? KtDeclaration
private val _returnedType: PsiType by lazyPub {
propertySymbol.type.asPsiType(
propertySymbol,
this@FirLightFieldForPropertySymbol,
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE
)
}
override fun getType(): PsiType = _returnedType
private val _name = propertySymbol.name.asString()
override fun getName(): String = _name
private val _modifierList: PsiModifierList by lazyPub {
val modifiersFromSymbol = propertySymbol.computeModalityForMethod(isTopLevel = isTopLevel, isOverride = false)
val basicModifiers = modifiersFromSymbol.add(
what = PsiModifier.STATIC,
`if` = forceStatic
)
val isJvmField = propertySymbol.hasJvmFieldAnnotation()
val visibility =
if (isJvmField) propertySymbol.computeVisibility(isTopLevel = false) else PsiModifier.PRIVATE
val modifiersWithVisibility = basicModifiers + visibility
val modifiers = modifiersWithVisibility.add(
what = PsiModifier.FINAL,
`if` = !isJvmField || propertySymbol.isVal
)
val annotations = propertySymbol.computeAnnotations(
parent = this,
nullability = propertySymbol.type.getTypeNullability(propertySymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE),
annotationUseSiteTarget = AnnotationUseSiteTarget.FIELD,
)
FirLightClassModifierList(this, modifiers, annotations)
}
override fun getModifierList(): PsiModifierList? = _modifierList
override fun getInitializer(): PsiExpression? = null //TODO
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightFieldForPropertySymbol &&
kotlinOrigin == other.kotlinOrigin &&
propertySymbol == other.propertySymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
}
@@ -0,0 +1,282 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
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 org.jetbrains.annotations.NotNull
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf
import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.isPrimitiveNumberOrUnsignedNumberType
import org.jetbrains.kotlin.fir.isPrimitiveType
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.typeCheckerContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirClassType
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.*
import org.jetbrains.kotlin.idea.frontend.api.types.*
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.typeConstructor
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import java.text.StringCharacterIterator
internal fun <L : Any> L.invalidAccess(): Nothing =
error("Cls delegate shouldn't be accessed for fir light classes! Qualified name: ${javaClass.name}")
private fun PsiElement.nonExistentType() = JavaPsiFacade.getElementFactory(project)
.createTypeFromText("error.NonExistentClass", this)
internal fun KtTypedSymbol.asPsiType(parent: PsiElement, phase: FirResolvePhase): PsiType =
type.asPsiType(this, parent, phase)
internal fun KtType.asPsiType(
context: KtSymbol,
parent: PsiElement,
phase: FirResolvePhase
): PsiType {
require(this is KtFirType)
require(context is KtFirSymbol<*>)
val session = context.firRef.withFir(phase) { it.session }
return coneType.asPsiType(session, TypeMappingMode.DEFAULT, parent)
}
internal fun KtClassOrObjectSymbol.typeForClassSymbol(psiElement: PsiElement): PsiType {
require(this is KtFirClassOrObjectSymbol)
val (session, type) = firRef.withFir(FirResolvePhase.TYPES) { firClass ->
firClass.session to ConeClassLikeTypeImpl(
firClass.symbol.toLookupTag(),
firClass.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), isNullable = false) }.toTypedArray(),
isNullable = false
)
}
return type.asPsiType(session, TypeMappingMode.DEFAULT, psiElement)
}
private fun ConeKotlinType.asPsiType(
session: FirSession,
mode: TypeMappingMode,
psiContext: PsiElement,
): PsiType {
if (this is ConeClassErrorType || this !is SimpleTypeMarker) return psiContext.nonExistentType()
if (this.typeArguments.any { it is ConeClassErrorType }) return psiContext.nonExistentType()
if (this is ConeClassLikeType) {
val classId = classId
if (classId != null && classId.shortClassName.asString() == SpecialNames.ANONYMOUS) return PsiType.NULL
}
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS)
//TODO Check thread safety
session.jvmTypeMapper.mapType(this, mode, signatureWriter)
val canonicalSignature = signatureWriter.toString()
if (canonicalSignature == "[L<error>;") return psiContext.nonExistentType()
val signature = StringCharacterIterator(canonicalSignature)
val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER)
val typeInfo = TypeInfo.fromString(javaType, false)
val typeText = TypeInfo.createTypeText(typeInfo) ?: return psiContext.nonExistentType()
val typeElement = ClsTypeElementImpl(psiContext, typeText, '\u0000')
return typeElement.type
}
private fun mapSupertype(psiContext: PsiElement, session: FirSession, supertype: ConeKotlinType, kotlinCollectionAsIs: Boolean = false) =
supertype.asPsiType(
session,
if (kotlinCollectionAsIs) TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS else TypeMappingMode.SUPER_TYPE,
psiContext
) as? PsiClassType
internal fun KtClassType.mapSupertype(
psiContext: PsiElement,
kotlinCollectionAsIs: Boolean = false
): PsiClassType? {
require(this is KtFirClassType)
val contextSymbol = this.classSymbol
require(contextSymbol is KtFirSymbol<*>)
val session = contextSymbol.firRef.withFir { it.session }
return mapSupertype(
psiContext,
session,
this.coneType,
kotlinCollectionAsIs,
)
}
internal enum class NullabilityType {
Nullable,
NotNull,
Unknown
}
internal val KtType.nullabilityType: NullabilityType
get() =
(this as? KtTypeWithNullability)?.let {
if (it.nullability == KtTypeNullability.NULLABLE) NullabilityType.Nullable else NullabilityType.NotNull
} ?: NullabilityType.Unknown
internal fun FirMemberDeclaration.computeSimpleModality(): Set<String> {
require(this !is FirConstructor)
val modifier = when (modality) {
Modality.FINAL -> PsiModifier.FINAL
Modality.ABSTRACT -> PsiModifier.ABSTRACT
Modality.SEALED -> PsiModifier.ABSTRACT
else -> null
}
return modifier?.let { setOf(it) } ?: emptySet()
}
internal fun KtSymbolWithModality<*>.computeSimpleModality(): String? = when (modality) {
KtSymbolModality.SEALED -> PsiModifier.ABSTRACT
KtCommonSymbolModality.FINAL -> PsiModifier.FINAL
KtCommonSymbolModality.ABSTRACT -> PsiModifier.ABSTRACT
KtCommonSymbolModality.OPEN -> null
else -> throw NotImplementedError()
}
internal fun FirMemberDeclaration.computeModalityForMethod(isTopLevel: Boolean): Set<String> {
require(this !is FirConstructor)
val simpleModifier = computeSimpleModality()
val withNative = if (isExternal) simpleModifier + PsiModifier.NATIVE else simpleModifier
val withTopLevelStatic = if (isTopLevel) withNative + PsiModifier.STATIC else withNative
return withTopLevelStatic
}
internal fun KtSymbolWithModality<KtCommonSymbolModality>.computeModalityForMethod(isTopLevel: Boolean, isOverride: Boolean): Set<String> {
require(this !is KtClassLikeSymbol)
val modality = mutableSetOf<String>()
computeSimpleModality()?.run {
if (this != PsiModifier.FINAL || !isOverride) {
modality.add(this)
}
}
if (this is KtFunctionSymbol && isExternal) {
modality.add(PsiModifier.NATIVE)
}
if (isTopLevel) {
modality.add(PsiModifier.STATIC)
}
return modality
}
internal fun FirMemberDeclaration.computeVisibility(isTopLevel: Boolean): String {
return when (this.visibility) {
// Top-level private class has PACKAGE_LOCAL visibility in Java
// Nested private class has PRIVATE visibility
Visibilities.Private -> if (isTopLevel) PsiModifier.PACKAGE_LOCAL else PsiModifier.PRIVATE
Visibilities.Protected -> PsiModifier.PROTECTED
else -> PsiModifier.PUBLIC
}
}
internal fun KtSymbolWithVisibility.computeVisibility(isTopLevel: Boolean): String {
return when (this.visibility) {
// Top-level private class has PACKAGE_LOCAL visibility in Java
// Nested private class has PRIVATE visibility
KtSymbolVisibility.PRIVATE -> if (isTopLevel) PsiModifier.PACKAGE_LOCAL else PsiModifier.PRIVATE
KtSymbolVisibility.PROTECTED -> PsiModifier.PROTECTED
else -> PsiModifier.PUBLIC
}
}
internal fun basicIsEquivalentTo(`this`: PsiElement?, that: PsiElement?): Boolean {
if (`this` == null || that == null) return false
if (`this` == that) return true
if (`this` !is KtLightElement<*, *>) return false
if (that !is KtLightElement<*, *>) return false
if (`this`.kotlinOrigin?.isEquivalentTo(that.kotlinOrigin) == true) return true
val thisMemberOrigin = (`this` as? KtLightMember<*>)?.lightMemberOrigin ?: return false
if (thisMemberOrigin.isEquivalentTo(that)) return true
val thatMemberOrigin = (that as? KtLightMember<*>)?.lightMemberOrigin ?: return false
return thisMemberOrigin.isEquivalentTo(thatMemberOrigin)
}
internal fun KtType.getTypeNullability(context: KtSymbol, phase: FirResolvePhase): NullabilityType {
if (nullabilityType != NullabilityType.NotNull) return nullabilityType
if (isUnit) return NullabilityType.NotNull
require(this is KtFirType)
require(context is KtFirSymbol<*>)
if (coneType is ConeTypeParameterType) {
// TODO Make supertype checking
// val subtypeOfNullableSuperType = context.firRef.withFir(phase) {
// it.session.typeCheckerContext.nullableAnyType().isSupertypeOf(it.session.typeCheckerContext, coneType)
// }
// if (!subtypeOfNullableSuperType) return NullabilityType.NotNull
if (!coneType.isMarkedNullable) return NullabilityType.Unknown
return NullabilityType.NotNull
}
val coneType = coneType as? ConeClassLikeType ?: return NullabilityType.NotNull
if (!coneType.isPrimitiveType()) {
return nullabilityType
}
if (coneType is ConeClassErrorType) return NullabilityType.NotNull
if (coneType.typeArguments.any { it is ConeClassErrorType }) return NullabilityType.NotNull
if (coneType.classId?.shortClassName?.asString() == SpecialNames.ANONYMOUS) return NullabilityType.NotNull
val canonicalSignature = context.firRef.withFir(phase) {
it.session.jvmTypeMapper.mapType(coneType, TypeMappingMode.DEFAULT).descriptor
}
if (canonicalSignature == "[L<error>;") return NullabilityType.NotNull
val isNotPrimitiveType = canonicalSignature.startsWith("L") || canonicalSignature.startsWith("[")
return if (isNotPrimitiveType) NullabilityType.NotNull else NullabilityType.Unknown
}
internal fun <T> Set<T>.add(what: T, `if`: Boolean): Set<T> =
applyIf(`if`) { this + what }
internal inline fun <T> T.applyIf(`if`: Boolean, body: T.() -> T): T =
if (`if`) body() else this
@@ -0,0 +1,127 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightParameterListBuilder
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_FOR_GETTER
import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_FOR_SETTER
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertyAccessorSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertyGetterSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySetterSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol
import org.jetbrains.kotlin.load.java.JvmAbi.getterName
import org.jetbrains.kotlin.load.java.JvmAbi.setterName
import org.jetbrains.kotlin.psi.KtDeclaration
internal class FirLightAccessorMethodForSymbol(
private val propertyAccessorSymbol: KtPropertyAccessorSymbol,
containingPropertySymbol: KtPropertySymbol,
lightMemberOrigin: LightMemberOrigin?,
containingClass: FirLightClassBase,
isTopLevel: Boolean
) : FirLightMethod(
lightMemberOrigin,
containingClass,
if (propertyAccessorSymbol is KtPropertyGetterSymbol) METHOD_INDEX_FOR_GETTER else METHOD_INDEX_FOR_SETTER
) {
private fun String.abiName(firPropertyAccessor: KtPropertyAccessorSymbol) =
if (firPropertyAccessor is KtPropertyGetterSymbol) getterName(this)
else setterName(this)
//TODO add JvmName
private val _name: String by lazyPub {
containingPropertySymbol.name.identifier
.abiName(propertyAccessorSymbol)
}
override fun getName(): String = _name
override fun isVarArgs(): Boolean = false
override val kotlinOrigin: KtDeclaration? =
(propertyAccessorSymbol.psi ?: containingPropertySymbol.psi) as? KtDeclaration
private val _annotations: List<PsiAnnotation> by lazyPub {
val accessorSite =
if (propertyAccessorSymbol is KtPropertyGetterSymbol) AnnotationUseSiteTarget.PROPERTY_GETTER
else AnnotationUseSiteTarget.PROPERTY_SETTER
containingPropertySymbol.computeAnnotations(
parent = this,
nullability = NullabilityType.Unknown,
annotationUseSiteTarget = accessorSite,
)
}
private val _modifiers: Set<String> by lazyPub {
val isOverride = propertyAccessorSymbol.isOverride || containingPropertySymbol.isOverride
val modifiers = propertyAccessorSymbol.computeModalityForMethod(isTopLevel, isOverride) +
propertyAccessorSymbol.computeVisibility(isTopLevel)
val isJvmStatic =
_annotations.any { it.qualifiedName == "kotlin.jvm.JvmStatic" }
if (isJvmStatic) return@lazyPub modifiers + PsiModifier.STATIC
modifiers
}
private val _modifierList: PsiModifierList by lazyPub {
FirLightClassModifierList(this, _modifiers, _annotations)
}
override fun getModifierList(): PsiModifierList = _modifierList
override fun isConstructor(): Boolean = false
private val _returnedType: PsiType? by lazyPub {
if (propertyAccessorSymbol !is KtPropertyGetterSymbol) return@lazyPub PsiType.VOID
return@lazyPub containingPropertySymbol.type.asPsiType(
context = containingPropertySymbol,
parent = this@FirLightAccessorMethodForSymbol,
phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE
)
}
override fun getReturnType(): PsiType? = _returnedType
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightAccessorMethodForSymbol &&
kotlinOrigin == other.kotlinOrigin &&
propertyAccessorSymbol == other.propertyAccessorSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
private val _parametersList by lazyPub {
val builder = LightParameterListBuilder(manager, language)
FirLightParameterForReceiver.tryGet(containingPropertySymbol, this)?.let {
builder.addParameter(it)
}
val propertyParameter = (propertyAccessorSymbol as? KtPropertySetterSymbol)?.parameter
if (propertyParameter != null) {
builder.addParameter(
FirLightParameterForSymbol(
parameterSymbol = propertyParameter,
containingMethod = this@FirLightAccessorMethodForSymbol
)
)
}
builder
}
override fun getParameterList(): PsiParameterList = _parametersList
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtConstructorSymbol
internal class FirLightConstructorForSymbol(
private val constructorSymbol: KtConstructorSymbol,
lightMemberOrigin: LightMemberOrigin?,
containingClass: FirLightClassBase,
methodIndex: Int,
) : FirLightMethodForSymbol(constructorSymbol, lightMemberOrigin, containingClass, methodIndex) {
private val _name: String? = containingClass.name
override fun getName(): String = _name ?: ""
override fun isConstructor(): Boolean = true
private val _annotations: List<PsiAnnotation> by lazyPub {
constructorSymbol.computeAnnotations(
parent = this,
nullability = NullabilityType.Unknown,
annotationUseSiteTarget = null,
)
}
private val _modifiers: Set<String> by lazyPub {
setOf(constructorSymbol.computeVisibility(isTopLevel = false))
}
private val _modifierList: PsiModifierList by lazyPub {
FirLightClassModifierList(this, _modifiers, _annotations)
}
override fun getModifierList(): PsiModifierList = _modifierList
override fun getReturnType(): PsiType? = null
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightConstructorForSymbol &&
kotlinOrigin == other.kotlinOrigin &&
constructorSymbol == other.constructorSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import com.intellij.psi.impl.PsiImplUtil
import com.intellij.psi.impl.PsiSuperMethodImplUtil
import com.intellij.psi.util.MethodSignature
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.KotlinLightReferenceListBuilder
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
internal abstract class FirLightMethod(
lightMemberOrigin: LightMemberOrigin?,
containingClass: KtLightClass,
private val methodIndex: Int
) : FirLightMemberImpl<PsiMethod>(lightMemberOrigin, containingClass), KtLightMethod {
override fun getBody(): PsiCodeBlock? = null
override fun getReturnTypeElement(): PsiTypeElement? = null
override fun setName(p0: String): PsiElement = cannotModify()
override fun isVarArgs() = PsiImplUtil.isVarArgs(this)
override fun getHierarchicalMethodSignature() = PsiSuperMethodImplUtil.getHierarchicalMethodSignature(this)
override fun findSuperMethodSignaturesIncludingStatic(checkAccess: Boolean): List<MethodSignatureBackedByPsiMethod> =
PsiSuperMethodImplUtil.findSuperMethodSignaturesIncludingStatic(this, checkAccess)
override fun findDeepestSuperMethod() = PsiSuperMethodImplUtil.findDeepestSuperMethod(this)
override fun findDeepestSuperMethods(): Array<out PsiMethod> = PsiSuperMethodImplUtil.findDeepestSuperMethods(this)
override fun findSuperMethods(): Array<out PsiMethod> = PsiSuperMethodImplUtil.findSuperMethods(this)
override fun findSuperMethods(checkAccess: Boolean): Array<out PsiMethod> =
PsiSuperMethodImplUtil.findSuperMethods(this, checkAccess)
override fun findSuperMethods(parentClass: PsiClass?): Array<out PsiMethod> =
PsiSuperMethodImplUtil.findSuperMethods(this, parentClass)
override fun getSignature(substitutor: PsiSubstitutor): MethodSignature =
MethodSignatureBackedByPsiMethod.create(this, substitutor)
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
override fun accept(visitor: PsiElementVisitor) {
if (visitor is JavaElementVisitor) {
visitor.visitMethod(this)
} else {
visitor.visitElement(this)
}
}
override val isMangled: Boolean = false
override fun getTypeParameters(): Array<PsiTypeParameter> = emptyArray() //TODO
override fun hasTypeParameters(): Boolean = false //TODO
override fun getTypeParameterList(): PsiTypeParameterList? = null //TODO
override fun getThrowsList(): PsiReferenceList =
KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST) //TODO()
override fun getDefaultValue(): PsiAnnotationMemberValue? = null //TODO()
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightParameterListBuilder
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.KotlinLightReferenceListBuilder
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
import org.jetbrains.kotlin.psi.KtDeclaration
import java.util.*
internal abstract class FirLightMethodForSymbol(
private val functionSymbol: KtFunctionLikeSymbol,
lightMemberOrigin: LightMemberOrigin?,
containingClass: FirLightClassBase,
methodIndex: Int,
argumentsSkipMask: BitSet? = null
) : FirLightMethod(
lightMemberOrigin,
containingClass,
methodIndex
) {
private var _isVarArgs: Boolean = functionSymbol.valueParameters.any { it.isVararg }
override fun isVarArgs(): Boolean = _isVarArgs
private val _parametersList by lazyPub {
val builder = LightParameterListBuilder(manager, language)
FirLightParameterForReceiver.tryGet(functionSymbol, this)?.let {
builder.addParameter(it)
}
functionSymbol.valueParameters.mapIndexed { index, parameter ->
val needToSkip = argumentsSkipMask?.get(index) == true
if (!needToSkip) {
builder.addParameter(
FirLightParameterForSymbol(
parameterSymbol = parameter,
containingMethod = this@FirLightMethodForSymbol
)
)
}
}
builder
}
override fun getParameterList(): PsiParameterList = _parametersList
override val kotlinOrigin: KtDeclaration? = functionSymbol.psi as? KtDeclaration
}
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.isUnit
import java.util.*
internal class FirLightSimpleMethodForSymbol(
private val functionSymbol: KtFunctionSymbol,
lightMemberOrigin: LightMemberOrigin?,
containingClass: FirLightClassBase,
methodIndex: Int,
isTopLevel: Boolean,
argumentsSkipMask: BitSet? = null
) : FirLightMethodForSymbol(
functionSymbol = functionSymbol,
lightMemberOrigin = lightMemberOrigin,
containingClass = containingClass,
methodIndex = methodIndex,
argumentsSkipMask = argumentsSkipMask
) {
private val _name: String by lazyPub {
functionSymbol.getJvmNameFromAnnotation(null) ?: functionSymbol.name.asString()
}
override fun getName(): String = _name
private val _annotations: List<PsiAnnotation> by lazyPub {
val nullability = if (functionSymbol.type.isUnit) NullabilityType.Unknown else functionSymbol.type.getTypeNullability(
functionSymbol,
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE
)
functionSymbol.computeAnnotations(
parent = this,
nullability = nullability,
annotationUseSiteTarget = null,
)
}
private val _modifiers: Set<String> by lazyPub {
if (functionSymbol.hasInlineOnlyAnnotation()) return@lazyPub setOf(PsiModifier.FINAL, PsiModifier.PRIVATE)
val modifiers = functionSymbol.computeModalityForMethod(isTopLevel = isTopLevel, functionSymbol.isOverride) +
functionSymbol.computeVisibility(isTopLevel = isTopLevel)
if (functionSymbol.hasJvmStaticAnnotation()) return@lazyPub modifiers + PsiModifier.STATIC
modifiers
}
private val _modifierList: PsiModifierList by lazyPub {
FirLightClassModifierList(this, _modifiers, _annotations)
}
override fun getModifierList(): PsiModifierList = _modifierList
override fun isConstructor(): Boolean = false
private val _returnedType: PsiType by lazyPub {
if (functionSymbol.type.isUnit) return@lazyPub PsiType.VOID
functionSymbol.asPsiType(this@FirLightSimpleMethodForSymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
}
override fun getReturnType(): PsiType = _returnedType
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightSimpleMethodForSymbol &&
kotlinOrigin == other.kotlinOrigin &&
functionSymbol == other.functionSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiModifierListOwner
import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.psi.KtModifierListOwner
internal class FirLightClassModifierList<T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(
containingDeclaration: T,
private val modifiers: Set<String>,
private val annotations: List<PsiAnnotation>
) : FirLightModifierList<T>(containingDeclaration) {
override fun hasModifierProperty(name: String): Boolean = name in modifiers
override val givenAnnotations: List<KtLightAbstractAnnotation>?
get() = invalidAccess()
override fun getAnnotations(): Array<out PsiAnnotation> = annotations.toTypedArray()
override fun findAnnotation(qualifiedName: String) = annotations.firstOrNull { it.qualifiedName == qualifiedName }
override fun equals(other: Any?): Boolean = this === other
override fun hashCode(): Int = kotlinOrigin.hashCode()
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiModifierListOwner
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.psi.KtModifierList
import org.jetbrains.kotlin.psi.KtModifierListOwner
internal abstract class FirLightModifierList<out T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(
protected val owner: T
) : KtLightElementBase(owner), PsiModifierList, KtLightElement<KtModifierList, PsiModifierListOwner> {
override val clsDelegate: PsiModifierListOwner
get() = invalidAccess()
override val kotlinOrigin: KtModifierList?
get() = owner.kotlinOrigin?.modifierList
override fun getParent() = owner
override fun hasExplicitModifier(name: String) = hasModifierProperty(name)
override fun setModifierProperty(name: String, value: Boolean) = cannotModify()
override fun checkSetModifierProperty(name: String, value: Boolean) = throw IncorrectOperationException()
override fun addAnnotation(qualifiedName: String): PsiAnnotation = cannotModify()
override fun getApplicableAnnotations(): Array<out PsiAnnotation> = annotations
override fun getAnnotations(): Array<out PsiAnnotation> = emptyArray() //TODO()
override fun findAnnotation(qualifiedName: String): PsiAnnotation? = null //TODO()
override fun isEquivalentTo(another: PsiElement?) =
another is FirLightModifierList<*> && owner == another.owner
override fun isWritable() = false
override fun toString() = "Light modifier list of $owner"
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
}
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.navigation.NavigationItem
import com.intellij.psi.*
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.psi.KtParameter
internal abstract class FirLightParameter(containingDeclaration: FirLightMethod) : PsiVariable, NavigationItem,
KtLightElement<KtParameter, PsiParameter>, KtLightParameter, KtLightElementBase(containingDeclaration) {
override val clsDelegate: PsiParameter
get() = invalidAccess()
override val givenAnnotations: List<KtLightAbstractAnnotation>
get() = invalidAccess()
override fun getTypeElement(): PsiTypeElement? = null
override fun getInitializer(): PsiExpression? = null
override fun hasInitializer(): Boolean = false
override fun computeConstantValue(): Any? = null
override fun getNameIdentifier(): PsiIdentifier? = null
abstract override fun getName(): String
@Throws(IncorrectOperationException::class)
override fun normalizeDeclaration() {
}
override fun setName(p0: String): PsiElement = TODO() //cannotModify()
override val method: KtLightMethod = containingDeclaration
override fun getDeclarationScope(): KtLightMethod = method
override fun accept(visitor: PsiElementVisitor) {
if (visitor is JavaElementVisitor) {
visitor.visitParameter(this)
}
}
override fun toString(): String = "Fir Light Parameter $name"
override fun isEquivalentTo(another: PsiElement?): Boolean =
basicIsEquivalentTo(this, another as? PsiParameter)
override fun getNavigationElement(): PsiElement = kotlinOrigin ?: method.navigationElement
override fun getUseScope(): SearchScope = kotlinOrigin?.useScope ?: LocalSearchScope(this)
override fun isValid() = parent.isValid
abstract override fun getType(): PsiType
override fun getContainingFile(): PsiFile = method.containingFile
override fun getParent(): PsiElement = method.parameterList
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
abstract override fun isVarArgs(): Boolean
}
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtPossibleExtensionSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.psi.KtParameter
internal class FirLightParameterForReceiver private constructor(
private val annotatedSymbol: KtAnnotatedSymbol,
type: KtType,
methodName: String,
method: FirLightMethod
) : FirLightParameter(method) {
companion object {
fun tryGet(
callableSymbol: KtCallableSymbol,
method: FirLightMethod
): FirLightParameterForReceiver? {
if (callableSymbol !is KtNamedSymbol) return null
if (callableSymbol !is KtAnnotatedSymbol) return null
if (callableSymbol !is KtPossibleExtensionSymbol) return null
if (!callableSymbol.isExtension) return null
val receiverType = callableSymbol.receiverType ?: return null
return FirLightParameterForReceiver(
annotatedSymbol = callableSymbol,
type = receiverType,
methodName = callableSymbol.name.asString(),
method = method
)
}
}
private val _name: String by lazyPub {
AsmUtil.getLabeledThisName(methodName, AsmUtil.LABELED_THIS_PARAMETER, AsmUtil.RECEIVER_PARAMETER_NAME)
}
override fun getName(): String = _name
override fun isVarArgs() = false
override fun hasModifierProperty(name: String): Boolean = false //TODO()
override val kotlinOrigin: KtParameter? = null
private val _annotations: List<PsiAnnotation> by lazyPub {
annotatedSymbol.computeAnnotations(
parent = this,
nullability = type.getTypeNullability(annotatedSymbol, FirResolvePhase.TYPES),
annotationUseSiteTarget = AnnotationUseSiteTarget.RECEIVER,
)
}
override fun getModifierList(): PsiModifierList = _modifierList
private val _modifierList: PsiModifierList by lazyPub {
FirLightClassModifierList(this, emptySet(), _annotations)
}
private val _type: PsiType by lazyPub {
type.asPsiType(annotatedSymbol, method, FirResolvePhase.TYPES)
}
override fun getType(): PsiType = _type
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightParameterForReceiver &&
kotlinOrigin == other.kotlinOrigin &&
annotatedSymbol == other.annotatedSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2020 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.idea.asJava
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtParameterSymbol
import org.jetbrains.kotlin.psi.KtParameter
internal class FirLightParameterForSymbol(
private val parameterSymbol: KtParameterSymbol,
containingMethod: FirLightMethod
) : FirLightParameter(containingMethod) {
private val _name: String = parameterSymbol.name.asString()
override fun getName(): String = _name
private val _isVarArgs: Boolean = parameterSymbol.isVararg
override fun isVarArgs() = _isVarArgs
override fun hasModifierProperty(name: String): Boolean =
modifierList.hasModifierProperty(name)
override val kotlinOrigin: KtParameter? = parameterSymbol.psi as? KtParameter
private val _annotations: List<PsiAnnotation> by lazyPub {
parameterSymbol.computeAnnotations(
parent = this,
nullability = parameterSymbol.type.getTypeNullability(parameterSymbol, FirResolvePhase.TYPES),
annotationUseSiteTarget = null,
)
}
override fun getModifierList(): PsiModifierList = _modifierList
private val _modifierList: PsiModifierList by lazyPub {
FirLightClassModifierList(this, emptySet(), _annotations)
}
private val _type by lazyPub {
val convertedType = parameterSymbol.asPsiType(this, FirResolvePhase.TYPES)
if (convertedType is PsiArrayType && parameterSymbol.isVararg) {
PsiEllipsisType(convertedType.componentType, convertedType.annotationProvider)
} else convertedType
}
override fun getType(): PsiType = _type
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightParameterForSymbol &&
kotlinOrigin == other.kotlinOrigin &&
parameterSymbol == other.parameterSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
}
@@ -15,4 +15,4 @@ class KtFirAnnotationCall(
override val useSiteTarget: AnnotationUseSiteTarget?,
override val psi: KtCallElement?,
override val arguments: List<KtNamedConstantValue>
) : KtAnnotationCall()
) : KtAnnotationCall()
@@ -60,6 +60,9 @@ internal class KtFirClassOrObjectSymbol(
builder.buildKtType(it)
}
}
override val primaryConstructor: KtConstructorSymbol? by firRef.withFirAndCache(FirResolvePhase.RAW_FIR) { fir ->
fir.getPrimaryConstructorIfAny()?.let { builder.buildConstructorSymbol(it) }
}
override val typeParameters by firRef.withFirAndCache {
fir.typeParameters.map { typeParameter ->
@@ -8,15 +8,8 @@ package org.jetbrains.kotlin.idea.asJava
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.impl.light.AbstractLightClass
import com.intellij.psi.impl.light.LightMethod
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
interface LightClassProvider {
+11
View File
@@ -100,6 +100,9 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
<projectService serviceInterface="org.jetbrains.kotlin.idea.asJava.LightClassProvider"
serviceImplementation="org.jetbrains.kotlin.idea.asJava.LightClassProviderFirImpl"/>
<projectService serviceInterface="org.jetbrains.kotlin.psi.KtFileClassProvider"
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.KtFileClassProviderImpl"/>
<completion.contributor language="kotlin"
id="KotlinCompletionContributor"
order="first"
@@ -204,6 +207,14 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/>
<java.elementFinder implementation="org.jetbrains.kotlin.asJava.finder.JavaElementFinder"/>
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinAsJavaSupport"
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IDEKotlinAsJavaFirSupport"/>
<projectService serviceInterface="org.jetbrains.kotlin.asJava.LightClassGenerationSupport"
serviceImplementation="org.jetbrains.kotlin.idea.asJava.FirLightClassGenerationSupport"/>
<elementDescriptionProvider
implementation="org.jetbrains.kotlin.idea.findUsages.KotlinElementDescriptionProviderBase"
order="first"/>