diff --git a/build.gradle.kts b/build.gradle.kts index 8560b4ddc71..3a95329412a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -850,7 +850,8 @@ tasks { ":idea:idea-frontend-api:test", ":idea:idea-frontend-fir:test", ":idea:idea-frontend-fir:idea-fir-low-level-api:test", - ":plugins:uast-kotlin-fir:test" + ":plugins:uast-kotlin-fir:test", + ":idea:idea-fir-fe10-binding:test" ) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt index d580d33dfa3..1307512f5c9 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt @@ -50,7 +50,7 @@ inline val FirCall.resolvedArgumentMapping: Map null } -inline val FirCall.argumentMapping: Map? +inline val FirCall.argumentMapping: LinkedHashMap? get() = when (val argumentList = argumentList) { is FirResolvedArgumentList -> argumentList.mapping is FirPartiallyResolvedArgumentList -> argumentList.mapping diff --git a/generators/build.gradle.kts b/generators/build.gradle.kts index 6d0e8dfcf06..efdb525f718 100644 --- a/generators/build.gradle.kts +++ b/generators/build.gradle.kts @@ -49,6 +49,7 @@ dependencies { testCompile(projectTests(":idea:idea-fir-performance-tests")) testCompile(projectTests(":idea:idea-frontend-fir")) testCompile(projectTests(":idea:idea-frontend-fir:idea-fir-low-level-api")) + testCompile(projectTests(":idea:idea-fir-fe10-binding")) testCompile(projectTests(":j2k")) testCompile(projectTests(":nj2k")) if (Ide.IJ()) { diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 0e9ea883307..8d3dab08388 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -109,10 +109,7 @@ import org.jetbrains.kotlin.idea.highlighter.* import org.jetbrains.kotlin.idea.imports.AbstractJsOptimizeImportsTest import org.jetbrains.kotlin.idea.imports.AbstractJvmOptimizeImportsTest import org.jetbrains.kotlin.idea.index.AbstractKotlinTypeAliasByExpansionShortNameIndexTest -import org.jetbrains.kotlin.idea.inspections.AbstractHLInspectionTest -import org.jetbrains.kotlin.idea.inspections.AbstractHLLocalInspectionTest -import org.jetbrains.kotlin.idea.inspections.AbstractLocalInspectionTest -import org.jetbrains.kotlin.idea.inspections.AbstractMultiFileLocalInspectionTest +import org.jetbrains.kotlin.idea.inspections.* import org.jetbrains.kotlin.idea.intentions.* import org.jetbrains.kotlin.idea.intentions.declarations.AbstractJoinLinesTest import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest @@ -1246,6 +1243,13 @@ fun main(args: Array) { } } + testGroup("idea/idea-fir-fe10-binding/tests", "idea") { + testClass { + val pattern = "^([\\w\\-_]+)\\.(kt|kts)$" + model("testData/intentions/conventionNameCalls/replaceContains", pattern = pattern) + } + } + testGroup("idea/scripting-support/test", "idea/scripting-support/testData") { testClass { model( diff --git a/idea/idea-fir-fe10-binding/build.gradle.kts b/idea/idea-fir-fe10-binding/build.gradle.kts new file mode 100644 index 00000000000..1122e5b0b11 --- /dev/null +++ b/idea/idea-fir-fe10-binding/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + kotlin("jvm") + id("jps-compatible") +} + +dependencies { + implementation(project(":idea:idea-frontend-fir")) + + testImplementation(projectTests(":idea:idea-fir")) + testImplementation(projectTests(":idea:idea-frontend-independent")) + + testImplementation(intellijDep()) + testImplementation(intellijCoreDep()) + testImplementation(toolsJar()) +} + +sourceSets { + "main" { projectDefault() } + "test" { projectDefault() } +} + +testsJar() + +projectTest { + dependsOn(":dist") + workingDir = rootDir + val useFirIdeaPlugin = kotlinBuildProperties.useFirIdeaPlugin + doFirst { + if (!useFirIdeaPlugin) { + error("Test task in the module should be executed with -Pidea.fir.plugin=true") + } + } +} diff --git a/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/BaseDescriptorsWrappers.kt b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/BaseDescriptorsWrappers.kt new file mode 100644 index 00000000000..e844a7572fd --- /dev/null +++ b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/BaseDescriptorsWrappers.kt @@ -0,0 +1,742 @@ +/* + * Copyright 2010-2021 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.fir.fe10 + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.AbstractReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl +import org.jetbrains.kotlin.idea.frontend.api.symbols.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.* +import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.psi.KtPureElement +import org.jetbrains.kotlin.resolve.constants.* +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.source.toSourceElement +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + + +/** + * List of known problems/not-implemented: + * - getOrigin return itself all the time. Formally it should return "unsubstituted" version of itself, but it isn't clear, + * if we really needed that nor how to implemented it. Btw, it is relevant only to member functions/properties (unlikely, but may be to + * inner classes) and not for "resulting descriptor". I.e. only class/interface type parameters could be substituted in FIR, + * there is no "resulting descriptor" and type arguments are passed together with the target function. + * - equals on descriptors and type constructors. It isn't clear what type of equality we should implement, + * will figure that later o real cases. + * See the functions below + */ + +internal fun FE10BindingContext.containerDeclarationImplementationPostponed(): Nothing = + implementationPostponed("It isn't clear what we really need and how to implement it") + +internal fun FE10BindingContext.typeAliasImplementationPlanned(): Nothing = + implementationPlanned("It is easy to implement, but it isn't first priority") + +interface KtSymbolBasedNamed : Named { + val ktSymbol: KtNamedSymbol + override fun getName(): Name = ktSymbol.name +} + +private fun Visibility.toDescriptorVisibility(): DescriptorVisibility = + when (this) { + Visibilities.Public -> DescriptorVisibilities.PUBLIC + Visibilities.Private -> DescriptorVisibilities.PRIVATE + Visibilities.PrivateToThis -> DescriptorVisibilities.PRIVATE_TO_THIS + Visibilities.Protected -> DescriptorVisibilities.PROTECTED + Visibilities.Internal -> DescriptorVisibilities.INTERNAL + Visibilities.Local -> DescriptorVisibilities.LOCAL + else -> error("Unknown visibility: $this") + } + +private fun KtClassKind.toDescriptorKlassKind(): ClassKind = + when (this) { + KtClassKind.CLASS -> ClassKind.CLASS + KtClassKind.ENUM_CLASS -> ClassKind.ENUM_CLASS + KtClassKind.ENUM_ENTRY -> ClassKind.ENUM_ENTRY + KtClassKind.ANNOTATION_CLASS -> ClassKind.ANNOTATION_CLASS + KtClassKind.OBJECT, KtClassKind.COMPANION_OBJECT, KtClassKind.ANONYMOUS_OBJECT -> ClassKind.OBJECT + KtClassKind.INTERFACE -> ClassKind.INTERFACE + } + +private fun KtConstantValue.toConstantValue(): ConstantValue<*> = + when (this) { + KtUnsupportedConstantValue -> ErrorValue.create("Error value for KtUnsupportedConstantValue") + is KtSimpleConstantValue<*> -> when (constantValueKind) { + ConstantValueKind.Null -> NullValue() + ConstantValueKind.Boolean -> BooleanValue(value as Boolean) + ConstantValueKind.Char -> CharValue(value as Char) + ConstantValueKind.Byte -> ByteValue(value as Byte) + ConstantValueKind.Short -> ShortValue(value as Short) + ConstantValueKind.Int -> IntValue(value as Int) + ConstantValueKind.Long -> LongValue(value as Long) + ConstantValueKind.String -> StringValue(value as String) + ConstantValueKind.Float -> FloatValue(value as Float) + ConstantValueKind.Double -> DoubleValue(value as Double) + ConstantValueKind.UnsignedByte -> UByteValue(value as Byte) + ConstantValueKind.UnsignedShort -> UShortValue(value as Short) + ConstantValueKind.UnsignedInt -> UIntValue(value as Int) + ConstantValueKind.UnsignedLong -> ULongValue(value as Long) + else -> error("Unexpected constant KtSimpleConstantValue: $value (class: ${value?.javaClass}") + } + } + +abstract class KtSymbolBasedDeclarationDescriptor(val context: FE10BindingContext) : DeclarationDescriptorWithSource { + abstract val ktSymbol: KtSymbol + override val annotations: Annotations + get() { + val ktAnnotations = (ktSymbol as? KtAnnotatedSymbol)?.annotations ?: return Annotations.EMPTY + return Annotations.create(ktAnnotations.map { KtSymbolBasedAnnotationDescriptor(it, context) }) + } + + override fun getSource(): SourceElement = ktSymbol.psi.safeAs().toSourceElement() + + override fun getContainingDeclaration(): DeclarationDescriptor { + if (ktSymbol !is KtSymbolWithKind) error("ContainingDeclaration should be overriden") + + val containerSymbol = context.withAnalysisSession { + (ktSymbol as KtSymbolWithKind).getContainingSymbol() + } + if (containerSymbol != null) + return containerSymbol.toDeclarationDescriptor(context) + + // i.e. declaration is top-level + return KtSymbolBasedPackageFragmentDescriptor(getPackageFqNameIfTopLevel(), context) + } + + protected abstract fun getPackageFqNameIfTopLevel(): FqName + + private fun KtSymbol.toSignature(): IdSignature = context.ktAnalysisSessionFacade.toSignature(this) + + override fun equals(other: Any?): Boolean { + if (other === this) return true + if (other !is KtSymbolBasedDeclarationDescriptor) return false + + ktSymbol.psi?.let { + return other.ktSymbol.psi == it + } + + return ktSymbol.toSignature() == other.ktSymbol.toSignature() + } + + override fun hashCode(): Int { + ktSymbol.psi?.let { return it.hashCode() } + return ktSymbol.toSignature().hashCode() + } + + override fun accept(visitor: DeclarationDescriptorVisitor?, data: D): R = noImplementation() + override fun acceptVoid(visitor: DeclarationDescriptorVisitor?): Unit = noImplementation() + + // stub for automatic Substitutable implementation for all relevant subclasses + fun substitute(substitutor: TypeSubstitutor): Nothing = noImplementation() + + protected fun noImplementation(): Nothing = context.noImplementation("ktSymbol = $ktSymbol") + protected fun implementationPostponed(): Nothing = context.implementationPostponed("ktSymbol = $ktSymbol") + protected fun implementationPlanned(): Nothing = context.implementationPlanned("ktSymbol = $ktSymbol") +} + +class KtSymbolBasedAnnotationDescriptor( + private val ktAnnotationCall: KtAnnotationCall, + val context: FE10BindingContext +) : AnnotationDescriptor { + override val type: KotlinType + get() = context.implementationPlanned("ktAnnotationCall = $ktAnnotationCall") + + override val fqName: FqName? + get() = ktAnnotationCall.classId?.asSingleFqName() + + override val allValueArguments: Map> = + ktAnnotationCall.arguments.associate { Name.identifier(it.name) to it.expression.toConstantValue() } + + override val source: SourceElement + get() = ktAnnotationCall.psi.toSourceElement() + +} + +class KtSymbolBasedClassDescriptor(override val ktSymbol: KtNamedClassOrObjectSymbol, context: FE10BindingContext) : + KtSymbolBasedDeclarationDescriptor(context), KtSymbolBasedNamed, ClassDescriptor { + + override fun isInner(): Boolean = ktSymbol.isInner + override fun isCompanionObject(): Boolean = ktSymbol.classKind == KtClassKind.COMPANION_OBJECT + override fun isData(): Boolean = ktSymbol.isData + override fun isInline(): Boolean = ktSymbol.isInline // seems like th`is `flag should be removed in favor of isValue + override fun isValue(): Boolean = ktSymbol.isInline + override fun isFun(): Boolean = ktSymbol.isFun + + override fun isExpect(): Boolean = implementationPostponed() + override fun isActual(): Boolean = implementationPostponed() + override fun isExternal(): Boolean = ktSymbol.isExternal + + override fun getVisibility(): DescriptorVisibility = ktSymbol.visibility.toDescriptorVisibility() + override fun getModality(): Modality = ktSymbol.modality + + override fun getKind(): ClassKind = ktSymbol.classKind.toDescriptorKlassKind() + + override fun getCompanionObjectDescriptor(): ClassDescriptor? = ktSymbol.companionObject?.let { + KtSymbolBasedClassDescriptor(it, context) + } + + override fun getTypeConstructor(): TypeConstructor = KtSymbolBasedClassTypeConstructor(this) + + override fun getDeclaredTypeParameters(): List = getTypeParameters(ktSymbol) + + override fun getDefaultType(): SimpleType { + val arguments = TypeUtils.getDefaultTypeProjections(typeConstructor.parameters) + return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( + Annotations.EMPTY, typeConstructor, arguments, false, + MemberScopeForKtSymbolBasedDescriptors { "ktSymbol = $ktSymbol" } + ) + } + + override fun getThisAsReceiverParameter(): ReceiverParameterDescriptor = + ReceiverParameterDescriptorImpl(this, ImplicitClassReceiver(this), Annotations.EMPTY) + + override fun getOriginal(): ClassDescriptor = this + + override fun getUnsubstitutedPrimaryConstructor(): ClassConstructorDescriptor? = context.withAnalysisSession { + ktSymbol.getDeclaredMemberScope().getConstructors().firstOrNull { it.isPrimary } + ?.let { KtSymbolBasedConstructorDescriptor(it, this@KtSymbolBasedClassDescriptor) } + } + + @OptIn(ExperimentalStdlibApi::class) + override fun getConstructors(): Collection = context.withAnalysisSession { + ktSymbol.getDeclaredMemberScope().getConstructors().map { + KtSymbolBasedConstructorDescriptor(it, this@KtSymbolBasedClassDescriptor) + }.toList() + } + + override fun getPackageFqNameIfTopLevel(): FqName = (ktSymbol.classIdIfNonLocal ?: error("should be top-level")).packageFqName + + override fun getSealedSubclasses(): Collection = implementationPostponed() + + override fun getMemberScope(typeArguments: MutableList): MemberScope = noImplementation() + override fun getMemberScope(typeSubstitution: TypeSubstitution): MemberScope = noImplementation() + override fun getUnsubstitutedMemberScope(): MemberScope = noImplementation() + override fun getUnsubstitutedInnerClassesScope(): MemberScope = noImplementation() + override fun getStaticScope(): MemberScope = noImplementation() + + override fun isDefinitelyNotSamInterface(): Boolean = noImplementation() + override fun getDefaultFunctionTypeForSamInterface(): SimpleType = noImplementation() +} + + +class KtSymbolBasedTypeParameterDescriptor( + override val ktSymbol: KtTypeParameterSymbol, context: FE10BindingContext +) : KtSymbolBasedDeclarationDescriptor(context), KtSymbolBasedNamed, TypeParameterDescriptor { + override fun isReified(): Boolean = ktSymbol.isReified + override fun getVariance(): Variance = ktSymbol.variance + + override fun getTypeConstructor(): TypeConstructor = KtSymbolBasedTypeParameterTypeConstructor(this) + + override fun getDefaultType(): SimpleType = + KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( + Annotations.EMPTY, typeConstructor, emptyList(), false, + MemberScopeForKtSymbolBasedDescriptors { "ktSymbol = $ktSymbol" } + ) + + override fun getUpperBounds(): List = ktSymbol.upperBounds.map { it.toKotlinType(context) } + override fun getOriginal(): TypeParameterDescriptor = this + + override fun getContainingDeclaration(): DeclarationDescriptor = context.containerDeclarationImplementationPostponed() + override fun getPackageFqNameIfTopLevel(): FqName = error("Should be called") + + // there is no such thing in FIR, and it seems like it isn't really needed for IDE and could be bypassed on client site + override fun getIndex(): Int = implementationPostponed() + + override fun isCapturedFromOuterDeclaration(): Boolean = noImplementation() + override fun getStorageManager(): StorageManager = noImplementation() +} + + +abstract class KtSymbolBasedFunctionLikeDescriptor(context: FE10BindingContext) : + KtSymbolBasedDeclarationDescriptor(context), FunctionDescriptor { + abstract override val ktSymbol: KtFunctionLikeSymbol + + override fun getReturnType(): KotlinType = ktSymbol.annotatedType.toKotlinType(context) + + override fun getValueParameters(): List = ktSymbol.valueParameters.mapIndexed { index, it -> + KtSymbolBasedValueParameterDescriptor(it, context,this, index) + } + + override fun hasStableParameterNames(): Boolean = implementationPostponed() + override fun hasSynthesizedParameterNames(): Boolean = implementationPostponed() + override fun getKind(): CallableMemberDescriptor.Kind = implementationPostponed() + + override fun getUserData(key: CallableDescriptor.UserDataKey?): V? = null + + override fun getOriginal(): FunctionDescriptor = this + + override fun isHiddenForResolutionEverywhereBesideSupercalls(): Boolean = implementationPostponed() + + override fun getInitialSignatureDescriptor(): FunctionDescriptor? = noImplementation() + override fun isHiddenToOvercomeSignatureClash(): Boolean = noImplementation() + + override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection) = noImplementation() + override fun newCopyBuilder(): FunctionDescriptor.CopyBuilder = noImplementation() + override fun copy( + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean + ): FunctionDescriptor = noImplementation() +} + +class KtSymbolBasedFunctionDescriptor(override val ktSymbol: KtFunctionSymbol, context: FE10BindingContext) : + KtSymbolBasedFunctionLikeDescriptor(context), + SimpleFunctionDescriptor, + KtSymbolBasedNamed { + override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = getExtensionReceiverParameter(ktSymbol) + override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = getDispatchReceiverParameter(ktSymbol) + + override fun getPackageFqNameIfTopLevel(): FqName = (ktSymbol.callableIdIfNonLocal ?: error("should be top-level")).packageName + + override fun isSuspend(): Boolean = ktSymbol.isSuspend + override fun isOperator(): Boolean = ktSymbol.isOperator + override fun isExternal(): Boolean = ktSymbol.isExternal + override fun isInline(): Boolean = ktSymbol.isInline + override fun isInfix(): Boolean = implementationPostponed() + override fun isTailrec(): Boolean = implementationPostponed() + + override fun isExpect(): Boolean = context.incorrectImplementation { false } + override fun isActual(): Boolean = context.incorrectImplementation { false } + + override fun getVisibility(): DescriptorVisibility = ktSymbol.visibility.toDescriptorVisibility() + override fun getModality(): Modality = ktSymbol.modality + + override fun getTypeParameters(): List = getTypeParameters(ktSymbol) + + + override fun getOverriddenDescriptors(): Collection { + val overriddenKtSymbols = context.withAnalysisSession { + ktSymbol.getAllOverriddenSymbols() + } + + return overriddenKtSymbols.map { KtSymbolBasedFunctionDescriptor(it as KtFunctionSymbol, context) } + } + + override fun copy( + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean + ): SimpleFunctionDescriptor = context.noImplementation() + + override fun getOriginal(): SimpleFunctionDescriptor = context.incorrectImplementation { this } + + override fun newCopyBuilder(): FunctionDescriptor.CopyBuilder = + context.noImplementation() +} + +class KtSymbolBasedConstructorDescriptor( + override val ktSymbol: KtConstructorSymbol, + private val ktSBClassDescriptor: KtSymbolBasedClassDescriptor +) : KtSymbolBasedFunctionLikeDescriptor(ktSBClassDescriptor.context), + ClassConstructorDescriptor { + override fun getName(): Name = Name.special("") + + override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = null + override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = getDispatchReceiverParameter(ktSymbol) + + override fun getConstructedClass(): ClassDescriptor = ktSBClassDescriptor + override fun getContainingDeclaration(): ClassDescriptor = ktSBClassDescriptor + override fun getPackageFqNameIfTopLevel(): FqName = error("should not be called") + + override fun isPrimary(): Boolean = ktSymbol.isPrimary + + override fun getReturnType(): KotlinType = ktSBClassDescriptor.defaultType + + override fun isSuspend(): Boolean = false + override fun isOperator(): Boolean = false + override fun isExternal(): Boolean = false + override fun isInline(): Boolean = false + override fun isInfix(): Boolean = false + override fun isTailrec(): Boolean = false + + override fun isExpect(): Boolean = implementationPostponed() + override fun isActual(): Boolean = implementationPostponed() + + override fun getVisibility(): DescriptorVisibility = ktSymbol.visibility.toDescriptorVisibility() + override fun getModality(): Modality = Modality.FINAL + + override fun getTypeParameters(): List = getTypeParameters(ktSymbol) + + override fun getOriginal(): ClassConstructorDescriptor = this + + override fun getOverriddenDescriptors(): Collection = emptyList() + + override fun copy( + newOwner: DeclarationDescriptor, + modality: Modality, + visibility: DescriptorVisibility, + kind: CallableMemberDescriptor.Kind, + copyOverrides: Boolean + ): ClassConstructorDescriptor = noImplementation() +} + +class KtSymbolBasedAnonymousFunctionDescriptor( + override val ktSymbol: KtAnonymousFunctionSymbol, + context: FE10BindingContext +) : KtSymbolBasedFunctionLikeDescriptor(context), SimpleFunctionDescriptor { + override fun getName(): Name = SpecialNames.ANONYMOUS_FUNCTION + + override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = getExtensionReceiverParameter(ktSymbol) + override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = null + + override fun getPackageFqNameIfTopLevel(): FqName = error("Impossible to be a top-level declaration") + + override fun isOperator(): Boolean = false + override fun isExternal(): Boolean = false + override fun isInline(): Boolean = false + override fun isInfix(): Boolean = false + override fun isTailrec(): Boolean = false + override fun isExpect(): Boolean = false + override fun isActual(): Boolean = false + + override fun getVisibility(): DescriptorVisibility = DescriptorVisibilities.LOCAL + override fun getModality(): Modality = Modality.FINAL + override fun getTypeParameters(): List = emptyList() + + // it doesn't seems like isSuspend are used in FIR for anonymous functions, but it used in FIR2IR so if we really need that + // we could implement that later + override fun isSuspend(): Boolean = implementationPostponed() + + override fun getOverriddenDescriptors(): Collection = emptyList() + + override fun copy( + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean + ): SimpleFunctionDescriptor = noImplementation() + + override fun getOriginal(): SimpleFunctionDescriptor = this + + override fun newCopyBuilder(): FunctionDescriptor.CopyBuilder = noImplementation() +} + +private fun KtSymbolBasedDeclarationDescriptor.getDispatchReceiverParameter(ktSymbol: KtPossibleMemberSymbol): ReceiverParameterDescriptor? { + val ktDispatchTypeAndAnnotations = ktSymbol.dispatchType ?: return null + return KtSymbolStubDispatchReceiverParameterDescriptor(ktDispatchTypeAndAnnotations, context) +} + +private fun T.getExtensionReceiverParameter( + ktSymbol: KtPossibleExtensionSymbol +): ReceiverParameterDescriptor? where T : KtSymbolBasedDeclarationDescriptor, T : CallableDescriptor { + val receiverTypeAndAnnotation = ktSymbol.receiverType ?: return null + val receiverValue = ExtensionReceiver(this, receiverTypeAndAnnotation.type.toKotlinType(context), null) + return ReceiverParameterDescriptorImpl(this, receiverValue, receiverTypeAndAnnotation.getDescriptorsAnnotations(context)) +} + +private fun KtSymbolBasedDeclarationDescriptor.getTypeParameters(ktSymbol: KtSymbolWithTypeParameters) = + ktSymbol.typeParameters.map { KtSymbolBasedTypeParameterDescriptor(it, context) } + +private class KtSymbolBasedReceiverValue(val ktType: KtType, val context: FE10BindingContext) : ReceiverValue { + override fun getType(): KotlinType = ktType.toKotlinType(context) + + override fun replaceType(newType: KotlinType): ReceiverValue = context.noImplementation("Should be called from IDE") + override fun getOriginal(): ReceiverValue = this +} + +// Don't think that annotation is important here, because containingDeclaration used way more then annotation and they are not supported here +private class KtSymbolStubDispatchReceiverParameterDescriptor( + val receiverType: KtType, + val context: FE10BindingContext +) : AbstractReceiverParameterDescriptor(Annotations.EMPTY) { + override fun getContainingDeclaration(): DeclarationDescriptor = context.containerDeclarationImplementationPostponed() + + override fun getValue(): ReceiverValue = KtSymbolBasedReceiverValue(receiverType, context) + + override fun copy(newOwner: DeclarationDescriptor): ReceiverParameterDescriptor = + context.noImplementation("Copy should be called from IDE code") +} + +class KtSymbolBasedValueParameterDescriptor( + override val ktSymbol: KtValueParameterSymbol, + context: FE10BindingContext, + val containingDeclaration: KtSymbolBasedFunctionLikeDescriptor, + index: Int = -1, +) : KtSymbolBasedDeclarationDescriptor(context), KtSymbolBasedNamed, ValueParameterDescriptor { + override val index: Int + + init { + if (index != -1) { + this.index = index + } else { + val containerSymbol = containingDeclaration.ktSymbol + this.index = containerSymbol.valueParameters.indexOfFirst { + it === ktSymbol + } + check(this.index != -1) { + "Parameter not found in container symbol = $containerSymbol" + } + } + } + + override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = null + override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = null + + override fun getTypeParameters(): List = emptyList() + + override fun getReturnType(): KotlinType = ktSymbol.annotatedType.toKotlinType(context) + + override fun getValueParameters(): List = emptyList() + override fun hasStableParameterNames(): Boolean = false + override fun hasSynthesizedParameterNames(): Boolean = false + + override fun getUserData(key: CallableDescriptor.UserDataKey?): V? = null + + override fun getVisibility(): DescriptorVisibility = DescriptorVisibilities.LOCAL + + override fun getType(): KotlinType = ktSymbol.annotatedType.toKotlinType(context) + override fun getContainingDeclaration(): CallableDescriptor = containingDeclaration + override fun getPackageFqNameIfTopLevel(): FqName = error("Couldn't be top-level") + + override fun declaresDefaultValue(): Boolean = ktSymbol.hasDefaultValue + + override val varargElementType: KotlinType? + get() { + if (!ktSymbol.isVararg) return null + return context.builtIns.getArrayElementType(type) + } + + override fun getOriginal(): ValueParameterDescriptor = context.incorrectImplementation { this } + + override fun copy(newOwner: CallableDescriptor, newName: Name, newIndex: Int): ValueParameterDescriptor = + context.noImplementation() + + override fun getOverriddenDescriptors(): Collection { + return containingDeclaration.overriddenDescriptors.map { valueParameters[index] } + } + + override val isCrossinline: Boolean + get() = implementationPostponed() + override val isNoinline: Boolean + get() = implementationPostponed() + + override fun isVar(): Boolean = false + override fun getCompileTimeInitializer(): ConstantValue<*>? = null + override fun isConst(): Boolean = false + + override fun equals(other: Any?): Boolean { + if (other === this) return true + if (other !is KtSymbolBasedValueParameterDescriptor) return false + return index == other.index && containingDeclaration == other.containingDeclaration + } + + override fun hashCode(): Int = containingDeclaration.hashCode() * 37 + index + +} + +class KtSymbolBasedPropertyDescriptor( + override val ktSymbol: KtPropertySymbol, + context: FE10BindingContext +) : KtSymbolBasedDeclarationDescriptor(context), KtSymbolBasedNamed, PropertyDescriptor { + override fun getPackageFqNameIfTopLevel(): FqName = (ktSymbol.callableIdIfNonLocal ?: error("should be top-level")).packageName + override fun getOriginal(): PropertyDescriptor = context.incorrectImplementation { this } + + override fun getVisibility(): DescriptorVisibility = ktSymbol.visibility.toDescriptorVisibility() + + override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = getExtensionReceiverParameter(ktSymbol) + + override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = getDispatchReceiverParameter(ktSymbol) + + override fun getTypeParameters(): List = emptyList() + + override fun getReturnType(): KotlinType = ktSymbol.annotatedType.toKotlinType(context) + + override fun getValueParameters(): List = emptyList() + override fun hasStableParameterNames(): Boolean = false + override fun hasSynthesizedParameterNames(): Boolean = false + + override fun getOverriddenDescriptors(): Collection = implementationPostponed() + + override fun getUserData(key: CallableDescriptor.UserDataKey?): V? = null + + override fun getType(): KotlinType = ktSymbol.annotatedType.toKotlinType(context) + + override fun isVar(): Boolean = !ktSymbol.isVal + + override fun getCompileTimeInitializer(): ConstantValue<*>? = ktSymbol.initializer?.toConstantValue() + + override fun isConst(): Boolean = ktSymbol.initializer != null + + override fun isLateInit(): Boolean = implementationPostponed() + + override fun getModality(): Modality = implementationPlanned() + + override fun isExpect(): Boolean = implementationPostponed() + override fun isActual(): Boolean = implementationPostponed() + override fun isExternal(): Boolean = implementationPlanned() + + override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection) = + noImplementation() + + override fun getKind(): CallableMemberDescriptor.Kind = implementationPlanned() + + override fun copy( + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean + ): CallableMemberDescriptor = noImplementation() + + override fun newCopyBuilder(): CallableMemberDescriptor.CopyBuilder = noImplementation() + + override fun isSetterProjectedOut(): Boolean = implementationPostponed() + + override fun getAccessors(): List = listOfNotNull(getter, setter) + + override fun getBackingField(): FieldDescriptor? = implementationPostponed() + override fun getDelegateField(): FieldDescriptor? = implementationPostponed() + override val isDelegated: Boolean + get() = implementationPostponed() + + override val getter: PropertyGetterDescriptor? + get() = ktSymbol.getter?.let { KtSymbolBasedPropertyGetterDescriptor(it, this) } + + override val setter: PropertySetterDescriptor? + get() = ktSymbol.setter?.let { KtSymbolBasedPropertySetterDescriptor(it, this) } +} + +abstract class KtSymbolBasedVariableAccessorDescriptor( + val propertyDescriptor: KtSymbolBasedPropertyDescriptor +) : KtSymbolBasedDeclarationDescriptor(propertyDescriptor.context), VariableAccessorDescriptor { + override abstract val ktSymbol: KtPropertyAccessorSymbol + + override fun getPackageFqNameIfTopLevel(): FqName = error("should be called") + override fun getContainingDeclaration(): DeclarationDescriptor = propertyDescriptor + override val correspondingVariable: VariableDescriptorWithAccessors + get() = propertyDescriptor + + override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = propertyDescriptor.extensionReceiverParameter + override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = propertyDescriptor.dispatchReceiverParameter + + override fun getTypeParameters(): List = emptyList() + + override fun getValueParameters(): List = emptyList() + override fun hasStableParameterNames(): Boolean = false + override fun hasSynthesizedParameterNames(): Boolean = false + override fun getUserData(key: CallableDescriptor.UserDataKey?): V? = null + + override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection) = + noImplementation() + + override fun getKind(): CallableMemberDescriptor.Kind = propertyDescriptor.kind + override fun getVisibility(): DescriptorVisibility = propertyDescriptor.visibility + + override fun getInitialSignatureDescriptor(): FunctionDescriptor? = + noImplementation() + + override fun isHiddenToOvercomeSignatureClash(): Boolean = false + + override fun isOperator(): Boolean = false + + override fun isInfix(): Boolean = false + + override fun isInline(): Boolean = ktSymbol.isInline + + override fun isTailrec(): Boolean = false + + override fun isHiddenForResolutionEverywhereBesideSupercalls(): Boolean = + implementationPostponed() + + override fun isSuspend(): Boolean = false + + override fun newCopyBuilder(): FunctionDescriptor.CopyBuilder = + noImplementation() + + override fun getModality(): Modality = implementationPlanned() + + override fun isExpect(): Boolean = implementationPostponed() + override fun isActual(): Boolean = implementationPostponed() + override fun isExternal(): Boolean = implementationPostponed() +} + +class KtSymbolBasedPropertyGetterDescriptor( + override val ktSymbol: KtPropertyGetterSymbol, + propertyDescriptor: KtSymbolBasedPropertyDescriptor +) : KtSymbolBasedVariableAccessorDescriptor(propertyDescriptor), PropertyGetterDescriptor { + override fun getReturnType(): KotlinType = propertyDescriptor.returnType + + override fun getName(): Name = Name.special("") + override fun isDefault(): Boolean = ktSymbol.isDefault + + override fun getCorrespondingProperty(): PropertyDescriptor = propertyDescriptor + + override fun copy( + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean + ): PropertyAccessorDescriptor = noImplementation() + + override fun getOriginal(): PropertyGetterDescriptor = context.incorrectImplementation { this } + override fun getOverriddenDescriptors(): Collection = implementationPostponed() +} + +class KtSymbolBasedPropertySetterDescriptor( + override val ktSymbol: KtPropertySetterSymbol, + propertyDescriptor: KtSymbolBasedPropertyDescriptor +) : KtSymbolBasedVariableAccessorDescriptor(propertyDescriptor), PropertySetterDescriptor { + override fun getReturnType(): KotlinType = propertyDescriptor.returnType + + override fun getName(): Name = Name.special("") + override fun isDefault(): Boolean = ktSymbol.isDefault + + override fun getCorrespondingProperty(): PropertyDescriptor = propertyDescriptor + + override fun copy( + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean + ): PropertyAccessorDescriptor = noImplementation() + + override fun getOriginal(): PropertySetterDescriptor = context.incorrectImplementation { this } + override fun getOverriddenDescriptors(): Collection = implementationPostponed() +} + + +class KtSymbolBasedPackageFragmentDescriptor( + override val fqName: FqName, + val context: FE10BindingContext +) : PackageFragmentDescriptor { + + override fun getName(): Name = fqName.shortName() + + override fun getOriginal(): DeclarationDescriptorWithSource = this + + override fun getSource(): SourceElement = SourceElement.NO_SOURCE + + override val annotations: Annotations + get() = Annotations.EMPTY + + override fun getContainingDeclaration(): ModuleDescriptor = context.moduleDescriptor + + override fun getMemberScope(): MemberScope = context.noImplementation() + + override fun accept(visitor: DeclarationDescriptorVisitor?, data: D): R = + context.noImplementation("IDE shouldn't use visitor on descriptors") + + override fun acceptVoid(visitor: DeclarationDescriptorVisitor?) = + context.noImplementation("IDE shouldn't use visitor on descriptors") +} \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/FE10BindingContext.kt b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/FE10BindingContext.kt new file mode 100644 index 00000000000..5b586e8e0a7 --- /dev/null +++ b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/FE10BindingContext.kt @@ -0,0 +1,181 @@ +/* + * Copyright 2010-2021 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.fir.fe10 + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.builtins.DefaultBuiltIns +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo +import org.jetbrains.kotlin.idea.caches.project.getModuleInfo +import org.jetbrains.kotlin.idea.fir.fe10.* +import org.jetbrains.kotlin.idea.fir.low.level.api.api.getResolveState +import org.jetbrains.kotlin.idea.frontend.api.* +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.EntityWasGarbageCollectedException +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.KtAnalysisSessionFe10BindingHolder +import org.jetbrains.kotlin.idea.frontend.api.symbols.* +import org.jetbrains.kotlin.idea.frontend.api.tokens.HackToForceAllowRunningAnalyzeOnEDT +import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken +import org.jetbrains.kotlin.idea.frontend.api.tokens.assertIsValidAndAccessible +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.trackers.createProjectWideOutOfBlockModificationTracker +import java.lang.ref.WeakReference + +interface FE10BindingContext { + val builtIns: KotlinBuiltIns + val ktAnalysisSessionFacade: KtAnalysisSessionFe10BindingHolder + val moduleDescriptor: ModuleDescriptor + + /** + * Legend: + * - where was decided, that KtSymbolBased descriptor is not support method, noImplementation() method is called. + * - where the implementation planned, but not yet here: implementationPlanned() + * - if there is no simple implementation and it isn't clear if it really needed -- implementationPostponed() + * - if there were no investigation -- autogenerated TODO("not implemented") called + * - if we could implement it right now, but not entirely correct -- wrap it into incorrect implementation + */ + fun noImplementation(additionalInfo: String = ""): Nothing + fun implementationPostponed(additionalInfo: String = ""): Nothing + fun implementationPlanned(additionalInfo: String = ""): Nothing + + fun incorrectImplementation(block: () -> R) = block() +} + +fun KtSymbol.toDeclarationDescriptor(context: FE10BindingContext): DeclarationDescriptor = + when (this) { + is KtNamedClassOrObjectSymbol -> KtSymbolBasedClassDescriptor(this, context) + is KtFunctionLikeSymbol -> toDeclarationDescriptor(context) + is KtValueParameterSymbol -> { + val containingSymbol = context.withAnalysisSession { this@toDeclarationDescriptor.getContainingSymbol() } + check(containingSymbol is KtFunctionLikeSymbol) { + "Unexpected containing symbol = $containingSymbol" + } + KtSymbolBasedValueParameterDescriptor(this, context, containingSymbol.toDeclarationDescriptor(context)) + } + else -> context.implementationPlanned() + } + +fun KtFunctionLikeSymbol.toDeclarationDescriptor(context: FE10BindingContext): KtSymbolBasedFunctionLikeDescriptor = + when (this) { + is KtFunctionSymbol -> KtSymbolBasedFunctionDescriptor(this, context) + is KtAnonymousFunctionSymbol -> KtSymbolBasedAnonymousFunctionDescriptor(this, context) + is KtConstructorSymbol -> { + val ktConstructorSymbol = this + val ktClassOrObject = context.withAnalysisSession { ktConstructorSymbol.getContainingSymbol() as KtNamedClassOrObjectSymbol } + KtSymbolBasedConstructorDescriptor(ktConstructorSymbol, KtSymbolBasedClassDescriptor(ktClassOrObject, context)) + } + else -> error("Unexpected kind of KtFunctionLikeSymbol: ${this.javaClass}") + } + +inline fun FE10BindingContext.withAnalysisSession(f: KtAnalysisSession.() -> R): R = f(ktAnalysisSessionFacade.analysisSession) + +class FE10BindingContextImpl( + val project: Project, + val ktElement: KtElement +) : FE10BindingContext { + private val token: ValidityToken = ValidityTokenForKtSymbolBasedWrappers(project) + + private val moduleInfo = ktElement.getModuleInfo() + + @OptIn(InvalidWayOfUsingAnalysisSession::class) + override val ktAnalysisSessionFacade = KtAnalysisSessionFe10BindingHolder.create(ktElement.getResolveState(), token) + + override val moduleDescriptor: ModuleDescriptor = KtSymbolBasedModuleDescriptorImpl(this, moduleInfo) + + override val builtIns: KotlinBuiltIns + get() = incorrectImplementation { DefaultBuiltIns.Instance } + + override fun noImplementation(additionalInfo: String): Nothing = + error("This method should not be called for wrappers. $additionalInfo") + + override fun implementationPostponed(additionalInfo: String): Nothing = + TODO("InvestigateLater and implement if needed. $additionalInfo") + + override fun implementationPlanned(additionalInfo: String): Nothing = + TODO("SE_to_implement. $additionalInfo") +} + +private class ValidityTokenForKtSymbolBasedWrappers(val project: Project) : ValidityToken() { + private val modificationTracker = project.createProjectWideOutOfBlockModificationTracker() + private val onCreatedTimeStamp = modificationTracker.modificationCount + + override fun isValid(): Boolean { + return true + } + + override fun getInvalidationReason(): String { + if (onCreatedTimeStamp != modificationTracker.modificationCount) return "PSI has changed since creation" + error("Getting invalidation reason for valid validity token") + } + + override fun isAccessible(): Boolean = true + + @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) + override fun getInaccessibilityReason(): String = error("Getting inaccessibility reason for validity token when it is accessible") +} + +// This class supposed to be used for non-declaration resolved fir elements, because of that we don't case about FIR phases. +// TODO: review FIR access -- by common IDEA FIR design access FIR should be under read lock +internal class FirWeakReference(firElement: T, private val token: ValidityToken) { + private val firWeakRef = WeakReference(firElement) + + inline fun withFir(action: (T) -> R): R { + return action(getFir()) + } + + fun getFir(): T { + token.assertIsValidAndAccessible() + return firWeakRef.get() ?: throw EntityWasGarbageCollectedException("FirElement") + } +} + +private class KtSymbolBasedModuleDescriptorImpl( + val context: FE10BindingContext, + val moduleInfo: IdeaModuleInfo +) : ModuleDescriptor { + override val builtIns: KotlinBuiltIns + get() = context.builtIns + + override val stableName: Name? + get() = context.noImplementation() + override val platform: TargetPlatform? + get() = moduleInfo.platform + + override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean = context.noImplementation() + override fun getPackage(fqName: FqName): PackageViewDescriptor = context.noImplementation() + override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection = context.noImplementation() + + override val allDependencyModules: List + get() = context.implementationPostponed() + override val expectedByModules: List + get() = context.implementationPostponed() + override val allExpectedByModules: Set + get() = context.implementationPostponed() + + override fun getCapability(capability: ModuleCapability): T? = null + + override val isValid: Boolean + get() = context.ktAnalysisSessionFacade.analysisSession.token.isValid() + + override fun assertValid() { + assert(context.ktAnalysisSessionFacade.analysisSession.token.isValid()) + } + + override fun getName(): Name = moduleInfo.name + + override fun getOriginal(): DeclarationDescriptor = this + + override fun acceptVoid(visitor: DeclarationDescriptorVisitor?) = context.noImplementation() + + override val annotations: Annotations + get() = context.incorrectImplementation { Annotations.EMPTY } + +} \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/KtSymbolBasedKotlinTypes.kt b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/KtSymbolBasedKotlinTypes.kt new file mode 100644 index 00000000000..b4f9aac6af3 --- /dev/null +++ b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/KtSymbolBasedKotlinTypes.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2010-2021 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.fir.fe10 + +import org.jetbrains.kotlin.builtins.DefaultBuiltIns +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.idea.frontend.api.KtStarProjectionTypeArgument +import org.jetbrains.kotlin.idea.frontend.api.KtTypeArgument +import org.jetbrains.kotlin.idea.frontend.api.KtTypeArgumentWithVariance +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtAnonymousObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedClassOrObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeAliasSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtTypeAndAnnotations +import org.jetbrains.kotlin.idea.frontend.api.types.* +import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.refinement.TypeRefinement +import org.jetbrains.kotlin.utils.Printer +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +abstract class KtSymbolBasedAbstractTypeConstructor internal constructor( + val ktSBDescriptor: T +) : TypeConstructor where T : KtSymbolBasedDeclarationDescriptor, T : ClassifierDescriptor { + override fun getDeclarationDescriptor(): ClassifierDescriptor = ktSBDescriptor + + // TODO: captured types + override fun isDenotable(): Boolean = true + + // for Intention|inspection it shouldn't be important what to use. + override fun getBuiltIns(): KotlinBuiltIns = DefaultBuiltIns.Instance + + // I don't think that we need to implement this method + override fun isFinal(): Boolean = ktSBDescriptor.context.implementationPostponed("ktSBDescriptor = $ktSBDescriptor") + + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = + ktSBDescriptor.context.noImplementation("ktSBDescriptor = $ktSBDescriptor") +} + +class KtSymbolBasedClassTypeConstructor(ktSBDescriptor: KtSymbolBasedClassDescriptor) : + KtSymbolBasedAbstractTypeConstructor(ktSBDescriptor) { + override fun getParameters(): List = + ktSBDescriptor.ktSymbol.typeParameters.map { KtSymbolBasedTypeParameterDescriptor(it, ktSBDescriptor.context) } + + override fun getSupertypes(): Collection = + ktSBDescriptor.ktSymbol.superTypes.map { it.toKotlinType(ktSBDescriptor.context) } +} + +class KtSymbolBasedTypeParameterTypeConstructor(ktSBDescriptor: KtSymbolBasedTypeParameterDescriptor) : + KtSymbolBasedAbstractTypeConstructor(ktSBDescriptor) { + override fun getParameters(): List = emptyList() + + override fun getSupertypes(): Collection = + ktSBDescriptor.ktSymbol.upperBounds.map { it.toKotlinType(ktSBDescriptor.context) } +} + +// This class is not suppose to be used as "is instance of" because scopes could be wrapped into other scopes +// so generally it isn't a good idea +internal class MemberScopeForKtSymbolBasedDescriptors(lazyDebugInfo: () -> String) : MemberScope { + private val additionalInfo by lazy(lazyDebugInfo) + + private fun noImplementation(): Nothing = + error("Scope for descriptors based on KtSymbols should not be used, additional info: $additionalInfo") + + override fun getContributedVariables(name: Name, location: LookupLocation): Collection = noImplementation() + override fun getContributedFunctions(name: Name, location: LookupLocation): Collection = noImplementation() + override fun getFunctionNames(): Set = noImplementation() + override fun getVariableNames(): Set = noImplementation() + override fun getClassifierNames(): Set = noImplementation() + override fun printScopeStructure(p: Printer): Unit = noImplementation() + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor = noImplementation() + + override fun getContributedDescriptors( + kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean + ): Collection = noImplementation() +} + +fun KtTypeAndAnnotations.getDescriptorsAnnotations(context: FE10BindingContext): Annotations = + Annotations.create(annotations.map { KtSymbolBasedAnnotationDescriptor(it, context) }) + +fun KtTypeAndAnnotations.toKotlinType(context: FE10BindingContext): UnwrappedType = + type.toKotlinType(context, getDescriptorsAnnotations(context)) + +fun KtTypeArgument.toTypeProjection(context: FE10BindingContext): TypeProjection = + when (this) { + KtStarProjectionTypeArgument -> StarProjectionForAbsentTypeParameter(context.builtIns) + is KtTypeArgumentWithVariance -> TypeProjectionImpl(variance, type.toKotlinType(context)) + } + +fun KtType.toKotlinType(context: FE10BindingContext, annotations: Annotations = Annotations.EMPTY): UnwrappedType { + if (this is KtNonDenotableType) return toKotlinType(context, annotations) + + val typeConstructor = when (this) { + is KtTypeParameterType -> KtSymbolBasedTypeParameterDescriptor(this.symbol, context).typeConstructor + is KtClassType -> when (val classLikeSymbol = classSymbol) { + is KtTypeAliasSymbol -> context.typeAliasImplementationPlanned() + is KtNamedClassOrObjectSymbol -> KtSymbolBasedClassDescriptor(classLikeSymbol, context).typeConstructor + is KtAnonymousObjectSymbol -> context.implementationPostponed() + } + is KtErrorType -> ErrorUtils.createErrorTypeConstructorWithCustomDebugName(error) + else -> error("Unexpected subclass: ${this.javaClass}") + } + + val ktTypeArguments = this.safeAs()?.typeArguments ?: emptyList() + + val markedAsNullable = this.safeAs()?.nullability == KtTypeNullability.NULLABLE + + return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( + annotations, typeConstructor, ktTypeArguments.map { it.toTypeProjection(context) }, markedAsNullable, + MemberScopeForKtSymbolBasedDescriptors { this.asStringForDebugging() } + ) +} + +fun KtNonDenotableType.toKotlinType(context: FE10BindingContext, annotations: Annotations = Annotations.EMPTY): UnwrappedType = + when (this) { + is KtFlexibleType -> KotlinTypeFactory.flexibleType( + lowerBound.toKotlinType(context, annotations) as SimpleType, + upperBound.toKotlinType(context, annotations) as SimpleType + ) + // most likely it isn't correct and intersectTypes(List) should be used, + // but I don't think that we will have the real problem with that implementation + is KtIntersectionType -> IntersectionTypeConstructor(conjuncts.map { it.toKotlinType(context) }).createType() + } \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/KtSymbolBasedResolutionFacade.kt b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/KtSymbolBasedResolutionFacade.kt new file mode 100644 index 00000000000..6be3c8c82dc --- /dev/null +++ b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/KtSymbolBasedResolutionFacade.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2010-2021 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.fir.fe10 + +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.analyzer.ModuleInfo +import org.jetbrains.kotlin.analyzer.ResolverForProject +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService +import org.jetbrains.kotlin.caches.resolve.PlatformAnalysisSettings +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.idea.FrontendInternals +import org.jetbrains.kotlin.idea.fir.fe10.binding.KtSymbolBasedBindingContext +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.diagnostics.BindingContextSuppressCache +import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + + +class KtSymbolBasedResolutionFacade( + override val project: Project, + val context: FE10BindingContext +) : ResolutionFacade { + override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext = KtSymbolBasedBindingContext(context) + + override fun analyze(elements: Collection, bodyResolveMode: BodyResolveMode): BindingContext = + KtSymbolBasedBindingContext(context) + + override fun analyzeWithAllCompilerChecks(elements: Collection, callback: DiagnosticSink.DiagnosticsCallback?): AnalysisResult { + return AnalysisResult.success(KtSymbolBasedBindingContext(context), context.moduleDescriptor) + } + + override fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode): DeclarationDescriptor { + val ktSymbol = context.withAnalysisSession { + declaration.getSymbol() + } + return ktSymbol.toDeclarationDescriptor(context) + } + + override val moduleDescriptor: ModuleDescriptor + get() = context.moduleDescriptor + + @FrontendInternals + override fun getFrontendService(serviceClass: Class): T { + TODO("Not yet implemented") + } + + @FrontendInternals + override fun getFrontendService(element: PsiElement, serviceClass: Class): T { + TODO("Not yet implemented") + } + + @FrontendInternals + override fun getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class): T { + TODO("Not yet implemented") + } + + override fun getIdeService(serviceClass: Class): T { + TODO("Not yet implemented") + } + + @FrontendInternals + override fun tryGetFrontendService(element: PsiElement, serviceClass: Class): T? { + TODO("Not yet implemented") + } + + override fun getResolverForProject(): ResolverForProject { + TODO("Not yet implemented") + } + +} + +class KtSymbolBasedKotlinCacheServiceImpl(val project: Project) : KotlinCacheService { + override fun getResolutionFacade(elements: List): ResolutionFacade = + KtSymbolBasedResolutionFacade(project, FE10BindingContextImpl(project, elements.first())) + + // todo: platform are ignored + override fun getResolutionFacade(elements: List, platform: TargetPlatform): ResolutionFacade = + KtSymbolBasedResolutionFacade(project, FE10BindingContextImpl(project, elements.first())) + + override fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade? = + file.safeAs()?.let { KtSymbolBasedResolutionFacade(project, FE10BindingContextImpl(project, it)) } + + override fun getSuppressionCache(): KotlinSuppressCache { + return BindingContextSuppressCache(BindingContext.EMPTY) + } + + override fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade? = + TODO("Not yet implemented") + + override fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, settings: PlatformAnalysisSettings): ResolutionFacade? { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/CallAndResolverCallWrappers.kt b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/CallAndResolverCallWrappers.kt new file mode 100644 index 00000000000..60fcb697c58 --- /dev/null +++ b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/CallAndResolverCallWrappers.kt @@ -0,0 +1,234 @@ +/* + * Copyright 2010-2021 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.fir.fe10.binding + +import com.intellij.lang.ASTNode +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration +import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression +import org.jetbrains.kotlin.fir.realPsi +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance +import org.jetbrains.kotlin.idea.fir.fe10.* +import org.jetbrains.kotlin.idea.fir.fe10.FirWeakReference +import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import java.util.* + +private fun FirExpression?.toExpressionReceiverValue(context: FE10BindingContext): ReceiverValue? { + if (this == null) return null + + if (this is FirThisReceiverExpression) { + val ktClassSymbol = + context.ktAnalysisSessionFacade.buildClassLikeSymbol(calleeReference.boundSymbol?.fir as FirClassLikeDeclaration<*>) + return ImplicitClassReceiver(ktClassSymbol.toDeclarationDescriptor(context) as ClassDescriptor) + } + val expression = realPsi.safeAs() ?: context.implementationPostponed() + return ExpressionReceiver.create( + expression, + context.ktAnalysisSessionFacade.buildKtType(typeRef).toKotlinType(context), + context.incorrectImplementation { BindingContext.EMPTY } + ) +} + +internal class FirSimpleWrapperCall( + val ktCall: KtCallExpression, + val firCall: FirWeakReference, + val context: FE10BindingContext +) : Call { + override fun getCallOperationNode(): ASTNode = ktCall.node + + override fun getExplicitReceiver(): Receiver? = firCall.withFir { it.explicitReceiver.toExpressionReceiverValue(context) } + + override fun getDispatchReceiver(): ReceiverValue? = null + + override fun getCalleeExpression(): KtExpression? = ktCall.calleeExpression + + override fun getValueArgumentList(): KtValueArgumentList? = ktCall.valueArgumentList + + override fun getValueArguments(): List = ktCall.valueArguments + + override fun getFunctionLiteralArguments(): List = ktCall.lambdaArguments + + override fun getTypeArguments(): List = ktCall.typeArguments + + override fun getTypeArgumentList(): KtTypeArgumentList? = ktCall.typeArgumentList + + override fun getCallElement(): KtElement = ktCall + + override fun getCallType(): Call.CallType = Call.CallType.DEFAULT +} + +internal class FirWrapperResolvedCall(val firSimpleWrapperCall: FirSimpleWrapperCall) : ResolvedCall { + private val firCall get() = firSimpleWrapperCall.firCall + private val context get() = firSimpleWrapperCall.context + + private val ktFunctionSymbol = firCall.withFir { + context.ktAnalysisSessionFacade.buildSymbol((it.calleeReference as FirResolvedNamedReference).resolvedSymbol.fir) as KtFunctionLikeSymbol + } + + private val _typeArguments: Map by lazy(LazyThreadSafetyMode.PUBLICATION) { + + if (firCall.getFir().typeArguments.isEmpty()) return@lazy emptyMap() + + val typeArguments = linkedMapOf() + for ((index, parameter) in candidateDescriptor.typeParameters.withIndex()) { + val firTypeProjectionWithVariance = firCall.getFir().typeArguments[index] as FirTypeProjectionWithVariance + val kotlinType = context.ktAnalysisSessionFacade.buildKtType(firTypeProjectionWithVariance.typeRef).toKotlinType(context) + typeArguments[parameter] = kotlinType + } + typeArguments + } + + private val arguments: Map by lazy(LazyThreadSafetyMode.PUBLICATION) { + val firArguments = firCall.withFir { it.argumentMapping } ?: context.implementationPostponed() + + val firParameterToResolvedValueArgument = hashMapOf() + val allArguments = firSimpleWrapperCall.valueArguments + firSimpleWrapperCall.functionLiteralArguments + var argumentIndex = 0 + for ((firExpression, firValueParameter) in firArguments.entries) { + if (firExpression is FirVarargArgumentsExpression) { + val varargArguments = mutableListOf() + for (subExpression in firExpression.arguments) { + val currentArgument = allArguments[argumentIndex]; argumentIndex++ + check(currentArgument.getArgumentExpression() === subExpression.realPsi) { + "Different psi: ${currentArgument.getArgumentExpression()} !== ${subExpression.realPsi}" + } + varargArguments.add(currentArgument) + } + firParameterToResolvedValueArgument[firValueParameter] = VarargValueArgument(varargArguments) + } else { + val currentArgument = allArguments[argumentIndex]; argumentIndex++ + check(currentArgument.getArgumentExpression() === firExpression.realPsi) { + "Different psi: ${currentArgument.getArgumentExpression()} !== ${firExpression.realPsi}" + } + firParameterToResolvedValueArgument[firValueParameter] = ExpressionValueArgument(currentArgument) + } + } + + val arguments = linkedMapOf() + for ((parameterIndex, parameter) in ktFunctionSymbol.valueParameters.withIndex()) { + val resolvedValueArgument = context.ktAnalysisSessionFacade.withFir(parameter) { it: FirValueParameter -> + firParameterToResolvedValueArgument[it] + } ?: DefaultValueArgument.DEFAULT + arguments[candidateDescriptor.valueParameters[parameterIndex]] = resolvedValueArgument + } + arguments + } + + override fun getStatus(): ResolutionStatus = + if (firCall.getFir().calleeReference is FirResolvedNamedReference) ResolutionStatus.SUCCESS else ResolutionStatus.OTHER_ERROR + + override fun getCall(): Call = firSimpleWrapperCall + + override fun getCandidateDescriptor(): CallableDescriptor { + return ktFunctionSymbol.toDeclarationDescriptor(context) + } + + override fun getResultingDescriptor(): CallableDescriptor = context.incorrectImplementation { candidateDescriptor } + + override fun getExtensionReceiver(): ReceiverValue? { + if (firCall.getFir().extensionReceiver === FirNoReceiverExpression) return null + + return firCall.getFir().extensionReceiver.toExpressionReceiverValue(context) + } + + override fun getDispatchReceiver(): ReceiverValue? { + if (firCall.getFir().dispatchReceiver === FirNoReceiverExpression) return null + + return firCall.getFir().dispatchReceiver.toExpressionReceiverValue(context) + } + + override fun getExplicitReceiverKind(): ExplicitReceiverKind { + if (firCall.getFir().explicitReceiver === null) return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER + if (firCall.getFir().explicitReceiver === firCall.getFir().extensionReceiver) return ExplicitReceiverKind.EXTENSION_RECEIVER + return ExplicitReceiverKind.DISPATCH_RECEIVER + } + + override fun getValueArguments(): Map = arguments + + override fun getValueArgumentsByIndex(): List = valueArguments.values.toList() + + override fun getArgumentMapping(valueArgument: ValueArgument): ArgumentMapping { + val firArguments = firCall.withFir { it.argumentMapping } ?: context.implementationPostponed() + val argumentExpression = valueArgument.getArgumentExpression() ?: context.implementationPostponed() + + var targetFirParameter: FirValueParameter? = null + outer@ for ((firExpression, firValueParameter) in firArguments.entries) { + if (firExpression is FirVarargArgumentsExpression) { + for (subExpression in firExpression.arguments) + if (subExpression.realPsi === argumentExpression) { + targetFirParameter = firValueParameter + break@outer + } + } else if (firExpression.realPsi === argumentExpression) { + targetFirParameter = firValueParameter + break@outer + } + } + if (targetFirParameter == null) return ArgumentUnmapped + + val parameterIndex = ktFunctionSymbol.valueParameters.indexOfFirst { + context.ktAnalysisSessionFacade.withFir(it) { it: FirValueParameter -> it === targetFirParameter } + } + if (parameterIndex == -1) error("Fir parameter not found :(") + + val parameterDescriptor = candidateDescriptor.valueParameters[parameterIndex] + return ArgumentMatchImpl(parameterDescriptor) + } + + override fun getTypeArguments(): Map = _typeArguments + + override fun getDataFlowInfoForArguments(): DataFlowInfoForArguments = context.noImplementation() + override fun getSmartCastDispatchReceiverType(): KotlinType? = context.noImplementation() +} + +class CallAndResolverCallWrappers(bindingContext: KtSymbolBasedBindingContext) { + private val context = bindingContext.context + + init { + bindingContext.registerGetterByKey(BindingContext.CALL, this::getCall) + bindingContext.registerGetterByKey(BindingContext.RESOLVED_CALL, this::getResolvedCall) + bindingContext.registerGetterByKey(BindingContext.REFERENCE_TARGET, this::getReferenceTarget) + } + + private fun getCall(element: KtElement): Call { + val ktCall = element.parent.safeAs() ?: context.implementationPostponed() + val firCall = when (val fir = element.getOrBuildFir(context.ktAnalysisSessionFacade.firResolveState)) { + is FirFunctionCall -> fir + is FirSafeCallExpression -> fir.regularQualifiedAccess as? FirFunctionCall + else -> null + } + + if (firCall != null) return FirSimpleWrapperCall(ktCall, FirWeakReference(firCall, context.ktAnalysisSessionFacade.analysisSession.token), context) + + // Call for property + context.implementationPostponed() + } + + private fun getResolvedCall(call: Call): ResolvedCall<*> { + check(call is FirSimpleWrapperCall) { + "Incorrect Call type: $call" + } + return FirWrapperResolvedCall(call) + } + + private fun getReferenceTarget(key: KtReferenceExpression): DeclarationDescriptor? { + val ktSymbol = context.withAnalysisSession { key.mainReference.resolveToSymbols().singleOrNull() } ?: return null + return ktSymbol.toDeclarationDescriptor(context) + } +} \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/KtSymbolBasedBindingContext.kt b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/KtSymbolBasedBindingContext.kt new file mode 100644 index 00000000000..5e1589f7a23 --- /dev/null +++ b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/KtSymbolBasedBindingContext.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2021 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.fir.fe10.binding + +import com.google.common.collect.ImmutableMap +import com.intellij.openapi.diagnostic.Logger +import org.jetbrains.kotlin.idea.fir.fe10.FE10BindingContext +import org.jetbrains.kotlin.idea.fir.fe10.toKotlinType +import org.jetbrains.kotlin.idea.fir.fe10.withAnalysisSession +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice +import org.jetbrains.kotlin.util.slicedMap.WritableSlice + +class KtSymbolBasedBindingContext(val context: FE10BindingContext) : BindingContext { + private val LOG = Logger.getInstance(KtSymbolBasedBindingContext::class.java) + + private val getterBySlice: MutableMap, (Nothing) -> Any?> = hashMapOf() + + init { + CallAndResolverCallWrappers(this) + ToDescriptorBindingContextValueProviders(this) + } + + fun registerGetterByKey(slice: ReadOnlySlice, getter: (K) -> V?) { + check(!getterBySlice.containsKey(slice)) { + "Key $slice already registered: ${getterBySlice[slice]}" + } + getterBySlice[slice] = getter + } + + override fun getDiagnostics(): Diagnostics = context.incorrectImplementation { Diagnostics.EMPTY } + + override fun get(slice: ReadOnlySlice, key: K): V? { + val getter = getterBySlice[slice] + if (getter == null) { + LOG.info("Key not registered: $slice") + return null + } + + @Suppress("UNCHECKED_CAST") + return (getter as (K) -> V?)(key) + } + + override fun getType(expression: KtExpression): KotlinType? = + context.withAnalysisSession { + expression.getKtType().toKotlinType(context) + } + + override fun getKeys(slice: WritableSlice?): Collection = + context.noImplementation() + + override fun getSliceContents(slice: ReadOnlySlice): ImmutableMap = + context.noImplementation() + + override fun addOwnDataTo(trace: BindingTrace, commitDiagnostics: Boolean) = + context.noImplementation() +} \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/ToDescriptorBindingContextValueProviders.kt b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/ToDescriptorBindingContextValueProviders.kt new file mode 100644 index 00000000000..8ed1ae32db3 --- /dev/null +++ b/idea/idea-fir-fe10-binding/src/org/jetbrains/kotlin/idea/fir/fe10/binding/ToDescriptorBindingContextValueProviders.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2021 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.fir.fe10.binding + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.fir.fe10.* +import org.jetbrains.kotlin.idea.frontend.api.symbols.* +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtTypeParameter +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +internal class ToDescriptorBindingContextValueProviders(bindingContext: KtSymbolBasedBindingContext) { + private val context = bindingContext.context + private val declarationToDescriptorGetters = mutableListOf<(PsiElement) -> DeclarationDescriptor?>() + + private inline fun KtSymbolBasedBindingContext.registerDeclarationToDescriptorByKey( + slice: ReadOnlySlice, + crossinline getter: (K) -> V? + ) { + declarationToDescriptorGetters.add { + if (it is K) getter(it) else null + } + registerGetterByKey(slice, { getter(it) }) + } + + init { + bindingContext.registerDeclarationToDescriptorByKey(BindingContext.CLASS, this::getClass) + bindingContext.registerDeclarationToDescriptorByKey(BindingContext.TYPE_PARAMETER, this::getTypeParameter) + bindingContext.registerDeclarationToDescriptorByKey(BindingContext.FUNCTION, this::getFunction) + bindingContext.registerDeclarationToDescriptorByKey(BindingContext.CONSTRUCTOR, this::getConstructor) + + + bindingContext.registerGetterByKey(BindingContext.DECLARATION_TO_DESCRIPTOR, this::getDeclarationToDescriptor) + } + + private inline fun PsiElement.getKtSymbolOfTypeOrNull(): T? = + this@ToDescriptorBindingContextValueProviders.context.withAnalysisSession { + this@getKtSymbolOfTypeOrNull.safeAs()?.getSymbol().safeAs() + } + + private fun getClass(key: PsiElement): ClassDescriptor? { + val ktClassSymbol = key.getKtSymbolOfTypeOrNull() ?: return null + + return KtSymbolBasedClassDescriptor(ktClassSymbol, context) + } + + private fun getTypeParameter(key: KtTypeParameter): TypeParameterDescriptor { + val ktTypeParameterSymbol = context.withAnalysisSession { key.getTypeParameterSymbol() } + return KtSymbolBasedTypeParameterDescriptor(ktTypeParameterSymbol, context) + } + + private fun getFunction(key: PsiElement): SimpleFunctionDescriptor? { + val ktFunctionLikeSymbol = key.getKtSymbolOfTypeOrNull() ?: return null + return ktFunctionLikeSymbol.toDeclarationDescriptor(context).safeAs() + } + + private fun getConstructor(key: PsiElement): ConstructorDescriptor? { + val ktConstructorSymbol = key.getKtSymbolOfTypeOrNull() ?: return null + val containerClass = context.withAnalysisSession { ktConstructorSymbol.getContainingSymbol() } + check(containerClass is KtNamedClassOrObjectSymbol) { + "Unexpected contained for Constructor symbol: $containerClass, ktConstructorSymbol = $ktConstructorSymbol" + } + + return KtSymbolBasedConstructorDescriptor(ktConstructorSymbol, KtSymbolBasedClassDescriptor(containerClass, context)) + } + + private fun getDeclarationToDescriptor(key: PsiElement): DeclarationDescriptor? { + for (getter in declarationToDescriptorGetters) { + getter(key)?.let { return it } + } + return null + } +} \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/tests/org/jetbrains/kotlin/idea/inspections/AbstractFe10BindingIntentionTest.kt b/idea/idea-fir-fe10-binding/tests/org/jetbrains/kotlin/idea/inspections/AbstractFe10BindingIntentionTest.kt new file mode 100644 index 00000000000..4b8a1795172 --- /dev/null +++ b/idea/idea-fir-fe10-binding/tests/org/jetbrains/kotlin/idea/inspections/AbstractFe10BindingIntentionTest.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2021 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.inspections + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest +import org.jetbrains.kotlin.test.utils.IgnoreTests +import java.io.File + +abstract class AbstractFe10BindingIntentionTest : AbstractIntentionTest() { + override fun isFirPlugin() = true + + // left empty because error reporting in FIR and old FE is different + override fun checkForErrorsBefore(fileText: String) {} + override fun checkForErrorsAfter(fileText: String) {} + + override fun doTestFor(mainFile: File, pathToFiles: Map, intentionAction: IntentionAction, fileText: String) { + IgnoreTests.runTestIfNotDisabledByFileDirective(mainFile.toPath(), IgnoreTests.DIRECTIVES.IGNORE_FE10_BINDING_BY_FIR, "after") { + super.doTestFor(mainFile, pathToFiles, intentionAction, fileText) + } + } +} \ No newline at end of file diff --git a/idea/idea-fir-fe10-binding/tests/org/jetbrains/kotlin/idea/inspections/Fe10BindingIntentionTestGenerated.java b/idea/idea-fir-fe10-binding/tests/org/jetbrains/kotlin/idea/inspections/Fe10BindingIntentionTestGenerated.java new file mode 100644 index 00000000000..16c9c6c5f1a --- /dev/null +++ b/idea/idea-fir-fe10-binding/tests/org/jetbrains/kotlin/idea/inspections/Fe10BindingIntentionTestGenerated.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010-2021 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.inspections; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/intentions/conventionNameCalls/replaceContains") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class Fe10BindingIntentionTestGenerated extends AbstractFe10BindingIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInReplaceContains() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/conventionNameCalls/replaceContains"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); + } + + @TestMetadata("containsFromJava.kt") + public void testContainsFromJava() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt"); + } + + @TestMetadata("containsInExpression.kt") + public void testContainsInExpression() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt"); + } + + @TestMetadata("extensionFunction.kt") + public void testExtensionFunction() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt"); + } + + @TestMetadata("functionLiteralArgument.kt") + public void testFunctionLiteralArgument() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt"); + } + + @TestMetadata("functionLiteralArgumentAfterSemicolon.kt") + public void testFunctionLiteralArgumentAfterSemicolon() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt"); + } + + @TestMetadata("functionLiteralArgumentAtStartOfBlock.kt") + public void testFunctionLiteralArgumentAtStartOfBlock() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt"); + } + + @TestMetadata("functionLiteralArgumentInExpression.kt") + public void testFunctionLiteralArgumentInExpression() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt"); + } + + @TestMetadata("invalidArgument.kt") + public void testInvalidArgument() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/invalidArgument.kt"); + } + + @TestMetadata("missingArgument.kt") + public void testMissingArgument() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/missingArgument.kt"); + } + + @TestMetadata("missingDefaultArgument.kt") + public void testMissingDefaultArgument() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/missingDefaultArgument.kt"); + } + + @TestMetadata("multipleArguments.kt") + public void testMultipleArguments() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/multipleArguments.kt"); + } + + @TestMetadata("notContains.kt") + public void testNotContains() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt"); + } + + @TestMetadata("qualifier.kt") + public void testQualifier() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt"); + } + + @TestMetadata("simpleArgument.kt") + public void testSimpleArgument() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt"); + } + + @TestMetadata("simpleStringLiteral.kt") + public void testSimpleStringLiteral() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt"); + } + + @TestMetadata("super.kt") + public void testSuper() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/super.kt"); + } + + @TestMetadata("twoArgsContainsFromJava.kt") + public void testTwoArgsContainsFromJava() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/twoArgsContainsFromJava.kt"); + } + + @TestMetadata("typeArguments.kt") + public void testTypeArguments() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt"); + } + + @TestMetadata("unacceptableVararg1.kt") + public void testUnacceptableVararg1() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/unacceptableVararg1.kt"); + } + + @TestMetadata("unacceptableVararg2.kt") + public void testUnacceptableVararg2() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/unacceptableVararg2.kt"); + } + + @TestMetadata("withoutOperatorModifier.kt") + public void testWithoutOperatorModifier() throws Exception { + runTest("idea/testData/intentions/conventionNameCalls/replaceContains/withoutOperatorModifier.kt"); + } +} diff --git a/idea/idea-fir/build.gradle.kts b/idea/idea-fir/build.gradle.kts index 0baa196ebfc..e3b8ba2c1da 100644 --- a/idea/idea-fir/build.gradle.kts +++ b/idea/idea-fir/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { compile(project(":idea:formatter")) compile(intellijDep()) compile(intellijCoreDep()) + implementation(project(":idea:idea-fir-fe10-binding")) // compile(project(":idea:idea-core")) @@ -26,6 +27,7 @@ dependencies { testCompileOnly(intellijDep()) testRuntime(intellijDep()) + testImplementation(project(":idea:idea-fir-fe10-binding")) compile(intellijPluginDep("java")) } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/KtAnalysisSessionFe10BindingHolder.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/KtAnalysisSessionFe10BindingHolder.kt new file mode 100644 index 00000000000..79b7f09cf09 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/KtAnalysisSessionFe10BindingHolder.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2021 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.frontend.api.fir.utils + +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState +import org.jetbrains.kotlin.idea.frontend.api.InvalidWayOfUsingAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.fir.buildSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.pointers.createSignature +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol +import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken +import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.ir.util.IdSignature + + +class KtAnalysisSessionFe10BindingHolder private constructor( + internal val firAnalysisSession: KtFirAnalysisSession +) { + val analysisSession: KtAnalysisSession get() = firAnalysisSession + + val firResolveState: FirModuleResolveState get() = firAnalysisSession.firResolveState + + fun buildClassLikeSymbol(fir: FirClassLikeDeclaration<*>): KtClassLikeSymbol = + firAnalysisSession.firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(fir) + + fun buildKtType(coneType: FirTypeRef): KtType = + firAnalysisSession.firSymbolBuilder.typeBuilder.buildKtType(coneType) + + fun buildSymbol(firElement: FirElement): KtSymbol? = firElement.buildSymbol(firAnalysisSession.firSymbolBuilder) + + @Suppress("UNCHECKED_CAST", "NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + inline fun withFir(ktSymbol: KtSymbol, crossinline action: (T) -> R) = + (ktSymbol as KtFirSymbol).firRef.withFir(action = action) + + fun toSignature(ktSymbol: KtSymbol): IdSignature = (ktSymbol as KtFirSymbol<*>).firRef.withFir { it.createSignature() } + + companion object { + @InvalidWayOfUsingAnalysisSession + fun create(firResolveState: FirModuleResolveState, token: ValidityToken): KtAnalysisSessionFe10BindingHolder { + val firAnalysisSession = KtFirAnalysisSession.createAnalysisSessionByResolveState(firResolveState, token) + return KtAnalysisSessionFe10BindingHolder(firAnalysisSession) + } + } +} \ No newline at end of file diff --git a/idea/idea-frontend-independent/tests/org/jetbrains/kotlin/test/utils/IgnoreTests.kt b/idea/idea-frontend-independent/tests/org/jetbrains/kotlin/test/utils/IgnoreTests.kt index 1207440b534..654ecbd3a5e 100644 --- a/idea/idea-frontend-independent/tests/org/jetbrains/kotlin/test/utils/IgnoreTests.kt +++ b/idea/idea-frontend-independent/tests/org/jetbrains/kotlin/test/utils/IgnoreTests.kt @@ -181,6 +181,8 @@ object IgnoreTests { const val FIX_ME = "// FIX_ME: " const val FIR_IDENTICAL = "// FIR_IDENTICAL" + + const val IGNORE_FE10_BINDING_BY_FIR = "// IGNORE_FE10_BINDING_BY_FIR" } enum class DirectivePosition { diff --git a/idea/resources-fir/META-INF/fe10Binding.xml b/idea/resources-fir/META-INF/fe10Binding.xml new file mode 100644 index 00000000000..598fdfa9f89 --- /dev/null +++ b/idea/resources-fir/META-INF/fe10Binding.xml @@ -0,0 +1,14 @@ + + + + + + + + org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceContainsIntention + Kotlin + + + + \ No newline at end of file diff --git a/idea/resources-fir/META-INF/plugin.xml b/idea/resources-fir/META-INF/plugin.xml index 556c4ed65e7..02c4bf50dc5 100644 --- a/idea/resources-fir/META-INF/plugin.xml +++ b/idea/resources-fir/META-INF/plugin.xml @@ -39,6 +39,7 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu + diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt index fcb6a65a8f8..84acc009667 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun foo() { val c = Container() c.contains(1) diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt.after index f82141b91e2..56c9bedce04 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/containsFromJava.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun foo() { val c = Container() 1 in c diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt index 42465755658..78b296ff6f8 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun doSomething(a: T) {} fun test() { diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt.after index 826ddb2ddd3..f00cde545f4 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/containsInExpression.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun doSomething(a: T) {} fun test() { diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt index 8ceea9daf18..1a1172f71a6 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test() operator fun Test.contains(a: Int) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt.after index 03e22435f2d..f4ec525d734 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/extensionFunction.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test() operator fun Test.contains(a: Int) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt index 5b7199bdfd6..a11a7f575f7 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(fn: () -> Boolean) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt.after index 984e5ca80a8..9fabbf324d3 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgument.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(fn: () -> Boolean) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt index 369b0319d99..904b55bcd32 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(fn: () -> Boolean) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt.after index 984e5ca80a8..9fabbf324d3 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAfterSemicolon.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(fn: () -> Boolean) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt index a982aaaa0de..dd895c4356e 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(fn: () -> Boolean) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt.after index 7f22728f2a2..7671be8acde 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentAtStartOfBlock.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(fn: () -> Boolean) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt index 4eec907d0e2..f821faf3821 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun doSomething(a: T) {} fun test() { diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt.after index c63d0cc5bb6..1107bf636e6 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/functionLiteralArgumentInExpression.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun doSomething(a: T) {} fun test() { diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/invalidArgument.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/invalidArgument.kt index d35cca01361..1da7c2fcd15 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/invalidArgument.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/invalidArgument.kt @@ -1,6 +1,7 @@ // IS_APPLICABLE: false // ERROR: Cannot find a parameter with this name: c // ERROR: 'operator' modifier is inapplicable on this function: must have a single value parameter +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: Int=1, b: Int=2): Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/missingArgument.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/missingArgument.kt index 253a006e1b7..8aa0ac09cdf 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/missingArgument.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/missingArgument.kt @@ -1,6 +1,7 @@ // IS_APPLICABLE: false // ERROR: No value passed for parameter 'b' // ERROR: 'operator' modifier is inapplicable on this function: must have a single value parameter +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: Int, b: Int): Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/missingDefaultArgument.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/missingDefaultArgument.kt index e84417350ea..4abc5e9a0c5 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/missingDefaultArgument.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/missingDefaultArgument.kt @@ -1,5 +1,7 @@ // IS_APPLICABLE: false // ERROR: 'operator' modifier is inapplicable on this function: must have a single value parameter +// IGNORE_FE10_BINDING_BY_FIR + fun test() { class Test{ operator fun contains(a: Int=1, b: Int=2) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt index 902e32f0ae9..a2d3aeb8776 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: Int) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt.after index 58db7c6dfb6..89e7e22eda3 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/notContains.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: Int) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt index d22131d10f8..4555f550344 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR class C { companion object { operator fun contains(s: String) = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt.after index a124b9b51bf..c00c41a3962 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/qualifier.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR class C { companion object { operator fun contains(s: String) = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt index 80b18cc023a..8a3abf68449 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: Int) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt.after index c0e7ff5d70d..43044407c1b 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleArgument.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: Int) : Boolean = true diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt index 71d267653ae..cafcf6e9946 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR @Suppress("INAPPLICABLE_OPERATOR_MODIFIER") public operator fun CharSequence.contains(other: CharSequence, ignoreCase: Boolean = false): Boolean = false fun test() { diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt.after index 62cf21faca3..61fa6b7ad90 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/simpleStringLiteral.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR @Suppress("INAPPLICABLE_OPERATOR_MODIFIER") public operator fun CharSequence.contains(other: CharSequence, ignoreCase: Boolean = false): Boolean = false fun test() { diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt index 023bf5859d4..9b002a3dfb4 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: T): Boolean = false diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt.after b/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt.after index 044a18fc1fc..7d862c47677 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt.after +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/typeArguments.kt.after @@ -1,3 +1,4 @@ +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(a: T): Boolean = false diff --git a/idea/testData/intentions/conventionNameCalls/replaceContains/unacceptableVararg1.kt b/idea/testData/intentions/conventionNameCalls/replaceContains/unacceptableVararg1.kt index 851a73a6693..60b352a0748 100644 --- a/idea/testData/intentions/conventionNameCalls/replaceContains/unacceptableVararg1.kt +++ b/idea/testData/intentions/conventionNameCalls/replaceContains/unacceptableVararg1.kt @@ -1,5 +1,6 @@ // IS_APPLICABLE: false // ERROR: 'operator' modifier is inapplicable on this function: must have a single value parameter +// IGNORE_FE10_BINDING_BY_FIR fun test() { class Test{ operator fun contains(vararg b: Int, c: Int = 0): Boolean = true diff --git a/settings.gradle b/settings.gradle index 25541cb84b0..fe52ae0d781 100644 --- a/settings.gradle +++ b/settings.gradle @@ -344,6 +344,7 @@ include ":compiler:test-infrastructure", include ":idea:idea-frontend-fir:idea-fir-low-level-api" include ":idea:idea-frontend-fir:idea-frontend-fir-generator" include ":idea:idea-fir-performance-tests" +include ":idea:idea-fir-fe10-binding" include ":plugins:parcelize:parcelize-compiler", ":plugins:parcelize:parcelize-ide",