From 541b9dab524adffc4e6b9305ca868feb1255eff7 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 4 Jul 2017 17:22:33 +0300 Subject: [PATCH] Introduce optimized BuiltInAnnotationDescriptor for built-in annotations It's built on a FQ name and avoids resolution of the annotation class descriptor as much as possible --- .../kotlin/UnsafeVarianceTypeSubstitution.kt | 8 ++-- .../kotlin/builtins/KotlinBuiltIns.java | 5 --- .../kotlin/builtins/functionTypes.kt | 23 ++++------- .../BuiltInAnnotationDescriptor.kt | 38 +++++++++++++++++++ .../descriptors/annotations/annotationUtil.kt | 22 ++++------- .../DeprecatedSymbolUsageFixBase.kt | 6 +-- 6 files changed, 61 insertions(+), 41 deletions(-) create mode 100644 core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/BuiltInAnnotationDescriptor.kt diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt index 7cc7b8030ce..6b1d3e45783 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt @@ -19,12 +19,14 @@ package org.jetbrains.kotlin.load.kotlin import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl +import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations -import org.jetbrains.kotlin.descriptors.annotations.createUnsafeVarianceAnnotation import org.jetbrains.kotlin.types.* -internal class UnsafeVarianceTypeSubstitution(kotlinBuiltIns: KotlinBuiltIns) : TypeSubstitution() { - private val unsafeVarianceAnnotations = AnnotationsImpl(listOf(kotlinBuiltIns.createUnsafeVarianceAnnotation())) +internal class UnsafeVarianceTypeSubstitution(builtIns: KotlinBuiltIns) : TypeSubstitution() { + private val unsafeVarianceAnnotations = AnnotationsImpl(listOf( + BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.unsafeVariance, emptyMap()) + )) override fun get(key: KotlinType) = null diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 479bad3ddc0..5196af914c2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -563,11 +563,6 @@ public abstract class KotlinBuiltIns { return getBuiltInClassByName("Throwable"); } - @NotNull - public ClassDescriptor getDeprecatedAnnotation() { - return getBuiltInClassByName(FQ_NAMES.deprecated.shortName()); - } - @Nullable private static ClassDescriptor getEnumEntry(@NotNull ClassDescriptor enumDescriptor, @NotNull String entryName) { ClassifierDescriptor result = enumDescriptor.getUnsubstitutedInnerClassesScope().getContributedClassifier( diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt index 0fe20799436..242c1e5adfd 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt @@ -20,10 +20,9 @@ import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFac import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.SourceElement -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl +import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name @@ -164,12 +163,10 @@ fun getFunctionTypeArgumentProjections( parameterTypes.mapIndexedTo(arguments) { index, type -> val name = parameterNames?.get(index)?.takeUnless { it.isSpecial } val typeToUse = if (name != null) { - val annotationClass = builtIns.getBuiltInClassByName(KotlinBuiltIns.FQ_NAMES.parameterName.shortName()) - val nameValue = ConstantValueFactory(builtIns).createStringValue(name.asString()) - val parameterNameAnnotation = AnnotationDescriptorImpl( - annotationClass.defaultType, - mapOf(Name.identifier("name") to nameValue), - SourceElement.NO_SOURCE + val parameterNameAnnotation = BuiltInAnnotationDescriptor( + builtIns, + KotlinBuiltIns.FQ_NAMES.parameterName, + mapOf(Name.identifier("name") to ConstantValueFactory(builtIns).createStringValue(name.asString())) ) type.replaceAnnotations(AnnotationsImpl(type.annotations + parameterNameAnnotation)) } @@ -199,18 +196,14 @@ fun createFunctionType( val parameterCount = if (receiverType == null) size else size + 1 val classDescriptor = if (suspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount) + // TODO: preserve laziness of given annotations val typeAnnotations = if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) { annotations } else { - val extensionFunctionAnnotation = AnnotationDescriptorImpl( - builtIns.getBuiltInClassByName(KotlinBuiltIns.FQ_NAMES.extensionFunctionType.shortName()).defaultType, - emptyMap(), SourceElement.NO_SOURCE - ) - - // TODO: preserve laziness of given annotations - AnnotationsImpl(annotations + extensionFunctionAnnotation) + AnnotationsImpl(annotations + + BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.extensionFunctionType, emptyMap())) } return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments) diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/BuiltInAnnotationDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/BuiltInAnnotationDescriptor.kt new file mode 100644 index 00000000000..e328c7fc9ee --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/BuiltInAnnotationDescriptor.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.descriptors.annotations + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.constants.ConstantValue +import org.jetbrains.kotlin.types.KotlinType +import kotlin.LazyThreadSafetyMode.PUBLICATION + +class BuiltInAnnotationDescriptor( + private val builtIns: KotlinBuiltIns, + override val fqName: FqName, + override val allValueArguments: Map> +) : AnnotationDescriptor { + override val type: KotlinType by lazy(PUBLICATION) { + builtIns.getBuiltInClassByFqName(fqName).defaultType + } + + override val source: SourceElement + get() = SourceElement.NO_SOURCE +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt index 0c70e7cc762..2d3a9ec3a0f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor -import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -36,23 +35,23 @@ fun KotlinBuiltIns.createDeprecatedAnnotation( replaceWith: String = "", level: String = "WARNING" ): AnnotationDescriptor { - val replaceWithAnnotation = AnnotationDescriptorImpl( - getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.replaceWith).defaultType, + val replaceWithAnnotation = BuiltInAnnotationDescriptor( + this, + KotlinBuiltIns.FQ_NAMES.replaceWith, mapOf( REPLACE_WITH_EXPRESSION_NAME to StringValue(replaceWith, this), REPLACE_WITH_IMPORTS_NAME to ArrayValue(emptyList(), getArrayType(Variance.INVARIANT, stringType), this) - ), - SourceElement.NO_SOURCE + ) ) - return AnnotationDescriptorImpl( - deprecatedAnnotation.defaultType, + return BuiltInAnnotationDescriptor( + this, + KotlinBuiltIns.FQ_NAMES.deprecated, mapOf( DEPRECATED_MESSAGE_NAME to StringValue(message, this), DEPRECATED_REPLACE_WITH_NAME to AnnotationValue(replaceWithAnnotation), DEPRECATED_LEVEL_NAME to EnumValue(getDeprecationLevelEnumEntry(level) ?: error("Deprecation level $level not found")) - ), - SourceElement.NO_SOURCE + ) ) } @@ -62,11 +61,6 @@ private val DEPRECATED_LEVEL_NAME = Name.identifier("level") private val REPLACE_WITH_EXPRESSION_NAME = Name.identifier("expression") private val REPLACE_WITH_IMPORTS_NAME = Name.identifier("imports") -fun KotlinBuiltIns.createUnsafeVarianceAnnotation(): AnnotationDescriptor { - val unsafeVarianceAnnotation = getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.unsafeVariance) - return AnnotationDescriptorImpl(unsafeVarianceAnnotation.defaultType, emptyMap(), SourceElement.NO_SOURCE) -} - private val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly") fun MemberDescriptor.isInlineOnlyOrReifiable(): Boolean = diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt index 93c6545cf6a..3565fafb837 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.quickfix.replaceWith import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor @@ -37,12 +38,10 @@ import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtSimpleNameExpression -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess import org.jetbrains.kotlin.resolve.constants.StringValue -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -73,8 +72,7 @@ abstract class DeprecatedSymbolUsageFixBase( companion object { fun fetchReplaceWithPattern(descriptor: DeclarationDescriptor, project: Project): ReplaceWith? { - val annotationClass = descriptor.builtIns.deprecatedAnnotation - val annotation = descriptor.annotations.findAnnotation(DescriptorUtils.getFqNameSafe(annotationClass)) ?: return null + val annotation = descriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated) ?: return null val replaceWithValue = annotation.argumentValue(kotlin.Deprecated::replaceWith.name) as? AnnotationDescriptor ?: return null val pattern = replaceWithValue.argumentValue(kotlin.ReplaceWith::expression.name) as? String ?: return null if (pattern.isEmpty()) return null