diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt index 3c741617e5d..32b6c3d11d9 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt @@ -8,24 +8,15 @@ 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.idea.asJava.classes.getOrCreateFirLightClass 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) @@ -38,23 +29,6 @@ class IDEKotlinAsJavaFirSupport(project: Project) : IDEKotlinAsJavaSupport(proje 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 - ) - } - } + getOrCreateFirLightClass(classOrObject) } \ No newline at end of file diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt index 92532113869..929bd7fd476 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt @@ -18,8 +18,6 @@ abstract class KtEnumEntrySymbol : KtVariableLikeSymbol(), KtSymbolWithDeclarati final override val symbolKind: KtSymbolKind get() = KtSymbolKind.MEMBER abstract val containingEnumClassIdIfNonLocal: ClassId? - abstract val hasBody: Boolean - abstract override fun createPointer(): KtSymbolPointer } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirFakeFileImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirFakeFileImpl.kt index 81714e44270..544278c910d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirFakeFileImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirFakeFileImpl.kt @@ -12,11 +12,12 @@ 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.idea.asJava.classes.getOrCreateFirLightClass 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))!! }, + { if (classOrObject.isTopLevel()) ktClass else getOrCreateFirLightClass(getOutermostClassOrObject(classOrObject))!! }, { null } ) { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt index c27bf26a7c5..74733d103d8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt @@ -66,6 +66,9 @@ internal fun KtAnnotatedSymbol.isHiddenByDeprecation(annotationUseSiteTarget: An internal fun KtAnnotatedSymbol.hasJvmFieldAnnotation(): Boolean = hasAnnotation("kotlin/jvm/JvmField", null) +internal fun KtAnnotatedSymbol.hasPublishedApiAnnotation(annotationUseSiteTarget: AnnotationUseSiteTarget? = null): Boolean = + hasAnnotation("kotlin/PublishedApi", annotationUseSiteTarget) + internal fun KtAnnotatedSymbol.hasJvmOverloadsAnnotation(): Boolean = hasAnnotation("kotlin/jvm/JvmOverloads", null) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassBase.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassBase.kt deleted file mode 100644 index a8aa43457fe..00000000000 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassBase.kt +++ /dev/null @@ -1,267 +0,0 @@ -/* - * 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 = myInnersCache.fields - - override fun getMethods(): Array = myInnersCache.methods - - override fun getConstructors(): Array = myInnersCache.constructors - - override fun getInnerClasses(): Array = myInnersCache.innerClasses - - override fun getAllFields(): Array = PsiClassImplUtil.getAllFields(this) - - override fun getAllMethods(): Array = PsiClassImplUtil.getAllMethods(this) - - override fun getAllInnerClasses(): Array = PsiClassImplUtil.getAllInnerClasses(this) - - override fun findFieldByName(name: String, checkBases: Boolean) = - myInnersCache.findFieldByName(name, checkBases) - - override fun findMethodsByName(name: String, checkBases: Boolean): Array = - 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 = - PsiClassImplUtil.getExtendsListTypes(this) - - override fun getImplementsListTypes(): Array = - 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 = - patternMethod?.let { PsiClassImplUtil.findMethodsBySignature(this, it, checkBases) } ?: emptyArray() - - override fun findMethodsAndTheirSubstitutorsByName( - @NonNls name: String?, - checkBases: Boolean - ): List?> = - PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases) - - override fun getAllMethodsAndTheirSubstitutors(): List?> { - 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, isTopLevel: Boolean, result: MutableList) { - 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, isTopLevel: Boolean, result: MutableList) { - //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 - ) - ) - } - } -} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForSymbol.kt deleted file mode 100644 index fbac14f7c11..00000000000 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForSymbol.kt +++ /dev/null @@ -1,350 +0,0 @@ -/* - * 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> { - - 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 = _ownFields - override fun getOwnMethods(): List = _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 = emptyArray() //TODO() - - override fun getOwnInnerClasses(): List { - val result = ArrayList() - - // 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().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 by lazyPub { - - val result = mutableListOf() - - 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 by lazyPub { - - val result = mutableListOf() - - classOrObjectSymbol.companionObject?.run { - result.add(FirLightFieldForObjectSymbol(this, this@FirLightClassForSymbol, null)) - - if (!isInterface) { - analyzeWithSymbolAsContext(this) { - getDeclaredMemberScope().getCallableSymbols() - .filterIsInstance() - .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() - .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, *>? = kotlinOrigin?.elementType - override fun getStub(): KotlinClassOrObjectStub? = kotlinOrigin?.stub - - override val originKind: LightClassOriginKind - get() = LightClassOriginKind.SOURCE - - override fun getQualifiedName() = kotlinOrigin?.fqName?.asString() - - override fun getInterfaces(): Array = PsiClassImplUtil.getInterfaces(this) - override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this) - override fun getSupers(): Array = PsiClassImplUtil.getSupers(this) - override fun getSuperTypes(): Array = PsiClassImplUtil.getSuperTypes(this) - override fun getVisibleSignatures(): MutableCollection = PsiSuperMethodImplUtil.getVisibleSignatures(this) - - override fun getRBrace(): PsiElement? = null - override fun getLBrace(): PsiElement? = null - - override fun getInitializers(): Array = 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 - ) - } - } - } -} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnnotationClassSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnnotationClassSymbol.kt new file mode 100644 index 00000000000..3e74e931ff1 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnnotationClassSymbol.kt @@ -0,0 +1,67 @@ +/* + * 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.classes + +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiReferenceList +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.idea.asJava.FirLightClassForClassOrObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassKind +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol +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.markers.KtSymbolVisibility + +internal class FirLightAnnotationClassSymbol( + private val classOrObjectSymbol: KtClassOrObjectSymbol, + manager: PsiManager +) : FirLightInterfaceOrAnnotationClassSymbol(classOrObjectSymbol, manager) { + + init { + require(classOrObjectSymbol.classKind == KtClassKind.ANNOTATION_CLASS) + } + + override fun isAnnotationType(): Boolean = true + + private val _ownFields: List by lazyPub { +//TODO + mutableListOf().also { + it.addCompanionObjectFieldIfNeeded() + } + } + + override fun getOwnFields(): List = _ownFields + + private val _ownMethods: List by lazyPub { +//TODO + val result = mutableListOf() + + analyzeWithSymbolAsContext(classOrObjectSymbol) { + val visibleDeclarations = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols() + .filterNot { it is KtFunctionSymbol && it.visibility == KtSymbolVisibility.PRIVATE } + .filterNot { it is KtConstructorSymbol } + + createMethods(visibleDeclarations, isTopLevel = false, result) + } + + result + } + + override fun getOwnMethods(): List = _ownMethods + + override fun getExtendsList(): PsiReferenceList? = null + + override fun equals(other: Any?): Boolean = + other is FirLightAnnotationClassSymbol && classOrObjectSymbol == other.classOrObjectSymbol + + override fun hashCode(): Int = classOrObjectSymbol.hashCode() + + override fun copy(): FirLightClassForClassOrObjectSymbol = FirLightAnnotationClassSymbol(classOrObjectSymbol, manager) +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassBase.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassBase.kt new file mode 100644 index 00000000000..d33adf7bde9 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassBase.kt @@ -0,0 +1,156 @@ +/* + * 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.PsiSuperMethodImplUtil +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.cannotModify +import org.jetbrains.kotlin.idea.KotlinLanguage +import javax.swing.Icon + +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 = myInnersCache.fields + + override fun getMethods(): Array = myInnersCache.methods + + override fun getConstructors(): Array = myInnersCache.constructors + + override fun getInnerClasses(): Array = myInnersCache.innerClasses + + override fun getAllFields(): Array = PsiClassImplUtil.getAllFields(this) + + override fun getAllMethods(): Array = PsiClassImplUtil.getAllMethods(this) + + override fun getAllInnerClasses(): Array = PsiClassImplUtil.getAllInnerClasses(this) + + override fun findFieldByName(name: String, checkBases: Boolean) = + myInnersCache.findFieldByName(name, checkBases) + + override fun findMethodsByName(name: String, checkBases: Boolean): Array = + 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 = + PsiClassImplUtil.getExtendsListTypes(this) + + override fun getImplementsListTypes(): Array = + 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 = + patternMethod?.let { PsiClassImplUtil.findMethodsBySignature(this, it, checkBases) } ?: emptyArray() + + override fun findMethodsAndTheirSubstitutorsByName( + @NonNls name: String?, + checkBases: Boolean + ): List?> = + PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases) + + override fun getAllMethodsAndTheirSubstitutors(): List?> { + return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD) + } + + override fun getRBrace(): PsiElement? = null + + override fun getLBrace(): PsiElement? = null + + override fun getInitializers(): Array = PsiClassInitializer.EMPTY_ARRAY + + override fun getElementIcon(flags: Int): Icon? = + throw UnsupportedOperationException("This should be done by KotlinFirIconProvider") + + override fun getVisibleSignatures(): MutableCollection = PsiSuperMethodImplUtil.getVisibleSignatures(this) + + override fun setName(name: String): PsiElement? = cannotModify() + + abstract override fun copy(): PsiElement + + override fun accept(visitor: PsiElementVisitor) { + if (visitor is JavaElementVisitor) { + visitor.visitClass(this) + } else { + visitor.visitElement(this) + } + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForClassOrObjectSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForClassOrObjectSymbol.kt new file mode 100644 index 00000000000..4634e076c21 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForClassOrObjectSymbol.kt @@ -0,0 +1,180 @@ +/* + * 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.search.SearchScope +import com.intellij.psi.stubs.IStubElementType +import com.intellij.psi.stubs.StubElement +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.asJava.classes.KotlinSuperTypeListBuilder +import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.idea.asJava.classes.getOrCreateFirLightClass +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.types.KtClassType +import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.idea.util.ifFalse +import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind +import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtClassBody +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.debugText.getDebugText +import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub + +internal abstract class FirLightClassForClassOrObjectSymbol( + private val classOrObjectSymbol: KtClassOrObjectSymbol, + manager: PsiManager +) : FirLightClassBase(manager), + StubBasedPsiElement> { + + private val isTopLevel: Boolean = classOrObjectSymbol.symbolKind == KtSymbolKind.TOP_LEVEL + + abstract override fun getModifierList(): PsiModifierList? + abstract override fun getOwnFields(): List + abstract override fun getOwnMethods(): List + override fun isDeprecated(): Boolean = false //TODO() + override fun getNameIdentifier(): KtLightIdentifier? = null //TODO() + abstract override fun getExtendsList(): PsiReferenceList? + abstract override fun getImplementsList(): PsiReferenceList? + override fun getTypeParameterList(): PsiTypeParameterList? = null //TODO() + override fun getTypeParameters(): Array = emptyArray() //TODO() + + abstract override fun getOwnInnerClasses(): List + + 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 + + protected fun createInheritanceList(forExtendsList: Boolean): PsiReferenceList { + + val role = if (forExtendsList) PsiReferenceList.Role.EXTENDS_LIST else PsiReferenceList.Role.IMPLEMENTS_LIST + + val listBuilder = KotlinSuperTypeListBuilder( + kotlinOrigin = kotlinOrigin?.getSuperTypeList(), + manager = manager, + language = language, + role = role + ) + + fun KtType.needToAddTypeIntoList(): Boolean { + if (this !is KtClassType) return false + + // Do not add redundant "extends java.lang.Object" anywhere + if (this.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 && this.classId == StandardClassIds.Enum) return false + + val isInterfaceType = + (this.classSymbol as? KtClassOrObjectSymbol)?.classKind == KtClassKind.INTERFACE + + return forExtendsList == !isInterfaceType + } + + //TODO Add support for kotlin.collections. + classOrObjectSymbol.superTypes + .filterIsInstance() + .filter { it.needToAddTypeIntoList() } + .mapNotNull { it.mapSupertype(this, kotlinCollectionAsIs = true) } + .forEach { listBuilder.addReference(it) } + + return listBuilder + } + + protected fun MutableList.addCompanionObjectFieldIfNeeded() { + classOrObjectSymbol.companionObject?.run { + add(FirLightFieldForObjectSymbol(this, this@FirLightClassForClassOrObjectSymbol, null)) + } + } + + private val _containingFile: PsiFile? by lazyPub { + + val kotlinOrigin = kotlinOrigin ?: return@lazyPub null + + val containingClass = isTopLevel.ifFalse { getOrCreateFirLightClass(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) + + abstract override fun equals(other: Any?): Boolean + + abstract override fun hashCode(): Int + + override fun getName(): String = classOrObjectSymbol.name.asString() + + override fun hasModifierProperty(@NonNls name: String): Boolean = modifierList?.hasModifierProperty(name) ?: false + + abstract override fun isInterface(): Boolean + + abstract override fun isAnnotationType(): Boolean + + abstract override fun isEnum(): Boolean + + 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) + + override fun toString() = + "${this::class.java.simpleName}:${kotlinOrigin?.getDebugText()}" + + override fun getUseScope(): SearchScope = kotlinOrigin?.useScope ?: TODO() + override fun getElementType(): IStubElementType, *>? = kotlinOrigin?.elementType + override fun getStub(): KotlinClassOrObjectStub? = kotlinOrigin?.stub + + override val originKind: LightClassOriginKind + get() = LightClassOriginKind.SOURCE + + override fun getQualifiedName() = kotlinOrigin?.fqName?.asString() + + override fun getInterfaces(): Array = PsiClassImplUtil.getInterfaces(this) + override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this) + override fun getSupers(): Array = PsiClassImplUtil.getSupers(this) + override fun getSuperTypes(): Array = PsiClassImplUtil.getSuperTypes(this) + + override fun getContainingClass(): PsiClass? { + + val containingBody = kotlinOrigin?.parent as? KtClassBody + val containingClass = containingBody?.parent as? KtClassOrObject + containingClass?.let { return getOrCreateFirLightClass(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 + + abstract override fun copy(): FirLightClassForClassOrObjectSymbol +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForEnumEntry.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForEnumEntry.kt new file mode 100644 index 00000000000..3765c197186 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForEnumEntry.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.psi.* +import com.intellij.psi.impl.PsiClassImplUtil +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.idea.asJava.* +import org.jetbrains.kotlin.idea.asJava.FirLightClassModifierList +import org.jetbrains.kotlin.idea.asJava.FirLightPsiJavaCodeReferenceElementWithNoReference +import org.jetbrains.kotlin.idea.asJava.classes.createMethods +import org.jetbrains.kotlin.idea.asJava.fields.FirLightFieldForEnumEntry +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtEnumEntrySymbol +import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType +import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind +import org.jetbrains.kotlin.psi.KtClassOrObject + +internal class FirLightClassForEnumEntry( + private val enumEntrySymbol: KtEnumEntrySymbol, + private val enumConstant: FirLightFieldForEnumEntry, + private val enumClass: FirLightClassForSymbol, + manager: PsiManager +) : FirLightClassBase(manager), PsiEnumConstantInitializer { + + override fun getName(): String? = enumEntrySymbol.name.asString() + + override fun getBaseClassType(): PsiClassType = enumConstant.type as PsiClassType //???TODO + + override fun getBaseClassReference(): PsiJavaCodeReferenceElement = + FirLightPsiJavaCodeReferenceElementWithNoReference(enumConstant) //???TODO + + override fun getArgumentList(): PsiExpressionList? = null + + override fun getEnumConstant(): PsiEnumConstant = enumConstant + + override fun isInQualifiedNew(): Boolean = false + + override fun equals(other: Any?): Boolean = + other is FirLightClassForEnumEntry && + this.enumEntrySymbol == other.enumEntrySymbol + + override fun hashCode(): Int = + enumEntrySymbol.hashCode() + + override fun copy(): PsiElement = + FirLightClassForEnumEntry(enumEntrySymbol, enumConstant, enumClass, manager) + + override fun toString(): String = "FirLightClassForEnumEntry for $name" + + override fun getNameIdentifier(): PsiIdentifier? = null //TODO + + private val _modifierList: PsiModifierList by lazyPub { + FirLightClassModifierList( + containingDeclaration = this, + modifiers = setOf(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL), + annotations = emptyList() + ) + } + + override fun getModifierList(): PsiModifierList? = _modifierList + + override fun hasModifierProperty(name: String): Boolean = + name == PsiModifier.PUBLIC || name == PsiModifier.STATIC || name == PsiModifier.FINAL + + override fun getContainingClass(): PsiClass? = enumClass + + override fun isDeprecated(): Boolean = false + + override fun getTypeParameters(): Array = emptyArray() + + override fun getTypeParameterList(): PsiTypeParameterList? = null + + override fun getQualifiedName(): String? = "${enumConstant.containingClass.qualifiedName}.${enumConstant.name}" + + override fun isInterface(): Boolean = false + + override fun isAnnotationType(): Boolean = false + + override fun isEnum(): Boolean = false + + private val _extendsList: PsiReferenceList? by lazyPub { + + val mappedType = (enumEntrySymbol.type as? KtClassType)?.let { + it.mapSupertype(this@FirLightClassForEnumEntry) + } ?: return@lazyPub null + + KotlinSuperTypeListBuilder( + kotlinOrigin = enumClass.kotlinOrigin?.getSuperTypeList(), + manager = manager, + language = language, + role = PsiReferenceList.Role.EXTENDS_LIST + ).also { + it.addReference(mappedType) + } + } + + override fun getExtendsList(): PsiReferenceList? = _extendsList + + override fun getImplementsList(): PsiReferenceList? = null + + override fun getSuperClass(): PsiClass? = enumClass + + override fun getInterfaces(): Array = PsiClass.EMPTY_ARRAY + + override fun getSupers(): Array = arrayOf(enumClass) + + override fun getSuperTypes(): Array = PsiClassImplUtil.getSuperTypes(this) + + override fun getParent(): PsiElement? = containingClass ?: containingFile + + override fun getScope(): PsiElement? = parent + + override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean = false //TODO + + override fun isInheritorDeep(baseClass: PsiClass?, classToByPass: PsiClass?): Boolean = false //TODO + + override val kotlinOrigin: KtClassOrObject? = enumConstant.kotlinOrigin + + override val originKind: LightClassOriginKind = LightClassOriginKind.SOURCE + + override fun getOwnFields(): MutableList = mutableListOf() + + override fun getOwnMethods(): MutableList { + val result = mutableListOf() + + analyzeWithSymbolAsContext(enumEntrySymbol) { + val callableSymbols = enumEntrySymbol.getDeclaredMemberScope().getCallableSymbols() + createMethods(callableSymbols, isTopLevel = false, result) + } + + return result + } + + override fun getOwnInnerClasses(): MutableList = mutableListOf() +} diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForFacade.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForFacade.kt similarity index 91% rename from idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForFacade.kt rename to idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForFacade.kt index 2a1db0cb593..7aad6cd5fdd 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForFacade.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForFacade.kt @@ -8,26 +8,23 @@ 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.asJava.classes.createFields +import org.jetbrains.kotlin.idea.asJava.classes.createMethods 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, @@ -200,20 +197,12 @@ class FirLightClassForFacade( override fun getAllInnerClasses(): Array = PsiClass.EMPTY_ARRAY - override fun getInitializers(): Array = PsiClassInitializer.EMPTY_ARRAY - override fun findInnerClassByName(@NonNls name: String, checkBases: Boolean): PsiClass? = null override fun isInheritorDeep(baseClass: PsiClass?, classToByPass: PsiClass?): Boolean = false - override fun getLBrace(): PsiElement? = null - - override fun getRBrace(): PsiElement? = null - override fun getName(): String = facadeClassFqName.shortName().asString() - override fun setName(name: String): PsiElement? = cannotModify() - override fun getQualifiedName() = facadeClassFqName.asString() override fun getNameIdentifier(): PsiIdentifier? = null @@ -225,8 +214,6 @@ class FirLightClassForFacade( 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 } @@ -267,6 +254,4 @@ class FirLightClassForFacade( override fun getStartOffsetInParent() = firstFileInFacade.startOffsetInParent override fun isWritable() = files.all { it.isWritable } - - override fun getVisibleSignatures(): MutableCollection = PsiSuperMethodImplUtil.getVisibleSignatures(this) } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForSymbol.kt new file mode 100644 index 00000000000..1f211b4b10b --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForSymbol.kt @@ -0,0 +1,195 @@ +/* + * 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.METHOD_INDEX_FOR_DEFAULT_CTOR +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.idea.asJava.classes.createFields +import org.jetbrains.kotlin.idea.asJava.classes.createMethods +import org.jetbrains.kotlin.idea.asJava.fields.FirLightFieldForEnumEntry +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.symbols.markers.KtSymbolWithVisibility + +internal class FirLightClassForSymbol( + private val classOrObjectSymbol: KtClassOrObjectSymbol, + manager: PsiManager +) : FirLightClassForClassOrObjectSymbol(classOrObjectSymbol, manager) { + + init { + require(classOrObjectSymbol.classKind != KtClassKind.INTERFACE && classOrObjectSymbol.classKind != KtClassKind.ANNOTATION_CLASS) + } + + internal fun tryGetEffectiveVisibility(symbol: KtCallableSymbol): KtSymbolVisibility? { + + if (symbol !is KtPropertySymbol && symbol !is KtFunctionSymbol) return null + + var visibility = (symbol as? KtSymbolWithVisibility)?.visibility + + analyzeWithSymbolAsContext(symbol) { + for (overriddenSymbol in symbol.getOverriddenSymbols(classOrObjectSymbol)) { + val newVisibility = (overriddenSymbol as? KtSymbolWithVisibility)?.visibility + if (newVisibility != null) { + visibility = newVisibility + } + } + } + + return visibility + } + + 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 = _ownFields + override fun getOwnMethods(): List = _ownMethods + override fun getExtendsList(): PsiReferenceList? = _extendsList + override fun getImplementsList(): PsiReferenceList? = _implementsList + + override fun getOwnInnerClasses(): List { + val result = ArrayList() + + // 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().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 + + private val _extendsList by lazyPub { createInheritanceList(forExtendsList = true) } + private val _implementsList by lazyPub { createInheritanceList(forExtendsList = false) } + + private val _ownMethods: List by lazyPub { + + val result = mutableListOf() + + analyzeWithSymbolAsContext(classOrObjectSymbol) { + val callableSymbols = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols() + val visibleDeclarations = callableSymbols.applyIf(isEnum) { + filterNot { function -> + function is KtFunctionSymbol && function.name.asString().let { it == "values" || it == "valueOf" } + } + } + + 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 by lazyPub { + + val result = mutableListOf() + + result.addCompanionObjectFieldIfNeeded() + + classOrObjectSymbol.companionObject?.run { + analyzeWithSymbolAsContext(this) { + getDeclaredMemberScope().getCallableSymbols() + .filterIsInstance() + .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 propertySymbols = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols() + .filterIsInstance() + .applyIf(classOrObjectSymbol.classKind == KtClassKind.COMPANION_OBJECT) { + filter { it.hasJvmFieldAnnotation() || it.isConst } + } + createFields(propertySymbols, isTopLevel = false, result) + + if (isEnum) { + classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols() + .filterIsInstance() + .mapTo(result) { FirLightFieldForEnumEntry(it, this@FirLightClassForSymbol, null) } + } + + } + + result + } + + override fun hashCode(): Int = classOrObjectSymbol.hashCode() + + override fun equals(other: Any?): Boolean = + this === other || (other is FirLightClassForSymbol && classOrObjectSymbol == other.classOrObjectSymbol) + + override fun isInterface(): Boolean = false + + override fun isAnnotationType(): Boolean = false + + override fun isEnum(): Boolean = + classOrObjectSymbol.classKind == KtClassKind.ENUM_CLASS + + override fun copy(): FirLightClassForSymbol = + FirLightClassForSymbol(classOrObjectSymbol, manager) +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceClassSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceClassSymbol.kt new file mode 100644 index 00000000000..44a14f165de --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceClassSymbol.kt @@ -0,0 +1,69 @@ +/* + * 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.classes + +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiReferenceList +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.idea.asJava.FirLightClassForClassOrObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassKind +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.markers.KtSymbolVisibility + +internal class FirLightInterfaceClassSymbol( + private val classOrObjectSymbol: KtClassOrObjectSymbol, + manager: PsiManager +) : FirLightInterfaceOrAnnotationClassSymbol(classOrObjectSymbol, manager) { + + init { + require(classOrObjectSymbol.classKind == KtClassKind.INTERFACE) + } + + private val _ownFields: List by lazyPub { + mutableListOf().also { + it.addCompanionObjectFieldIfNeeded() + } + } + + override fun getOwnFields(): List = _ownFields + + private val _ownMethods: List by lazyPub { + + val result = mutableListOf() + + analyzeWithSymbolAsContext(classOrObjectSymbol) { + val visibleDeclarations = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols() + .filterNot { it is KtFunctionSymbol && it.visibility == KtSymbolVisibility.PRIVATE } + + createMethods(visibleDeclarations, isTopLevel = false, result) + } + + result + } + + override fun getOwnMethods(): List = _ownMethods + + override fun equals(other: Any?): Boolean = + other === this || (other is FirLightInterfaceClassSymbol && classOrObjectSymbol == other.classOrObjectSymbol) + + override fun hashCode(): Int = classOrObjectSymbol.hashCode() + + override fun isAnnotationType(): Boolean = false + + override fun copy(): FirLightClassForClassOrObjectSymbol = + FirLightInterfaceClassSymbol(classOrObjectSymbol, manager) + + private val _extendsList: PsiReferenceList by lazyPub { + createInheritanceList(forExtendsList = false) + } + + override fun getExtendsList(): PsiReferenceList? = _extendsList +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceOrAnnotationClassSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceOrAnnotationClassSymbol.kt new file mode 100644 index 00000000000..77d9eafa9f1 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceOrAnnotationClassSymbol.kt @@ -0,0 +1,48 @@ +/* + * 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.classes + +import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.idea.asJava.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassKind +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind + +internal abstract class FirLightInterfaceOrAnnotationClassSymbol( + private val classOrObjectSymbol: KtClassOrObjectSymbol, + manager: PsiManager +) : FirLightClassForClassOrObjectSymbol(classOrObjectSymbol, manager) { + + init { + require(classOrObjectSymbol.classKind == KtClassKind.INTERFACE || classOrObjectSymbol.classKind == KtClassKind.ANNOTATION_CLASS) + } + + private val _modifierList: PsiModifierList? by lazyPub { + + val isTopLevel: Boolean = classOrObjectSymbol.symbolKind == KtSymbolKind.TOP_LEVEL + + val modifiers = mutableSetOf(classOrObjectSymbol.computeVisibility(isTopLevel), PsiModifier.ABSTRACT) + + val annotations = classOrObjectSymbol.computeAnnotations( + parent = this@FirLightInterfaceOrAnnotationClassSymbol, + nullability = NullabilityType.Unknown, + annotationUseSiteTarget = null, + ) + + FirLightClassModifierList(this@FirLightInterfaceOrAnnotationClassSymbol, modifiers, annotations) + } + + override fun getModifierList(): PsiModifierList? = _modifierList + + override fun getImplementsList(): PsiReferenceList? = null + + override fun getOwnInnerClasses(): List = emptyList() + + override fun isInterface(): Boolean = true + + override fun isEnum(): Boolean = false +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt new file mode 100644 index 00000000000..a3b4b5cc41d --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt @@ -0,0 +1,214 @@ +/* + * 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.classes + +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.METHOD_INDEX_BASE +import org.jetbrains.kotlin.asJava.classes.safeIsLocal +import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass +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.asJava.* +import org.jetbrains.kotlin.idea.asJava.FirLightClassForSymbol +import org.jetbrains.kotlin.idea.asJava.fields.FirLightFieldForEnumEntry +import org.jetbrains.kotlin.idea.frontend.api.analyze +import org.jetbrains.kotlin.idea.frontend.api.symbols.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtCommonSymbolModality +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClass +import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral +import java.util.* + +fun getOrCreateFirLightClass(classOrObject: KtClassOrObject): KtLightClass? = + CachedValuesManager.getCachedValue(classOrObject) { + CachedValueProvider.Result + .create( + createFirLightClassNoCache(classOrObject), + KotlinModificationTrackerService.getInstance(classOrObject.project).outOfBlockModificationTracker + ) + } + +fun createFirLightClassNoCache(classOrObject: KtClassOrObject): KtLightClass? { + + val containingFile = classOrObject.containingFile + if (containingFile is KtCodeFragment) { + // Avoid building light classes for code fragments + return null + } + + if (containingFile is KtFile && containingFile.isCompiled) return null + + if (classOrObject.shouldNotBeVisibleAsLightClass()) { + return null + } + + return when { + classOrObject is KtEnumEntry -> lightClassForEnumEntry(classOrObject) + classOrObject.isObjectLiteral() -> return null //TODO + classOrObject.safeIsLocal() -> return null //TODO + classOrObject.hasModifier(KtTokens.INLINE_KEYWORD) -> return null //TODO + else -> { + analyze(classOrObject) { + val symbol = classOrObject.getClassOrObjectSymbol() + when (symbol.classKind) { + KtClassKind.INTERFACE -> FirLightInterfaceClassSymbol(symbol, classOrObject.manager) + KtClassKind.ANNOTATION_CLASS -> FirLightAnnotationClassSymbol(symbol, classOrObject.manager) + else -> FirLightClassForSymbol(symbol, classOrObject.manager) + } + } + } + } +} + + +private fun lightClassForEnumEntry(ktEnumEntry: KtEnumEntry): KtLightClass? { + if (ktEnumEntry.body == null) return null + + val firClass = ktEnumEntry + .containingClass() + ?.let { getOrCreateFirLightClass(it) } as? FirLightClassForSymbol + ?: return null + + val targetField = firClass.ownFields + .firstOrNull { it is FirLightFieldForEnumEntry && it.kotlinOrigin == ktEnumEntry } + ?: return null + + return (targetField as? FirLightFieldForEnumEntry)?.initializingClass as? KtLightClass +} + +internal fun FirLightClassBase.createMethods( + declarations: Sequence, + isTopLevel: Boolean, + result: MutableList +) { + 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@createMethods, + 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@createMethods, + isTopLevel = isTopLevel, + methodIndex = methodIndex++, + argumentsSkipMask = skipMask + ) + ) + } + } + } + is KtConstructorSymbol -> { + result.add( + FirLightConstructorForSymbol( + constructorSymbol = declaration, + lightMemberOrigin = null, + containingClass = this@createMethods, + 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@createMethods, + isTopLevel = isTopLevel + ) + ) + } + + val setter = declaration.setter?.takeIf { + !isAnnotationType && + !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@createMethods, + isTopLevel = isTopLevel + ) + ) + } + } + } + } +} + +internal fun FirLightClassBase.createFields( + declarations: Sequence, + isTopLevel: Boolean, + result: MutableList +) { + //TODO isHiddenByDeprecation + for (declaration in declarations) { + if (declaration !is KtPropertySymbol) continue + + if (!declaration.hasBackingField) continue + if (declaration.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.FIELD)) continue + if (declaration.modality == KtCommonSymbolModality.ABSTRACT) continue + + result.add( + FirLightFieldForPropertySymbol( + propertySymbol = declaration, + containingClass = this@createFields, + lightMemberOrigin = null, + isTopLevel = isTopLevel + ) + ) + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithReference.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithReference.kt index c04f5966860..848deb7bdc7 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithReference.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithReference.kt @@ -5,10 +5,7 @@ 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), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldEnumEntry.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldEnumEntry.kt new file mode 100644 index 00000000000..bef733f5b39 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldEnumEntry.kt @@ -0,0 +1,79 @@ +/* + * 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.fields + +import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.* +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.asJava.FirLightClassForSymbol +import org.jetbrains.kotlin.idea.asJava.FirLightClassModifierList +import org.jetbrains.kotlin.idea.asJava.FirLightField +import org.jetbrains.kotlin.idea.asJava.asPsiType +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtEnumEntrySymbol +import org.jetbrains.kotlin.idea.util.ifTrue +import org.jetbrains.kotlin.psi.KtEnumEntry + +internal class FirLightFieldForEnumEntry( + private val enumEntrySymbol: KtEnumEntrySymbol, + containingClass: FirLightClassForSymbol, + override val lightMemberOrigin: LightMemberOrigin? +) : FirLightField(containingClass, lightMemberOrigin), PsiEnumConstant { + + private val _modifierList by lazyPub { + FirLightClassModifierList( + containingDeclaration = this@FirLightFieldForEnumEntry, + modifiers = setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC), + annotations = emptyList() + ) + } + + override fun getModifierList(): PsiModifierList? = _modifierList + + override val kotlinOrigin: KtEnumEntry? = enumEntrySymbol.psi as? KtEnumEntry + + //TODO Make with KtSymbols + private val hasBody: Boolean get() = kotlinOrigin?.let { it.body != null } ?: true + + private val _initializingClass: PsiEnumConstantInitializer? by lazyPub { + hasBody.ifTrue { + FirLightClassForEnumEntry( + enumEntrySymbol = enumEntrySymbol, + enumConstant = this@FirLightFieldForEnumEntry, + enumClass = containingClass, + manager = manager + ) + } + } + + override fun getInitializingClass(): PsiEnumConstantInitializer? = _initializingClass + override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer = + _initializingClass ?: cannotModify() + + override fun getArgumentList(): PsiExpressionList? = null + override fun resolveMethod(): PsiMethod? = null + override fun resolveConstructor(): PsiMethod? = null + + override fun resolveMethodGenerics(): JavaResolveResult = JavaResolveResult.EMPTY + + override fun hasInitializer() = true + override fun computeConstantValue(visitedVars: MutableSet?) = this + + override fun getName(): String = enumEntrySymbol.name.asString() + + private val _type: PsiType by lazyPub { + enumEntrySymbol.type.asPsiType(enumEntrySymbol, this@FirLightFieldForEnumEntry, FirResolvePhase.TYPES) + } + + override fun getType(): PsiType = _type + override fun getInitializer(): PsiExpression? = null + + override fun hashCode(): Int = enumEntrySymbol.hashCode() + + override fun equals(other: Any?): Boolean = + other is FirLightFieldForEnumEntry && + enumEntrySymbol == other.enumEntrySymbol +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt index 10ca3eaac55..9ad155160d2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt @@ -13,7 +13,6 @@ 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 @@ -42,15 +41,19 @@ internal class FirLightFieldForPropertySymbol( private val _modifierList: PsiModifierList by lazyPub { - val modifiersFromSymbol = propertySymbol.computeModalityForMethod(isTopLevel = isTopLevel, isOverride = false) + val isJvmField = propertySymbol.hasJvmFieldAnnotation() + val suppressFinal = !isJvmField && !propertySymbol.isVal + + val modifiersFromSymbol = propertySymbol.computeModalityForMethod( + isTopLevel = isTopLevel, + suppressFinal = suppressFinal + ) val basicModifiers = modifiersFromSymbol.add( what = PsiModifier.STATIC, `if` = forceStatic ) - val isJvmField = propertySymbol.hasJvmFieldAnnotation() - val visibility = if (isJvmField) propertySymbol.computeVisibility(isTopLevel = false) else PsiModifier.PRIVATE @@ -58,7 +61,7 @@ internal class FirLightFieldForPropertySymbol( val modifiers = modifiersWithVisibility.add( what = PsiModifier.FINAL, - `if` = !isJvmField || propertySymbol.isVal + `if` = !suppressFinal ) val annotations = propertySymbol.computeAnnotations( diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt index 48cb918721f..f5288743966 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt @@ -22,6 +22,7 @@ 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.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.typeCheckerContext import org.jetbrains.kotlin.fir.types.* @@ -31,10 +32,7 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymb 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.* import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.* import org.jetbrains.kotlin.idea.frontend.api.types.* import org.jetbrains.kotlin.load.kotlin.TypeMappingMode @@ -89,6 +87,7 @@ private fun ConeKotlinType.asPsiType( if (this.typeArguments.any { it is ConeClassErrorType }) return psiContext.nonExistentType() if (this is ConeClassLikeType) { val classId = classId + //TODO make anonymous type deriving if (classId != null && classId.shortClassName.asString() == SpecialNames.ANONYMOUS) return PsiType.NULL } @@ -98,8 +97,10 @@ private fun ConeKotlinType.asPsiType( val canonicalSignature = signatureWriter.toString() - if (canonicalSignature == "[L;") return psiContext.nonExistentType() - val signature = StringCharacterIterator(canonicalSignature) + if (canonicalSignature.contains("L")) return psiContext.nonExistentType() + //TODO Fix it in typemapper + val patchedCanonicalSignature = canonicalSignature.replace(SpecialNames.ANONYMOUS, "java.lang.Object") + val signature = StringCharacterIterator(patchedCanonicalSignature) val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER) val typeInfo = TypeInfo.fromString(javaType, false) val typeText = TypeInfo.createTypeText(typeInfo) ?: return psiContext.nonExistentType() @@ -178,13 +179,16 @@ internal fun FirMemberDeclaration.computeModalityForMethod(isTopLevel: Boolean): return withTopLevelStatic } -internal fun KtSymbolWithModality.computeModalityForMethod(isTopLevel: Boolean, isOverride: Boolean): Set { +internal fun KtSymbolWithModality.computeModalityForMethod( + isTopLevel: Boolean, + suppressFinal: Boolean +): Set { require(this !is KtClassLikeSymbol) val modality = mutableSetOf() computeSimpleModality()?.run { - if (this != PsiModifier.FINAL || !isOverride) { + if (this != PsiModifier.FINAL || !suppressFinal) { modality.add(this) } } @@ -209,14 +213,15 @@ internal fun FirMemberDeclaration.computeVisibility(isTopLevel: Boolean): String } } -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 KtSymbolWithVisibility.computeVisibility(isTopLevel: Boolean): String = + visibility.toPsiVisibility(isTopLevel) + +internal fun KtSymbolVisibility.toPsiVisibility(isTopLevel: Boolean): String = when (this) { + // 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 { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt index 696ca996303..d4519a771ea 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt @@ -11,12 +11,17 @@ 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.builtins.StandardNames +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper 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.idea.frontend.api.fir.analyzeWithSymbolAsContext +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirPropertyGetterSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.* +import org.jetbrains.kotlin.idea.util.ifTrue +import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.load.java.JvmAbi.getterName import org.jetbrains.kotlin.load.java.JvmAbi.setterName import org.jetbrains.kotlin.psi.KtDeclaration @@ -26,7 +31,7 @@ internal class FirLightAccessorMethodForSymbol( containingPropertySymbol: KtPropertySymbol, lightMemberOrigin: LightMemberOrigin?, containingClass: FirLightClassBase, - isTopLevel: Boolean + isTopLevel: Boolean, ) : FirLightMethod( lightMemberOrigin, containingClass, @@ -36,10 +41,11 @@ internal class FirLightAccessorMethodForSymbol( if (firPropertyAccessor is KtPropertyGetterSymbol) getterName(this) else setterName(this) - //TODO add JvmName private val _name: String by lazyPub { - containingPropertySymbol.name.identifier - .abiName(propertyAccessorSymbol) + val defaultName = containingPropertySymbol.name.identifier.let { + if (containingClass.isAnnotationType) it else it.abiName(propertyAccessorSymbol) + } + containingPropertySymbol.computeJvmMethodName(defaultName, accessorSite) } override fun getName(): String = _name @@ -49,10 +55,12 @@ internal class FirLightAccessorMethodForSymbol( override val kotlinOrigin: KtDeclaration? = (propertyAccessorSymbol.psi ?: containingPropertySymbol.psi) as? KtDeclaration - private val _annotations: List by lazyPub { - val accessorSite = + private val accessorSite + get() = if (propertyAccessorSymbol is KtPropertyGetterSymbol) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER + + private val _annotations: List by lazyPub { containingPropertySymbol.computeAnnotations( parent = this, nullability = NullabilityType.Unknown, @@ -61,17 +69,28 @@ internal class FirLightAccessorMethodForSymbol( } private val _modifiers: Set by lazyPub { + val isOverrideMethod = propertyAccessorSymbol.isOverride || containingPropertySymbol.isOverride + val isInterfaceMethod = containingClass.isInterface - val isOverride = propertyAccessorSymbol.isOverride || containingPropertySymbol.isOverride - val modifiers = propertyAccessorSymbol.computeModalityForMethod(isTopLevel, isOverride) + - propertyAccessorSymbol.computeVisibility(isTopLevel) + val visibility = isOverrideMethod.ifTrue { + (containingClass as? FirLightClassForSymbol) + ?.tryGetEffectiveVisibility(containingPropertySymbol) + ?.toPsiVisibility(isTopLevel) + } ?: propertyAccessorSymbol.computeVisibility(isTopLevel) - val isJvmStatic = - _annotations.any { it.qualifiedName == "kotlin.jvm.JvmStatic" } - - if (isJvmStatic) return@lazyPub modifiers + PsiModifier.STATIC + val modifiers = containingPropertySymbol.computeModalityForMethod( + isTopLevel = isTopLevel, + suppressFinal = isOverrideMethod || isInterfaceMethod + ) + visibility modifiers + .add( + what = PsiModifier.STATIC, + `if` = _annotations.any { it.qualifiedName == "kotlin.jvm.JvmStatic" } + ).add( + what = PsiModifier.ABSTRACT, + `if` = isInterfaceMethod + ) } private val _modifierList: PsiModifierList by lazyPub { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethod.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethod.kt index a2ef3e0b305..d1a4b089bd6 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethod.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethod.kt @@ -15,6 +15,12 @@ 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 +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility +import org.jetbrains.kotlin.idea.util.module internal abstract class FirLightMethod( lightMemberOrigin: LightMemberOrigin?, @@ -74,4 +80,19 @@ internal abstract class FirLightMethod( KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST) //TODO() override fun getDefaultValue(): PsiAnnotationMemberValue? = null //TODO() + + protected fun T.computeJvmMethodName( + defaultName: String, + annotationUseSiteTarget: AnnotationUseSiteTarget? = null + ): String where T : KtAnnotatedSymbol, T : KtSymbolWithVisibility { + getJvmNameFromAnnotation(annotationUseSiteTarget)?.let { return it } + + if (visibility != KtSymbolVisibility.INTERNAL) return defaultName + + val moduleName = module?.name ?: return defaultName + + if (hasPublishedApiAnnotation(annotationUseSiteTarget)) return defaultName + + return KotlinTypeMapper.InternalNameMapper.mangleInternalName(defaultName, moduleName) + } } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethodForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethodForSymbol.kt index a47bbbc10a8..6b843d8662d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethodForSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethodForSymbol.kt @@ -12,6 +12,7 @@ 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.lexer.KtTokens import org.jetbrains.kotlin.psi.KtDeclaration import java.util.* diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt index 99d6ab3a9a3..95a73dcafeb 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt @@ -14,6 +14,8 @@ 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 org.jetbrains.kotlin.idea.util.ifTrue +import org.jetbrains.kotlin.lexer.KtTokens import java.util.* internal class FirLightSimpleMethodForSymbol( @@ -32,7 +34,7 @@ internal class FirLightSimpleMethodForSymbol( ) { private val _name: String by lazyPub { - functionSymbol.getJvmNameFromAnnotation(null) ?: functionSymbol.name.asString() + functionSymbol.computeJvmMethodName(functionSymbol.name.asString()) } override fun getName(): String = _name @@ -51,16 +53,34 @@ internal class FirLightSimpleMethodForSymbol( ) } + open class X { + open val x: Int = 2 + open fun u() = 2 + } + private val _modifiers: Set by lazyPub { if (functionSymbol.hasInlineOnlyAnnotation()) return@lazyPub setOf(PsiModifier.FINAL, PsiModifier.PRIVATE) - val modifiers = functionSymbol.computeModalityForMethod(isTopLevel = isTopLevel, functionSymbol.isOverride) + - functionSymbol.computeVisibility(isTopLevel = isTopLevel) + val isOverrideMethod = functionSymbol.isOverride - if (functionSymbol.hasJvmStaticAnnotation()) return@lazyPub modifiers + PsiModifier.STATIC + val visibility = isOverrideMethod.ifTrue { + (containingClass as? FirLightClassForSymbol) + ?.tryGetEffectiveVisibility(functionSymbol) + ?.toPsiVisibility(isTopLevel) + } ?: functionSymbol.computeVisibility(isTopLevel = isTopLevel) - modifiers + val finalModifier = kotlinOrigin?.hasModifier(KtTokens.FINAL_KEYWORD) == true + + val modifiers = functionSymbol.computeModalityForMethod( + isTopLevel = isTopLevel, + suppressFinal = !finalModifier && isOverrideMethod + ) + visibility + + modifiers.add( + what = PsiModifier.STATIC, + `if` = functionSymbol.hasJvmStaticAnnotation() + ) } private val _modifierList: PsiModifierList by lazyPub { @@ -79,10 +99,7 @@ internal class FirLightSimpleMethodForSymbol( override fun getReturnType(): PsiType = _returnedType override fun equals(other: Any?): Boolean = - this === other || - (other is FirLightSimpleMethodForSymbol && - kotlinOrigin == other.kotlinOrigin && - functionSymbol == other.functionSymbol) + this === other || (other is FirLightSimpleMethodForSymbol && functionSymbol == other.functionSymbol) - override fun hashCode(): Int = kotlinOrigin.hashCode() + override fun hashCode(): Int = functionSymbol.hashCode() } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt index 738e0e0fff3..abbc9132299 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.scope @@ -29,7 +30,6 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymb import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirEnumEntrySymbol import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType import org.jetbrains.kotlin.idea.frontend.api.fir.utils.EnclosingDeclarationContext -import org.jetbrains.kotlin.idea.frontend.api.fir.utils.FirRefWithValidityCheck import org.jetbrains.kotlin.idea.frontend.api.fir.utils.buildCompletionContext import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef import org.jetbrains.kotlin.idea.frontend.api.scopes.* @@ -57,38 +57,42 @@ internal class KtFirScopeProvider( private val declaredMemberScopeCache = IdentityHashMap() private val packageMemberScopeCache = IdentityHashMap() - private fun KtSymbolWithDeclarations.firRef(): FirRefWithValidityCheck>? = when (this) { - is KtFirClassOrObjectSymbol -> this.firRef - is KtFirEnumEntrySymbol -> this.initializerFirRef + private inline fun KtSymbolWithDeclarations.withFirForScope(crossinline body: (FirClass<*>) -> T): T? = when (this) { + is KtFirClassOrObjectSymbol -> firRef.withFir(FirResolvePhase.SUPER_TYPES, body) + is KtFirEnumEntrySymbol -> firRef.withFir(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { + val initializer = it.initializer + check(initializer is FirAnonymousObject) + body(initializer) + } else -> error { "Unknown KtSymbolWithDeclarations implementation ${this::class.qualifiedName}" } } override fun getMemberScope(classSymbol: KtSymbolWithDeclarations): KtMemberScope = withValidityAssertion { memberScopeCache.getOrPut(classSymbol) { - val firRef = classSymbol.firRef() - ?: return@getOrPut KtFirEmptyMemberScope(classSymbol) + val firScope = classSymbol.withFirForScope { fir -> + val firSession = fir.session + fir.unsubstitutedScope( + firSession, + firResolveState.firTransformerProvider.getScopeSession(firSession), + withForcedTypeCalculator = false + ) + } ?: return@getOrPut KtFirEmptyMemberScope(classSymbol) + + firScopeStorage.register(firScope) - val firScope = - firRef.withFir(FirResolvePhase.SUPER_TYPES) { fir -> - val firSession = fir.session - fir.unsubstitutedScope( - firSession, - firResolveState.firTransformerProvider.getScopeSession(firSession), - withForcedTypeCalculator = false - ) - }.also(firScopeStorage::register) KtFirMemberScope(classSymbol, firScope, token, builder) } } override fun getDeclaredMemberScope(classSymbol: KtSymbolWithDeclarations): KtDeclaredMemberScope = withValidityAssertion { declaredMemberScopeCache.getOrPut(classSymbol) { - val firRef = classSymbol.firRef() - ?: return@getOrPut KtFirEmptyMemberScope(classSymbol) + val firScope = classSymbol.withFirForScope { + declaredMemberScope(it) + } ?: return@getOrPut KtFirEmptyMemberScope(classSymbol) + + firScopeStorage.register(firScope) - val firScope = firRef.withFir(FirResolvePhase.SUPER_TYPES) { declaredMemberScope(it) } - .also(firScopeStorage::register) KtFirDeclaredMemberScope(classSymbol, firScope, token, builder) } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt index 5d92572bd84..3c6ce6fc5d1 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt @@ -9,7 +9,9 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.isSubstitutionOverride import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors import org.jetbrains.kotlin.fir.scopes.processClassifiersByName +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.idea.frontend.api.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder @@ -73,6 +75,15 @@ internal fun FirScope.getCallableSymbols(callableNames: Collection, builde } callables.add(symbol) } + + if (name.isSpecial && name.asString() == "") { + processDeclaredConstructors { firConstructor -> + firConstructor.fir.let { fir -> + callables.add(builder.buildConstructorSymbol(fir)) + } + } + } + yieldAll(callables) } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirEnumEntrySymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirEnumEntrySymbol.kt index 11c83ac9298..31e28b8687f 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirEnumEntrySymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirEnumEntrySymbol.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.symbols import com.intellij.psi.PsiElement import org.jetbrains.kotlin.fir.containingClass -import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject import org.jetbrains.kotlin.fir.declarations.FirEnumEntry import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.idea.fir.findPsi @@ -16,7 +15,6 @@ import org.jetbrains.kotlin.idea.frontend.api.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.pointers.KtFirEnumEntrySymbolPointer import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.pointers.createSignature -import org.jetbrains.kotlin.idea.frontend.api.fir.utils.FirRefWithValidityCheck import org.jetbrains.kotlin.idea.frontend.api.fir.utils.firRef import org.jetbrains.kotlin.idea.frontend.api.symbols.KtEnumEntrySymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtPsiBasedSymbolPointer @@ -41,8 +39,6 @@ internal class KtFirEnumEntrySymbol( override val containingEnumClassIdIfNonLocal: ClassId? get() = firRef.withFir { it.containingClass()?.classId?.takeUnless { it.isLocal } } - override val hasBody: Boolean get() = firRef.withFir { it.initializer != null } - override fun createPointer(): KtSymbolPointer { KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it } return KtFirEnumEntrySymbolPointer(containingEnumClassIdIfNonLocal!!, firRef.withFir { it.createSignature() }) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/firSymbolUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/firSymbolUtils.kt index 53ea8f98684..8d59e319cbd 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/firSymbolUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/firSymbolUtils.kt @@ -22,7 +22,7 @@ internal inline fun Modality?.getSymbolModality() Modality.OPEN -> KtCommonSymbolModality.OPEN Modality.ABSTRACT -> KtCommonSymbolModality.ABSTRACT Modality.SEALED -> KtSymbolModality.SEALED - null -> KtCommonSymbolModality.UNKNOWN + null -> error("Symbol modality should not be null, looks like the fir symbol was not properly resolved") } as? M ?: error("Sealed modality can only be applied to class") internal inline fun KtFirSymbol.getModality() =