Prohibit protected constructor calls that are not super-calls in subtypes
#KT-11649 Fixed
This commit is contained in:
@@ -73,6 +73,8 @@ public interface Errors {
|
||||
DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory3<PsiElement, DeclarationDescriptor, Visibility, DeclarationDescriptor> INVISIBLE_MEMBER = DiagnosticFactory3.create(ERROR, CALL_ELEMENT);
|
||||
|
||||
DiagnosticFactory1<KtExpression, ConstructorDescriptor> PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
// Exposed visibility group
|
||||
DiagnosticFactory3<PsiElement, EffectiveVisibility, DescriptorWithRelation, EffectiveVisibility> EXPOSED_PROPERTY_TYPE = DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory3<PsiElement, EffectiveVisibility, DescriptorWithRelation, EffectiveVisibility> EXPOSED_FUNCTION_RETURN_TYPE = DiagnosticFactory3.create(ERROR);
|
||||
|
||||
+2
@@ -97,6 +97,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(INVISIBLE_REFERENCE, "Cannot access ''{0}'': it is ''{1}'' in {2}", NAME, TO_STRING, NAME_OF_PARENT_OR_FILE);
|
||||
MAP.put(INVISIBLE_MEMBER, "Cannot access ''{0}'': it is ''{1}'' in {2}", NAME, TO_STRING, NAME_OF_PARENT_OR_FILE);
|
||||
|
||||
MAP.put(PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL, "Protected constructor ''{0}'' from other classes can only be used in super-call", Renderers.SHORT_NAMES_IN_TYPES);
|
||||
|
||||
MAP.put(EXPOSED_PROPERTY_TYPE, "''{0}'' property exposes its ''{2}'' type{1}", TO_STRING, TO_STRING, TO_STRING);
|
||||
MAP.put(EXPOSED_FUNCTION_RETURN_TYPE, "''{0}'' function exposes its ''{2}'' return type{1}", TO_STRING, TO_STRING, TO_STRING);
|
||||
MAP.put(EXPOSED_PARAMETER_TYPE, "''{0}'' function exposes its ''{2}'' parameter type{1}", TO_STRING, TO_STRING, TO_STRING);
|
||||
|
||||
@@ -69,7 +69,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
|
||||
private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(),
|
||||
SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(),
|
||||
ConstructorHeaderCallChecker)
|
||||
ConstructorHeaderCallChecker, ProtectedConstructorCallChecker)
|
||||
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
||||
private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator(), OperatorValidator(), InfixValidator())
|
||||
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.calls.checkers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
|
||||
import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
|
||||
object ProtectedConstructorCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) {
|
||||
val descriptor = resolvedCall.resultingDescriptor as? ConstructorDescriptor ?: return
|
||||
val constructorOwner = descriptor.containingDeclaration.original
|
||||
val scopeOwner = context.scope.ownerDescriptor
|
||||
|
||||
if (descriptor.visibility.normalize() != Visibilities.PROTECTED) return
|
||||
// Error already reported
|
||||
if (!Visibilities.isVisibleWithAnyReceiver(descriptor, scopeOwner)) return
|
||||
|
||||
val calleeExpression = resolvedCall.call.calleeExpression ?: return
|
||||
|
||||
// Permit constructor super-calls
|
||||
when (calleeExpression) {
|
||||
is KtConstructorCalleeExpression -> if (calleeExpression.parent is KtSuperTypeCallEntry) return
|
||||
is KtConstructorDelegationReferenceExpression -> return
|
||||
}
|
||||
|
||||
// Permit calls within class
|
||||
if (scopeOwner.parentsWithSelf.any { it.original === constructorOwner }) return
|
||||
|
||||
// Using FALSE_IF_PROTECTED helps us to check that descriptor doesn't meet conditions of java package/static-protected
|
||||
// (i.e. being in the same package)
|
||||
// And without ProtectedConstructorCallChecker such calls would be allowed only because they are performed within subclass
|
||||
// of constructor owner
|
||||
@Suppress("DEPRECATION")
|
||||
if (Visibilities.findInvisibleMember(Visibilities.FALSE_IF_PROTECTED, descriptor, scopeOwner) == descriptor) {
|
||||
context.trace.report(Errors.PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL.on(calleeExpression, descriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user