Refactoring: ExposedVisibilityChecker extracted from DeclarationsChecker

This commit is contained in:
Mikhail Glukhikh
2016-04-15 13:01:16 +03:00
parent ed4ccc6a19
commit 6acd4bc21d
2 changed files with 138 additions and 94 deletions
@@ -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
@@ -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
}
}