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) {
|
public void runDeclarationCheckers(@NotNull KtDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
|
||||||
DeclarationCheckerContext context = new DeclarationCheckerContext(
|
DeclarationCheckerContext context = new DeclarationCheckerContext(
|
||||||
trace, languageVersionSettings, deprecationResolver, moduleDescriptor, expectActualTracker
|
trace, languageVersionSettings, deprecationResolver, moduleDescriptor, expectActualTracker,
|
||||||
|
missingSupertypesResolver
|
||||||
);
|
);
|
||||||
for (DeclarationChecker checker : declarationCheckers) {
|
for (DeclarationChecker checker : declarationCheckers) {
|
||||||
checker.check(declaration, descriptor, context);
|
checker.check(declaration, descriptor, context);
|
||||||
@@ -291,6 +292,7 @@ public class ModifiersChecker {
|
|||||||
private final ExpectActualTracker expectActualTracker;
|
private final ExpectActualTracker expectActualTracker;
|
||||||
private final DeprecationResolver deprecationResolver;
|
private final DeprecationResolver deprecationResolver;
|
||||||
private final ModuleDescriptor moduleDescriptor;
|
private final ModuleDescriptor moduleDescriptor;
|
||||||
|
private final MissingSupertypesResolver missingSupertypesResolver;
|
||||||
|
|
||||||
public ModifiersChecker(
|
public ModifiersChecker(
|
||||||
@NotNull AnnotationChecker annotationChecker,
|
@NotNull AnnotationChecker annotationChecker,
|
||||||
@@ -298,7 +300,8 @@ public class ModifiersChecker {
|
|||||||
@NotNull LanguageVersionSettings languageVersionSettings,
|
@NotNull LanguageVersionSettings languageVersionSettings,
|
||||||
@NotNull ExpectActualTracker expectActualTracker,
|
@NotNull ExpectActualTracker expectActualTracker,
|
||||||
@NotNull DeprecationResolver deprecationResolver,
|
@NotNull DeprecationResolver deprecationResolver,
|
||||||
@NotNull ModuleDescriptor moduleDescriptor
|
@NotNull ModuleDescriptor moduleDescriptor,
|
||||||
|
@NotNull MissingSupertypesResolver missingSupertypesResolver
|
||||||
) {
|
) {
|
||||||
this.annotationChecker = annotationChecker;
|
this.annotationChecker = annotationChecker;
|
||||||
this.declarationCheckers = declarationCheckers;
|
this.declarationCheckers = declarationCheckers;
|
||||||
@@ -306,6 +309,7 @@ public class ModifiersChecker {
|
|||||||
this.expectActualTracker = expectActualTracker;
|
this.expectActualTracker = expectActualTracker;
|
||||||
this.deprecationResolver = deprecationResolver;
|
this.deprecationResolver = deprecationResolver;
|
||||||
this.moduleDescriptor = moduleDescriptor;
|
this.moduleDescriptor = moduleDescriptor;
|
||||||
|
this.missingSupertypesResolver = missingSupertypesResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ class CallCompleter(
|
|||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
private val deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
private val effectSystem: EffectSystem,
|
private val effectSystem: EffectSystem,
|
||||||
private val dataFlowValueFactory: DataFlowValueFactory
|
private val dataFlowValueFactory: DataFlowValueFactory,
|
||||||
|
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||||
) {
|
) {
|
||||||
fun <D : CallableDescriptor> completeCall(
|
fun <D : CallableDescriptor> completeCall(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
@@ -78,7 +79,7 @@ class CallCompleter(
|
|||||||
|
|
||||||
if (context.trace.wantsDiagnostics()) {
|
if (context.trace.wantsDiagnostics()) {
|
||||||
if (resolvedCall == null) {
|
if (resolvedCall == null) {
|
||||||
checkMissingSupertypes(context, moduleDescriptor)
|
checkMissingSupertypes(context, missingSupertypesResolver)
|
||||||
} else {
|
} else {
|
||||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||||
resolvedCall.variableCall.call.calleeExpression
|
resolvedCall.variableCall.call.calleeExpression
|
||||||
@@ -88,7 +89,7 @@ class CallCompleter(
|
|||||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||||
else resolvedCall.call.callElement
|
else resolvedCall.call.callElement
|
||||||
|
|
||||||
val callCheckerContext = CallCheckerContext(context, deprecationResolver, moduleDescriptor)
|
val callCheckerContext = CallCheckerContext(context, deprecationResolver, moduleDescriptor, missingSupertypesResolver)
|
||||||
for (callChecker in callCheckers) {
|
for (callChecker in callCheckers) {
|
||||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||||
|
|
||||||
@@ -105,12 +106,15 @@ class CallCompleter(
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkMissingSupertypes(context: BasicCallResolutionContext, moduleDescriptor: ModuleDescriptor) {
|
private fun checkMissingSupertypes(
|
||||||
|
context: BasicCallResolutionContext,
|
||||||
|
missingSupertypesResolver: MissingSupertypesResolver
|
||||||
|
) {
|
||||||
val call = context.call
|
val call = context.call
|
||||||
val explicitReceiver = call.explicitReceiver.safeAs<ReceiverValue>()
|
val explicitReceiver = call.explicitReceiver.safeAs<ReceiverValue>() ?: return
|
||||||
?: return
|
|
||||||
MissingDependencySupertypeChecker.checkSupertypes(
|
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.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
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.context.ResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
@@ -42,6 +43,7 @@ class CallCheckerContext @JvmOverloads constructor(
|
|||||||
val resolutionContext: ResolutionContext<*>,
|
val resolutionContext: ResolutionContext<*>,
|
||||||
override val deprecationResolver: DeprecationResolver,
|
override val deprecationResolver: DeprecationResolver,
|
||||||
override val moduleDescriptor: ModuleDescriptor,
|
override val moduleDescriptor: ModuleDescriptor,
|
||||||
|
val missingSupertypesResolver: MissingSupertypesResolver,
|
||||||
override val trace: BindingTrace = resolutionContext.trace
|
override val trace: BindingTrace = resolutionContext.trace
|
||||||
) : CheckerContext {
|
) : CheckerContext {
|
||||||
val scope: LexicalScope
|
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.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
|
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.CompletedCallInfo
|
import org.jetbrains.kotlin.resolve.calls.components.CompletedCallInfo
|
||||||
@@ -49,7 +50,8 @@ class CoroutineInferenceSession(
|
|||||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||||
private val deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
private val typeApproximator: TypeApproximator
|
private val typeApproximator: TypeApproximator,
|
||||||
|
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||||
) : ManyCandidatesResolver<CallableDescriptor>(
|
) : ManyCandidatesResolver<CallableDescriptor>(
|
||||||
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns
|
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns
|
||||||
) {
|
) {
|
||||||
@@ -222,7 +224,7 @@ class CoroutineInferenceSession(
|
|||||||
return ResolvedAtomCompleter(
|
return ResolvedAtomCompleter(
|
||||||
resultSubstitutor, context, kotlinToResolvedCallTransformer,
|
resultSubstitutor, context, kotlinToResolvedCallTransformer,
|
||||||
expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, builtIns,
|
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.deprecation.DeprecationResolver
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
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.*
|
||||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||||
@@ -75,7 +73,8 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||||
val deprecationResolver: DeprecationResolver,
|
val deprecationResolver: DeprecationResolver,
|
||||||
val moduleDescriptor: ModuleDescriptor,
|
val moduleDescriptor: ModuleDescriptor,
|
||||||
val topLevelCallContext: BasicCallResolutionContext?
|
val topLevelCallContext: BasicCallResolutionContext?,
|
||||||
|
val missingSupertypesResolver: MissingSupertypesResolver
|
||||||
) : KotlinResolutionCallbacks {
|
) : KotlinResolutionCallbacks {
|
||||||
class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) {
|
class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) {
|
||||||
val returnStatements = ArrayList<Pair<KtReturnExpression, LambdaContextInfo?>>()
|
val returnStatements = ArrayList<Pair<KtReturnExpression, LambdaContextInfo?>>()
|
||||||
@@ -161,7 +160,8 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter,
|
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter,
|
||||||
callComponents, builtIns, topLevelCallContext, stubsForPostponedVariables, trace,
|
callComponents, builtIns, topLevelCallContext, stubsForPostponedVariables, trace,
|
||||||
kotlinToResolvedCallTransformer, expressionTypingServices, argumentTypeResolver,
|
kotlinToResolvedCallTransformer, expressionTypingServices, argumentTypeResolver,
|
||||||
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, typeApproximator
|
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, typeApproximator,
|
||||||
|
missingSupertypesResolver
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|||||||
+3
-2
@@ -72,7 +72,8 @@ class KotlinToResolvedCallTransformer(
|
|||||||
private val builtIns: KotlinBuiltIns,
|
private val builtIns: KotlinBuiltIns,
|
||||||
private val typeSystemContext: TypeSystemInferenceExtensionContextDelegate,
|
private val typeSystemContext: TypeSystemInferenceExtensionContextDelegate,
|
||||||
private val smartCastManager: SmartCastManager,
|
private val smartCastManager: SmartCastManager,
|
||||||
private val typeApproximator: TypeApproximator
|
private val typeApproximator: TypeApproximator,
|
||||||
|
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC
|
private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC
|
||||||
@@ -134,7 +135,7 @@ class KotlinToResolvedCallTransformer(
|
|||||||
val ktPrimitiveCompleter = ResolvedAtomCompleter(
|
val ktPrimitiveCompleter = ResolvedAtomCompleter(
|
||||||
resultSubstitutor, context, this, expressionTypingServices, argumentTypeResolver,
|
resultSubstitutor, context, this, expressionTypingServices, argumentTypeResolver,
|
||||||
doubleColonExpressionResolver, builtIns, deprecationResolver, moduleDescriptor, dataFlowValueFactory,
|
doubleColonExpressionResolver, builtIns, deprecationResolver, moduleDescriptor, dataFlowValueFactory,
|
||||||
typeApproximator
|
typeApproximator, missingSupertypesResolver
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!ErrorUtils.isError(candidate.candidateDescriptor)) {
|
if (!ErrorUtils.isError(candidate.candidateDescriptor)) {
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ class PSICallResolver(
|
|||||||
private val deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
private val callableReferenceResolver: CallableReferenceResolver,
|
private val callableReferenceResolver: CallableReferenceResolver,
|
||||||
private val candidateInterceptor: CandidateInterceptor
|
private val candidateInterceptor: CandidateInterceptor,
|
||||||
|
private val missingSupertypesResolver: MissingSupertypesResolver
|
||||||
) {
|
) {
|
||||||
private val givenCandidatesName = Name.special("<given candidates>")
|
private val givenCandidatesName = Name.special("<given candidates>")
|
||||||
|
|
||||||
@@ -182,7 +183,7 @@ class PSICallResolver(
|
|||||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
||||||
dataFlowValueFactory, inferenceSession, constantExpressionEvaluator, typeResolver,
|
dataFlowValueFactory, inferenceSession, constantExpressionEvaluator, typeResolver,
|
||||||
this, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents,
|
this, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents,
|
||||||
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, context
|
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, context, missingSupertypesResolver
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
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.psi.KtNamedFunction
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
|
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||||
@@ -49,9 +50,12 @@ class ResolvedAtomCompleter(
|
|||||||
private val deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
private val dataFlowValueFactory: DataFlowValueFactory,
|
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 val topLevelTrace = topLevelCallCheckerContext.trace
|
||||||
|
|
||||||
private fun complete(resolvedAtom: ResolvedAtom) {
|
private fun complete(resolvedAtom: ResolvedAtom) {
|
||||||
@@ -90,7 +94,7 @@ class ResolvedAtomCompleter(
|
|||||||
val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall
|
val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall
|
||||||
if (ErrorUtils.isError(resolvedCall.candidateDescriptor)) {
|
if (ErrorUtils.isError(resolvedCall.candidateDescriptor)) {
|
||||||
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, topLevelTrace, lastCall as NewResolvedCallImpl<*>)
|
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, topLevelTrace, lastCall as NewResolvedCallImpl<*>)
|
||||||
checkMissingReceiverSupertypes(resolvedCall, moduleDescriptor, topLevelTrace)
|
checkMissingReceiverSupertypes(resolvedCall, missingSupertypesResolver, topLevelTrace)
|
||||||
return resolvedCall
|
return resolvedCall
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +105,8 @@ class ResolvedAtomCompleter(
|
|||||||
CallCheckerContext(
|
CallCheckerContext(
|
||||||
resolutionContextForPartialCall.replaceBindingTrace(topLevelTrace),
|
resolutionContextForPartialCall.replaceBindingTrace(topLevelTrace),
|
||||||
deprecationResolver,
|
deprecationResolver,
|
||||||
moduleDescriptor
|
moduleDescriptor,
|
||||||
|
missingSupertypesResolver
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
topLevelCallCheckerContext
|
topLevelCallCheckerContext
|
||||||
@@ -119,7 +124,7 @@ class ResolvedAtomCompleter(
|
|||||||
|
|
||||||
private fun checkMissingReceiverSupertypes(
|
private fun checkMissingReceiverSupertypes(
|
||||||
resolvedCall: ResolvedCall<CallableDescriptor>,
|
resolvedCall: ResolvedCall<CallableDescriptor>,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
missingSupertypesResolver: MissingSupertypesResolver,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
val receiverValue = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver
|
val receiverValue = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver
|
||||||
@@ -128,7 +133,7 @@ class ResolvedAtomCompleter(
|
|||||||
receiverType,
|
receiverType,
|
||||||
resolvedCall.call.callElement,
|
resolvedCall.call.callElement,
|
||||||
trace,
|
trace,
|
||||||
moduleDescriptor
|
missingSupertypesResolver
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
|||||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
|
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
|
||||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||||
|
|
||||||
interface DeclarationChecker {
|
interface DeclarationChecker {
|
||||||
@@ -33,5 +34,6 @@ class DeclarationCheckerContext(
|
|||||||
override val languageVersionSettings: LanguageVersionSettings,
|
override val languageVersionSettings: LanguageVersionSettings,
|
||||||
override val deprecationResolver: DeprecationResolver,
|
override val deprecationResolver: DeprecationResolver,
|
||||||
override val moduleDescriptor: ModuleDescriptor,
|
override val moduleDescriptor: ModuleDescriptor,
|
||||||
val expectActualTracker: ExpectActualTracker
|
val expectActualTracker: ExpectActualTracker,
|
||||||
|
val missingSupertypesResolver: MissingSupertypesResolver
|
||||||
) : CheckerContext
|
) : CheckerContext
|
||||||
|
|||||||
+37
-42
@@ -12,29 +12,27 @@ import org.jetbrains.kotlin.psi.KtDeclaration
|
|||||||
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
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.CallChecker
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
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.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
|
||||||
|
|
||||||
object MissingDependencySupertypeChecker {
|
object MissingDependencySupertypeChecker {
|
||||||
object ForDeclarations : DeclarationChecker {
|
object ForDeclarations : DeclarationChecker {
|
||||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||||
val trace = context.trace
|
val trace = context.trace
|
||||||
val module = context.moduleDescriptor
|
|
||||||
|
|
||||||
if (descriptor is ClassDescriptor) {
|
if (descriptor is ClassDescriptor) {
|
||||||
checkSupertypes(descriptor.defaultType, declaration, trace, module)
|
checkSupertypes(descriptor, declaration, trace, context.missingSupertypesResolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (declaration is KtTypeParameterListOwner) {
|
if (declaration is KtTypeParameterListOwner) {
|
||||||
for (ktTypeParameter in declaration.typeParameters) {
|
for (ktTypeParameter in declaration.typeParameters) {
|
||||||
val typeParameterDescriptor = trace.bindingContext.get(BindingContext.TYPE_PARAMETER, ktTypeParameter) ?: continue
|
val typeParameterDescriptor = trace.bindingContext.get(BindingContext.TYPE_PARAMETER, ktTypeParameter) ?: continue
|
||||||
for (upperBound in typeParameterDescriptor.upperBounds) {
|
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) {
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
val descriptor = resolvedCall.resultingDescriptor
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
|
||||||
// Constructor call leads to resolution of supertypes of enclosing class if it's an inner class constructor
|
val errorReported = checkSupertypes(
|
||||||
checkHierarchy(descriptor.dispatchReceiverParameter?.declaration, reportOn, context)
|
descriptor.dispatchReceiverParameter?.declaration, reportOn,
|
||||||
// The constructed class' own supertypes are not resolved after constructor call,
|
context.trace, context.missingSupertypesResolver
|
||||||
// so its containing declaration should not be checked.
|
)
|
||||||
if (descriptor !is ConstructorDescriptor) {
|
if (descriptor !is ConstructorDescriptor && !errorReported) {
|
||||||
checkHierarchy(descriptor.containingDeclaration, reportOn, context)
|
// The constructed class' own supertypes are not resolved after constructor call,
|
||||||
checkHierarchy(descriptor.extensionReceiverParameter?.declaration, reportOn, context)
|
// 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
|
private val ReceiverParameterDescriptor.declaration
|
||||||
get() = value.type.constructor.declarationDescriptor
|
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(
|
fun checkSupertypes(
|
||||||
classifierType: KotlinType,
|
classifierType: KotlinType,
|
||||||
reportOn: PsiElement,
|
reportOn: PsiElement,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
moduleDescriptor: ModuleDescriptor
|
missingSupertypesResolver: MissingSupertypesResolver
|
||||||
) {
|
) = checkSupertypes(classifierType.constructor.declarationDescriptor, reportOn, trace, missingSupertypesResolver)
|
||||||
val classifierDescriptor = classifierType.constructor.declarationDescriptor ?: return
|
|
||||||
|
|
||||||
for (supertype in classifierType.supertypes()) {
|
// true for reported error
|
||||||
val supertypeDeclaration = supertype.constructor.declarationDescriptor
|
fun checkSupertypes(
|
||||||
|
declaration: DeclarationDescriptor?,
|
||||||
|
reportOn: PsiElement,
|
||||||
|
trace: BindingTrace,
|
||||||
|
missingSupertypesResolver: MissingSupertypesResolver
|
||||||
|
): Boolean {
|
||||||
|
if (declaration !is ClassifierDescriptor)
|
||||||
|
return false
|
||||||
|
|
||||||
/*
|
val missingSupertypes = missingSupertypesResolver.getMissingSuperClassifiers(declaration)
|
||||||
* TODO: expects are not checked, because findClassAcrossModuleDependencies does not work with actualization via type alias
|
for (missingClassifier in missingSupertypes) {
|
||||||
* Type parameters are skipped here, bounds of type parameters are checked in declaration checker separately
|
trace.report(
|
||||||
* Local declarations are ignored for optimization
|
Errors.MISSING_DEPENDENCY_SUPERCLASS.on(
|
||||||
*/
|
reportOn,
|
||||||
if (supertypeDeclaration !is ClassDescriptor || supertypeDeclaration.isExpect) continue
|
missingClassifier.fqNameSafe,
|
||||||
if (supertypeDeclaration.visibility == Visibilities.LOCAL) continue
|
declaration.fqNameSafe
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
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
|
// 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
|
// Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace
|
||||||
CallCheckerContext callCheckerContext =
|
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) {
|
for (CallChecker checker : components.callCheckers) {
|
||||||
checker.check(resolvedCall, expression, callCheckerContext);
|
checker.check(resolvedCall, expression, callCheckerContext);
|
||||||
}
|
}
|
||||||
@@ -1038,7 +1044,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private CallCheckerContext createCallCheckerContext(@NotNull ExpressionTypingContext context) {
|
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
|
@Override
|
||||||
|
|||||||
+6
@@ -66,6 +66,7 @@ public class ExpressionTypingComponents {
|
|||||||
/*package*/ DataFlowValueFactory dataFlowValueFactory;
|
/*package*/ DataFlowValueFactory dataFlowValueFactory;
|
||||||
/*package*/ NewKotlinTypeChecker kotlinTypeChecker;
|
/*package*/ NewKotlinTypeChecker kotlinTypeChecker;
|
||||||
/*package*/ TypeResolutionInterceptor typeResolutionInterceptor;
|
/*package*/ TypeResolutionInterceptor typeResolutionInterceptor;
|
||||||
|
/*package*/ MissingSupertypesResolver missingSupertypesResolver;
|
||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -252,4 +253,9 @@ public class ExpressionTypingComponents {
|
|||||||
public void setTypeResolutionInterceptor(@NotNull TypeResolutionInterceptor typeResolutionInterceptor) {
|
public void setTypeResolutionInterceptor(@NotNull TypeResolutionInterceptor typeResolutionInterceptor) {
|
||||||
this.typeResolutionInterceptor = typeResolutionInterceptor;
|
this.typeResolutionInterceptor = typeResolutionInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public void setMissingSupertypesResolver(@NotNull MissingSupertypesResolver missingSupertypesResolver) {
|
||||||
|
this.missingSupertypesResolver = missingSupertypesResolver;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user