org.jetbrains.kotlin.resolve.ShadowedExtensionChecker.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
import org.jetbrains.kotlin.resolve.calls.results.*
import org.jetbrains.kotlin.resolve.descriptorUtil.hasHidesMembersAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.varargParameterPosition
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.util.OperatorNameConventions
class ShadowedExtensionChecker(val typeSpecificityComparator: TypeSpecificityComparator, val trace: DiagnosticSink) {
fun checkDeclaration(declaration: KtDeclaration, descriptor: DeclarationDescriptor) {
if (declaration.name == null) return
if (descriptor !is CallableMemberDescriptor) return
if (descriptor.hasHidesMembersAnnotation()) return
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return
if (extensionReceiverType.isError) return
if (extensionReceiverType.isMarkedNullable) return
when (descriptor) {
is FunctionDescriptor ->
checkShadowedExtensionFunction(declaration, descriptor, trace)
is PropertyDescriptor ->
checkShadowedExtensionProperty(declaration, descriptor, trace)
}
}
private fun checkShadowedExtensionFunction(declaration: KtDeclaration, extensionFunction: FunctionDescriptor, trace: DiagnosticSink) {
val memberScope = extensionFunction.extensionReceiverParameter?.type?.memberScope ?: return
val contributedFunctions =
memberScope.getContributedFunctions(extensionFunction.name, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
for (memberFunction in contributedFunctions) {
if (memberFunction.isPublic() && isExtensionFunctionShadowedByMemberFunction(extensionFunction, memberFunction)) {
trace.report(Errors.EXTENSION_SHADOWED_BY_MEMBER.on(declaration, memberFunction))
return
}
}
val nestedClass = memberScope.getContributedClassifier(extensionFunction.name, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
if (nestedClass is ClassDescriptor && nestedClass.isInner && nestedClass.isPublic()) {
for (constructor in nestedClass.constructors) {
if (constructor.isPublic() && isExtensionFunctionShadowedByMemberFunction(extensionFunction, constructor)) {
trace.report(Errors.EXTENSION_FUNCTION_SHADOWED_BY_INNER_CLASS_CONSTRUCTOR.on(declaration, constructor))
return
}
}
}
val contributedVariables =
memberScope.getContributedVariables(extensionFunction.name, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
for (memberProperty in contributedVariables) {
if (!memberProperty.isPublic()) continue
val invokeOperator = getInvokeOperatorShadowingExtensionFunction(extensionFunction, memberProperty)
if (invokeOperator != null) {
trace.report(
Errors.EXTENSION_FUNCTION_SHADOWED_BY_MEMBER_PROPERTY_WITH_INVOKE.on(
declaration,
memberProperty,
invokeOperator
)
)
return
}
}
}
private fun DeclarationDescriptorWithVisibility.isPublic() =
visibility.normalize() == DescriptorVisibilities.PUBLIC
private fun isExtensionFunctionShadowedByMemberFunction(extension: FunctionDescriptor, member: FunctionDescriptor): Boolean {
// Permissive check:
// (1) functions should have same number of arguments;
// (2) varargs should be in the same positions;
// (3) extension signature should be not less specific than member signature.
// (1) & (2) are required so that we can match signatures easily.
if (extension.valueParameters.size != member.valueParameters.size) return false
if (extension.varargParameterPosition() != member.varargParameterPosition()) return false
if (extension.isOperator && !member.isOperator) return false
if (extension.isInfix && !member.isInfix) return false
val extensionSignature = FlatSignature.createForPossiblyShadowedExtension(extension)
val memberSignature = FlatSignature.createFromCallableDescriptor(member)
return isSignatureEquallyOrMoreSpecific(extensionSignature, memberSignature)
}
private fun getInvokeOperatorShadowingExtensionFunction(
extension: FunctionDescriptor,
member: PropertyDescriptor
): FunctionDescriptor? =
member.type.memberScope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
.firstOrNull { it.isPublic() && it.isOperator && isExtensionFunctionShadowedByMemberFunction(extension, it) }
private fun isSignatureEquallyOrMoreSpecific(
extensionSignature: FlatSignature,
memberSignature: FlatSignature
): Boolean =
ConstraintSystemBuilderImpl.forSpecificity().isSignatureEquallyOrMoreSpecific(
extensionSignature,
memberSignature,
OverloadabilitySpecificityCallbacks,
typeSpecificityComparator
)
private fun checkShadowedExtensionProperty(declaration: KtDeclaration, extensionProperty: PropertyDescriptor, trace: DiagnosticSink) {
val memberScope = extensionProperty.extensionReceiverParameter?.type?.memberScope ?: return
memberScope.getContributedVariables(extensionProperty.name, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
.firstOrNull { it.isPublic() && !it.isExtension }
?.let { memberProperty ->
trace.report(Errors.EXTENSION_SHADOWED_BY_MEMBER.on(declaration, memberProperty))
}
}
}