diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index 9e616eb4490..97b528802dc 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -550,11 +550,17 @@ fun KtClassOrObject.defaultJavaAncestorQualifiedName(): String? { } fun KtClassOrObject.shouldNotBeVisibleAsLightClass(): Boolean { + + if (containingFile is KtCodeFragment) { + // Avoid building light classes for code fragments + return true + } + if (parentsWithSelf.filterIsInstance().any { it.hasExpectModifier() }) { return true } - if (safeIsLocal()) { + if (isLocal) { if (containingFile.virtualFile == null) return true if (hasParseErrorsAround(this) || PsiUtilCore.hasErrorElementChild(this)) return true } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/implUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/implUtils.kt index 69905ce29e4..5660c7e6be0 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/implUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/implUtils.kt @@ -50,9 +50,9 @@ fun PsiReferenceList.addSuperTypeEntry( } } -internal fun KtClassOrObject.getExternalDependencies(): List { +fun KtClassOrObject.getExternalDependencies(): List { return with(KotlinModificationTrackerService.getInstance(project)) { - if (!safeIsLocal()) return listOf(outOfBlockModificationTracker) + if (!this@getExternalDependencies.isLocal) return listOf(outOfBlockModificationTracker) else when (val file = containingFile) { is KtFile -> listOf(outOfBlockModificationTracker, fileModificationTracker(file)) else -> listOf(outOfBlockModificationTracker) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt index 30f4e3b54d4..92f0d4ceb05 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt @@ -32,13 +32,13 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind import org.jetbrains.kotlin.types.RawType -internal const val METHOD_INDEX_FOR_GETTER = 1 -internal const val METHOD_INDEX_FOR_SETTER = 2 -internal const val METHOD_INDEX_FOR_DEFAULT_CTOR = 3 -internal const val METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR = 4 -internal const val METHOD_INDEX_FOR_NON_ORIGIN_METHOD = 5 -internal const val METHOD_INDEX_FOR_SCRIPT_MAIN = 6 -internal const val METHOD_INDEX_BASE = 7 +const val METHOD_INDEX_FOR_GETTER = 1 +const val METHOD_INDEX_FOR_SETTER = 2 +const val METHOD_INDEX_FOR_DEFAULT_CTOR = 3 +const val METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR = 4 +const val METHOD_INDEX_FOR_NON_ORIGIN_METHOD = 5 +const val METHOD_INDEX_FOR_SCRIPT_MAIN = 6 +const val METHOD_INDEX_BASE = 7 internal abstract class KtUltraLightMethod( internal val delegate: PsiMethod, diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt index 8d54ba5b08b..89bebc5a10e 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt @@ -26,7 +26,6 @@ import com.intellij.psi.util.PsiUtilCore import com.intellij.util.SmartList import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport -import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.isValidJavaFqName @@ -73,7 +72,7 @@ class JavaElementFinder( for (declaration in classOrObjectDeclarations) { if (declaration !is KtEnumEntry) { - val lightClass = declaration.toLightClass() + val lightClass = kotlinAsJavaSupport.getLightClass(declaration) if (lightClass != null) { answer.add(lightClass) } @@ -90,7 +89,7 @@ class JavaElementFinder( ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() //NOTE: can't filter out more interfaces right away because decompiled declarations do not have member bodies if (classOrObject is KtClass && classOrObject.isInterface()) { - val interfaceClass = classOrObject.toLightClass() ?: continue + val interfaceClass = kotlinAsJavaSupport.getLightClass(classOrObject) ?: continue val implsClass = interfaceClass.findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false) ?: continue answer.add(implsClass) } @@ -141,7 +140,7 @@ class JavaElementFinder( val declarations = kotlinAsJavaSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope) for (declaration in declarations) { - val aClass = declaration.toLightClass() ?: continue + val aClass = kotlinAsJavaSupport.getLightClass(declaration) ?: continue answer.add(aClass) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt index 372013b9479..805f6ed485b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt @@ -36,9 +36,21 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.utils.sure -class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport() { +open class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport() { private val psiManager: PsiManager = PsiManager.getInstance(project) + protected open fun createLightClassForSourceDeclaration(classOrObject: KtClassOrObject): KtLightClass? = + KtLightClassForSourceDeclaration.create(classOrObject) + + protected open fun createLightClassForScript(script: KtScript): KtLightClass? = + KtLightClassForScript.create(script) + + protected open fun createLightClassForFacade( + manager: PsiManager, + facadeClassFqName: FqName, + searchScope: GlobalSearchScope + ): KtLightClass? = KtLightClassForFacade.createForFacade(psiManager, facadeClassFqName, searchScope) + override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection { val facadeFilesInPackage = project.runReadActionInSmartMode { KotlinFileFacadeClassByPackageIndex.getInstance().get(packageFqName.asString(), project, scope) @@ -139,7 +151,7 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport if (virtualFile != null) { when { ProjectRootsUtil.isProjectSourceFile(project, virtualFile) -> - return KtLightClassForSourceDeclaration.create(classOrObject) + return createLightClassForSourceDeclaration(classOrObject) ProjectRootsUtil.isLibraryClassFile(project, virtualFile) -> return getLightClassForDecompiledClassOrObject(classOrObject) ProjectRootsUtil.isLibrarySourceFile(project, virtualFile) -> @@ -152,17 +164,17 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport classOrObject.containingFile.originalFile.virtualFile != null ) { // explicit request to create light class from dummy.kt - return KtLightClassForSourceDeclaration.create(classOrObject) + return createLightClassForSourceDeclaration(classOrObject) } return null } - override fun getLightClassForScript(script: KtScript): KtLightClassForScript? { + override fun getLightClassForScript(script: KtScript): KtLightClass? { if (!script.isValid) { return null } - return KtLightClassForScript.create(script) + return createLightClassForScript(script) } override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection { @@ -229,7 +241,7 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport private fun tryCreateFacadesForSourceFiles(moduleInfo: IdeaModuleInfo, facadeFqName: FqName): PsiClass? { if (moduleInfo !is ModuleSourceInfo && moduleInfo !is PlatformModuleInfo) return null - return KtLightClassForFacade.createForFacade(psiManager, facadeFqName, moduleInfo.contentScope()) + return createLightClassForFacade(psiManager, facadeFqName, moduleInfo.contentScope()) } override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection { 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 new file mode 100644 index 00000000000..3c741617e5d --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.resolve + +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiManager +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass +import org.jetbrains.kotlin.idea.asJava.FirLightClassForFacade +import org.jetbrains.kotlin.idea.asJava.FirLightClassForSymbol +import org.jetbrains.kotlin.idea.frontend.api.analyze +import org.jetbrains.kotlin.idea.util.ifTrue +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtEnumEntry +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtScript + +class IDEKotlinAsJavaFirSupport(project: Project) : IDEKotlinAsJavaSupport(project) { + + + //TODO Make caching + override fun createLightClassForFacade(manager: PsiManager, facadeClassFqName: FqName, searchScope: GlobalSearchScope): KtLightClass? { + val sources = findFilesForFacade(facadeClassFqName, searchScope) + .filterNot { it.isCompiled } + + if (sources.isEmpty()) return null + + return FirLightClassForFacade(manager, facadeClassFqName, sources) + } + + override fun createLightClassForScript(script: KtScript): KtLightClass? = null + + private fun KtClassOrObject.isSupportedByFitLightClasses() = + containingFile.let { it is KtFile && !it.isCompiled } && + !isLocal /*TODO*/ && + this !is KtEnumEntry /*TODO*/ && + !shouldNotBeVisibleAsLightClass() + + override fun createLightClassForSourceDeclaration(classOrObject: KtClassOrObject): KtLightClass? = + classOrObject.isSupportedByFitLightClasses().ifTrue { + CachedValuesManager.getCachedValue(classOrObject) { + CachedValueProvider.Result + .create( + FirLightClassForSymbol( + analyze(classOrObject) { classOrObject.getClassOrObjectSymbol() }, + classOrObject.manager + ), + KotlinModificationTrackerService.getInstance(classOrObject.project).outOfBlockModificationTracker + ) + } + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..81714e44270 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirFakeFileImpl.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject +import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass +import org.jetbrains.kotlin.psi.KtClassOrObject + +class FirFakeFileImpl(private val classOrObject: KtClassOrObject, ktClass: KtLightClass) : FakeFileForLightClass( + classOrObject.containingKtFile, + { if (classOrObject.isTopLevel()) ktClass else FirLightClassForSymbol.create(getOutermostClassOrObject(classOrObject))!! }, + { null } +) { + + override fun findReferenceAt(offset: Int) = ktFile.findReferenceAt(offset) + + override fun processDeclarations( + processor: PsiScopeProcessor, + state: ResolveState, + lastParent: PsiElement?, + place: PsiElement + ): Boolean { + if (!super.processDeclarations(processor, state, lastParent, place)) return false + + // We have to explicitly process package declarations if current file belongs to default package + // so that Java resolve can find classes located in that package + val packageName = packageName + if (packageName.isNotEmpty()) return true + + val aPackage = JavaPsiFacade.getInstance(classOrObject.project).findPackage(packageName) + if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false + + return true + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirLightMemberImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirLightMemberImpl.kt new file mode 100644 index 00000000000..310e6580d60 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/FirLightMemberImpl.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiIdentifier +import com.intellij.psi.PsiMember +import com.intellij.psi.PsiMethod +import com.intellij.psi.javadoc.PsiDocComment +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightElementBase +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +import org.jetbrains.kotlin.asJava.elements.KtLightMember +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtNamedDeclaration + +internal abstract class FirLightMemberImpl( + override val lightMemberOrigin: LightMemberOrigin?, + private val containingClass: KtLightClass, +) : KtLightElementBase(containingClass), PsiMember, KtLightMember { + + override val clsDelegate: T + get() = invalidAccess() + + private val lightIdentifier by lazyPub { KtLightIdentifier(this, kotlinOrigin as? KtNamedDeclaration) } + + override fun hasModifierProperty(name: String): Boolean = modifierList?.hasModifierProperty(name) ?: false + + override fun toString(): String = "${this::class.java.simpleName}:$name" + + override fun getContainingClass() = containingClass + + override fun getNameIdentifier(): PsiIdentifier = lightIdentifier + + override val kotlinOrigin: KtDeclaration? get() = lightMemberOrigin?.originalElement + + override fun getDocComment(): PsiDocComment? = null //TODO() + + override fun isDeprecated(): Boolean = false //TODO() + + abstract override fun getName(): String + + override fun isValid(): Boolean = + parent.isValid && lightMemberOrigin?.isValid() != false + + override fun isEquivalentTo(another: PsiElement?): Boolean = + basicIsEquivalentTo(this, another as? PsiMethod) + + abstract override fun hashCode(): Int + + abstract override fun equals(other: Any?): Boolean +} \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/asJava/LightClassProviderFirImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/LightClassProviderFirImpl.kt similarity index 74% rename from idea/idea-fir/src/org/jetbrains/kotlin/idea/asJava/LightClassProviderFirImpl.kt rename to idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/LightClassProviderFirImpl.kt index be1491eb978..80ba2d43f01 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/asJava/LightClassProviderFirImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/LightClassProviderFirImpl.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.asJava import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.* import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.psi.* @@ -14,33 +15,26 @@ class LightClassProviderFirImpl : LightClassProvider { return null } - override fun getLightClassMethods(function: KtFunction): List { - return emptyList() - } + override fun getLightClassMethods(function: KtFunction): List = + LightClassUtil.getLightClassMethods(function) - override fun getLightClassParameterDeclarations(parameter: KtParameter): List { - return emptyList() - } + override fun getLightClassParameterDeclarations(parameter: KtParameter): List = + LightClassUtil.getLightClassPropertyMethods(parameter).allDeclarations - override fun getLightClassPropertyDeclarations(property: KtProperty): List { - return emptyList() - } + override fun getLightClassPropertyDeclarations(property: KtProperty): List = + LightClassUtil.getLightClassPropertyMethods(property).allDeclarations - override fun toLightClassWithBuiltinMapping(classOrObject: KtClassOrObject): PsiClass? { - return null - } + override fun toLightClassWithBuiltinMapping(classOrObject: KtClassOrObject): PsiClass? = + null - override fun toLightMethods(psiElement: PsiElement): List { - return emptyList() - } + override fun toLightMethods(psiElement: PsiElement): List = + psiElement.toLightMethods() - override fun toLightClass(classOrObject: KtClassOrObject): KtLightClass? { - return null - } + override fun toLightClass(classOrObject: KtClassOrObject): KtLightClass? = + classOrObject.toLightClass() - override fun toLightElements(ktElement: KtElement): List { - return emptyList() - } + override fun toLightElements(ktElement: KtElement): List = + ktElement.toLightElements() override fun createKtFakeLightClass(kotlinOrigin: KtClassOrObject): PsiClass? { return null diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirAnnotationParameterList.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirAnnotationParameterList.kt new file mode 100644 index 00000000000..919b82aa1a3 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirAnnotationParameterList.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.impl.light.LightIdentifier +import org.jetbrains.kotlin.asJava.classes.cannotModify +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightElementBase +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedConstantValue +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue +import org.jetbrains.kotlin.psi.KtElement + +internal class FirAnnotationParameterList( + parent: FirLightAbstractAnnotation, + private val annotationCall: KtAnnotationCall, +) : KtLightElementBase(parent), PsiAnnotationParameterList { + + private val _attributes: Array by lazyPub { + annotationCall.arguments.map { + FirNameValuePairForAnnotationArgument(it, this) + }.toTypedArray() + } + + override fun getAttributes(): Array = _attributes + + override val kotlinOrigin: KtElement? get() = null + + //TODO: EQ GHC EQIV +} + +private class FirNameValuePairForAnnotationArgument( + private val constantValue: KtNamedConstantValue, + parent: PsiElement +) : KtLightElementBase(parent), PsiNameValuePair { + + override val kotlinOrigin: KtElement? get() = null + + private val _value by lazyPub { + (constantValue.expression as? KtSimpleConstantValue<*>)?.createPsiLiteral(this) + } + + override fun setValue(p0: PsiAnnotationMemberValue) = cannotModify() + + private val _nameIdentifier: PsiIdentifier by lazyPub { + LightIdentifier(parent.manager, constantValue.name) + } + + override fun getNameIdentifier(): PsiIdentifier = _nameIdentifier + + override fun getValue(): PsiAnnotationMemberValue? = _value + + override fun getLiteralValue(): String? = (value as? PsiLiteralExpression)?.value?.toString() + + override fun getName(): String = constantValue.name +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAbstractAnnotation.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAbstractAnnotation.kt new file mode 100644 index 00000000000..453bbb0ad72 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAbstractAnnotation.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.impl.PsiImplUtil +import org.jetbrains.kotlin.asJava.classes.cannotModify +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall +import org.jetbrains.kotlin.psi.* + +internal abstract class FirLightAbstractAnnotation(parent: PsiElement) : + KtLightElementBase(parent), PsiAnnotation, KtLightElement { + + override val clsDelegate: PsiAnnotation + get() = invalidAccess() + + override fun getOwner() = parent as? PsiAnnotationOwner + + private val KtExpression.nameReference: KtNameReferenceExpression? + get() = when (this) { + is KtConstructorCalleeExpression -> constructorReferenceExpression as? KtNameReferenceExpression + else -> this as? KtNameReferenceExpression + } + + private val _nameReferenceElement: PsiJavaCodeReferenceElement by lazyPub { + val ktElement = kotlinOrigin?.navigationElement ?: this + val reference = (kotlinOrigin as? KtAnnotationEntry)?.typeReference?.reference + ?: (kotlinOrigin?.calleeExpression?.nameReference)?.references?.firstOrNull() + + if (reference != null) FirLightPsiJavaCodeReferenceElementWithReference(ktElement, reference) + else FirLightPsiJavaCodeReferenceElementWithNoReference(ktElement) + } + + override fun getNameReferenceElement(): PsiJavaCodeReferenceElement = _nameReferenceElement + + private class FirAnnotationParameterList(parent: PsiAnnotation) : KtLightElementBase(parent), PsiAnnotationParameterList { + override val kotlinOrigin: KtElement? = null + override fun getAttributes(): Array = emptyArray() //TODO() + } + + private val annotationParameterList: PsiAnnotationParameterList = FirAnnotationParameterList(this) + + override fun getParameterList(): PsiAnnotationParameterList = annotationParameterList + + override fun delete() { + kotlinOrigin?.delete() + } + + override fun toString() = "@$qualifiedName" + + abstract override fun equals(other: Any?): Boolean + + abstract override fun hashCode(): Int + + override fun setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify() +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAnnotationForAnnotationCall.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAnnotationForAnnotationCall.kt new file mode 100644 index 00000000000..19e5d90a6f0 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAnnotationForAnnotationCall.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.impl.PsiImplUtil +import com.intellij.util.IncorrectOperationException +import org.jetbrains.kotlin.asJava.classes.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue +import org.jetbrains.kotlin.psi.KtCallElement + +internal class FirLightAnnotationForAnnotationCall( + private val annotationCall: KtAnnotationCall, + parent: PsiElement, +) : FirLightAbstractAnnotation(parent) { + + override fun findAttributeValue(attributeName: String?): PsiAnnotationMemberValue? = + PsiImplUtil.findAttributeValue(this, attributeName) + + override fun findDeclaredAttributeValue(attributeName: String?) = + PsiImplUtil.findDeclaredAttributeValue(this, attributeName) + + private val _parameterList: PsiAnnotationParameterList by lazyPub { + FirAnnotationParameterList(this@FirLightAnnotationForAnnotationCall, annotationCall) + } + + override fun getParameterList(): PsiAnnotationParameterList = _parameterList + + override val kotlinOrigin: KtCallElement? = annotationCall.psi + + override fun getQualifiedName(): String? = annotationCall.classId?.asSingleFqName()?.asString() + + override fun getName(): String? = qualifiedName + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightAnnotationForAnnotationCall && + kotlinOrigin == other.kotlinOrigin && + annotationCall == other.annotationCall) + + override fun hashCode(): Int = kotlinOrigin.hashCode() + + override fun isEquivalentTo(another: PsiElement?): Boolean = + basicIsEquivalentTo(this, another as? PsiAnnotation) +} + +private fun escapeString(str: String): String = buildString { + str.forEach { char -> + val escaped = when (char) { + '\n' -> "\\n" + '\r' -> "\\r" + '\t' -> "\\t" + '\"' -> "\\\"" + '\\' -> "\\\\" + else -> "$char" + } + append(escaped) + } +} + +private fun KtSimpleConstantValue<*>.asStringForPsiLiteral(parent: PsiElement): String = + when (val value = this.constant) { + is String -> "\"${escapeString(value)}\"" + is Long -> "${value}L" + is Float -> "${value}f" + else -> value?.toString() ?: "null" + } + +internal fun KtSimpleConstantValue<*>.createPsiLiteral(parent: PsiElement): PsiExpression? { + val asString = asStringForPsiLiteral(parent) + val instance = PsiElementFactory.getInstance(parent.project) + return try { + instance.createExpressionFromText(asString, parent) + } catch (_: IncorrectOperationException) { + null + } +} diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightSimpleAnnotation.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightSimpleAnnotation.kt new file mode 100644 index 00000000000..2f3d757b098 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightSimpleAnnotation.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiAnnotationMemberValue +import com.intellij.psi.PsiElement +import com.intellij.psi.impl.PsiImplUtil +import org.jetbrains.kotlin.psi.KtCallElement + +internal class FirLightSimpleAnnotation( + private val fqName: String?, + parent: PsiElement +) : FirLightAbstractAnnotation(parent) { + override val kotlinOrigin: KtCallElement? = null + + override fun getQualifiedName(): String? = fqName + + override fun getName(): String? = fqName + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightSimpleAnnotation && fqName == other.fqName && parent == other.parent) + + override fun hashCode(): Int = fqName.hashCode() + + override fun findAttributeValue(attributeName: String?): PsiAnnotationMemberValue? = null + + override fun findDeclaredAttributeValue(attributeName: String?): PsiAnnotationMemberValue? = null +} 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 new file mode 100644 index 00000000000..c27bf26a7c5 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt @@ -0,0 +1,118 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiElement +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.fir.FirSymbolOwner +import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.references.FirNamedReference +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirAnnotationCall +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.mapAnnotationParameters +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue + +internal fun KtAnnotatedSymbol.hasJvmSyntheticAnnotation(annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean = + hasAnnotation("kotlin/jvm/JvmSynthetic", annotationUseSiteTarget) + +internal fun KtAnnotatedSymbol.getJvmNameFromAnnotation(annotationUseSiteTarget: AnnotationUseSiteTarget? = null): String? { + val annotation = annotations.firstOrNull { + val siteTarget = it.useSiteTarget + (siteTarget == null || siteTarget == annotationUseSiteTarget) && + it.classId?.asString() == "kotlin/jvm/JvmName" + } + + return annotation?.let { + (it.arguments.firstOrNull()?.expression as? KtSimpleConstantValue<*>)?.constant as? String + } +} + +internal fun KtAnnotatedSymbol.isHiddenByDeprecation(annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean { + + //TODO Move it to HL API + require(this is KtFirSymbol<*>) + + return this.firRef.withFir(FirResolvePhase.TYPES) { + if (it !is FirAnnotatedDeclaration) return@withFir false + + val deprecatedAnnotationCall = it.annotations.firstOrNull { annotationCall -> + val siteTarget = annotationCall.useSiteTarget + (siteTarget == null || siteTarget == annotationUseSiteTarget) && + annotationCall.classId?.asString() == "kotlin/Deprecated" + } ?: return@withFir false + + val qualifiedExpression = mapAnnotationParameters(deprecatedAnnotationCall, it.session)["level"] as? FirQualifiedAccessExpression + ?: return@withFir false + + val calleeReference = (qualifiedExpression.calleeReference as? FirNamedReference)?.name?.asString() + + calleeReference == "HIDDEN" + } +} + + +internal fun KtAnnotatedSymbol.hasJvmFieldAnnotation(): Boolean = + hasAnnotation("kotlin/jvm/JvmField", null) + +internal fun KtAnnotatedSymbol.hasJvmOverloadsAnnotation(): Boolean = + hasAnnotation("kotlin/jvm/JvmOverloads", null) + +internal fun KtAnnotatedSymbol.hasJvmStaticAnnotation(): Boolean = + hasAnnotation("kotlin/jvm/JvmStatic", null) + +internal fun KtAnnotatedSymbol.hasInlineOnlyAnnotation(): Boolean = + hasAnnotation("kotlin/internal/InlineOnly", null) + +internal fun KtAnnotatedSymbol.hasAnnotation(classIdString: String, annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean = + annotations.any { + val siteTarget = it.useSiteTarget + (siteTarget == null || siteTarget == annotationUseSiteTarget) && it.classId?.asString() == classIdString + } + +internal fun KtAnnotatedSymbol.computeAnnotations( + parent: PsiElement, + nullability: NullabilityType, + annotationUseSiteTarget: AnnotationUseSiteTarget? +): List { + + if (nullability == NullabilityType.Unknown && annotations.isEmpty()) return emptyList() + + val nullabilityAnnotation = when (nullability) { + NullabilityType.NotNull -> NotNull::class.java + NullabilityType.Nullable -> Nullable::class.java + else -> null + }?.let { + FirLightSimpleAnnotation(it.name, parent) + } + + if (annotations.isEmpty()) { + return if (nullabilityAnnotation != null) listOf(nullabilityAnnotation) else emptyList() + } + + val result = mutableListOf() + for (annotation in annotations) { + + val siteTarget = annotation.useSiteTarget + if (siteTarget == null || siteTarget == annotationUseSiteTarget) { + result.add(FirLightAnnotationForAnnotationCall(annotation, parent)) + } + } + + if (nullabilityAnnotation != null) { + result.add(nullabilityAnnotation) + } + + return result +} \ No newline at end of file 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 new file mode 100644 index 00000000000..a8aa43457fe --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassBase.kt @@ -0,0 +1,267 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.navigation.ItemPresentation +import com.intellij.navigation.ItemPresentationProviders +import com.intellij.openapi.util.Pair +import com.intellij.psi.* +import com.intellij.psi.impl.PsiClassImplUtil +import com.intellij.psi.impl.PsiImplUtil +import com.intellij.psi.impl.light.LightElement +import com.intellij.psi.impl.source.PsiExtensibleClass +import com.intellij.psi.javadoc.PsiDocComment +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.util.PsiUtil +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import org.jetbrains.kotlin.asJava.classes.KotlinClassInnerStuffCache +import org.jetbrains.kotlin.asJava.classes.KotlinClassInnerStuffCache.Companion.processDeclarationsInEnum +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_BASE +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.idea.KotlinLanguage + +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtConstructorSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol +import java.util.* + +abstract class FirLightClassBase protected constructor(manager: PsiManager) : LightElement(manager, KotlinLanguage.INSTANCE), PsiClass, + KtLightClass, PsiExtensibleClass { + + override val clsDelegate: PsiClass + get() = invalidAccess() + + protected open val myInnersCache = KotlinClassInnerStuffCache( + myClass = this, + externalDependencies = listOf(KotlinModificationTrackerService.getInstance(manager.project).outOfBlockModificationTracker) + ) + + override fun getFields(): Array = 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/FirLightClassForFacade.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForFacade.kt new file mode 100644 index 00000000000..f3dc7b268ab --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForFacade.kt @@ -0,0 +1,281 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.openapi.util.Comparing +import com.intellij.openapi.util.TextRange +import com.intellij.psi.* +import com.intellij.psi.impl.PsiSuperMethodImplUtil +import com.intellij.psi.impl.light.LightEmptyImplementsList +import com.intellij.psi.impl.light.LightModifierList +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.asJava.classes.* +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil +import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.types.ConeNullability +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacade +import org.jetbrains.kotlin.idea.frontend.api.analyze +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.isPrivate +import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd +import javax.swing.Icon + +class FirLightClassForFacade( + manager: PsiManager, + private val facadeClassFqName: FqName, + private val files: Collection +) : FirLightClassBase(manager) { + + override val clsDelegate: PsiClass get() = invalidAccess() + + private val isMultiFileClass: Boolean by lazyPub { + files.size > 1 || files.any { + JvmFileClassUtil.findAnnotationEntryOnFileNoResolve( + file = it, + shortName = JvmFileClassUtil.JVM_MULTIFILE_CLASS_SHORT + ) != null + } + } + + private val _modifierList: PsiModifierList by lazyPub { + if (isMultiFileClass) + return@lazyPub LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL) + + val modifiers = setOf(PsiModifier.PUBLIC, PsiModifier.FINAL) + +// val annotations = files.flatMap { file -> +// file.withFir> { +// computeAnnotations( +// parent = this@FirLightClassForFacade, +// nullability = ConeNullability.UNKNOWN, +// annotationUseSiteTarget = AnnotationUseSiteTarget.FILE +// ) +// } +// } + val annotations = emptyList() //TODO + + FirLightClassModifierList(this@FirLightClassForFacade, modifiers, annotations) + } + + override fun getModifierList(): PsiModifierList = _modifierList + + override fun getScope(): PsiElement? = parent + + private inline fun KtFile.withFir(body: T.() -> K): K { + val resolveState = LowLevelFirApiFacade.getResolveStateFor(this) + return LowLevelFirApiFacade.withFirFile(this, resolveState) { + require(it is T) + it.body() + } + } + + private fun loadMethodsFromFile( + file: KtFile, + result: MutableList + ) { + //it.isHiddenByDeprecation(support) + val declarations = file.declarations + .filterIsInstance() + .filterNot { multiFileClass && it.isPrivate() } + + if (declarations.isEmpty()) return + + val symbols = analyze(file) { + declarations.mapNotNull { + it.getSymbol() as? KtCallableSymbol + } + } + + createMethods(symbols.asSequence(), isTopLevel = true, result) + } + + private val _ownMethods: List by lazyPub { + val result = mutableListOf() + for (file in files) { + loadMethodsFromFile(file, result) + } + result + } + + private val multiFileClass: Boolean by lazyPub { + false //TODO +// files.any { +// it.withFir { +// this.hasAnnotation(JvmFileClassUtil.JVM_MULTIFILE_CLASS.asString()) +// } +// } + } + + private fun loadFieldsFromFile( + file: KtFile, + result: MutableList + ) { + + //it.isHiddenByDeprecation(support) + val declarations = file.declarations + .filterIsInstance() + .filterNot { multiFileClass && it is FirProperty && it.isConst } + + if (declarations.isEmpty()) return + + val symbols = analyze(file) { + declarations.mapNotNull { + it.getSymbol() as? KtCallableSymbol + } + } + + createFields(symbols.asSequence(), isTopLevel = true, result) + } + + private val _ownFields: List by lazyPub { + val result = mutableListOf() + for (file in files) { + loadFieldsFromFile(file, result) + } + result + } + + override fun getOwnFields() = _ownFields + + override fun getOwnMethods() = _ownMethods + + override fun copy(): FirLightClassForFacade = + FirLightClassForFacade(manager, facadeClassFqName, files) + + private val firstFileInFacade by lazyPub { files.iterator().next() } + + private val packageFqName: FqName = + facadeClassFqName.parent() + + private val modifierList: PsiModifierList = + LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL) + + private val implementsList: LightEmptyImplementsList = + LightEmptyImplementsList(manager) + + private val packageClsFile = FakeFileForLightClass( + firstFileInFacade, + lightClass = { this }, + stub = { null }, + packageFqName = packageFqName + ) + + override fun getParent(): PsiElement = containingFile + + override val kotlinOrigin: KtClassOrObject? get() = null + + val fqName: FqName + get() = facadeClassFqName + + override fun hasModifierProperty(@NonNls name: String) = modifierList.hasModifierProperty(name) + + override fun getExtendsList(): PsiReferenceList? = null + + override fun isDeprecated() = false + + override fun isInterface() = false + + override fun isAnnotationType() = false + + override fun isEnum() = false + + override fun getContainingClass(): PsiClass? = null + + override fun getContainingFile() = packageClsFile + + override fun hasTypeParameters() = false + + override fun getTypeParameters(): Array = PsiTypeParameter.EMPTY_ARRAY + + override fun getTypeParameterList(): PsiTypeParameterList? = null + + override fun getImplementsList() = implementsList + + override fun getInterfaces(): Array = PsiClass.EMPTY_ARRAY + + override fun getInnerClasses(): Array = PsiClass.EMPTY_ARRAY + + override fun getOwnInnerClasses(): List = listOf() + + override fun getAllInnerClasses(): Array = PsiClass.EMPTY_ARRAY + + override fun getInitializers(): Array = PsiClassInitializer.EMPTY_ARRAY + + override fun findInnerClassByName(@NonNls name: String, checkBases: Boolean): PsiClass? = null + + override fun isInheritorDeep(baseClass: PsiClass?, classToByPass: PsiClass?): Boolean = false + + override fun getLBrace(): PsiElement? = null + + override fun getRBrace(): PsiElement? = null + + override fun getName(): String = facadeClassFqName.shortName().asString() + + override fun setName(name: String): PsiElement? = cannotModify() + + override fun getQualifiedName() = facadeClassFqName.asString() + + override fun getNameIdentifier(): PsiIdentifier? = null + + override fun isValid() = files.all { it.isValid && it.hasTopLevelCallables() && facadeClassFqName == it.javaFileFacadeFqName } + + override fun getNavigationElement() = firstFileInFacade + + override fun isEquivalentTo(another: PsiElement?): Boolean = + equals(another) || another is FirLightClassForFacade && Comparing.equal(another.qualifiedName, qualifiedName) + + override fun getElementIcon(flags: Int): Icon? = throw UnsupportedOperationException("This should be done by JetIconProvider") + + override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean { + return baseClass.qualifiedName == CommonClassNames.JAVA_LANG_OBJECT + } + + override fun getSuperClass(): PsiClass? { + return JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope) + } + + override fun getSupers(): Array = + superClass?.let { arrayOf(it) } ?: arrayOf() + + override fun getSuperTypes(): Array = + arrayOf(PsiType.getJavaLangObject(manager, resolveScope)) + + override fun equals(other: Any?): Boolean { + if (other !is FirLightClassForFacade) return false + if (this === other) return true + + if (this.hashCode() != other.hashCode()) return false + if (manager != other.manager) return false + if (facadeClassFqName != other.facadeClassFqName) return false + return true + } + + override fun hashCode() = facadeClassFqName.hashCode() + + override fun toString() = "${KtLightClassForFacade::class.java.simpleName}:$facadeClassFqName" + + override val originKind: LightClassOriginKind + get() = LightClassOriginKind.SOURCE + + override fun getText() = firstFileInFacade.text ?: "" + + override fun getTextRange(): TextRange = firstFileInFacade.textRange ?: TextRange.EMPTY_RANGE + + override fun getTextOffset() = firstFileInFacade.textOffset + + override fun getStartOffsetInParent() = firstFileInFacade.startOffsetInParent + + override fun isWritable() = files.all { it.isWritable } + + override fun getVisibleSignatures(): MutableCollection = PsiSuperMethodImplUtil.getVisibleSignatures(this) +} \ 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 new file mode 100644 index 00000000000..fbac14f7c11 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/class/FirLightClassForSymbol.kt @@ -0,0 +1,350 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.openapi.util.Comparing +import com.intellij.psi.* +import com.intellij.psi.impl.InheritanceImplUtil +import com.intellij.psi.impl.PsiClassImplUtil +import com.intellij.psi.impl.PsiSuperMethodImplUtil +import com.intellij.psi.search.SearchScope +import com.intellij.psi.stubs.IStubElementType +import com.intellij.psi.stubs.StubElement +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.util.IncorrectOperationException +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import org.jetbrains.kotlin.asJava.classes.* +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.idea.frontend.api.analyze +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext +import org.jetbrains.kotlin.idea.frontend.api.symbols.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility +import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType +import org.jetbrains.kotlin.idea.util.ifFalse +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.debugText.getDebugText +import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral +import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub +import javax.swing.Icon +import kotlin.collections.ArrayList + +class FirLightClassForSymbol( + private val classOrObjectSymbol: KtClassOrObjectSymbol, + manager: PsiManager +) : + FirLightClassBase(manager), + StubBasedPsiElement> { + + 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/codeReferences/FirLightPsiJavaCodeReferenceElementBase.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementBase.kt new file mode 100644 index 00000000000..7d0200d1d31 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementBase.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.scope.PsiScopeProcessor + +internal abstract class FirLightPsiJavaCodeReferenceElementBase(private val ktElement: PsiElement) : + PsiElement by ktElement, + PsiJavaCodeReferenceElement { + + override fun multiResolve(incompleteCode: Boolean): Array = emptyArray() + + override fun processVariants(processor: PsiScopeProcessor) { } + + override fun advancedResolve(incompleteCode: Boolean): JavaResolveResult = + JavaResolveResult.EMPTY + + override fun getQualifier(): PsiElement? = null + + override fun getReferenceName(): String? = null + + override fun getReferenceNameElement(): PsiElement? = null + + override fun getParameterList(): PsiReferenceParameterList? = null + + override fun getTypeParameters(): Array = emptyArray() + + override fun isQualified(): Boolean = false + + override fun getQualifiedName(): String? = null +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithNoReference.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithNoReference.kt new file mode 100644 index 00000000000..59f9313d479 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithNoReference.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.util.IncorrectOperationException + +internal class FirLightPsiJavaCodeReferenceElementWithNoReference(private val ktElement: PsiElement): + FirLightPsiJavaCodeReferenceElementBase(ktElement), + PsiReference { + + override fun getElement(): PsiElement = ktElement + + override fun getRangeInElement(): TextRange = ktElement.textRange + + override fun resolve(): PsiElement? = null + + override fun getCanonicalText(): String = "" + + override fun handleElementRename(newElementName: String): PsiElement = element + + @Throws(IncorrectOperationException::class) + override fun bindToElement(element: PsiElement): PsiElement = + throw IncorrectOperationException("can't rename FirLightPsiJavaCodeReferenceElementWithNoReference") + + override fun isReferenceTo(element: PsiElement): Boolean = false + + override fun isSoft(): Boolean = false +} \ 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 new file mode 100644 index 00000000000..c04f5966860 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/codeReferences/FirLightPsiJavaCodeReferenceElementWithReference.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.* +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.util.IncorrectOperationException + +internal class FirLightPsiJavaCodeReferenceElementWithReference(private val ktElement: PsiElement, reference: PsiReference): + FirLightPsiJavaCodeReferenceElementBase(ktElement), + PsiReference by reference { + + override fun getElement(): PsiElement = ktElement +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightField.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightField.kt new file mode 100644 index 00000000000..8768cfcec55 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightField.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.lang.Language +import com.intellij.psi.* +import com.intellij.psi.impl.ElementPresentationUtil +import com.intellij.ui.IconManager +import com.intellij.util.IncorrectOperationException +import com.intellij.util.PlatformIcons +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.cannotModify +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.psi.KtNamedDeclaration +import javax.swing.Icon + +internal abstract class FirLightField protected constructor( + private val containingClass: KtLightClass, + lightMemberOrigin: LightMemberOrigin?, +) : FirLightMemberImpl(lightMemberOrigin, containingClass), KtLightField { + + override val clsDelegate: PsiField get() = invalidAccess() + + override fun setInitializer(initializer: PsiExpression?) = cannotModify() + + override fun isEquivalentTo(another: PsiElement?): Boolean = + basicIsEquivalentTo(this, another as? PsiField) + + override fun getLanguage(): Language = KotlinLanguage.INSTANCE + + override fun getParent() = containingClass + override fun getContainingClass() = containingClass + override fun getContainingFile(): PsiFile? = containingClass.containingFile + override fun hasInitializer(): Boolean = initializer !== null + + override fun computeConstantValue(): Any? = null //TODO _constantInitializer?.value + + override fun computeConstantValue(visitedVars: MutableSet?): Any? = computeConstantValue() + + override fun setName(@NonNls name: String): PsiElement { + (kotlinOrigin as? KtNamedDeclaration)?.setName(name) + return this + } + + override fun toString(): String = "KtLightField:$name" + + override fun getTypeElement(): PsiTypeElement? = null + + @Throws(IncorrectOperationException::class) + override fun normalizeDeclaration() { + } + + override fun isVisibilitySupported(): Boolean = true + + override fun getElementIcon(flags: Int): Icon? { + val baseIcon = IconManager.getInstance().createLayeredIcon( + this, + PlatformIcons.VARIABLE_ICON, ElementPresentationUtil.getFlags( + this, + false + ) + ) + return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon) + } + + abstract override fun equals(other: Any?): Boolean + + abstract override fun hashCode(): Int + + override fun accept(visitor: PsiElementVisitor) { + if (visitor is JavaElementVisitor) { + visitor.visitField(this) + } else { + visitor.visitElement(this) + } + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt new file mode 100644 index 00000000000..34a54f7eb55 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiExpression +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiModifierList +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassKind +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol +import org.jetbrains.kotlin.psi.KtDeclaration + +internal class FirLightFieldForObjectSymbol( + private val objectSymbol: KtClassOrObjectSymbol, + containingClass: KtLightClass, + lightMemberOrigin: LightMemberOrigin?, +) : FirLightField(containingClass, lightMemberOrigin) { + + override val kotlinOrigin: KtDeclaration? = objectSymbol.psi as? KtDeclaration + + private val _name = if (objectSymbol.classKind == KtClassKind.COMPANION_OBJECT) objectSymbol.name.asString() else "INSTANCE" + override fun getName(): String = _name + + private val _modifierList: PsiModifierList by lazyPub { + val modifiers = setOf(objectSymbol.computeVisibility(isTopLevel = false), PsiModifier.STATIC, PsiModifier.FINAL) + val notNullAnnotation = FirLightSimpleAnnotation("org.jetbrains.annotations.NotNull", this) + FirLightClassModifierList(this, modifiers, listOf(notNullAnnotation)) + } + + override fun getModifierList(): PsiModifierList? = _modifierList + + private val _type: PsiType by lazyPub { + objectSymbol.typeForClassSymbol(this@FirLightFieldForObjectSymbol) + } + + override fun getType(): PsiType = _type + + override fun getInitializer(): PsiExpression? = null //TODO + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightFieldForObjectSymbol && + kotlinOrigin == other.kotlinOrigin && + objectSymbol == other.objectSymbol) + + override fun hashCode(): Int = kotlinOrigin.hashCode() +} \ 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 new file mode 100644 index 00000000000..10ca3eaac55 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiExpression +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiModifierList +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertyGetterSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.psi.KtDeclaration + +internal class FirLightFieldForPropertySymbol( + private val propertySymbol: KtPropertySymbol, + containingClass: FirLightClassBase, + lightMemberOrigin: LightMemberOrigin?, + isTopLevel: Boolean, + forceStatic: Boolean = false +) : FirLightField(containingClass, lightMemberOrigin) { + + override val kotlinOrigin: KtDeclaration? = propertySymbol.psi as? KtDeclaration + + private val _returnedType: PsiType by lazyPub { + propertySymbol.type.asPsiType( + propertySymbol, + this@FirLightFieldForPropertySymbol, + FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE + ) + } + + override fun getType(): PsiType = _returnedType + + private val _name = propertySymbol.name.asString() + override fun getName(): String = _name + + private val _modifierList: PsiModifierList by lazyPub { + + val modifiersFromSymbol = propertySymbol.computeModalityForMethod(isTopLevel = isTopLevel, isOverride = false) + + val basicModifiers = modifiersFromSymbol.add( + what = PsiModifier.STATIC, + `if` = forceStatic + ) + + val isJvmField = propertySymbol.hasJvmFieldAnnotation() + + val visibility = + if (isJvmField) propertySymbol.computeVisibility(isTopLevel = false) else PsiModifier.PRIVATE + + val modifiersWithVisibility = basicModifiers + visibility + + val modifiers = modifiersWithVisibility.add( + what = PsiModifier.FINAL, + `if` = !isJvmField || propertySymbol.isVal + ) + + val annotations = propertySymbol.computeAnnotations( + parent = this, + nullability = propertySymbol.type.getTypeNullability(propertySymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE), + annotationUseSiteTarget = AnnotationUseSiteTarget.FIELD, + ) + + FirLightClassModifierList(this, modifiers, annotations) + } + + override fun getModifierList(): PsiModifierList? = _modifierList + + + override fun getInitializer(): PsiExpression? = null //TODO + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightFieldForPropertySymbol && + kotlinOrigin == other.kotlinOrigin && + propertySymbol == other.propertySymbol) + + override fun hashCode(): Int = kotlinOrigin.hashCode() +} \ No newline at end of file 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 new file mode 100644 index 00000000000..48cb918721f --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt @@ -0,0 +1,282 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.impl.cache.TypeInfo +import com.intellij.psi.impl.compiled.ClsTypeElementImpl +import com.intellij.psi.impl.compiled.SignatureParsing +import com.intellij.psi.impl.compiled.StubBuildingVisitor +import org.jetbrains.annotations.NotNull +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.asJava.elements.KtLightMember +import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf +import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.isPrimitiveNumberOrUnsignedNumberType +import org.jetbrains.kotlin.fir.isPrimitiveType +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.typeCheckerContext +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl +import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirClassType +import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.* +import org.jetbrains.kotlin.idea.frontend.api.types.* +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.model.SimpleTypeMarker +import org.jetbrains.kotlin.types.model.typeConstructor +import org.jetbrains.kotlin.types.typeUtil.isTypeParameter +import java.text.StringCharacterIterator + +internal fun L.invalidAccess(): Nothing = + error("Cls delegate shouldn't be accessed for fir light classes! Qualified name: ${javaClass.name}") + + +private fun PsiElement.nonExistentType() = JavaPsiFacade.getElementFactory(project) + .createTypeFromText("error.NonExistentClass", this) + +internal fun KtTypedSymbol.asPsiType(parent: PsiElement, phase: FirResolvePhase): PsiType = + type.asPsiType(this, parent, phase) + +internal fun KtType.asPsiType( + context: KtSymbol, + parent: PsiElement, + phase: FirResolvePhase +): PsiType { + require(this is KtFirType) + require(context is KtFirSymbol<*>) + + val session = context.firRef.withFir(phase) { it.session } + return coneType.asPsiType(session, TypeMappingMode.DEFAULT, parent) +} + +internal fun KtClassOrObjectSymbol.typeForClassSymbol(psiElement: PsiElement): PsiType { + require(this is KtFirClassOrObjectSymbol) + val (session, type) = firRef.withFir(FirResolvePhase.TYPES) { firClass -> + firClass.session to ConeClassLikeTypeImpl( + firClass.symbol.toLookupTag(), + firClass.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), isNullable = false) }.toTypedArray(), + isNullable = false + ) + } + return type.asPsiType(session, TypeMappingMode.DEFAULT, psiElement) +} + +private fun ConeKotlinType.asPsiType( + session: FirSession, + mode: TypeMappingMode, + psiContext: PsiElement, +): PsiType { + + if (this is ConeClassErrorType || this !is SimpleTypeMarker) return psiContext.nonExistentType() + if (this.typeArguments.any { it is ConeClassErrorType }) return psiContext.nonExistentType() + if (this is ConeClassLikeType) { + val classId = classId + if (classId != null && classId.shortClassName.asString() == SpecialNames.ANONYMOUS) return PsiType.NULL + } + + val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) + //TODO Check thread safety + session.jvmTypeMapper.mapType(this, mode, signatureWriter) + + val canonicalSignature = signatureWriter.toString() + + if (canonicalSignature == "[L;") return psiContext.nonExistentType() + val signature = StringCharacterIterator(canonicalSignature) + val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER) + val typeInfo = TypeInfo.fromString(javaType, false) + val typeText = TypeInfo.createTypeText(typeInfo) ?: return psiContext.nonExistentType() + + val typeElement = ClsTypeElementImpl(psiContext, typeText, '\u0000') + return typeElement.type +} + +private fun mapSupertype(psiContext: PsiElement, session: FirSession, supertype: ConeKotlinType, kotlinCollectionAsIs: Boolean = false) = + supertype.asPsiType( + session, + if (kotlinCollectionAsIs) TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS else TypeMappingMode.SUPER_TYPE, + psiContext + ) as? PsiClassType + +internal fun KtClassType.mapSupertype( + psiContext: PsiElement, + kotlinCollectionAsIs: Boolean = false +): PsiClassType? { + require(this is KtFirClassType) + val contextSymbol = this.classSymbol + require(contextSymbol is KtFirSymbol<*>) + + val session = contextSymbol.firRef.withFir { it.session } + + return mapSupertype( + psiContext, + session, + this.coneType, + kotlinCollectionAsIs, + ) +} + +internal enum class NullabilityType { + Nullable, + NotNull, + Unknown +} + +internal val KtType.nullabilityType: NullabilityType + get() = + (this as? KtTypeWithNullability)?.let { + if (it.nullability == KtTypeNullability.NULLABLE) NullabilityType.Nullable else NullabilityType.NotNull + } ?: NullabilityType.Unknown + + +internal fun FirMemberDeclaration.computeSimpleModality(): Set { + require(this !is FirConstructor) + + val modifier = when (modality) { + Modality.FINAL -> PsiModifier.FINAL + Modality.ABSTRACT -> PsiModifier.ABSTRACT + Modality.SEALED -> PsiModifier.ABSTRACT + else -> null + } + + return modifier?.let { setOf(it) } ?: emptySet() +} + +internal fun KtSymbolWithModality<*>.computeSimpleModality(): String? = when (modality) { + KtSymbolModality.SEALED -> PsiModifier.ABSTRACT + KtCommonSymbolModality.FINAL -> PsiModifier.FINAL + KtCommonSymbolModality.ABSTRACT -> PsiModifier.ABSTRACT + KtCommonSymbolModality.OPEN -> null + else -> throw NotImplementedError() +} + +internal fun FirMemberDeclaration.computeModalityForMethod(isTopLevel: Boolean): Set { + require(this !is FirConstructor) + + val simpleModifier = computeSimpleModality() + + val withNative = if (isExternal) simpleModifier + PsiModifier.NATIVE else simpleModifier + val withTopLevelStatic = if (isTopLevel) withNative + PsiModifier.STATIC else withNative + + return withTopLevelStatic +} + +internal fun KtSymbolWithModality.computeModalityForMethod(isTopLevel: Boolean, isOverride: Boolean): Set { + require(this !is KtClassLikeSymbol) + + val modality = mutableSetOf() + + computeSimpleModality()?.run { + if (this != PsiModifier.FINAL || !isOverride) { + modality.add(this) + } + } + + if (this is KtFunctionSymbol && isExternal) { + modality.add(PsiModifier.NATIVE) + } + if (isTopLevel) { + modality.add(PsiModifier.STATIC) + } + + return modality +} + +internal fun FirMemberDeclaration.computeVisibility(isTopLevel: Boolean): String { + return when (this.visibility) { + // Top-level private class has PACKAGE_LOCAL visibility in Java + // Nested private class has PRIVATE visibility + Visibilities.Private -> if (isTopLevel) PsiModifier.PACKAGE_LOCAL else PsiModifier.PRIVATE + Visibilities.Protected -> PsiModifier.PROTECTED + else -> PsiModifier.PUBLIC + } +} + +internal fun KtSymbolWithVisibility.computeVisibility(isTopLevel: Boolean): String { + return when (this.visibility) { + // Top-level private class has PACKAGE_LOCAL visibility in Java + // Nested private class has PRIVATE visibility + KtSymbolVisibility.PRIVATE -> if (isTopLevel) PsiModifier.PACKAGE_LOCAL else PsiModifier.PRIVATE + KtSymbolVisibility.PROTECTED -> PsiModifier.PROTECTED + else -> PsiModifier.PUBLIC + } +} + +internal fun basicIsEquivalentTo(`this`: PsiElement?, that: PsiElement?): Boolean { + if (`this` == null || that == null) return false + if (`this` == that) return true + + if (`this` !is KtLightElement<*, *>) return false + if (that !is KtLightElement<*, *>) return false + if (`this`.kotlinOrigin?.isEquivalentTo(that.kotlinOrigin) == true) return true + + val thisMemberOrigin = (`this` as? KtLightMember<*>)?.lightMemberOrigin ?: return false + if (thisMemberOrigin.isEquivalentTo(that)) return true + + val thatMemberOrigin = (that as? KtLightMember<*>)?.lightMemberOrigin ?: return false + return thisMemberOrigin.isEquivalentTo(thatMemberOrigin) +} + +internal fun KtType.getTypeNullability(context: KtSymbol, phase: FirResolvePhase): NullabilityType { + + if (nullabilityType != NullabilityType.NotNull) return nullabilityType + + if (isUnit) return NullabilityType.NotNull + + require(this is KtFirType) + require(context is KtFirSymbol<*>) + + if (coneType is ConeTypeParameterType) { +// TODO Make supertype checking +// val subtypeOfNullableSuperType = context.firRef.withFir(phase) { +// it.session.typeCheckerContext.nullableAnyType().isSupertypeOf(it.session.typeCheckerContext, coneType) +// } +// if (!subtypeOfNullableSuperType) return NullabilityType.NotNull + + if (!coneType.isMarkedNullable) return NullabilityType.Unknown + return NullabilityType.NotNull + } + + val coneType = coneType as? ConeClassLikeType ?: return NullabilityType.NotNull + + if (!coneType.isPrimitiveType()) { + return nullabilityType + } + + if (coneType is ConeClassErrorType) return NullabilityType.NotNull + if (coneType.typeArguments.any { it is ConeClassErrorType }) return NullabilityType.NotNull + if (coneType.classId?.shortClassName?.asString() == SpecialNames.ANONYMOUS) return NullabilityType.NotNull + + val canonicalSignature = context.firRef.withFir(phase) { + it.session.jvmTypeMapper.mapType(coneType, TypeMappingMode.DEFAULT).descriptor + } + + if (canonicalSignature == "[L;") return NullabilityType.NotNull + + val isNotPrimitiveType = canonicalSignature.startsWith("L") || canonicalSignature.startsWith("[") + + return if (isNotPrimitiveType) NullabilityType.NotNull else NullabilityType.Unknown +} + +internal fun Set.add(what: T, `if`: Boolean): Set = + applyIf(`if`) { this + what } + +internal inline fun T.applyIf(`if`: Boolean, body: T.() -> T): T = + if (`if`) body() else this \ No newline at end of file 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 new file mode 100644 index 00000000000..696ca996303 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt @@ -0,0 +1,127 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.impl.light.LightParameterListBuilder +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_FOR_GETTER +import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_FOR_SETTER +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertyAccessorSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertyGetterSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySetterSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.load.java.JvmAbi.getterName +import org.jetbrains.kotlin.load.java.JvmAbi.setterName +import org.jetbrains.kotlin.psi.KtDeclaration + +internal class FirLightAccessorMethodForSymbol( + private val propertyAccessorSymbol: KtPropertyAccessorSymbol, + containingPropertySymbol: KtPropertySymbol, + lightMemberOrigin: LightMemberOrigin?, + containingClass: FirLightClassBase, + isTopLevel: Boolean +) : FirLightMethod( + lightMemberOrigin, + containingClass, + if (propertyAccessorSymbol is KtPropertyGetterSymbol) METHOD_INDEX_FOR_GETTER else METHOD_INDEX_FOR_SETTER +) { + private fun String.abiName(firPropertyAccessor: KtPropertyAccessorSymbol) = + if (firPropertyAccessor is KtPropertyGetterSymbol) getterName(this) + else setterName(this) + + //TODO add JvmName + private val _name: String by lazyPub { + containingPropertySymbol.name.identifier + .abiName(propertyAccessorSymbol) + } + + override fun getName(): String = _name + + override fun isVarArgs(): Boolean = false + + override val kotlinOrigin: KtDeclaration? = + (propertyAccessorSymbol.psi ?: containingPropertySymbol.psi) as? KtDeclaration + + private val _annotations: List by lazyPub { + val accessorSite = + if (propertyAccessorSymbol is KtPropertyGetterSymbol) AnnotationUseSiteTarget.PROPERTY_GETTER + else AnnotationUseSiteTarget.PROPERTY_SETTER + containingPropertySymbol.computeAnnotations( + parent = this, + nullability = NullabilityType.Unknown, + annotationUseSiteTarget = accessorSite, + ) + } + + private val _modifiers: Set by lazyPub { + + val isOverride = propertyAccessorSymbol.isOverride || containingPropertySymbol.isOverride + val modifiers = propertyAccessorSymbol.computeModalityForMethod(isTopLevel, isOverride) + + propertyAccessorSymbol.computeVisibility(isTopLevel) + + val isJvmStatic = + _annotations.any { it.qualifiedName == "kotlin.jvm.JvmStatic" } + + if (isJvmStatic) return@lazyPub modifiers + PsiModifier.STATIC + + modifiers + } + + private val _modifierList: PsiModifierList by lazyPub { + FirLightClassModifierList(this, _modifiers, _annotations) + } + + override fun getModifierList(): PsiModifierList = _modifierList + + override fun isConstructor(): Boolean = false + + private val _returnedType: PsiType? by lazyPub { + if (propertyAccessorSymbol !is KtPropertyGetterSymbol) return@lazyPub PsiType.VOID + return@lazyPub containingPropertySymbol.type.asPsiType( + context = containingPropertySymbol, + parent = this@FirLightAccessorMethodForSymbol, + phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE + ) + } + + override fun getReturnType(): PsiType? = _returnedType + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightAccessorMethodForSymbol && + kotlinOrigin == other.kotlinOrigin && + propertyAccessorSymbol == other.propertyAccessorSymbol) + + override fun hashCode(): Int = kotlinOrigin.hashCode() + + + private val _parametersList by lazyPub { + val builder = LightParameterListBuilder(manager, language) + + FirLightParameterForReceiver.tryGet(containingPropertySymbol, this)?.let { + builder.addParameter(it) + } + + val propertyParameter = (propertyAccessorSymbol as? KtPropertySetterSymbol)?.parameter + + if (propertyParameter != null) { + builder.addParameter( + FirLightParameterForSymbol( + parameterSymbol = propertyParameter, + containingMethod = this@FirLightAccessorMethodForSymbol + ) + ) + } + + builder + } + + override fun getParameterList(): PsiParameterList = _parametersList +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightConstructorForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightConstructorForSymbol.kt new file mode 100644 index 00000000000..5a1eb452fe4 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightConstructorForSymbol.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiModifierList +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtConstructorSymbol + +internal class FirLightConstructorForSymbol( + private val constructorSymbol: KtConstructorSymbol, + lightMemberOrigin: LightMemberOrigin?, + containingClass: FirLightClassBase, + methodIndex: Int, +) : FirLightMethodForSymbol(constructorSymbol, lightMemberOrigin, containingClass, methodIndex) { + + private val _name: String? = containingClass.name + + override fun getName(): String = _name ?: "" + + override fun isConstructor(): Boolean = true + + private val _annotations: List by lazyPub { + constructorSymbol.computeAnnotations( + parent = this, + nullability = NullabilityType.Unknown, + annotationUseSiteTarget = null, + ) + } + + private val _modifiers: Set by lazyPub { + setOf(constructorSymbol.computeVisibility(isTopLevel = false)) + } + + private val _modifierList: PsiModifierList by lazyPub { + FirLightClassModifierList(this, _modifiers, _annotations) + } + + override fun getModifierList(): PsiModifierList = _modifierList + + override fun getReturnType(): PsiType? = null + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightConstructorForSymbol && + kotlinOrigin == other.kotlinOrigin && + constructorSymbol == other.constructorSymbol) + + override fun hashCode(): Int = kotlinOrigin.hashCode() +} \ No newline at end of file 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 new file mode 100644 index 00000000000..a2ef3e0b305 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethod.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.impl.PsiImplUtil +import com.intellij.psi.impl.PsiSuperMethodImplUtil +import com.intellij.psi.util.MethodSignature +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.KotlinLightReferenceListBuilder +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.cannotModify +import org.jetbrains.kotlin.asJava.elements.KtLightMethod + +internal abstract class FirLightMethod( + lightMemberOrigin: LightMemberOrigin?, + containingClass: KtLightClass, + private val methodIndex: Int +) : FirLightMemberImpl(lightMemberOrigin, containingClass), KtLightMethod { + + override fun getBody(): PsiCodeBlock? = null + + override fun getReturnTypeElement(): PsiTypeElement? = null + + override fun setName(p0: String): PsiElement = cannotModify() + + override fun isVarArgs() = PsiImplUtil.isVarArgs(this) + + override fun getHierarchicalMethodSignature() = PsiSuperMethodImplUtil.getHierarchicalMethodSignature(this) + + override fun findSuperMethodSignaturesIncludingStatic(checkAccess: Boolean): List = + PsiSuperMethodImplUtil.findSuperMethodSignaturesIncludingStatic(this, checkAccess) + + override fun findDeepestSuperMethod() = PsiSuperMethodImplUtil.findDeepestSuperMethod(this) + + override fun findDeepestSuperMethods(): Array = PsiSuperMethodImplUtil.findDeepestSuperMethods(this) + + override fun findSuperMethods(): Array = PsiSuperMethodImplUtil.findSuperMethods(this) + + override fun findSuperMethods(checkAccess: Boolean): Array = + PsiSuperMethodImplUtil.findSuperMethods(this, checkAccess) + + override fun findSuperMethods(parentClass: PsiClass?): Array = + PsiSuperMethodImplUtil.findSuperMethods(this, parentClass) + + override fun getSignature(substitutor: PsiSubstitutor): MethodSignature = + MethodSignatureBackedByPsiMethod.create(this, substitutor) + + abstract override fun equals(other: Any?): Boolean + + abstract override fun hashCode(): Int + + override fun accept(visitor: PsiElementVisitor) { + if (visitor is JavaElementVisitor) { + visitor.visitMethod(this) + } else { + visitor.visitElement(this) + } + } + + override val isMangled: Boolean = false + + override fun getTypeParameters(): Array = emptyArray() //TODO + + override fun hasTypeParameters(): Boolean = false //TODO + + override fun getTypeParameterList(): PsiTypeParameterList? = null //TODO + + override fun getThrowsList(): PsiReferenceList = + KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST) //TODO() + + override fun getDefaultValue(): PsiAnnotationMemberValue? = null //TODO() +} \ 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 new file mode 100644 index 00000000000..a47bbbc10a8 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightMethodForSymbol.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import com.intellij.psi.impl.light.LightParameterListBuilder +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.KotlinLightReferenceListBuilder +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol +import org.jetbrains.kotlin.psi.KtDeclaration +import java.util.* + +internal abstract class FirLightMethodForSymbol( + private val functionSymbol: KtFunctionLikeSymbol, + lightMemberOrigin: LightMemberOrigin?, + containingClass: FirLightClassBase, + methodIndex: Int, + argumentsSkipMask: BitSet? = null +) : FirLightMethod( + lightMemberOrigin, + containingClass, + methodIndex +) { + private var _isVarArgs: Boolean = functionSymbol.valueParameters.any { it.isVararg } + + override fun isVarArgs(): Boolean = _isVarArgs + + private val _parametersList by lazyPub { + val builder = LightParameterListBuilder(manager, language) + + FirLightParameterForReceiver.tryGet(functionSymbol, this)?.let { + builder.addParameter(it) + } + + functionSymbol.valueParameters.mapIndexed { index, parameter -> + val needToSkip = argumentsSkipMask?.get(index) == true + if (!needToSkip) { + builder.addParameter( + FirLightParameterForSymbol( + parameterSymbol = parameter, + containingMethod = this@FirLightMethodForSymbol + ) + ) + } + } + + builder + } + + override fun getParameterList(): PsiParameterList = _parametersList + + override val kotlinOrigin: KtDeclaration? = functionSymbol.psi as? KtDeclaration +} \ No newline at end of file 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 new file mode 100644 index 00000000000..99d6ab3a9a3 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiModifierList +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.idea.frontend.api.types.isUnit +import java.util.* + +internal class FirLightSimpleMethodForSymbol( + private val functionSymbol: KtFunctionSymbol, + lightMemberOrigin: LightMemberOrigin?, + containingClass: FirLightClassBase, + methodIndex: Int, + isTopLevel: Boolean, + argumentsSkipMask: BitSet? = null +) : FirLightMethodForSymbol( + functionSymbol = functionSymbol, + lightMemberOrigin = lightMemberOrigin, + containingClass = containingClass, + methodIndex = methodIndex, + argumentsSkipMask = argumentsSkipMask +) { + + private val _name: String by lazyPub { + functionSymbol.getJvmNameFromAnnotation(null) ?: functionSymbol.name.asString() + } + + override fun getName(): String = _name + + private val _annotations: List by lazyPub { + + val nullability = if (functionSymbol.type.isUnit) NullabilityType.Unknown else functionSymbol.type.getTypeNullability( + functionSymbol, + FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE + ) + + functionSymbol.computeAnnotations( + parent = this, + nullability = nullability, + annotationUseSiteTarget = null, + ) + } + + private val _modifiers: Set by lazyPub { + + if (functionSymbol.hasInlineOnlyAnnotation()) return@lazyPub setOf(PsiModifier.FINAL, PsiModifier.PRIVATE) + + val modifiers = functionSymbol.computeModalityForMethod(isTopLevel = isTopLevel, functionSymbol.isOverride) + + functionSymbol.computeVisibility(isTopLevel = isTopLevel) + + if (functionSymbol.hasJvmStaticAnnotation()) return@lazyPub modifiers + PsiModifier.STATIC + + modifiers + } + + private val _modifierList: PsiModifierList by lazyPub { + FirLightClassModifierList(this, _modifiers, _annotations) + } + + override fun getModifierList(): PsiModifierList = _modifierList + + override fun isConstructor(): Boolean = false + + private val _returnedType: PsiType by lazyPub { + if (functionSymbol.type.isUnit) return@lazyPub PsiType.VOID + functionSymbol.asPsiType(this@FirLightSimpleMethodForSymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) + } + + override fun getReturnType(): PsiType = _returnedType + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightSimpleMethodForSymbol && + kotlinOrigin == other.kotlinOrigin && + functionSymbol == other.functionSymbol) + + override fun hashCode(): Int = kotlinOrigin.hashCode() +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/modifierLists/FirLightClassModifierList.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/modifierLists/FirLightClassModifierList.kt new file mode 100644 index 00000000000..92592d8c4a7 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/modifierLists/FirLightClassModifierList.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiModifierListOwner +import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.psi.KtModifierListOwner + +internal class FirLightClassModifierList>( + containingDeclaration: T, + private val modifiers: Set, + private val annotations: List +) : FirLightModifierList(containingDeclaration) { + override fun hasModifierProperty(name: String): Boolean = name in modifiers + + override val givenAnnotations: List? + get() = invalidAccess() + + override fun getAnnotations(): Array = annotations.toTypedArray() + override fun findAnnotation(qualifiedName: String) = annotations.firstOrNull { it.qualifiedName == qualifiedName } + + override fun equals(other: Any?): Boolean = this === other + + override fun hashCode(): Int = kotlinOrigin.hashCode() +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/modifierLists/FirLightModifierList.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/modifierLists/FirLightModifierList.kt new file mode 100644 index 00000000000..f18ac6720db --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/modifierLists/FirLightModifierList.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiModifierList +import com.intellij.psi.PsiModifierListOwner +import com.intellij.util.IncorrectOperationException +import org.jetbrains.kotlin.asJava.classes.cannotModify +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.psi.KtModifierList +import org.jetbrains.kotlin.psi.KtModifierListOwner + +internal abstract class FirLightModifierList>( + protected val owner: T +) : KtLightElementBase(owner), PsiModifierList, KtLightElement { + + override val clsDelegate: PsiModifierListOwner + get() = invalidAccess() + + override val kotlinOrigin: KtModifierList? + get() = owner.kotlinOrigin?.modifierList + + override fun getParent() = owner + + override fun hasExplicitModifier(name: String) = hasModifierProperty(name) + + override fun setModifierProperty(name: String, value: Boolean) = cannotModify() + override fun checkSetModifierProperty(name: String, value: Boolean) = throw IncorrectOperationException() + override fun addAnnotation(qualifiedName: String): PsiAnnotation = cannotModify() + + override fun getApplicableAnnotations(): Array = annotations + + override fun getAnnotations(): Array = emptyArray() //TODO() + override fun findAnnotation(qualifiedName: String): PsiAnnotation? = null //TODO() + + override fun isEquivalentTo(another: PsiElement?) = + another is FirLightModifierList<*> && owner == another.owner + + override fun isWritable() = false + + override fun toString() = "Light modifier list of $owner" + + abstract override fun equals(other: Any?): Boolean + + abstract override fun hashCode(): Int +} diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameter.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameter.kt new file mode 100644 index 00000000000..b674aea8b9b --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameter.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.navigation.NavigationItem +import com.intellij.psi.* +import com.intellij.psi.search.LocalSearchScope +import com.intellij.psi.search.SearchScope +import com.intellij.util.IncorrectOperationException +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.psi.KtParameter + +internal abstract class FirLightParameter(containingDeclaration: FirLightMethod) : PsiVariable, NavigationItem, + KtLightElement, KtLightParameter, KtLightElementBase(containingDeclaration) { + + override val clsDelegate: PsiParameter + get() = invalidAccess() + + override val givenAnnotations: List + get() = invalidAccess() + + override fun getTypeElement(): PsiTypeElement? = null + override fun getInitializer(): PsiExpression? = null + override fun hasInitializer(): Boolean = false + override fun computeConstantValue(): Any? = null + override fun getNameIdentifier(): PsiIdentifier? = null + + abstract override fun getName(): String + + @Throws(IncorrectOperationException::class) + override fun normalizeDeclaration() { + } + + override fun setName(p0: String): PsiElement = TODO() //cannotModify() + + override val method: KtLightMethod = containingDeclaration + + override fun getDeclarationScope(): KtLightMethod = method + + override fun accept(visitor: PsiElementVisitor) { + if (visitor is JavaElementVisitor) { + visitor.visitParameter(this) + } + } + + override fun toString(): String = "Fir Light Parameter $name" + + override fun isEquivalentTo(another: PsiElement?): Boolean = + basicIsEquivalentTo(this, another as? PsiParameter) + + override fun getNavigationElement(): PsiElement = kotlinOrigin ?: method.navigationElement + + override fun getUseScope(): SearchScope = kotlinOrigin?.useScope ?: LocalSearchScope(this) + + override fun isValid() = parent.isValid + + abstract override fun getType(): PsiType + + override fun getContainingFile(): PsiFile = method.containingFile + + override fun getParent(): PsiElement = method.parameterList + + abstract override fun equals(other: Any?): Boolean + + abstract override fun hashCode(): Int + + abstract override fun isVarArgs(): Boolean +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForReceiver.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForReceiver.kt new file mode 100644 index 00000000000..fbb96c86c34 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForReceiver.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiModifierList +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtPossibleExtensionSymbol +import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.psi.KtParameter + +internal class FirLightParameterForReceiver private constructor( + private val annotatedSymbol: KtAnnotatedSymbol, + type: KtType, + methodName: String, + method: FirLightMethod +) : FirLightParameter(method) { + + companion object { + fun tryGet( + callableSymbol: KtCallableSymbol, + method: FirLightMethod + ): FirLightParameterForReceiver? { + + if (callableSymbol !is KtNamedSymbol) return null + if (callableSymbol !is KtAnnotatedSymbol) return null + if (callableSymbol !is KtPossibleExtensionSymbol) return null + + if (!callableSymbol.isExtension) return null + val receiverType = callableSymbol.receiverType ?: return null + + return FirLightParameterForReceiver( + annotatedSymbol = callableSymbol, + type = receiverType, + methodName = callableSymbol.name.asString(), + method = method + ) + } + } + + private val _name: String by lazyPub { + AsmUtil.getLabeledThisName(methodName, AsmUtil.LABELED_THIS_PARAMETER, AsmUtil.RECEIVER_PARAMETER_NAME) + } + + override fun getName(): String = _name + + override fun isVarArgs() = false + override fun hasModifierProperty(name: String): Boolean = false //TODO() + + override val kotlinOrigin: KtParameter? = null + + private val _annotations: List by lazyPub { + annotatedSymbol.computeAnnotations( + parent = this, + nullability = type.getTypeNullability(annotatedSymbol, FirResolvePhase.TYPES), + annotationUseSiteTarget = AnnotationUseSiteTarget.RECEIVER, + ) + } + + override fun getModifierList(): PsiModifierList = _modifierList + private val _modifierList: PsiModifierList by lazyPub { + FirLightClassModifierList(this, emptySet(), _annotations) + } + + private val _type: PsiType by lazyPub { + type.asPsiType(annotatedSymbol, method, FirResolvePhase.TYPES) + } + + override fun getType(): PsiType = _type + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightParameterForReceiver && + kotlinOrigin == other.kotlinOrigin && + annotatedSymbol == other.annotatedSymbol) + + override fun hashCode(): Int = kotlinOrigin.hashCode() +} + + diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForSymbol.kt new file mode 100644 index 00000000000..b5924e94336 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForSymbol.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava + +import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtParameterSymbol +import org.jetbrains.kotlin.psi.KtParameter + +internal class FirLightParameterForSymbol( + private val parameterSymbol: KtParameterSymbol, + containingMethod: FirLightMethod +) : FirLightParameter(containingMethod) { + private val _name: String = parameterSymbol.name.asString() + override fun getName(): String = _name + + private val _isVarArgs: Boolean = parameterSymbol.isVararg + override fun isVarArgs() = _isVarArgs + override fun hasModifierProperty(name: String): Boolean = + modifierList.hasModifierProperty(name) + + override val kotlinOrigin: KtParameter? = parameterSymbol.psi as? KtParameter + + private val _annotations: List by lazyPub { + parameterSymbol.computeAnnotations( + parent = this, + nullability = parameterSymbol.type.getTypeNullability(parameterSymbol, FirResolvePhase.TYPES), + annotationUseSiteTarget = null, + ) + } + + override fun getModifierList(): PsiModifierList = _modifierList + private val _modifierList: PsiModifierList by lazyPub { + FirLightClassModifierList(this, emptySet(), _annotations) + } + + private val _type by lazyPub { + val convertedType = parameterSymbol.asPsiType(this, FirResolvePhase.TYPES) + + if (convertedType is PsiArrayType && parameterSymbol.isVararg) { + PsiEllipsisType(convertedType.componentType, convertedType.annotationProvider) + } else convertedType + } + + override fun getType(): PsiType = _type + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightParameterForSymbol && + kotlinOrigin == other.kotlinOrigin && + parameterSymbol == other.parameterSymbol) + + override fun hashCode(): Int = kotlinOrigin.hashCode() +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirAnnotationCall.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirAnnotationCall.kt index 4072b9f8687..c092f0653f9 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirAnnotationCall.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirAnnotationCall.kt @@ -15,4 +15,4 @@ class KtFirAnnotationCall( override val useSiteTarget: AnnotationUseSiteTarget?, override val psi: KtCallElement?, override val arguments: List -) : KtAnnotationCall() \ No newline at end of file +) : KtAnnotationCall() diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirClassOrObjectSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirClassOrObjectSymbol.kt index a197a918578..260aaf1ee64 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirClassOrObjectSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirClassOrObjectSymbol.kt @@ -60,6 +60,9 @@ internal class KtFirClassOrObjectSymbol( builder.buildKtType(it) } } + override val primaryConstructor: KtConstructorSymbol? by firRef.withFirAndCache(FirResolvePhase.RAW_FIR) { fir -> + fir.getPrimaryConstructorIfAny()?.let { builder.buildConstructorSymbol(it) } + } override val typeParameters by firRef.withFirAndCache { fir.typeParameters.map { typeParameter -> diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/asJava/LightClassProvider.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/asJava/LightClassProvider.kt index 625bb04ff5c..9d7f6affab0 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/asJava/LightClassProvider.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/asJava/LightClassProvider.kt @@ -8,15 +8,8 @@ package org.jetbrains.kotlin.idea.asJava import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.psi.* -import com.intellij.psi.impl.light.AbstractLightClass -import com.intellij.psi.impl.light.LightMethod import org.jetbrains.kotlin.asJava.classes.KtLightClass -import org.jetbrains.kotlin.asJava.elements.KtLightElement -import org.jetbrains.kotlin.idea.KotlinLanguage -import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport -import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject interface LightClassProvider { diff --git a/idea/resources-fir/META-INF/plugin.xml b/idea/resources-fir/META-INF/plugin.xml index abb1f81a657..fefad5ae0a1 100644 --- a/idea/resources-fir/META-INF/plugin.xml +++ b/idea/resources-fir/META-INF/plugin.xml @@ -100,6 +100,9 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu + + + + + + + +