Memoize deprecations-related computations
It might be helpful for performance as these methods are called for each resolution candidate and in the same time they scan the whole overridden tree of a callable member
This commit is contained in:
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.codegen.serialization.JvmStringTable;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.JvmTarget;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
@@ -43,7 +42,6 @@ import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.DeprecationUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||
@@ -204,7 +202,7 @@ public class AsmUtil {
|
||||
}
|
||||
|
||||
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) {
|
||||
int flags = getCommonCallableFlags(functionDescriptor);
|
||||
int flags = getCommonCallableFlags(functionDescriptor, state);
|
||||
|
||||
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
|
||||
if (flagAnnotation.hasAnnotation(functionDescriptor.getOriginal())) {
|
||||
@@ -245,17 +243,11 @@ public class AsmUtil {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) {
|
||||
public static int getCommonCallableFlags(FunctionDescriptor functionDescriptor, @NotNull GenerationState state) {
|
||||
int flags = getVisibilityAccessFlag(functionDescriptor);
|
||||
flags |= getVarargsFlag(functionDescriptor);
|
||||
flags |= getDeprecatedAccessFlag(functionDescriptor);
|
||||
if (DeprecationUtilKt.isDeprecatedHidden(functionDescriptor, LanguageVersionSettingsImpl.DEFAULT)
|
||||
|| functionDescriptor instanceof PropertyAccessorDescriptor
|
||||
&& DeprecationUtilKt.isDeprecatedHidden(
|
||||
((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty(),
|
||||
LanguageVersionSettingsImpl.DEFAULT
|
||||
)
|
||||
) {
|
||||
if (state.getDeprecationProvider().isDeprecatedHidden(functionDescriptor)) {
|
||||
flags |= ACC_SYNTHETIC;
|
||||
}
|
||||
return flags;
|
||||
|
||||
+1
-2
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.psi.KtPureElement
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOriginFromPure
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
@@ -129,7 +128,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
) {
|
||||
val typeMapper = state.typeMapper
|
||||
val isStatic = AsmUtil.isStaticMethod(contextKind, functionDescriptor)
|
||||
val baseMethodFlags = AsmUtil.getCommonCallableFlags(functionDescriptor) and Opcodes.ACC_VARARGS.inv()
|
||||
val baseMethodFlags = AsmUtil.getCommonCallableFlags(functionDescriptor, state) and Opcodes.ACC_VARARGS.inv()
|
||||
val remainingParameters = getRemainingParameters(functionDescriptor.original, substituteCount)
|
||||
val flags =
|
||||
baseMethodFlags or
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import java.io.File
|
||||
|
||||
class GenerationState @JvmOverloads constructor(
|
||||
@@ -95,6 +96,8 @@ class GenerationState @JvmOverloads constructor(
|
||||
val deserializationConfiguration: DeserializationConfiguration =
|
||||
CompilerDeserializationConfiguration(configuration.languageVersionSettings)
|
||||
|
||||
val deprecationProvider = DeprecationResolver(LockBasedStorageManager.NO_LOCKS, configuration.languageVersionSettings)
|
||||
|
||||
init {
|
||||
val icComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
||||
if (icComponents != null) {
|
||||
|
||||
+3
-1
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
@@ -102,7 +103,8 @@ class JvmModuleAccessibilityChecker(project: Project) : CallChecker {
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
val virtualFile = element.containingFile.virtualFile
|
||||
when (targetDescriptor) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.synthetic
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.components.SamConversionResolver
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
@@ -26,10 +27,11 @@ class JavaSyntheticScopes(
|
||||
storageManager: StorageManager,
|
||||
lookupTracker: LookupTracker,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
samConventionResolver: SamConversionResolver
|
||||
samConventionResolver: SamConversionResolver,
|
||||
deprecationResolver: DeprecationResolver
|
||||
): SyntheticScopes {
|
||||
override val scopes = listOf(
|
||||
JavaSyntheticPropertiesScope(storageManager, lookupTracker),
|
||||
SamAdapterFunctionsScope(storageManager, languageVersionSettings, samConventionResolver)
|
||||
SamAdapterFunctionsScope(storageManager, languageVersionSettings, samConventionResolver, deprecationResolver)
|
||||
)
|
||||
}
|
||||
|
||||
+4
-3
@@ -34,8 +34,8 @@ import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.ResolutionScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScope
|
||||
@@ -51,7 +51,8 @@ interface SamAdapterExtensionFunctionDescriptor : FunctionDescriptor, SyntheticM
|
||||
class SamAdapterFunctionsScope(
|
||||
storageManager: StorageManager,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val samResolver: SamConversionResolver
|
||||
private val samResolver: SamConversionResolver,
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
) : SyntheticScope {
|
||||
private val extensionForFunction = storageManager.createMemoizedFunctionWithNullableValues<FunctionDescriptor, FunctionDescriptor> { function ->
|
||||
extensionForFunctionNotCached(function)
|
||||
@@ -83,7 +84,7 @@ class SamAdapterFunctionsScope(
|
||||
if (!function.hasJavaOriginInHierarchy()) return null //TODO: should we go into base at all?
|
||||
if (!SingleAbstractMethodUtils.isSamAdapterNecessary(function)) return null
|
||||
if (function.returnType == null) return null
|
||||
if (function.isHiddenInResolution(languageVersionSettings)) return null
|
||||
if (deprecationResolver.isHiddenInResolution(function)) return null
|
||||
return MyFunctionDescriptor.create(function, samResolver)
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class LazyTopDownAnalyzer(
|
||||
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
|
||||
) {
|
||||
fun analyzeDeclarations(
|
||||
@@ -215,7 +216,7 @@ class LazyTopDownAnalyzer(
|
||||
|
||||
resolveImportsInAllFiles(c)
|
||||
|
||||
ClassifierUsageChecker.check(declarations, trace, languageVersionSettings, classifierUsageCheckers)
|
||||
ClassifierUsageChecker.check(declarations, trace, languageVersionSettings, deprecationResolver, classifierUsageCheckers)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ class CallCompleter(
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val callCheckers: Iterable<CallChecker>,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
fun <D : CallableDescriptor> completeCall(
|
||||
context: BasicCallResolutionContext,
|
||||
@@ -91,7 +92,7 @@ class CallCompleter(
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else resolvedCall.call.callElement
|
||||
|
||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings)
|
||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings, deprecationResolver)
|
||||
for (callChecker in callCheckers) {
|
||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
@@ -37,7 +38,8 @@ interface CallChecker {
|
||||
class CallCheckerContext(
|
||||
val resolutionContext: ResolutionContext<*>,
|
||||
val trace: BindingTrace,
|
||||
val languageVersionSettings: LanguageVersionSettings
|
||||
val languageVersionSettings: LanguageVersionSettings,
|
||||
val deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
val scope: LexicalScope
|
||||
get() = resolutionContext.scope
|
||||
@@ -48,7 +50,11 @@ class CallCheckerContext(
|
||||
val isAnnotationContext: Boolean
|
||||
get() = resolutionContext.isAnnotationContext
|
||||
|
||||
constructor(c: ResolutionContext<*>, languageVersionSettings: LanguageVersionSettings) : this(c, c.trace, languageVersionSettings)
|
||||
constructor(
|
||||
c: ResolutionContext<*>,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) : this(c, c.trace, languageVersionSettings, deprecationResolver)
|
||||
}
|
||||
|
||||
// Use this utility to avoid premature computation of deferred return type of a resolved callable descriptor.
|
||||
|
||||
+8
-6
@@ -29,27 +29,29 @@ import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtUnaryExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.createDeprecationDiagnostic
|
||||
import org.jetbrains.kotlin.resolve.getDeprecations
|
||||
|
||||
object DeprecatedCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
check(resolvedCall.resultingDescriptor, context.trace, reportOn, context.languageVersionSettings)
|
||||
check(resolvedCall.resultingDescriptor, context.trace, reportOn, context.languageVersionSettings, context.deprecationResolver)
|
||||
}
|
||||
|
||||
private fun check(
|
||||
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement, languageVersionSettings: LanguageVersionSettings
|
||||
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
// Objects will be checked by DeprecatedClassifierUsageChecker
|
||||
if (targetDescriptor is FakeCallableDescriptorForObject) return
|
||||
|
||||
val deprecations = targetDescriptor.getDeprecations(languageVersionSettings).toMutableList()
|
||||
val deprecations = deprecationResolver.getDeprecations(targetDescriptor).toMutableList()
|
||||
|
||||
// avoid duplicating diagnostic when deprecation for property effectively deprecates setter
|
||||
if (targetDescriptor is PropertySetterDescriptor) {
|
||||
deprecations -= targetDescriptor.correspondingProperty.getDeprecations(languageVersionSettings)
|
||||
deprecations -= deprecationResolver.getDeprecations(targetDescriptor.correspondingProperty)
|
||||
}
|
||||
|
||||
if (deprecations.isNotEmpty()) {
|
||||
@@ -58,7 +60,7 @@ object DeprecatedCallChecker : CallChecker {
|
||||
}
|
||||
}
|
||||
else if (targetDescriptor is PropertyDescriptor && shouldCheckPropertyGetter(element)) {
|
||||
targetDescriptor.getter?.let { check(it, trace, element, languageVersionSettings) }
|
||||
targetDescriptor.getter?.let { check(it, trace, element, languageVersionSettings, deprecationResolver) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -16,10 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtSuperExpression
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
||||
@@ -28,11 +28,10 @@ import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionStatelessCa
|
||||
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinResolutionStatelessCallbacksImpl(
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
) : KotlinResolutionStatelessCallbacks {
|
||||
override fun isDescriptorFromSource(descriptor: CallableDescriptor) =
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor) != null
|
||||
@@ -48,7 +47,7 @@ class KotlinResolutionStatelessCallbacksImpl(
|
||||
kotlinCall is PSIKotlinCallImpl && isSuperOrDelegatingConstructorCall(kotlinCall.psiCall)
|
||||
|
||||
override fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall) =
|
||||
descriptor.isHiddenInResolution(languageVersionSettings, isSuperOrDelegatingConstructorCall(kotlinCall))
|
||||
deprecationResolver.isHiddenInResolution(descriptor, isSuperOrDelegatingConstructorCall(kotlinCall))
|
||||
|
||||
override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean =
|
||||
receiver?.psiExpression is KtSuperExpression
|
||||
@@ -58,4 +57,4 @@ class KotlinResolutionStatelessCallbacksImpl(
|
||||
|
||||
override fun getVariableCandidateIfInvoke(functionCall: KotlinCall) =
|
||||
functionCall.safeAs<PSIKotlinCallForInvoke>()?.variableCall
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -66,10 +66,11 @@ class KotlinToResolvedCallTransformer(
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
private val additionalDiagnosticReporter: AdditionalDiagnosticReporter
|
||||
) {
|
||||
) {
|
||||
|
||||
fun <D : CallableDescriptor> onlyTransform(
|
||||
resolvedCallAtom: ResolvedCallAtom
|
||||
@@ -90,7 +91,7 @@ class KotlinToResolvedCallTransformer(
|
||||
val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor()
|
||||
val ktPrimitiveCompleter = ResolvedAtomCompleter(resultSubstitutor, context.trace, context, this,
|
||||
expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver,
|
||||
languageFeatureSettings)
|
||||
languageFeatureSettings, deprecationResolver)
|
||||
|
||||
for (subKtPrimitive in candidate.subResolvedAtoms) {
|
||||
ktPrimitiveCompleter.completeAll(subKtPrimitive)
|
||||
|
||||
+7
-4
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.CandidateResolver
|
||||
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallKind
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
|
||||
@@ -45,7 +47,6 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
@@ -66,7 +67,8 @@ class NewResolutionOldInference(
|
||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||
private val syntheticScopes: SyntheticScopes,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
sealed class ResolutionKind<D : CallableDescriptor>(val kotlinCallKind: KotlinCallKind = KotlinCallKind.UNSUPPORTED) {
|
||||
abstract internal fun createTowerProcessor(
|
||||
@@ -200,7 +202,7 @@ class NewResolutionOldInference(
|
||||
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
||||
val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments)
|
||||
|
||||
if (candidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
|
||||
if (deprecationResolver.isHiddenInResolution(candidate.descriptor, basicCallContext.isSuperCall)) {
|
||||
return@map MyCandidate(listOf(HiddenDescriptor), resolvedCall)
|
||||
}
|
||||
|
||||
@@ -357,7 +359,8 @@ class NewResolutionOldInference(
|
||||
}
|
||||
}
|
||||
|
||||
if (towerCandidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
|
||||
|
||||
if (deprecationResolver.isHiddenInResolution(towerCandidate.descriptor, basicCallContext.isSuperCall)) {
|
||||
return MyCandidate(listOf(HiddenDescriptor), candidateCall)
|
||||
}
|
||||
|
||||
|
||||
+9
-4
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
@@ -37,7 +38,10 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.IndexedParametersSubstitution
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
@@ -51,9 +55,10 @@ class ResolvedAtomCompleter(
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings)
|
||||
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings, deprecationResolver)
|
||||
|
||||
fun completeAndReport(resolvedAtom: ResolvedAtom) {
|
||||
when (resolvedAtom) {
|
||||
@@ -198,4 +203,4 @@ class ResolvedAtomCompleter(
|
||||
|
||||
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
||||
|
||||
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
|
||||
@@ -28,7 +29,8 @@ object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
targetDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings) { version ->
|
||||
trace.report(Errors.API_NOT_AVAILABLE.on(element, version.versionString, languageVersionSettings.apiVersion.versionString))
|
||||
|
||||
+5
-2
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -36,7 +37,8 @@ interface ClassifierUsageChecker {
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
)
|
||||
|
||||
companion object {
|
||||
@@ -44,6 +46,7 @@ interface ClassifierUsageChecker {
|
||||
declarations: Collection<PsiElement>,
|
||||
trace: BindingTrace,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver,
|
||||
checkers: Iterable<ClassifierUsageChecker>
|
||||
) {
|
||||
val visitor = object : KtTreeVisitorVoid() {
|
||||
@@ -71,7 +74,7 @@ interface ClassifierUsageChecker {
|
||||
|
||||
private fun runCheckersWithTarget(target: ClassifierDescriptor, expression: KtReferenceExpression) {
|
||||
for (checker in checkers) {
|
||||
checker.check(target, trace, expression, languageVersionSettings)
|
||||
checker.check(target, trace, expression, languageVersionSettings, deprecationResolver)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -21,18 +21,19 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtThisExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.createDeprecationDiagnostic
|
||||
import org.jetbrains.kotlin.resolve.getDeprecations
|
||||
|
||||
class DeprecatedClassifierUsageChecker : ClassifierUsageChecker {
|
||||
override fun check(
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
if (element.parent is KtThisExpression) return
|
||||
for (deprecation in targetDescriptor.getDeprecations(languageVersionSettings)) {
|
||||
for (deprecation in deprecationResolver.getDeprecations(targetDescriptor)) {
|
||||
trace.report(createDeprecationDiagnostic(element, deprecation, languageVersionSettings))
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType
|
||||
@@ -95,7 +96,8 @@ object MissingDependencyClassChecker : CallChecker {
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
diagnosticFor(targetDescriptor, element)?.let(trace::report)
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfo
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
@@ -146,133 +147,6 @@ private fun Deprecation.wrapInTypeAliasExpansion(typeAliasDescriptor: TypeAliasD
|
||||
else -> this
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.getDeprecations(languageVersionSettings: LanguageVersionSettings): List<Deprecation> {
|
||||
val deprecations = this.getOwnDeprecations(languageVersionSettings)
|
||||
if (deprecations.isNotEmpty()) {
|
||||
return deprecations
|
||||
}
|
||||
|
||||
if (this is CallableMemberDescriptor) {
|
||||
return listOfNotNull(deprecationByOverridden(this, languageVersionSettings))
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun KotlinType.deprecationsByConstituentTypes(languageVersionSettings: LanguageVersionSettings): List<Deprecation> =
|
||||
SmartList<Deprecation>().also { deprecations ->
|
||||
TypeUtils.contains(this) { type ->
|
||||
type.constructor.declarationDescriptor?.run {
|
||||
deprecations.addAll(getDeprecations(languageVersionSettings))
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun deprecationByOverridden(root: CallableMemberDescriptor, languageVersionSettings: LanguageVersionSettings): Deprecation? {
|
||||
val visited = HashSet<CallableMemberDescriptor>()
|
||||
val deprecations = LinkedHashSet<Deprecation>()
|
||||
var hasUndeprecatedOverridden = false
|
||||
|
||||
fun traverse(node: CallableMemberDescriptor) {
|
||||
if (node in visited) return
|
||||
|
||||
visited.add(node)
|
||||
|
||||
val deprecationsByAnnotation = node.getOwnDeprecations(languageVersionSettings)
|
||||
val overriddenDescriptors = node.original.overriddenDescriptors
|
||||
when {
|
||||
deprecationsByAnnotation.isNotEmpty() -> {
|
||||
deprecations.addAll(deprecationsByAnnotation)
|
||||
}
|
||||
overriddenDescriptors.isEmpty() -> {
|
||||
hasUndeprecatedOverridden = true
|
||||
return
|
||||
}
|
||||
else -> {
|
||||
overriddenDescriptors.forEach(::traverse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(root)
|
||||
|
||||
if (hasUndeprecatedOverridden || deprecations.isEmpty()) return null
|
||||
|
||||
return DeprecatedByOverridden(deprecations)
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.getOwnDeprecations(languageVersionSettings: LanguageVersionSettings): List<Deprecation> {
|
||||
// The problem is that declaration `mod` in built-ins has @Deprecated annotation but actually it was deprecated only in version 1.1
|
||||
if (this is FunctionDescriptor && this.isOperatorMod() && KotlinBuiltIns.isUnderKotlinPackage(this)) {
|
||||
if (!shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
val result = SmartList<Deprecation>()
|
||||
|
||||
fun addDeprecationIfPresent(target: DeclarationDescriptor) {
|
||||
val annotation = target.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated)
|
||||
?: target.annotations.findAnnotation(JAVA_DEPRECATED)
|
||||
if (annotation != null) {
|
||||
val deprecatedByAnnotation = DeprecatedByAnnotation(annotation, target)
|
||||
val deprecation = when (target) {
|
||||
is TypeAliasConstructorDescriptor -> DeprecatedTypealiasByAnnotation(target.typeAliasDescriptor, deprecatedByAnnotation)
|
||||
else -> deprecatedByAnnotation
|
||||
}
|
||||
result.add(deprecation)
|
||||
}
|
||||
|
||||
val sinceKotlinInfo =
|
||||
(target as? DeserializedMemberDescriptor)?.sinceKotlinInfo
|
||||
?: (target as? DeserializedClassDescriptor)?.sinceKotlinInfo
|
||||
if (sinceKotlinInfo != null) {
|
||||
// We're using ApiVersion because it's convenient to compare versions, "-api-version" is not involved in any way
|
||||
// TODO: usage of ApiVersion is confusing here, refactor
|
||||
if (ApiVersion.createBySinceKotlinInfo(sinceKotlinInfo) >
|
||||
ApiVersion.createByLanguageVersion(languageVersionSettings.languageVersion)) {
|
||||
result.add(DeprecatedBySinceKotlinInfo(sinceKotlinInfo, target))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addUseSiteTargetedDeprecationIfPresent(annotatedDescriptor: DeclarationDescriptor, useSiteTarget: AnnotationUseSiteTarget?) {
|
||||
if (useSiteTarget != null) {
|
||||
val annotation = Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, KotlinBuiltIns.FQ_NAMES.deprecated)
|
||||
?: Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, JAVA_DEPRECATED)
|
||||
if (annotation != null) {
|
||||
result.add(DeprecatedByAnnotation(annotation, this))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDeprecationIfPresent(this)
|
||||
addUseSiteTargetedDeprecationIfPresent(this, AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this))
|
||||
|
||||
when (this) {
|
||||
is TypeAliasDescriptor -> {
|
||||
expandedType.deprecationsByConstituentTypes(languageVersionSettings).mapTo(result) { it.wrapInTypeAliasExpansion(this) }
|
||||
}
|
||||
is DescriptorDerivedFromTypeAlias -> {
|
||||
result.addAll(typeAliasDescriptor.getOwnDeprecations(languageVersionSettings))
|
||||
}
|
||||
is ConstructorDescriptor -> {
|
||||
addDeprecationIfPresent(containingDeclaration)
|
||||
}
|
||||
is PropertyAccessorDescriptor -> {
|
||||
addDeprecationIfPresent(correspondingProperty)
|
||||
|
||||
addUseSiteTargetedDeprecationIfPresent(
|
||||
correspondingProperty,
|
||||
if (this is PropertyGetterDescriptor) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return result.distinct()
|
||||
}
|
||||
|
||||
internal fun createDeprecationDiagnostic(
|
||||
element: PsiElement, deprecation: Deprecation, languageVersionSettings: LanguageVersionSettings
|
||||
): Diagnostic {
|
||||
@@ -310,17 +184,157 @@ enum class DeprecationLevelValue {
|
||||
WARNING, ERROR, HIDDEN
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.isDeprecatedHidden(languageVersionSettings: LanguageVersionSettings): Boolean =
|
||||
getDeprecations(languageVersionSettings).any { it.deprecationLevel == HIDDEN }
|
||||
|
||||
@JvmOverloads
|
||||
fun DeclarationDescriptor.isHiddenInResolution(languageVersionSettings: LanguageVersionSettings, isSuperCall: Boolean = false): Boolean {
|
||||
if (this is FunctionDescriptor) {
|
||||
if (isHiddenToOvercomeSignatureClash) return true
|
||||
if (isHiddenForResolutionEverywhereBesideSupercalls && !isSuperCall) return true
|
||||
class DeprecationResolver(
|
||||
storageManager: StorageManager,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
private val deprecations = storageManager.createMemoizedFunction { descriptor: DeclarationDescriptor ->
|
||||
val deprecations = descriptor.getOwnDeprecations()
|
||||
when {
|
||||
deprecations.isNotEmpty() -> deprecations
|
||||
descriptor is CallableMemberDescriptor -> listOfNotNull(deprecationByOverridden(descriptor))
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkSinceKotlinVersionAccessibility(languageVersionSettings)) return true
|
||||
private val isHiddenBecauseOfKotlinVersionAccessibility = storageManager.createMemoizedFunction { descriptor: DeclarationDescriptor ->
|
||||
descriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings)
|
||||
}
|
||||
|
||||
return isDeprecatedHidden(languageVersionSettings)
|
||||
fun getDeprecations(
|
||||
descriptor: DeclarationDescriptor
|
||||
) = deprecations(descriptor.original)
|
||||
|
||||
|
||||
fun isDeprecatedHidden(descriptor: DeclarationDescriptor): Boolean =
|
||||
getDeprecations(descriptor).any { it.deprecationLevel == HIDDEN }
|
||||
|
||||
@JvmOverloads
|
||||
fun isHiddenInResolution(
|
||||
descriptor: DeclarationDescriptor,
|
||||
isSuperCall: Boolean = false
|
||||
): Boolean {
|
||||
if (descriptor is FunctionDescriptor) {
|
||||
if (descriptor.isHiddenToOvercomeSignatureClash) return true
|
||||
if (descriptor.isHiddenForResolutionEverywhereBesideSupercalls && !isSuperCall) return true
|
||||
}
|
||||
|
||||
if (!isHiddenBecauseOfKotlinVersionAccessibility(descriptor.original)) return true
|
||||
|
||||
return isDeprecatedHidden(descriptor)
|
||||
}
|
||||
|
||||
private fun KotlinType.deprecationsByConstituentTypes(): List<Deprecation> =
|
||||
SmartList<Deprecation>().also { deprecations ->
|
||||
TypeUtils.contains(this) { type ->
|
||||
type.constructor.declarationDescriptor?.let {
|
||||
deprecations.addAll(getDeprecations(it))
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun deprecationByOverridden(root: CallableMemberDescriptor): Deprecation? {
|
||||
val visited = HashSet<CallableMemberDescriptor>()
|
||||
val deprecations = LinkedHashSet<Deprecation>()
|
||||
var hasUndeprecatedOverridden = false
|
||||
|
||||
fun traverse(node: CallableMemberDescriptor) {
|
||||
if (node in visited) return
|
||||
|
||||
visited.add(node)
|
||||
|
||||
val deprecationsByAnnotation = node.getOwnDeprecations()
|
||||
val overriddenDescriptors = node.original.overriddenDescriptors
|
||||
when {
|
||||
deprecationsByAnnotation.isNotEmpty() -> {
|
||||
deprecations.addAll(deprecationsByAnnotation)
|
||||
}
|
||||
overriddenDescriptors.isEmpty() -> {
|
||||
hasUndeprecatedOverridden = true
|
||||
return
|
||||
}
|
||||
else -> {
|
||||
overriddenDescriptors.forEach(::traverse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(root)
|
||||
|
||||
if (hasUndeprecatedOverridden || deprecations.isEmpty()) return null
|
||||
|
||||
return DeprecatedByOverridden(deprecations)
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.getOwnDeprecations(): List<Deprecation> {
|
||||
// The problem is that declaration `mod` in built-ins has @Deprecated annotation but actually it was deprecated only in version 1.1
|
||||
if (this is FunctionDescriptor && this.isOperatorMod() && KotlinBuiltIns.isUnderKotlinPackage(this)) {
|
||||
if (!shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
val result = SmartList<Deprecation>()
|
||||
|
||||
fun addDeprecationIfPresent(target: DeclarationDescriptor) {
|
||||
val annotation = target.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated)
|
||||
?: target.annotations.findAnnotation(JAVA_DEPRECATED)
|
||||
if (annotation != null) {
|
||||
val deprecatedByAnnotation = DeprecatedByAnnotation(annotation, target)
|
||||
val deprecation = when (target) {
|
||||
is TypeAliasConstructorDescriptor -> DeprecatedTypealiasByAnnotation(target.typeAliasDescriptor, deprecatedByAnnotation)
|
||||
else -> deprecatedByAnnotation
|
||||
}
|
||||
result.add(deprecation)
|
||||
}
|
||||
|
||||
val sinceKotlinInfo =
|
||||
(target as? DeserializedMemberDescriptor)?.sinceKotlinInfo
|
||||
?: (target as? DeserializedClassDescriptor)?.sinceKotlinInfo
|
||||
if (sinceKotlinInfo != null) {
|
||||
// We're using ApiVersion because it's convenient to compare versions, "-api-version" is not involved in any way
|
||||
// TODO: usage of ApiVersion is confusing here, refactor
|
||||
if (ApiVersion.createBySinceKotlinInfo(sinceKotlinInfo) >
|
||||
ApiVersion.createByLanguageVersion(languageVersionSettings.languageVersion)) {
|
||||
result.add(DeprecatedBySinceKotlinInfo(sinceKotlinInfo, target))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addUseSiteTargetedDeprecationIfPresent(annotatedDescriptor: DeclarationDescriptor, useSiteTarget: AnnotationUseSiteTarget?) {
|
||||
if (useSiteTarget != null) {
|
||||
val annotation = Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, KotlinBuiltIns.FQ_NAMES.deprecated)
|
||||
?: Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, JAVA_DEPRECATED)
|
||||
if (annotation != null) {
|
||||
result.add(DeprecatedByAnnotation(annotation, this))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDeprecationIfPresent(this)
|
||||
addUseSiteTargetedDeprecationIfPresent(this, AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this))
|
||||
|
||||
when (this) {
|
||||
is TypeAliasDescriptor -> {
|
||||
expandedType.deprecationsByConstituentTypes().mapTo(result) { it.wrapInTypeAliasExpansion(this) }
|
||||
}
|
||||
is DescriptorDerivedFromTypeAlias -> {
|
||||
result.addAll(typeAliasDescriptor.getOwnDeprecations())
|
||||
}
|
||||
is ConstructorDescriptor -> {
|
||||
addDeprecationIfPresent(containingDeclaration)
|
||||
}
|
||||
is PropertyAccessorDescriptor -> {
|
||||
addDeprecationIfPresent(correspondingProperty)
|
||||
|
||||
addUseSiteTargetedDeprecationIfPresent(
|
||||
correspondingProperty,
|
||||
if (this is PropertyGetterDescriptor) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return result.distinct()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtImportsFactory
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
@@ -51,7 +48,8 @@ class FileScopeFactory(
|
||||
private val ktImportsFactory: KtImportsFactory,
|
||||
private val platformToKotlinClassMap: PlatformToKotlinClassMap,
|
||||
private val defaultImportProvider: DefaultImportProvider,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
/* avoid constructing psi for default imports prematurely (time consuming in some scenarios) */
|
||||
private val defaultImports by storageManager.createLazyValue {
|
||||
@@ -112,7 +110,8 @@ class FileScopeFactory(
|
||||
fun createImportResolver(indexedImports: IndexedImports, trace: BindingTrace, excludedImports: List<FqName>? = null) =
|
||||
LazyImportResolver(
|
||||
storageManager, qualifiedExpressionResolver, moduleDescriptor, platformToKotlinClassMap, languageVersionSettings,
|
||||
indexedImports, aliasImportNames concat excludedImports, trace, packageFragment
|
||||
indexedImports, aliasImportNames concat excludedImports, trace, packageFragment,
|
||||
deprecationResolver
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -81,7 +81,8 @@ class LazyImportResolver(
|
||||
val indexedImports: IndexedImports,
|
||||
excludedImportNames: Collection<FqName>,
|
||||
private val traceForImportResolve: BindingTrace,
|
||||
private val packageFragment: PackageFragmentDescriptor
|
||||
private val packageFragment: PackageFragmentDescriptor,
|
||||
val deprecationResolver: DeprecationResolver
|
||||
) : ImportResolver {
|
||||
private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues {
|
||||
directive: KtImportDirective ->
|
||||
@@ -208,7 +209,7 @@ class LazyImportScope(
|
||||
private fun isClassifierVisible(descriptor: ClassifierDescriptor): Boolean {
|
||||
if (filteringKind == FilteringKind.ALL) return true
|
||||
|
||||
if (descriptor.isHiddenInResolution(importResolver.languageVersionSettings)) return false
|
||||
if (importResolver.deprecationResolver.isHiddenInResolution(descriptor)) return false
|
||||
|
||||
val visibility = (descriptor as DeclarationDescriptorWithVisibility).visibility
|
||||
val includeVisible = filteringKind == FilteringKind.VISIBLE_CLASSES
|
||||
|
||||
+11
-3
@@ -633,7 +633,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
trace.record(CALL, expression, call);
|
||||
|
||||
if (context.trace.wantsDiagnostics()) {
|
||||
CallCheckerContext callCheckerContext = new CallCheckerContext(context, components.languageVersionSettings);
|
||||
CallCheckerContext callCheckerContext =
|
||||
createCallCheckerContext(context);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
}
|
||||
@@ -934,7 +935,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
if (resolvedCall != null && trace.wantsDiagnostics()) {
|
||||
// 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, trace, components.languageVersionSettings);
|
||||
CallCheckerContext callCheckerContext =
|
||||
new CallCheckerContext(context, trace, components.languageVersionSettings, components.deprecationResolver);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
}
|
||||
@@ -1001,13 +1003,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
resolvedCall.markCallAsCompleted();
|
||||
|
||||
if (context.trace.wantsDiagnostics()) {
|
||||
CallCheckerContext callCheckerContext = new CallCheckerContext(context, components.languageVersionSettings);
|
||||
CallCheckerContext callCheckerContext =
|
||||
createCallCheckerContext(context);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallCheckerContext createCallCheckerContext(@NotNull ExpressionTypingContext context) {
|
||||
return new CallCheckerContext(context, components.languageVersionSettings, components.deprecationResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KotlinTypeInfo visitBinaryExpression(@NotNull KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||
ExpressionTypingContext context = isBinaryExpressionDependentOnExpectedType(expression)
|
||||
|
||||
+6
@@ -63,6 +63,7 @@ public class ExpressionTypingComponents {
|
||||
/*package*/ Iterable<RttiExpressionChecker> rttiExpressionCheckers;
|
||||
/*package*/ WrappedTypeFactory wrappedTypeFactory;
|
||||
/*package*/ CollectionLiteralResolver collectionLiteralResolver;
|
||||
/*package*/ DeprecationResolver deprecationResolver;
|
||||
|
||||
@Inject
|
||||
public void setGlobalContext(@NotNull GlobalContext globalContext) {
|
||||
@@ -213,4 +214,9 @@ public class ExpressionTypingComponents {
|
||||
public void setCollectionLiteralResolver(CollectionLiteralResolver collectionLiteralResolver) {
|
||||
this.collectionLiteralResolver = collectionLiteralResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDeprecationResolver(DeprecationResolver deprecationResolver) {
|
||||
this.deprecationResolver = deprecationResolver;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.idea.codeInsight
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
@@ -31,10 +30,10 @@ import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtVariableDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.resolve.scopes.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectAllFromMeAndParent
|
||||
@@ -77,7 +76,7 @@ class ReferenceVariantsHelper(
|
||||
): Collection<DeclarationDescriptor> {
|
||||
var variants: Collection<DeclarationDescriptor>
|
||||
= getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useReceiverType)
|
||||
.filter { !it.isHiddenInResolution(resolutionFacade.frontendService<LanguageVersionSettings>()) && visibilityFilter(it) }
|
||||
.filter { !resolutionFacade.frontendService<DeprecationResolver>().isHiddenInResolution(it) && visibilityFilter(it) }
|
||||
|
||||
if (filterOutShadowed) {
|
||||
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, contextElement, callTypeAndReceiver)?.let {
|
||||
@@ -415,4 +414,4 @@ fun ResolutionScope.collectSyntheticStaticMembersAndConstructors(
|
||||
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java)
|
||||
return (syntheticScopes.collectSyntheticStaticFunctions(this) + syntheticScopes.collectSyntheticConstructors(this))
|
||||
.filter { kindFilter.accepts(it) && nameFilter(it.name) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.intellij.psi.search.PsiShortNamesCache
|
||||
import com.intellij.psi.stubs.StringStubIndexExtension
|
||||
import com.intellij.util.indexing.IdFilter
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.KotlinShortNamesCache
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.*
|
||||
@@ -44,7 +43,7 @@ import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.contains
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
import org.jetbrains.kotlin.resolve.scopes.collectSyntheticStaticFunctions
|
||||
@@ -68,7 +67,7 @@ class KotlinIndicesHelper(
|
||||
private val scopeWithoutKotlin = scope.excludeKotlinSources() as GlobalSearchScope
|
||||
|
||||
private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@ {
|
||||
if (it.isHiddenInResolution(resolutionFacade.frontendService<LanguageVersionSettings>())) return@filter false
|
||||
if (resolutionFacade.frontendService<DeprecationResolver>().isHiddenInResolution(it)) return@filter false
|
||||
if (!visibilityFilter(it)) return@filter false
|
||||
if (applyExcludeSettings && it.isExcludedFromAutoImport(project, file)) return@filter false
|
||||
true
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
@@ -39,8 +38,8 @@ import org.jetbrains.kotlin.idea.kdoc.KDocRenderer
|
||||
import org.jetbrains.kotlin.idea.kdoc.findKDoc
|
||||
import org.jetbrains.kotlin.idea.kdoc.isBoringBuiltinClass
|
||||
import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
|
||||
@@ -49,12 +48,12 @@ import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.deprecatedByAnnotationReplaceWithExpression
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.getDeprecations
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
||||
|
||||
@@ -246,20 +245,20 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() {
|
||||
return "No documentation available"
|
||||
}
|
||||
|
||||
return renderKotlin(context, declarationDescriptor, quickNavigation, declaration.languageVersionSettings)
|
||||
return renderKotlin(context, declarationDescriptor, quickNavigation, declaration)
|
||||
}
|
||||
|
||||
private fun renderKotlinImplicitLambdaParameter(element: KtReferenceExpression, quickNavigation: Boolean): String? {
|
||||
val context = element.analyze(BodyResolveMode.PARTIAL)
|
||||
val target = element.mainReference.resolveToDescriptors(context).singleOrNull() as? ValueParameterDescriptor? ?: return null
|
||||
return renderKotlin(context, target, quickNavigation, element.languageVersionSettings)
|
||||
return renderKotlin(context, target, quickNavigation, element)
|
||||
}
|
||||
|
||||
private fun renderKotlin(
|
||||
context: BindingContext,
|
||||
declarationDescriptor: DeclarationDescriptor,
|
||||
quickNavigation: Boolean,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
ktElement: KtElement
|
||||
): String {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var declarationDescriptor = declarationDescriptor
|
||||
@@ -278,7 +277,8 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() {
|
||||
renderedDecl = "<pre>$renderedDecl</pre>"
|
||||
}
|
||||
|
||||
renderedDecl += renderDeprecationInfo(declarationDescriptor, languageVersionSettings)
|
||||
val deprecationProvider = ktElement.getResolutionFacade().frontendService<DeprecationResolver>()
|
||||
renderedDecl += renderDeprecationInfo(declarationDescriptor, deprecationProvider)
|
||||
|
||||
if (!quickNavigation) {
|
||||
val comment = declarationDescriptor.findKDoc()
|
||||
@@ -310,9 +310,9 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() {
|
||||
|
||||
private fun renderDeprecationInfo(
|
||||
declarationDescriptor: DeclarationDescriptor,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
deprecationResolver: DeprecationResolver
|
||||
): String {
|
||||
val deprecation = declarationDescriptor.getDeprecations(languageVersionSettings).firstOrNull() ?: return ""
|
||||
val deprecation = deprecationResolver.getDeprecations(declarationDescriptor).firstOrNull() ?: return ""
|
||||
|
||||
return buildString {
|
||||
wrapTag("DL") {
|
||||
|
||||
+3
-4
@@ -30,7 +30,6 @@ import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.ui.GuiUtils
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
@@ -50,9 +49,9 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
import org.jetbrains.kotlin.resolve.scopes.collectSyntheticExtensionProperties
|
||||
@@ -76,7 +75,7 @@ class ConflictingExtensionPropertyInspection : AbstractKotlinInspection(), Clean
|
||||
val conflictingExtension = conflictingSyntheticExtension(propertyDescriptor, syntheticScopes) ?: return
|
||||
|
||||
// don't report on hidden declarations
|
||||
if (propertyDescriptor.isHiddenInResolution(resolutionFacade.frontendService<LanguageVersionSettings>())) return
|
||||
if (resolutionFacade.frontendService<DeprecationResolver>().isHiddenInResolution(propertyDescriptor)) return
|
||||
|
||||
val fixes = createFixes(property, conflictingExtension, isOnTheFly)
|
||||
|
||||
@@ -251,4 +250,4 @@ class ConflictingExtensionPropertyInspection : AbstractKotlinInspection(), Clean
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -21,14 +21,15 @@ import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtPropertyAccessor
|
||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||
import org.jetbrains.kotlin.resolve.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.deprecatedByOverriddenMessage
|
||||
import org.jetbrains.kotlin.resolve.getDeprecations
|
||||
|
||||
class OverridingDeprecatedMemberInspection : AbstractKotlinInspection() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
@@ -44,7 +45,9 @@ class OverridingDeprecatedMemberInspection : AbstractKotlinInspection() {
|
||||
private fun registerProblemIfNeeded(declaration: KtDeclaration, targetForProblem: PsiElement) {
|
||||
val accessorDescriptor = declaration.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: return
|
||||
|
||||
val message = accessorDescriptor.getDeprecations(declaration.languageVersionSettings)
|
||||
val deprecationProvider = declaration.getResolutionFacade().frontendService<DeprecationResolver>()
|
||||
|
||||
val message = deprecationProvider.getDeprecations(accessorDescriptor)
|
||||
.firstOrNull()
|
||||
?.deprecatedByOverriddenMessage() ?: return
|
||||
val problem = holder.manager.createProblemDescriptor(
|
||||
|
||||
Reference in New Issue
Block a user