Refactoring: ExposedVisibilityChecker extracted from DeclarationsChecker
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user