From 6acd4bc21d6df933d409b0d915a3072a9ff772f4 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 15 Apr 2016 13:01:16 +0300 Subject: [PATCH] Refactoring: ExposedVisibilityChecker extracted from DeclarationsChecker --- .../kotlin/resolve/DeclarationsChecker.kt | 100 +------------ .../resolve/ExposedVisibilityChecker.kt | 132 ++++++++++++++++++ 2 files changed, 138 insertions(+), 94 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 562c2c60833..0e8198d44e1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -88,6 +88,8 @@ class DeclarationsChecker( private val modifiersChecker = modifiersChecker.withTrace(trace) + private val exposedChecker = ExposedVisibilityChecker(trace) + fun KtDeclaration.checkTypeReferences() = checkTypeReferences(trace) fun process(bodiesResolveContext: BodiesResolveContext) { @@ -116,7 +118,7 @@ class DeclarationsChecker( classOrObject.checkTypeReferences() modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor) identifierChecker.checkDeclaration(classOrObject, trace) - checkClassExposedType(classOrObject, classDescriptor) + exposedChecker.checkClassHeader(classOrObject, classDescriptor) } for ((function, functionDescriptor) in bodiesResolveContext.functions.entries) { @@ -135,7 +137,7 @@ class DeclarationsChecker( for ((declaration, constructorDescriptor) in bodiesResolveContext.secondaryConstructors.entries) { checkConstructorDeclaration(constructorDescriptor, declaration) - checkFunctionExposedType(declaration, constructorDescriptor) + exposedChecker.checkFunction(declaration, constructorDescriptor) } } @@ -263,56 +265,6 @@ class DeclarationsChecker( } } - private fun checkClassExposedType(klass: KtClassOrObject, classDescriptor: ClassDescriptor) { - checkExposedSupertypes(klass, classDescriptor) - checkExposedParameterBounds(klass, classDescriptor) - - val constructor = klass.getPrimaryConstructor() ?: return - val constructorDescriptor = classDescriptor.unsubstitutedPrimaryConstructor ?: return - checkFunctionExposedType(constructor, constructorDescriptor) - } - - private fun checkExposedParameterBounds(klass: KtClassOrObject, classDescriptor: ClassDescriptor) { - val classVisibility = classDescriptor.effectiveVisibility() - val typeParameterList = klass.typeParameters - classDescriptor.declaredTypeParameters.forEachIndexed { i, typeParameterDescriptor -> - if (i >= typeParameterList.size) return - for (upperBound in typeParameterDescriptor.upperBounds) { - val restricting = upperBound.leastPermissiveDescriptor(classVisibility) - if (restricting != null) { - trace.report(EXPOSED_TYPE_PARAMETER_BOUND.on(typeParameterList[i], classVisibility, - restricting, restricting.effectiveVisibility())) - break - } - } - } - } - - private fun checkExposedSupertypes(klass: KtClassOrObject, classDescriptor: ClassDescriptor) { - val classVisibility = classDescriptor.effectiveVisibility() - val isInterface = classDescriptor.kind == ClassKind.INTERFACE - val delegationList = klass.getSuperTypeListEntries() - classDescriptor.typeConstructor.supertypes.forEachIndexed { i, superType -> - if (i >= delegationList.size) return - val superDescriptor = TypeUtils.getClassDescriptor(superType) ?: return@forEachIndexed - val superIsInterface = superDescriptor.kind == ClassKind.INTERFACE - if (superIsInterface != isInterface) { - return@forEachIndexed - } - val restricting = superType.leastPermissiveDescriptor(classVisibility) - if (restricting != null) { - if (isInterface) { - trace.report(EXPOSED_SUPER_INTERFACE.on(delegationList[i], classVisibility, - restricting, restricting.effectiveVisibility())) - } - else { - trace.report(EXPOSED_SUPER_CLASS.on(delegationList[i], classVisibility, - restricting, restricting.effectiveVisibility())) - } - } - } - } - private fun checkObject(declaration: KtObjectDeclaration, classDescriptor: ClassDescriptorWithResolutionScopes) { checkOpenMembers(classDescriptor) if (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) { @@ -445,7 +397,7 @@ class DeclarationsChecker( checkPropertyInitializer(property, propertyDescriptor) checkAccessors(property, propertyDescriptor) checkTypeParameterConstraints(property) - checkPropertyExposedType(property, propertyDescriptor) + exposedChecker.checkProperty(property, propertyDescriptor) checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor) checkImplicitCallableType(property, propertyDescriptor) } @@ -623,27 +575,6 @@ class DeclarationsChecker( } } - private fun checkMemberReceiverExposedType(typeReference: KtTypeReference?, memberDescriptor: CallableMemberDescriptor) { - if (typeReference == null) return - val receiverParameterDescriptor = memberDescriptor.extensionReceiverParameter ?: return - val memberVisibility = memberDescriptor.effectiveVisibility() - val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility) - if (restricting != null) { - trace.report(EXPOSED_RECEIVER_TYPE.on(typeReference, memberVisibility, - restricting, restricting.effectiveVisibility())) - } - } - - private fun checkPropertyExposedType(property: KtProperty, propertyDescriptor: PropertyDescriptor) { - val propertyVisibility = propertyDescriptor.effectiveVisibility() - val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility) - if (restricting != null) { - trace.report(EXPOSED_PROPERTY_TYPE.on(property.nameIdentifier ?: property, propertyVisibility, - restricting, restricting.effectiveVisibility())) - } - checkMemberReceiverExposedType(property.receiverTypeReference, propertyDescriptor) - } - fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) { val typeParameterList = function.typeParameterList val nameIdentifier = function.nameIdentifier @@ -653,7 +584,7 @@ class DeclarationsChecker( } checkTypeParameterConstraints(function) checkImplicitCallableType(function, functionDescriptor) - checkFunctionExposedType(function, functionDescriptor) + exposedChecker.checkFunction(function, functionDescriptor) checkVarargParameters(trace, functionDescriptor) val containingDescriptor = functionDescriptor.containingDeclaration @@ -704,25 +635,6 @@ class DeclarationsChecker( } } - private fun checkFunctionExposedType(function: KtFunction, functionDescriptor: FunctionDescriptor) { - val functionVisibility = functionDescriptor.effectiveVisibility() - if (function !is KtConstructor<*>) { - val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility) - if (restricting != null) { - trace.report(EXPOSED_FUNCTION_RETURN_TYPE.on(function.nameIdentifier ?: function, functionVisibility, - restricting, restricting.effectiveVisibility())) - } - } - functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor -> - val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility) - if (restricting != null && i < function.valueParameters.size) { - trace.report(EXPOSED_PARAMETER_TYPE.on(function.valueParameters[i], functionVisibility, - restricting, restricting.effectiveVisibility())) - } - } - checkMemberReceiverExposedType(function.receiverTypeReference, functionDescriptor) - } - private fun checkAccessors(property: KtProperty, propertyDescriptor: PropertyDescriptor) { for (accessorDescriptor in propertyDescriptor.accessors) { val accessor = if (accessorDescriptor is PropertyGetterDescriptor) property.getter else property.setter diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt new file mode 100644 index 00000000000..ec098589800 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.types.TypeUtils + +// Checker for all seven EXPOSED_* errors +// All functions return true if everything is OK, or false in case of any errors +class ExposedVisibilityChecker(private val trace: BindingTrace) { + + // NB: does not check any members + fun checkClassHeader(klass: KtClassOrObject, classDescriptor: ClassDescriptor): Boolean { + var result = checkSupertypes(klass, classDescriptor) + result = result and checkParameterBounds(klass, classDescriptor) + + val constructor = klass.getPrimaryConstructor() ?: return result + val constructorDescriptor = classDescriptor.unsubstitutedPrimaryConstructor ?: return result + return result and checkFunction(constructor, constructorDescriptor) + } + + fun checkFunction(function: KtFunction, functionDescriptor: FunctionDescriptor): Boolean { + val functionVisibility = functionDescriptor.effectiveVisibility() + var result = true + if (function !is KtConstructor<*>) { + val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility) + if (restricting != null) { + trace.report(Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(function.nameIdentifier ?: function, functionVisibility, + restricting, restricting.effectiveVisibility())) + result = false + } + } + functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor -> + val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility) + if (restricting != null && i < function.valueParameters.size) { + trace.report(Errors.EXPOSED_PARAMETER_TYPE.on(function.valueParameters[i], functionVisibility, + restricting, restricting.effectiveVisibility())) + result = false + } + } + return result and checkMemberReceiver(function.receiverTypeReference, functionDescriptor) + } + + fun checkProperty(property: KtProperty, propertyDescriptor: PropertyDescriptor): Boolean { + val propertyVisibility = propertyDescriptor.effectiveVisibility() + val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility) + var result = true + if (restricting != null) { + trace.report(Errors.EXPOSED_PROPERTY_TYPE.on(property.nameIdentifier ?: property, propertyVisibility, + restricting, restricting.effectiveVisibility())) + result = false + } + return result and checkMemberReceiver(property.receiverTypeReference, propertyDescriptor) + } + + private fun checkMemberReceiver(typeReference: KtTypeReference?, memberDescriptor: CallableMemberDescriptor): Boolean { + if (typeReference == null) return true + val receiverParameterDescriptor = memberDescriptor.extensionReceiverParameter ?: return true + val memberVisibility = memberDescriptor.effectiveVisibility() + val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility) + if (restricting != null) { + trace.report(Errors.EXPOSED_RECEIVER_TYPE.on(typeReference, memberVisibility, + restricting, restricting.effectiveVisibility())) + return false + } + return true + } + + private fun checkSupertypes(klass: KtClassOrObject, classDescriptor: ClassDescriptor): Boolean { + val classVisibility = classDescriptor.effectiveVisibility() + val isInterface = classDescriptor.kind == ClassKind.INTERFACE + val delegationList = klass.getSuperTypeListEntries() + var result = true + classDescriptor.typeConstructor.supertypes.forEachIndexed { i, superType -> + if (i >= delegationList.size) return result + val superDescriptor = TypeUtils.getClassDescriptor(superType) ?: return@forEachIndexed + val superIsInterface = superDescriptor.kind == ClassKind.INTERFACE + if (superIsInterface != isInterface) { + return@forEachIndexed + } + val restricting = superType.leastPermissiveDescriptor(classVisibility) + if (restricting != null) { + if (isInterface) { + trace.report(Errors.EXPOSED_SUPER_INTERFACE.on(delegationList[i], classVisibility, + restricting, restricting.effectiveVisibility())) + } + else { + trace.report(Errors.EXPOSED_SUPER_CLASS.on(delegationList[i], classVisibility, + restricting, restricting.effectiveVisibility())) + } + result = false + } + } + return result + } + + private fun checkParameterBounds(klass: KtClassOrObject, classDescriptor: ClassDescriptor): Boolean { + val classVisibility = classDescriptor.effectiveVisibility() + val typeParameterList = klass.typeParameters + var result = true + classDescriptor.declaredTypeParameters.forEachIndexed { i, typeParameterDescriptor -> + if (i >= typeParameterList.size) return result + for (upperBound in typeParameterDescriptor.upperBounds) { + val restricting = upperBound.leastPermissiveDescriptor(classVisibility) + if (restricting != null) { + trace.report(Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(typeParameterList[i], classVisibility, + restricting, restricting.effectiveVisibility())) + result = false + break + } + } + } + return result + } +} +