Refactoring: ExposedVisibilityChecker extracted from DeclarationsChecker
This commit is contained in:
@@ -88,6 +88,8 @@ class DeclarationsChecker(
|
|||||||
|
|
||||||
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
||||||
|
|
||||||
|
private val exposedChecker = ExposedVisibilityChecker(trace)
|
||||||
|
|
||||||
fun KtDeclaration.checkTypeReferences() = checkTypeReferences(trace)
|
fun KtDeclaration.checkTypeReferences() = checkTypeReferences(trace)
|
||||||
|
|
||||||
fun process(bodiesResolveContext: BodiesResolveContext) {
|
fun process(bodiesResolveContext: BodiesResolveContext) {
|
||||||
@@ -116,7 +118,7 @@ class DeclarationsChecker(
|
|||||||
classOrObject.checkTypeReferences()
|
classOrObject.checkTypeReferences()
|
||||||
modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor)
|
modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor)
|
||||||
identifierChecker.checkDeclaration(classOrObject, trace)
|
identifierChecker.checkDeclaration(classOrObject, trace)
|
||||||
checkClassExposedType(classOrObject, classDescriptor)
|
exposedChecker.checkClassHeader(classOrObject, classDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((function, functionDescriptor) in bodiesResolveContext.functions.entries) {
|
for ((function, functionDescriptor) in bodiesResolveContext.functions.entries) {
|
||||||
@@ -135,7 +137,7 @@ class DeclarationsChecker(
|
|||||||
|
|
||||||
for ((declaration, constructorDescriptor) in bodiesResolveContext.secondaryConstructors.entries) {
|
for ((declaration, constructorDescriptor) in bodiesResolveContext.secondaryConstructors.entries) {
|
||||||
checkConstructorDeclaration(constructorDescriptor, declaration)
|
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) {
|
private fun checkObject(declaration: KtObjectDeclaration, classDescriptor: ClassDescriptorWithResolutionScopes) {
|
||||||
checkOpenMembers(classDescriptor)
|
checkOpenMembers(classDescriptor)
|
||||||
if (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) {
|
if (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) {
|
||||||
@@ -445,7 +397,7 @@ class DeclarationsChecker(
|
|||||||
checkPropertyInitializer(property, propertyDescriptor)
|
checkPropertyInitializer(property, propertyDescriptor)
|
||||||
checkAccessors(property, propertyDescriptor)
|
checkAccessors(property, propertyDescriptor)
|
||||||
checkTypeParameterConstraints(property)
|
checkTypeParameterConstraints(property)
|
||||||
checkPropertyExposedType(property, propertyDescriptor)
|
exposedChecker.checkProperty(property, propertyDescriptor)
|
||||||
checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor)
|
checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor)
|
||||||
checkImplicitCallableType(property, 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) {
|
fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) {
|
||||||
val typeParameterList = function.typeParameterList
|
val typeParameterList = function.typeParameterList
|
||||||
val nameIdentifier = function.nameIdentifier
|
val nameIdentifier = function.nameIdentifier
|
||||||
@@ -653,7 +584,7 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
checkTypeParameterConstraints(function)
|
checkTypeParameterConstraints(function)
|
||||||
checkImplicitCallableType(function, functionDescriptor)
|
checkImplicitCallableType(function, functionDescriptor)
|
||||||
checkFunctionExposedType(function, functionDescriptor)
|
exposedChecker.checkFunction(function, functionDescriptor)
|
||||||
checkVarargParameters(trace, functionDescriptor)
|
checkVarargParameters(trace, functionDescriptor)
|
||||||
|
|
||||||
val containingDescriptor = functionDescriptor.containingDeclaration
|
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) {
|
private fun checkAccessors(property: KtProperty, propertyDescriptor: PropertyDescriptor) {
|
||||||
for (accessorDescriptor in propertyDescriptor.accessors) {
|
for (accessorDescriptor in propertyDescriptor.accessors) {
|
||||||
val accessor = if (accessorDescriptor is PropertyGetterDescriptor) property.getter else property.setter
|
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