Introduce component for caching missing supertypes
Profiling has shown, that supertype hierarchy scan for all calls has considerable performance cost. However, missing supertypes may be calculated only once per descriptor which would help avoiding multiple supertype hierarchy scans for resolved calls from the same class. New memoizer is injected into call completers and checker contexts and then used for retrieving missing super classifiers. #KT-19234 Fixed
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
|
||||
class MissingSupertypesResolver(
|
||||
storageManager: StorageManager,
|
||||
private val moduleDescriptor: ModuleDescriptor
|
||||
) {
|
||||
fun getMissingSuperClassifiers(descriptor: ClassifierDescriptor) = missingClassifiers(descriptor)
|
||||
|
||||
private val missingClassifiers = storageManager.createMemoizedFunction { classifier: ClassifierDescriptor ->
|
||||
doGetMissingClassifiers(classifier)
|
||||
}
|
||||
|
||||
private fun doGetMissingClassifiers(descriptor: ClassifierDescriptor): Set<ClassifierDescriptor> {
|
||||
val missingSuperClassifiers = mutableSetOf<ClassifierDescriptor>()
|
||||
val type = descriptor.defaultType
|
||||
|
||||
for (supertype in type.supertypes()) {
|
||||
val supertypeDeclaration = supertype.constructor.declarationDescriptor
|
||||
|
||||
/*
|
||||
* TODO: expects are not checked, because findClassAcrossModuleDependencies does not work with actualization via type alias
|
||||
* Type parameters are skipped here in favor to explicit checks for bounds, local declarations are ignored for optimization
|
||||
*/
|
||||
if (supertypeDeclaration !is ClassDescriptor || supertypeDeclaration.isExpect) continue
|
||||
if (supertypeDeclaration.visibility == Visibilities.LOCAL) continue
|
||||
|
||||
val superTypeClassId = supertypeDeclaration.classId ?: continue
|
||||
val dependency = moduleDescriptor.findClassAcrossModuleDependencies(superTypeClassId)
|
||||
|
||||
if (dependency == null || dependency is NotFoundClasses.MockClassDescriptor) {
|
||||
missingSuperClassifiers.add(supertypeDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
return missingSuperClassifiers.toSet()
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,8 @@ public class ModifiersChecker {
|
||||
|
||||
public void runDeclarationCheckers(@NotNull KtDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
|
||||
DeclarationCheckerContext context = new DeclarationCheckerContext(
|
||||
trace, languageVersionSettings, deprecationResolver, moduleDescriptor, expectActualTracker
|
||||
trace, languageVersionSettings, deprecationResolver, moduleDescriptor, expectActualTracker,
|
||||
missingSupertypesResolver
|
||||
);
|
||||
for (DeclarationChecker checker : declarationCheckers) {
|
||||
checker.check(declaration, descriptor, context);
|
||||
@@ -291,6 +292,7 @@ public class ModifiersChecker {
|
||||
private final ExpectActualTracker expectActualTracker;
|
||||
private final DeprecationResolver deprecationResolver;
|
||||
private final ModuleDescriptor moduleDescriptor;
|
||||
private final MissingSupertypesResolver missingSupertypesResolver;
|
||||
|
||||
public ModifiersChecker(
|
||||
@NotNull AnnotationChecker annotationChecker,
|
||||
@@ -298,7 +300,8 @@ public class ModifiersChecker {
|
||||
@NotNull LanguageVersionSettings languageVersionSettings,
|
||||
@NotNull ExpectActualTracker expectActualTracker,
|
||||
@NotNull DeprecationResolver deprecationResolver,
|
||||
@NotNull ModuleDescriptor moduleDescriptor
|
||||
@NotNull ModuleDescriptor moduleDescriptor,
|
||||
@NotNull MissingSupertypesResolver missingSupertypesResolver
|
||||
) {
|
||||
this.annotationChecker = annotationChecker;
|
||||
this.declarationCheckers = declarationCheckers;
|
||||
@@ -306,6 +309,7 @@ public class ModifiersChecker {
|
||||
this.expectActualTracker = expectActualTracker;
|
||||
this.deprecationResolver = deprecationResolver;
|
||||
this.moduleDescriptor = moduleDescriptor;
|
||||
this.missingSupertypesResolver = missingSupertypesResolver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -59,7 +59,8 @@ class CallCompleter(
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val effectSystem: EffectSystem,
|
||||
private val dataFlowValueFactory: DataFlowValueFactory
|
||||
private val dataFlowValueFactory: DataFlowValueFactory,
|
||||
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||
) {
|
||||
fun <D : CallableDescriptor> completeCall(
|
||||
context: BasicCallResolutionContext,
|
||||
@@ -78,7 +79,7 @@ class CallCompleter(
|
||||
|
||||
if (context.trace.wantsDiagnostics()) {
|
||||
if (resolvedCall == null) {
|
||||
checkMissingSupertypes(context, moduleDescriptor)
|
||||
checkMissingSupertypes(context, missingSupertypesResolver)
|
||||
} else {
|
||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||
resolvedCall.variableCall.call.calleeExpression
|
||||
@@ -88,7 +89,7 @@ class CallCompleter(
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else resolvedCall.call.callElement
|
||||
|
||||
val callCheckerContext = CallCheckerContext(context, deprecationResolver, moduleDescriptor)
|
||||
val callCheckerContext = CallCheckerContext(context, deprecationResolver, moduleDescriptor, missingSupertypesResolver)
|
||||
for (callChecker in callCheckers) {
|
||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||
|
||||
@@ -105,12 +106,15 @@ class CallCompleter(
|
||||
return results
|
||||
}
|
||||
|
||||
private fun checkMissingSupertypes(context: BasicCallResolutionContext, moduleDescriptor: ModuleDescriptor) {
|
||||
private fun checkMissingSupertypes(
|
||||
context: BasicCallResolutionContext,
|
||||
missingSupertypesResolver: MissingSupertypesResolver
|
||||
) {
|
||||
val call = context.call
|
||||
val explicitReceiver = call.explicitReceiver.safeAs<ReceiverValue>()
|
||||
?: return
|
||||
val explicitReceiver = call.explicitReceiver.safeAs<ReceiverValue>() ?: return
|
||||
|
||||
MissingDependencySupertypeChecker.checkSupertypes(
|
||||
explicitReceiver.type, call.callElement, context.trace, moduleDescriptor
|
||||
explicitReceiver.type, call.callElement, context.trace, missingSupertypesResolver
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
@@ -42,6 +43,7 @@ class CallCheckerContext @JvmOverloads constructor(
|
||||
val resolutionContext: ResolutionContext<*>,
|
||||
override val deprecationResolver: DeprecationResolver,
|
||||
override val moduleDescriptor: ModuleDescriptor,
|
||||
val missingSupertypesResolver: MissingSupertypesResolver,
|
||||
override val trace: BindingTrace = resolutionContext.trace
|
||||
) : CheckerContext {
|
||||
val scope: LexicalScope
|
||||
|
||||
+4
-2
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CompletedCallInfo
|
||||
@@ -49,7 +50,8 @@ class CoroutineInferenceSession(
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val typeApproximator: TypeApproximator
|
||||
private val typeApproximator: TypeApproximator,
|
||||
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||
) : ManyCandidatesResolver<CallableDescriptor>(
|
||||
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns
|
||||
) {
|
||||
@@ -222,7 +224,7 @@ class CoroutineInferenceSession(
|
||||
return ResolvedAtomCompleter(
|
||||
resultSubstitutor, context, kotlinToResolvedCallTransformer,
|
||||
expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, builtIns,
|
||||
deprecationResolver, moduleDescriptor, context.dataFlowValueFactory, typeApproximator
|
||||
deprecationResolver, moduleDescriptor, context.dataFlowValueFactory, typeApproximator, missingSupertypesResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -38,8 +38,6 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
@@ -75,7 +73,8 @@ class KotlinResolutionCallbacksImpl(
|
||||
val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
val deprecationResolver: DeprecationResolver,
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val topLevelCallContext: BasicCallResolutionContext?
|
||||
val topLevelCallContext: BasicCallResolutionContext?,
|
||||
val missingSupertypesResolver: MissingSupertypesResolver
|
||||
) : KotlinResolutionCallbacks {
|
||||
class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) {
|
||||
val returnStatements = ArrayList<Pair<KtReturnExpression, LambdaContextInfo?>>()
|
||||
@@ -161,7 +160,8 @@ class KotlinResolutionCallbacksImpl(
|
||||
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter,
|
||||
callComponents, builtIns, topLevelCallContext, stubsForPostponedVariables, trace,
|
||||
kotlinToResolvedCallTransformer, expressionTypingServices, argumentTypeResolver,
|
||||
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, typeApproximator
|
||||
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, typeApproximator,
|
||||
missingSupertypesResolver
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
||||
+3
-2
@@ -72,7 +72,8 @@ class KotlinToResolvedCallTransformer(
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val typeSystemContext: TypeSystemInferenceExtensionContextDelegate,
|
||||
private val smartCastManager: SmartCastManager,
|
||||
private val typeApproximator: TypeApproximator
|
||||
private val typeApproximator: TypeApproximator,
|
||||
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||
) {
|
||||
companion object {
|
||||
private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC
|
||||
@@ -134,7 +135,7 @@ class KotlinToResolvedCallTransformer(
|
||||
val ktPrimitiveCompleter = ResolvedAtomCompleter(
|
||||
resultSubstitutor, context, this, expressionTypingServices, argumentTypeResolver,
|
||||
doubleColonExpressionResolver, builtIns, deprecationResolver, moduleDescriptor, dataFlowValueFactory,
|
||||
typeApproximator
|
||||
typeApproximator, missingSupertypesResolver
|
||||
)
|
||||
|
||||
if (!ErrorUtils.isError(candidate.candidateDescriptor)) {
|
||||
|
||||
@@ -69,7 +69,8 @@ class PSICallResolver(
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val callableReferenceResolver: CallableReferenceResolver,
|
||||
private val candidateInterceptor: CandidateInterceptor
|
||||
private val candidateInterceptor: CandidateInterceptor,
|
||||
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||
) {
|
||||
private val givenCandidatesName = Name.special("<given candidates>")
|
||||
|
||||
@@ -182,7 +183,7 @@ class PSICallResolver(
|
||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
||||
dataFlowValueFactory, inferenceSession, constantExpressionEvaluator, typeResolver,
|
||||
this, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents,
|
||||
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, context
|
||||
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, context, missingSupertypesResolver
|
||||
)
|
||||
|
||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||
|
||||
+11
-6
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
@@ -49,9 +50,12 @@ class ResolvedAtomCompleter(
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val dataFlowValueFactory: DataFlowValueFactory,
|
||||
private val typeApproximator: TypeApproximator
|
||||
private val typeApproximator: TypeApproximator,
|
||||
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||
) {
|
||||
private val topLevelCallCheckerContext = CallCheckerContext(topLevelCallContext, deprecationResolver, moduleDescriptor)
|
||||
private val topLevelCallCheckerContext = CallCheckerContext(
|
||||
topLevelCallContext, deprecationResolver, moduleDescriptor, missingSupertypesResolver
|
||||
)
|
||||
private val topLevelTrace = topLevelCallCheckerContext.trace
|
||||
|
||||
private fun complete(resolvedAtom: ResolvedAtom) {
|
||||
@@ -90,7 +94,7 @@ class ResolvedAtomCompleter(
|
||||
val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall
|
||||
if (ErrorUtils.isError(resolvedCall.candidateDescriptor)) {
|
||||
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, topLevelTrace, lastCall as NewResolvedCallImpl<*>)
|
||||
checkMissingReceiverSupertypes(resolvedCall, moduleDescriptor, topLevelTrace)
|
||||
checkMissingReceiverSupertypes(resolvedCall, missingSupertypesResolver, topLevelTrace)
|
||||
return resolvedCall
|
||||
}
|
||||
|
||||
@@ -101,7 +105,8 @@ class ResolvedAtomCompleter(
|
||||
CallCheckerContext(
|
||||
resolutionContextForPartialCall.replaceBindingTrace(topLevelTrace),
|
||||
deprecationResolver,
|
||||
moduleDescriptor
|
||||
moduleDescriptor,
|
||||
missingSupertypesResolver
|
||||
)
|
||||
else
|
||||
topLevelCallCheckerContext
|
||||
@@ -119,7 +124,7 @@ class ResolvedAtomCompleter(
|
||||
|
||||
private fun checkMissingReceiverSupertypes(
|
||||
resolvedCall: ResolvedCall<CallableDescriptor>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
missingSupertypesResolver: MissingSupertypesResolver,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
val receiverValue = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver
|
||||
@@ -128,7 +133,7 @@ class ResolvedAtomCompleter(
|
||||
receiverType,
|
||||
resolvedCall.call.callElement,
|
||||
trace,
|
||||
moduleDescriptor
|
||||
missingSupertypesResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
|
||||
interface DeclarationChecker {
|
||||
@@ -33,5 +34,6 @@ class DeclarationCheckerContext(
|
||||
override val languageVersionSettings: LanguageVersionSettings,
|
||||
override val deprecationResolver: DeprecationResolver,
|
||||
override val moduleDescriptor: ModuleDescriptor,
|
||||
val expectActualTracker: ExpectActualTracker
|
||||
val expectActualTracker: ExpectActualTracker,
|
||||
val missingSupertypesResolver: MissingSupertypesResolver
|
||||
) : CheckerContext
|
||||
|
||||
+37
-42
@@ -12,29 +12,27 @@ import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
|
||||
object MissingDependencySupertypeChecker {
|
||||
object ForDeclarations : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
val trace = context.trace
|
||||
val module = context.moduleDescriptor
|
||||
|
||||
if (descriptor is ClassDescriptor) {
|
||||
checkSupertypes(descriptor.defaultType, declaration, trace, module)
|
||||
checkSupertypes(descriptor, declaration, trace, context.missingSupertypesResolver)
|
||||
}
|
||||
|
||||
if (declaration is KtTypeParameterListOwner) {
|
||||
for (ktTypeParameter in declaration.typeParameters) {
|
||||
val typeParameterDescriptor = trace.bindingContext.get(BindingContext.TYPE_PARAMETER, ktTypeParameter) ?: continue
|
||||
for (upperBound in typeParameterDescriptor.upperBounds) {
|
||||
checkSupertypes(upperBound, ktTypeParameter, trace, module)
|
||||
checkSupertypes(upperBound, ktTypeParameter, trace, context.missingSupertypesResolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,57 +43,54 @@ object MissingDependencySupertypeChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val descriptor = resolvedCall.resultingDescriptor
|
||||
|
||||
// Constructor call leads to resolution of supertypes of enclosing class if it's an inner class constructor
|
||||
checkHierarchy(descriptor.dispatchReceiverParameter?.declaration, reportOn, context)
|
||||
// The constructed class' own supertypes are not resolved after constructor call,
|
||||
// so its containing declaration should not be checked.
|
||||
if (descriptor !is ConstructorDescriptor) {
|
||||
checkHierarchy(descriptor.containingDeclaration, reportOn, context)
|
||||
checkHierarchy(descriptor.extensionReceiverParameter?.declaration, reportOn, context)
|
||||
val errorReported = checkSupertypes(
|
||||
descriptor.dispatchReceiverParameter?.declaration, reportOn,
|
||||
context.trace, context.missingSupertypesResolver
|
||||
)
|
||||
if (descriptor !is ConstructorDescriptor && !errorReported) {
|
||||
// The constructed class' own supertypes are not resolved after constructor call,
|
||||
// so its containing declaration should not be checked.
|
||||
// Dispatch receiver is checked before for case of inner class constructor call.
|
||||
checkSupertypes(descriptor.containingDeclaration, reportOn, context.trace, context.missingSupertypesResolver)
|
||||
checkSupertypes(
|
||||
descriptor.extensionReceiverParameter?.declaration, reportOn,
|
||||
context.trace, context.missingSupertypesResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val ReceiverParameterDescriptor.declaration
|
||||
get() = value.type.constructor.declarationDescriptor
|
||||
|
||||
private fun checkHierarchy(declaration: DeclarationDescriptor?, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
if (declaration !is ClassifierDescriptor) return
|
||||
|
||||
checkSupertypes(declaration.defaultType, reportOn, context.trace, context.moduleDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
// true for reported error
|
||||
fun checkSupertypes(
|
||||
classifierType: KotlinType,
|
||||
reportOn: PsiElement,
|
||||
trace: BindingTrace,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
) {
|
||||
val classifierDescriptor = classifierType.constructor.declarationDescriptor ?: return
|
||||
missingSupertypesResolver: MissingSupertypesResolver
|
||||
) = checkSupertypes(classifierType.constructor.declarationDescriptor, reportOn, trace, missingSupertypesResolver)
|
||||
|
||||
for (supertype in classifierType.supertypes()) {
|
||||
val supertypeDeclaration = supertype.constructor.declarationDescriptor
|
||||
// true for reported error
|
||||
fun checkSupertypes(
|
||||
declaration: DeclarationDescriptor?,
|
||||
reportOn: PsiElement,
|
||||
trace: BindingTrace,
|
||||
missingSupertypesResolver: MissingSupertypesResolver
|
||||
): Boolean {
|
||||
if (declaration !is ClassifierDescriptor)
|
||||
return false
|
||||
|
||||
/*
|
||||
* TODO: expects are not checked, because findClassAcrossModuleDependencies does not work with actualization via type alias
|
||||
* Type parameters are skipped here, bounds of type parameters are checked in declaration checker separately
|
||||
* Local declarations are ignored for optimization
|
||||
*/
|
||||
if (supertypeDeclaration !is ClassDescriptor || supertypeDeclaration.isExpect) continue
|
||||
if (supertypeDeclaration.visibility == Visibilities.LOCAL) continue
|
||||
|
||||
val superTypeClassId = supertypeDeclaration.classId ?: continue
|
||||
val dependency = moduleDescriptor.findClassAcrossModuleDependencies(superTypeClassId)
|
||||
|
||||
if (dependency == null || dependency is NotFoundClasses.MockClassDescriptor) {
|
||||
trace.report(
|
||||
Errors.MISSING_DEPENDENCY_SUPERCLASS.on(
|
||||
reportOn,
|
||||
supertypeDeclaration.fqNameSafe,
|
||||
classifierDescriptor.fqNameSafe
|
||||
)
|
||||
val missingSupertypes = missingSupertypesResolver.getMissingSuperClassifiers(declaration)
|
||||
for (missingClassifier in missingSupertypes) {
|
||||
trace.report(
|
||||
Errors.MISSING_DEPENDENCY_SUPERCLASS.on(
|
||||
reportOn,
|
||||
missingClassifier.fqNameSafe,
|
||||
declaration.fqNameSafe
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
return missingSupertypes.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
+13
-2
@@ -961,7 +961,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
// Call must be validated with the actual, not temporary trace in order to report operator diagnostic
|
||||
// Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace
|
||||
CallCheckerContext callCheckerContext =
|
||||
new CallCheckerContext(context, components.deprecationResolver, components.moduleDescriptor, trace);
|
||||
new CallCheckerContext(
|
||||
context,
|
||||
components.deprecationResolver,
|
||||
components.moduleDescriptor,
|
||||
components.missingSupertypesResolver,
|
||||
trace
|
||||
);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
}
|
||||
@@ -1038,7 +1044,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
@NotNull
|
||||
private CallCheckerContext createCallCheckerContext(@NotNull ExpressionTypingContext context) {
|
||||
return new CallCheckerContext(context, components.deprecationResolver, components.moduleDescriptor);
|
||||
return new CallCheckerContext(
|
||||
context,
|
||||
components.deprecationResolver,
|
||||
components.moduleDescriptor,
|
||||
components.missingSupertypesResolver
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+6
@@ -66,6 +66,7 @@ public class ExpressionTypingComponents {
|
||||
/*package*/ DataFlowValueFactory dataFlowValueFactory;
|
||||
/*package*/ NewKotlinTypeChecker kotlinTypeChecker;
|
||||
/*package*/ TypeResolutionInterceptor typeResolutionInterceptor;
|
||||
/*package*/ MissingSupertypesResolver missingSupertypesResolver;
|
||||
|
||||
|
||||
@Inject
|
||||
@@ -252,4 +253,9 @@ public class ExpressionTypingComponents {
|
||||
public void setTypeResolutionInterceptor(@NotNull TypeResolutionInterceptor typeResolutionInterceptor) {
|
||||
this.typeResolutionInterceptor = typeResolutionInterceptor;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setMissingSupertypesResolver(@NotNull MissingSupertypesResolver missingSupertypesResolver) {
|
||||
this.missingSupertypesResolver = missingSupertypesResolver;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user