From 46d8f45c11530a855f1bbe6cc576b57f984779ca Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Fri, 14 Jun 2019 19:55:17 +0700 Subject: [PATCH] Apply LiftReturnOrAssignmentInspection on idea --- .../jetbrains/kotlin/idea/util/CallType.kt | 156 +++++------ .../idea/completion/CompletionSession.kt | 180 +++++++------ .../completion/KDocCompletionContributor.kt | 70 ++--- .../idea/completion/KeywordCompletion.kt | 243 ++++++++++-------- .../idea/completion/OverridesCompletion.kt | 12 +- .../test/AbstractKeywordCompletionTest.kt | 10 +- .../kotlin/idea/core/KotlinIndicesHelper.kt | 225 ++++++++-------- .../KotlinBreadcrumbsInfoProvider.kt | 77 +++--- .../idea/refactoring/elementSelectionUtils.kt | 141 +++++----- 9 files changed, 592 insertions(+), 522 deletions(-) diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt index 060b5bbe8cb..9fd228e1b55 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt @@ -56,7 +56,8 @@ sealed class CallType(val descriptorKindFilter: Descript object SAFE : CallType(DescriptorKindFilter.ALL) - object SUPER_MEMBERS : CallType(DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions exclude AbstractMembersExclude) + object SUPER_MEMBERS : + CallType(DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions exclude AbstractMembersExclude) object INFIX : CallType(DescriptorKindFilter.FUNCTIONS exclude NonInfixExclude) @@ -68,15 +69,17 @@ sealed class CallType(val descriptorKindFilter: Descript object PACKAGE_DIRECTIVE : CallType(DescriptorKindFilter.PACKAGES) - object TYPE : CallType(DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude DescriptorKindExclude.EnumEntry) + object TYPE : + CallType(DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude DescriptorKindExclude.EnumEntry) object DELEGATE : CallType(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude) - object ANNOTATION : CallType(DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude NonAnnotationClassifierExclude) + object ANNOTATION : + CallType(DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude NonAnnotationClassifierExclude) private object NonInfixExclude : DescriptorKindExclude() { override fun excludes(descriptor: DeclarationDescriptor) = - !(descriptor is SimpleFunctionDescriptor && descriptor.isInfix) + !(descriptor is SimpleFunctionDescriptor && descriptor.isInfix) override val fullyExcludedDescriptorKinds: Int get() = 0 @@ -84,15 +87,15 @@ sealed class CallType(val descriptorKindFilter: Descript private object NonOperatorExclude : DescriptorKindExclude() { override fun excludes(descriptor: DeclarationDescriptor) = - !(descriptor is SimpleFunctionDescriptor && descriptor.isOperator) + !(descriptor is SimpleFunctionDescriptor && descriptor.isOperator) override val fullyExcludedDescriptorKinds: Int get() = 0 } private object CallableReferenceExclude : DescriptorKindExclude() { - override fun excludes(descriptor: DeclarationDescriptor) /* currently not supported for locals and synthetic */ - = descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED + override fun excludes(descriptor: DeclarationDescriptor) /* currently not supported for locals and synthetic */ = + descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED override val fullyExcludedDescriptorKinds: Int get() = 0 @@ -108,8 +111,8 @@ sealed class CallType(val descriptorKindFilter: Descript } private object AbstractMembersExclude : DescriptorKindExclude() { - override fun excludes(descriptor: DeclarationDescriptor) - = descriptor is CallableMemberDescriptor && descriptor.modality == Modality.ABSTRACT + override fun excludes(descriptor: DeclarationDescriptor) = + descriptor is CallableMemberDescriptor && descriptor.modality == Modality.ABSTRACT override val fullyExcludedDescriptorKinds: Int get() = 0 @@ -117,19 +120,27 @@ sealed class CallType(val descriptorKindFilter: Descript } sealed class CallTypeAndReceiver>( - val callType: TCallType, - val receiver: TReceiver + val callType: TCallType, + val receiver: TReceiver ) { object UNKNOWN : CallTypeAndReceiver(CallType.UNKNOWN, null) object DEFAULT : CallTypeAndReceiver(CallType.DEFAULT, null) class DOT(receiver: KtExpression) : CallTypeAndReceiver(CallType.DOT, receiver) class SAFE(receiver: KtExpression) : CallTypeAndReceiver(CallType.SAFE, receiver) - class SUPER_MEMBERS(receiver: KtSuperExpression) : CallTypeAndReceiver(CallType.SUPER_MEMBERS, receiver) + class SUPER_MEMBERS(receiver: KtSuperExpression) : + CallTypeAndReceiver(CallType.SUPER_MEMBERS, receiver) + class INFIX(receiver: KtExpression) : CallTypeAndReceiver(CallType.INFIX, receiver) class OPERATOR(receiver: KtExpression) : CallTypeAndReceiver(CallType.OPERATOR, receiver) - class CALLABLE_REFERENCE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.CALLABLE_REFERENCE, receiver) - class IMPORT_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.IMPORT_DIRECTIVE, receiver) - class PACKAGE_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.PACKAGE_DIRECTIVE, receiver) + class CALLABLE_REFERENCE(receiver: KtExpression?) : + CallTypeAndReceiver(CallType.CALLABLE_REFERENCE, receiver) + + class IMPORT_DIRECTIVE(receiver: KtExpression?) : + CallTypeAndReceiver(CallType.IMPORT_DIRECTIVE, receiver) + + class PACKAGE_DIRECTIVE(receiver: KtExpression?) : + CallTypeAndReceiver(CallType.PACKAGE_DIRECTIVE, receiver) + class TYPE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.TYPE, receiver) class DELEGATE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.DELEGATE, receiver) class ANNOTATION(receiver: KtExpression?) : CallTypeAndReceiver(CallType.ANNOTATION, receiver) @@ -138,26 +149,26 @@ sealed class CallTypeAndReceiver { val parent = expression.parent if (parent is KtCallableReferenceExpression && expression == parent.callableReference) { - return CallTypeAndReceiver.CALLABLE_REFERENCE(parent.receiverExpression) + return CALLABLE_REFERENCE(parent.receiverExpression) } val receiverExpression = expression.getReceiverExpression() if (expression.isImportDirectiveExpression()) { - return CallTypeAndReceiver.IMPORT_DIRECTIVE(receiverExpression) + return IMPORT_DIRECTIVE(receiverExpression) } if (expression.isPackageDirectiveExpression()) { - return CallTypeAndReceiver.PACKAGE_DIRECTIVE(receiverExpression) + return PACKAGE_DIRECTIVE(receiverExpression) } if (parent is KtUserType) { val constructorCallee = (parent.parent as? KtTypeReference)?.parent as? KtConstructorCalleeExpression if (constructorCallee != null && constructorCallee.parent is KtAnnotationEntry) { - return CallTypeAndReceiver.ANNOTATION(receiverExpression) + return ANNOTATION(receiverExpression) } - return CallTypeAndReceiver.TYPE(receiverExpression) + return TYPE(receiverExpression) } when (expression) { @@ -168,12 +179,12 @@ sealed class CallTypeAndReceiver { if (parent.operationToken == KtTokens.IDENTIFIER) - CallTypeAndReceiver.INFIX(receiverExpression) + INFIX(receiverExpression) else - CallTypeAndReceiver.OPERATOR(receiverExpression) + OPERATOR(receiverExpression) } - is KtUnaryExpression -> CallTypeAndReceiver.OPERATOR(receiverExpression) + is KtUnaryExpression -> OPERATOR(receiverExpression) else -> error("Unknown parent for JetOperationReferenceExpression: $parent with text '${parent.text}'") } @@ -181,26 +192,26 @@ sealed class CallTypeAndReceiver { if (receiverExpression == null) { - return CallTypeAndReceiver.DEFAULT + return DEFAULT } if (receiverExpression is KtSuperExpression) { - return CallTypeAndReceiver.SUPER_MEMBERS(receiverExpression) + return SUPER_MEMBERS(receiverExpression) } return when (parent) { is KtCallExpression -> { if ((parent.parent as KtQualifiedExpression).operationSign == KtTokens.SAFE_ACCESS) - CallTypeAndReceiver.SAFE(receiverExpression) + SAFE(receiverExpression) else - CallTypeAndReceiver.DOT(receiverExpression) + DOT(receiverExpression) } is KtQualifiedExpression -> { if (parent.operationSign == KtTokens.SAFE_ACCESS) - CallTypeAndReceiver.SAFE(receiverExpression) + SAFE(receiverExpression) else - CallTypeAndReceiver.DOT(receiverExpression) + DOT(receiverExpression) } else -> error("Unknown parent for JetNameReferenceExpression with receiver: $parent") @@ -226,22 +237,22 @@ data class ReceiverType( } fun CallTypeAndReceiver<*, *>.receiverTypes( - bindingContext: BindingContext, - contextElement: PsiElement, - moduleDescriptor: ModuleDescriptor, - resolutionFacade: ResolutionFacade, - stableSmartCastsOnly: Boolean + bindingContext: BindingContext, + contextElement: PsiElement, + moduleDescriptor: ModuleDescriptor, + resolutionFacade: ResolutionFacade, + stableSmartCastsOnly: Boolean ): Collection? { return receiverTypesWithIndex(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly)?.map { it.type } } fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex( - bindingContext: BindingContext, - contextElement: PsiElement, - moduleDescriptor: ModuleDescriptor, - resolutionFacade: ResolutionFacade, - stableSmartCastsOnly: Boolean, - withImplicitReceiversWhenExplicitPresent: Boolean = false + bindingContext: BindingContext, + contextElement: PsiElement, + moduleDescriptor: ModuleDescriptor, + resolutionFacade: ResolutionFacade, + stableSmartCastsOnly: Boolean, + withImplicitReceiversWhenExplicitPresent: Boolean = false ): Collection? { val languageVersionSettings = resolutionFacade.frontendService() @@ -249,20 +260,19 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex( when (this) { is CallTypeAndReceiver.CALLABLE_REFERENCE -> { if (receiver != null) { - val lhs = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] ?: return emptyList() - when (lhs) { - is DoubleColonLHS.Type -> return listOf(ReceiverType(lhs.type, 0)) + return when (val lhs = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] ?: return emptyList()) { + is DoubleColonLHS.Type -> listOf(ReceiverType(lhs.type, 0)) is DoubleColonLHS.Expression -> { val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext) - return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, - moduleDescriptor, stableSmartCastsOnly, languageVersionSettings, - resolutionFacade.frontendService()) - .map { ReceiverType(it, 0) } + receiverValueTypes( + receiverValue, lhs.dataFlowInfo, bindingContext, + moduleDescriptor, stableSmartCastsOnly, languageVersionSettings, + resolutionFacade.frontendService() + ).map { ReceiverType(it, 0) } } } - } - else { + } else { return emptyList() } } @@ -279,10 +289,10 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex( val qualifier = receiver.superTypeQualifier return if (qualifier != null) { listOfNotNull(bindingContext.getType(receiver)).map { ReceiverType(it, 0) } - } - else { + } else { val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade) - val classDescriptor = resolutionScope.ownerDescriptor.parentsWithSelf.firstIsInstanceOrNull() ?: return emptyList() + val classDescriptor = + resolutionScope.ownerDescriptor.parentsWithSelf.firstIsInstanceOrNull() ?: return emptyList() classDescriptor.typeConstructor.supertypesWithAny().map { ReceiverType(it, 0) } } } @@ -299,10 +309,13 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex( val expressionReceiver = receiverExpression?.let { val receiverType = - bindingContext.getType(receiverExpression) ?: - (bindingContext.get(BindingContext.QUALIFIER, receiverExpression) as? ClassQualifier)?.descriptor?.classValueType ?: - (bindingContext.get(BindingContext.QUALIFIER, receiverExpression) as? TypeAliasQualifier)?.classDescriptor?.classValueType ?: - return emptyList() + bindingContext.getType(receiverExpression) ?: (bindingContext.get( + BindingContext.QUALIFIER, + receiverExpression + ) as? ClassQualifier)?.descriptor?.classValueType ?: (bindingContext.get( + BindingContext.QUALIFIER, + receiverExpression + ) as? TypeAliasQualifier)?.classDescriptor?.classValueType ?: return emptyList() ExpressionReceiver.create(receiverExpression, receiverType, bindingContext) } @@ -319,7 +332,7 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex( fun addReceiverType(receiverValue: ReceiverValue, implicit: Boolean) { val types = receiverValueTypes( receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly, languageVersionSettings, - resolutionFacade.frontendService() + resolutionFacade.frontendService() ) types.mapTo(result) { type -> ReceiverType(type, receiverIndex, receiverValue.takeIf { implicit }) } @@ -336,26 +349,25 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex( } private fun receiverValueTypes( - receiverValue: ReceiverValue, - dataFlowInfo: DataFlowInfo, - bindingContext: BindingContext, - moduleDescriptor: ModuleDescriptor, - stableSmartCastsOnly: Boolean, - languageVersionSettings: LanguageVersionSettings, - dataFlowValueFactory: DataFlowValueFactory + receiverValue: ReceiverValue, + dataFlowInfo: DataFlowInfo, + bindingContext: BindingContext, + moduleDescriptor: ModuleDescriptor, + stableSmartCastsOnly: Boolean, + languageVersionSettings: LanguageVersionSettings, + dataFlowValueFactory: DataFlowValueFactory ): List { val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor) return if (dataFlowValue.isStable || !stableSmartCastsOnly) { // we don't include smart cast receiver types for "unstable" receiver value to mark members grayed SmartCastManager().getSmartCastVariantsWithLessSpecificExcluded( - receiverValue, - bindingContext, - moduleDescriptor, - dataFlowInfo, - languageVersionSettings, - dataFlowValueFactory + receiverValue, + bindingContext, + moduleDescriptor, + dataFlowInfo, + languageVersionSettings, + dataFlowValueFactory ) - } - else { + } else { listOf(receiverValue.type) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 25d2130c651..48e874264bd 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -39,11 +39,11 @@ import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.util.* +import org.jetbrains.kotlin.platform.isCommon +import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.module -import org.jetbrains.kotlin.platform.isCommon -import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.types.TypeUtils @@ -53,28 +53,28 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import java.util.* class CompletionSessionConfiguration( - val useBetterPrefixMatcherForNonImportedClasses: Boolean, - val nonAccessibleDeclarations: Boolean, - val javaGettersAndSetters: Boolean, - val javaClassesNotToBeUsed: Boolean, - val staticMembers: Boolean, - val dataClassComponentFunctions: Boolean + val useBetterPrefixMatcherForNonImportedClasses: Boolean, + val nonAccessibleDeclarations: Boolean, + val javaGettersAndSetters: Boolean, + val javaClassesNotToBeUsed: Boolean, + val staticMembers: Boolean, + val dataClassComponentFunctions: Boolean ) fun CompletionSessionConfiguration(parameters: CompletionParameters) = CompletionSessionConfiguration( - useBetterPrefixMatcherForNonImportedClasses = parameters.invocationCount < 2, - nonAccessibleDeclarations = parameters.invocationCount >= 2, - javaGettersAndSetters = parameters.invocationCount >= 2, - javaClassesNotToBeUsed = parameters.invocationCount >= 2, - staticMembers = parameters.invocationCount >= 2, - dataClassComponentFunctions = parameters.invocationCount >= 2 + useBetterPrefixMatcherForNonImportedClasses = parameters.invocationCount < 2, + nonAccessibleDeclarations = parameters.invocationCount >= 2, + javaGettersAndSetters = parameters.invocationCount >= 2, + javaClassesNotToBeUsed = parameters.invocationCount >= 2, + staticMembers = parameters.invocationCount >= 2, + dataClassComponentFunctions = parameters.invocationCount >= 2 ) abstract class CompletionSession( - protected val configuration: CompletionSessionConfiguration, - protected val parameters: CompletionParameters, - protected val toFromOriginalFileMapper: ToFromOriginalFileMapper, - resultSet: CompletionResultSet + protected val configuration: CompletionSessionConfiguration, + protected val parameters: CompletionParameters, + protected val toFromOriginalFileMapper: ToFromOriginalFileMapper, + resultSet: CompletionResultSet ) { init { CompletionBenchmarkSink.instance.onCompletionStarted(this) @@ -97,13 +97,11 @@ abstract class CompletionSession( if (reference.expression is KtLabelReferenceExpression) { this.nameExpression = null this.expression = reference.expression.parent.parent as? KtExpressionWithLabel - } - else { + } else { this.nameExpression = reference.expression this.expression = nameExpression } - } - else { + } else { this.nameExpression = null this.expression = null } @@ -116,29 +114,36 @@ abstract class CompletionSession( private val kotlinIdentifierPartPattern = StandardPatterns.character().javaIdentifierPart().andNot(singleCharPattern('$')) protected val prefix = CompletionUtil.findIdentifierPrefix( - parameters.position.containingFile, - parameters.offset, - kotlinIdentifierPartPattern or singleCharPattern('@'), - kotlinIdentifierStartPattern)!! + parameters.position.containingFile, + parameters.offset, + kotlinIdentifierPartPattern or singleCharPattern('@'), + kotlinIdentifierStartPattern + )!! protected val prefixMatcher = CamelHumpMatcher(prefix) protected val descriptorNameFilter: (String) -> Boolean = prefixMatcher.asStringNameFilter() - protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = configuration.nonAccessibleDeclarations) } - protected val isVisibleFilterCheckAlways: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = false) } + protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = + { isVisibleDescriptor(it, completeNonAccessible = configuration.nonAccessibleDeclarations) } + protected val isVisibleFilterCheckAlways: (DeclarationDescriptor) -> Boolean = + { isVisibleDescriptor(it, completeNonAccessible = false) } - protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, - resolutionFacade, - moduleDescriptor, - isVisibleFilter, - NotPropertiesService.getNotProperties(position)) + protected val referenceVariantsHelper = ReferenceVariantsHelper( + bindingContext, + resolutionFacade, + moduleDescriptor, + isVisibleFilter, + NotPropertiesService.getNotProperties(position) + ) - protected val callTypeAndReceiver = if (nameExpression == null) CallTypeAndReceiver.UNKNOWN else CallTypeAndReceiver.detect(nameExpression) + protected val callTypeAndReceiver = + if (nameExpression == null) CallTypeAndReceiver.UNKNOWN else CallTypeAndReceiver.detect(nameExpression) protected val receiverTypes = nameExpression?.let { detectReceiverTypes(bindingContext, nameExpression, callTypeAndReceiver) } - protected val basicLookupElementFactory = BasicLookupElementFactory(project, InsertHandlerProvider(callTypeAndReceiver.callType) { expectedInfos }) + protected val basicLookupElementFactory = + BasicLookupElementFactory(project, InsertHandlerProvider(callTypeAndReceiver.callType) { expectedInfos }) // LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) { @@ -155,12 +160,14 @@ abstract class CompletionSession( protected fun indicesHelper(mayIncludeInaccessible: Boolean): KotlinIndicesHelper { val filter = if (mayIncludeInaccessible) isVisibleFilter else isVisibleFilterCheckAlways - return KotlinIndicesHelper(resolutionFacade, - searchScope, - filter, - filterOutPrivate = !mayIncludeInaccessible, - declarationTranslator = { toFromOriginalFileMapper.toSyntheticFile(it) }, - file = file) + return KotlinIndicesHelper( + resolutionFacade, + searchScope, + filter, + filterOutPrivate = !mayIncludeInaccessible, + declarationTranslator = { toFromOriginalFileMapper.toSyntheticFile(it) }, + file = file + ) } private fun isVisibleDescriptor(descriptor: DeclarationDescriptor, completeNonAccessible: Boolean): Boolean { @@ -253,20 +260,22 @@ abstract class CompletionSession( protected open fun createSorter(): CompletionSorter { var sorter = CompletionSorter.defaultSorter(parameters, prefixMatcher)!! - sorter = sorter.weighBefore("stats", DeprecatedWeigher, PriorityWeigher, PreferGetSetMethodsToPropertyWeigher, - NotImportedWeigher(importableFqNameClassifier), - NotImportedStaticMemberWeigher(importableFqNameClassifier), - KindWeigher, CallableWeigher) + sorter = sorter.weighBefore( + "stats", DeprecatedWeigher, PriorityWeigher, PreferGetSetMethodsToPropertyWeigher, + NotImportedWeigher(importableFqNameClassifier), + NotImportedStaticMemberWeigher(importableFqNameClassifier), + KindWeigher, CallableWeigher + ) sorter = sorter.weighAfter("stats", VariableOrFunctionWeigher, ImportedWeigher(importableFqNameClassifier)) val preferContextElementsWeigher = PreferContextElementsWeigher(inDescriptor) - sorter = if (callTypeAndReceiver is CallTypeAndReceiver.SUPER_MEMBERS) { // for completion after "super." strictly prefer the current member - sorter.weighBefore("kotlin.deprecated", preferContextElementsWeigher) - } - else { - sorter.weighBefore("kotlin.proximity", preferContextElementsWeigher) - } + sorter = + if (callTypeAndReceiver is CallTypeAndReceiver.SUPER_MEMBERS) { // for completion after "super." strictly prefer the current member + sorter.weighBefore("kotlin.deprecated", preferContextElementsWeigher) + } else { + sorter.weighBefore("kotlin.proximity", preferContextElementsWeigher) + } sorter = sorter.weighBefore("middleMatching", PreferMatchingItemWeigher) @@ -275,10 +284,10 @@ abstract class CompletionSession( sorter = sorter.weighAfter("kotlin.proximity", ByNameAlphabeticalWeigher, PreferLessParametersWeigher) - if (expectedInfos.all { it.fuzzyType?.type?.isUnit() == true }) { - sorter = sorter.weighBefore("prefix", PreferDslMembers) + sorter = if (expectedInfos.all { it.fuzzyType?.type?.isUnit() == true }) { + sorter.weighBefore("prefix", PreferDslMembers) } else { - sorter = sorter.weighAfter("kotlin.preferContextElements", PreferDslMembers) + sorter.weighAfter("kotlin.preferContextElements", PreferDslMembers) } return sorter @@ -288,28 +297,29 @@ abstract class CompletionSession( if (expectedInfos.isEmpty()) return null var context = expectedInfos - .mapNotNull { it.fuzzyType?.type?.constructor?.declarationDescriptor?.importableFqName } - .distinct() - .singleOrNull() - ?.let { "expectedType=$it" } + .mapNotNull { it.fuzzyType?.type?.constructor?.declarationDescriptor?.importableFqName } + .distinct() + .singleOrNull() + ?.let { "expectedType=$it" } if (context == null) { context = expectedInfos - .mapNotNull { it.expectedName } - .distinct() - .singleOrNull() - ?.let { "expectedName=$it" } + .mapNotNull { it.expectedName } + .distinct() + .singleOrNull() + ?.let { "expectedName=$it" } } return context } protected val referenceVariantsCollector = if (nameExpression != null) { - ReferenceVariantsCollector(referenceVariantsHelper, indicesHelper(true), prefixMatcher, - nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext, - importableFqNameClassifier, configuration) - } - else { + ReferenceVariantsCollector( + referenceVariantsHelper, indicesHelper(true), prefixMatcher, + nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext, + importableFqNameClassifier, configuration + ) + } else { null } @@ -319,7 +329,9 @@ abstract class CompletionSession( protected fun referenceVariantsWithSingleFunctionTypeParameter(): ReferenceVariants? { val variants = referenceVariantsCollector?.allCollected ?: return null - val filter = { descriptor: DeclarationDescriptor -> descriptor is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(descriptor) } + val filter = { descriptor: DeclarationDescriptor -> + descriptor is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(descriptor) + } return ReferenceVariants(variants.imported.filter(filter), variants.notImportedExtensions.filter(filter)) } @@ -336,20 +348,21 @@ abstract class CompletionSession( val expressionReceiver = ExpressionReceiver.create(explicitReceiver, runtimeType, bindingContext) val (variants, notImportedExtensions) = ReferenceVariantsCollector( - referenceVariantsHelper, indicesHelper(true), prefixMatcher, - nameExpression!!, callTypeAndReceiver, resolutionFacade, bindingContext, - importableFqNameClassifier, configuration, runtimeReceiver = expressionReceiver + referenceVariantsHelper, indicesHelper(true), prefixMatcher, + nameExpression!!, callTypeAndReceiver, resolutionFacade, bindingContext, + importableFqNameClassifier, configuration, runtimeReceiver = expressionReceiver ).collectReferenceVariants(descriptorKindFilter!!) val filteredVariants = filterVariantsForRuntimeReceiverType(variants, referenceVariants.imported) - val filteredNotImportedExtensions = filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants.notImportedExtensions) + val filteredNotImportedExtensions = + filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants.notImportedExtensions) val runtimeVariants = ReferenceVariants(filteredVariants, filteredNotImportedExtensions) return Pair(runtimeVariants, lookupElementFactory.copy(receiverTypes = listOf(ReceiverType(runtimeType, 0)))) } private fun filterVariantsForRuntimeReceiverType( - runtimeVariants: Collection, - baseVariants: Collection + runtimeVariants: Collection, + baseVariants: Collection ): Collection { val baseVariantsByName = baseVariants.groupBy { it.name } val result = ArrayList() @@ -371,12 +384,11 @@ abstract class CompletionSession( protected fun processTopLevelCallables(processor: (CallableDescriptor) -> Unit) { val shadowedFilter = ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression!!, callTypeAndReceiver) - ?.createNonImportedDeclarationsFilter(referenceVariantsCollector!!.allCollected.imported) + ?.createNonImportedDeclarationsFilter(referenceVariantsCollector!!.allCollected.imported) indicesHelper(true).processTopLevelCallables({ prefixMatcher.prefixMatches(it) }) { if (shadowedFilter != null) { shadowedFilter(listOf(it)).singleOrNull()?.let(processor) - } - else { + } else { processor(it) } } @@ -395,13 +407,17 @@ abstract class CompletionSession( } protected open fun createLookupElementFactory(contextVariablesProvider: ContextVariablesProvider): LookupElementFactory { - return LookupElementFactory(basicLookupElementFactory, receiverTypes, - callTypeAndReceiver.callType, inDescriptor, contextVariablesProvider) + return LookupElementFactory( + basicLookupElementFactory, receiverTypes, + callTypeAndReceiver.callType, inDescriptor, contextVariablesProvider + ) } - protected fun detectReceiverTypes(bindingContext: BindingContext, - nameExpression: KtSimpleNameExpression, - callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection? { + protected fun detectReceiverTypes( + bindingContext: BindingContext, + nameExpression: KtSimpleNameExpression, + callTypeAndReceiver: CallTypeAndReceiver<*, *> + ): Collection? { var receiverTypes = callTypeAndReceiver.receiverTypesWithIndex( bindingContext, nameExpression, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = true, /* we don't include smart cast receiver types for "unstable" receiver value to mark members grayed */ diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt index 633c8fc6791..be3e43859bc 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt @@ -46,16 +46,23 @@ import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered class KDocCompletionContributor : CompletionContributor() { init { - extend(CompletionType.BASIC, psiElement().inside(KDocName::class.java), - KDocNameCompletionProvider) + extend( + CompletionType.BASIC, psiElement().inside(KDocName::class.java), + KDocNameCompletionProvider + ) - extend(CompletionType.BASIC, - psiElement().afterLeaf( - StandardPatterns.or(psiElement(KDocTokens.LEADING_ASTERISK), psiElement(KDocTokens.START))), - KDocTagCompletionProvider) + extend( + CompletionType.BASIC, + psiElement().afterLeaf( + StandardPatterns.or(psiElement(KDocTokens.LEADING_ASTERISK), psiElement(KDocTokens.START)) + ), + KDocTagCompletionProvider + ) - extend(CompletionType.BASIC, - psiElement(KDocTokens.TAG_NAME), KDocTagCompletionProvider) + extend( + CompletionType.BASIC, + psiElement(KDocTokens.TAG_NAME), KDocTagCompletionProvider + ) } } @@ -66,9 +73,9 @@ object KDocNameCompletionProvider : CompletionProvider() { } class KDocNameCompletionSession( - parameters: CompletionParameters, - toFromOriginalFileMapper: ToFromOriginalFileMapper, - resultSet: CompletionResultSet + parameters: CompletionParameters, + toFromOriginalFileMapper: ToFromOriginalFileMapper, + resultSet: CompletionResultSet ) : CompletionSession(CompletionSessionConfiguration(parameters), parameters, toFromOriginalFileMapper, resultSet) { override val descriptorKindFilter: DescriptorKindFilter? get() = null @@ -81,39 +88,42 @@ class KDocNameCompletionSession( val declarationDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] ?: return if (kdocLink.getTagIfSubject()?.knownTag == KDocKnownTag.PARAM) { addParamCompletions(position, declarationDescriptor) - } - else { + } else { addLinkCompletions(declarationDescriptor, kdocLink) } } - private fun addParamCompletions(position: KDocName, - declarationDescriptor: DeclarationDescriptor) { + private fun addParamCompletions( + position: KDocName, + declarationDescriptor: DeclarationDescriptor + ) { val section = position.getContainingSection() val documentedParameters = section.findTagsByName("param").map { it.getSubjectName() }.toSet() getParamDescriptors(declarationDescriptor) - .filter { it.name.asString() !in documentedParameters } - .forEach { - collector.addElement(basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true)) - } + .filter { it.name.asString() !in documentedParameters } + .forEach { + collector.addElement(basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true)) + } } - private fun collectDescriptorsForLinkCompletion(declarationDescriptor: DeclarationDescriptor, kDocLink: KDocLink): Collection { + private fun collectDescriptorsForLinkCompletion( + declarationDescriptor: DeclarationDescriptor, + kDocLink: KDocLink + ): Collection { val contextScope = getKDocLinkResolutionScope(resolutionFacade, declarationDescriptor) val qualifiedLink = kDocLink.getLinkText().split('.').dropLast(1) val nameFilter = descriptorNameFilter.toNameFilter() - if (qualifiedLink.isNotEmpty()) { - val parentDescriptors = resolveKDocLink(bindingContext, resolutionFacade, declarationDescriptor, kDocLink.getTagIfSubject(), qualifiedLink) - return parentDescriptors - .flatMap { - val scope = getKDocLinkMemberScope(it, contextScope) - scope.getContributedDescriptors(nameFilter = nameFilter) - } - } - else { - return contextScope.collectDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter, changeNamesForAliased = true) + return if (qualifiedLink.isNotEmpty()) { + val parentDescriptors = + resolveKDocLink(bindingContext, resolutionFacade, declarationDescriptor, kDocLink.getTagIfSubject(), qualifiedLink) + parentDescriptors.flatMap { + val scope = getKDocLinkMemberScope(it, contextScope) + scope.getContributedDescriptors(nameFilter = nameFilter) + } + } else { + contextScope.collectDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter, changeNamesForAliased = true) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt index f972ed8d1b9..09a7fe2a639 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt @@ -39,7 +39,6 @@ import org.jetbrains.kotlin.idea.completion.handlers.createKeywordConstructLooku import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* @@ -52,46 +51,49 @@ open class KeywordLookupObject object KeywordCompletion { private val ALL_KEYWORDS = (KEYWORDS.types + SOFT_KEYWORDS.types) - .map { it as KtKeywordToken } + .map { it as KtKeywordToken } - private val KEYWORDS_TO_IGNORE_PREFIX = TokenSet.create(OVERRIDE_KEYWORD /* it's needed to complete overrides that should be work by member name too */) + private val KEYWORDS_TO_IGNORE_PREFIX = + TokenSet.create(OVERRIDE_KEYWORD /* it's needed to complete overrides that should be work by member name too */) private val COMPOUND_KEYWORDS = mapOf( - COMPANION_KEYWORD to OBJECT_KEYWORD, - DATA_KEYWORD to CLASS_KEYWORD, - ENUM_KEYWORD to CLASS_KEYWORD, - ANNOTATION_KEYWORD to CLASS_KEYWORD, - SEALED_KEYWORD to CLASS_KEYWORD, - LATEINIT_KEYWORD to VAR_KEYWORD, - CONST_KEYWORD to VAL_KEYWORD, - SUSPEND_KEYWORD to FUN_KEYWORD + COMPANION_KEYWORD to OBJECT_KEYWORD, + DATA_KEYWORD to CLASS_KEYWORD, + ENUM_KEYWORD to CLASS_KEYWORD, + ANNOTATION_KEYWORD to CLASS_KEYWORD, + SEALED_KEYWORD to CLASS_KEYWORD, + LATEINIT_KEYWORD to VAR_KEYWORD, + CONST_KEYWORD to VAL_KEYWORD, + SUSPEND_KEYWORD to FUN_KEYWORD ) private val KEYWORD_CONSTRUCTS = mapOf( - IF_KEYWORD to "fun foo() { if (caret)", - WHILE_KEYWORD to "fun foo() { while(caret)", - FOR_KEYWORD to "fun foo() { for(caret)", - TRY_KEYWORD to "fun foo() { try {\ncaret\n}", - CATCH_KEYWORD to "fun foo() { try {} catch (caret)", - FINALLY_KEYWORD to "fun foo() { try {\n}\nfinally{\ncaret\n}", - DO_KEYWORD to "fun foo() { do {\ncaret\n}", - INIT_KEYWORD to "class C { init {\ncaret\n}", - CONSTRUCTOR_KEYWORD to "class C { constructor(caret)" + IF_KEYWORD to "fun foo() { if (caret)", + WHILE_KEYWORD to "fun foo() { while(caret)", + FOR_KEYWORD to "fun foo() { for(caret)", + TRY_KEYWORD to "fun foo() { try {\ncaret\n}", + CATCH_KEYWORD to "fun foo() { try {} catch (caret)", + FINALLY_KEYWORD to "fun foo() { try {\n}\nfinally{\ncaret\n}", + DO_KEYWORD to "fun foo() { do {\ncaret\n}", + INIT_KEYWORD to "class C { init {\ncaret\n}", + CONSTRUCTOR_KEYWORD to "class C { constructor(caret)" ) - private val NO_SPACE_AFTER = listOf(THIS_KEYWORD, - SUPER_KEYWORD, - NULL_KEYWORD, - TRUE_KEYWORD, - FALSE_KEYWORD, - BREAK_KEYWORD, - CONTINUE_KEYWORD, - ELSE_KEYWORD, - WHEN_KEYWORD, - FILE_KEYWORD, - DYNAMIC_KEYWORD, - GET_KEYWORD, - SET_KEYWORD).map { it.value} + "companion object" + private val NO_SPACE_AFTER = listOf( + THIS_KEYWORD, + SUPER_KEYWORD, + NULL_KEYWORD, + TRUE_KEYWORD, + FALSE_KEYWORD, + BREAK_KEYWORD, + CONTINUE_KEYWORD, + ELSE_KEYWORD, + WHEN_KEYWORD, + FILE_KEYWORD, + DYNAMIC_KEYWORD, + GET_KEYWORD, + SET_KEYWORD + ).map { it.value } + "companion object" fun complete(position: PsiElement, prefix: String, isJvmModule: Boolean, consumer: (LookupElement) -> Unit) { if (!GENERAL_FILTER.isAcceptable(position, position)) return @@ -187,40 +189,40 @@ object KeywordCompletion { } } - private val GENERAL_FILTER = NotFilter(OrFilter( + private val GENERAL_FILTER = NotFilter( + OrFilter( CommentFilter(), ParentFilter(ClassFilter(KtLiteralStringTemplateEntry::class.java)), ParentFilter(ClassFilter(KtConstantExpression::class.java)), FileFilter(ClassFilter(KtTypeCodeFragment::class.java)), LeftNeighbour(TextFilter(".")), LeftNeighbour(TextFilter("?.")) - )) + ) + ) private class CommentFilter() : ElementFilter { - override fun isAcceptable(element : Any?, context : PsiElement?) - = (element is PsiElement) && KtPsiUtil.isInComment(element) + override fun isAcceptable(element: Any?, context: PsiElement?) = (element is PsiElement) && KtPsiUtil.isInComment(element) - override fun isClassAcceptable(hintClass: Class) - = true + override fun isClassAcceptable(hintClass: Class) = true } - private class ParentFilter(filter : ElementFilter) : PositionElementFilter() { + private class ParentFilter(filter: ElementFilter) : PositionElementFilter() { init { setFilter(filter) } - override fun isAcceptable(element : Any?, context : PsiElement?) : Boolean { + override fun isAcceptable(element: Any?, context: PsiElement?): Boolean { val parent = (element as? PsiElement)?.parent return parent != null && (filter?.isAcceptable(parent, context) ?: true) } } - private class FileFilter(filter : ElementFilter) : PositionElementFilter() { + private class FileFilter(filter: ElementFilter) : PositionElementFilter() { init { setFilter(filter) } - override fun isAcceptable(element : Any?, context : PsiElement?) : Boolean { + override fun isAcceptable(element: Any?, context: PsiElement?): Boolean { val file = (element as? PsiElement)?.containingFile return file != null && (filter?.isAcceptable(file, context) ?: true) } @@ -241,20 +243,20 @@ object KeywordCompletion { var isAfterTry = false var isAfterCatch = false - if (prevLeaf.node.elementType == KtTokens.RBRACE) { - val blockParent = (prevLeaf.parent as? KtBlockExpression)?.parent - when (blockParent) { + if (prevLeaf.node.elementType == RBRACE) { + when ((prevLeaf.parent as? KtBlockExpression)?.parent) { is KtTryExpression -> isAfterTry = true - is KtCatchClause -> { isAfterTry = true; isAfterCatch = true } + is KtCatchClause -> { + isAfterTry = true; isAfterCatch = true + } } } if (isAfterThen) { - if (isAfterTry) { - prefixText += "if (a)\n" - } - else { - prefixText += "if (a) {}\n" + prefixText += if (isAfterTry) { + "if (a)\n" + } else { + "if (a) {}\n" } } if (isAfterTry) { @@ -266,16 +268,15 @@ object KeywordCompletion { } return buildFilterWithContext(prefixText, prevParent, position) - } - else { + } else { val lastExpression = prevParent - .siblings(forward = false, withItself = false) - .firstIsInstanceOrNull() + .siblings(forward = false, withItself = false) + .firstIsInstanceOrNull() if (lastExpression != null) { val contextAfterExpression = lastExpression - .siblings(forward = true, withItself = false) - .takeWhile { it != prevParent } - .joinToString { it.text } + .siblings(forward = true, withItself = false) + .takeWhile { it != prevParent } + .joinToString { it.text } return buildFilterWithContext(prefixText + "x" + contextAfterExpression, prevParent, position) } } @@ -296,13 +297,11 @@ object KeywordCompletion { } is KtDeclaration -> { - val scope = parent.parent - when (scope) { + when (parent.parent) { is KtClassOrObject -> { return if (parent is KtPrimaryConstructor) { buildFilterWithReducedContext("class X ", parent, position) - } - else { + } else { buildFilterWithReducedContext("class X { ", parent, position) } } @@ -330,26 +329,34 @@ object KeywordCompletion { } } - private fun buildFilterWithContext(prefixText: String, - contextElement: PsiElement, - position: PsiElement): (KtKeywordToken) -> Boolean { + private fun buildFilterWithContext( + prefixText: String, + contextElement: PsiElement, + position: PsiElement + ): (KtKeywordToken) -> Boolean { val offset = position.getStartOffsetInAncestor(contextElement) val truncatedContext = contextElement.text!!.substring(0, offset) return buildFilterByText(prefixText + truncatedContext, position) } - private fun buildFilterWithReducedContext(prefixText: String, - contextElement: PsiElement?, - position: PsiElement): (KtKeywordToken) -> Boolean { + private fun buildFilterWithReducedContext( + prefixText: String, + contextElement: PsiElement?, + position: PsiElement + ): (KtKeywordToken) -> Boolean { val builder = StringBuilder() buildReducedContextBefore(builder, position, contextElement) return buildFilterByText(prefixText + builder.toString(), position) } - private fun buildFilesWithKeywordApplication(keywordTokenType: KtKeywordToken, prefixText: String, psiFactory: KtPsiFactory): Sequence { + private fun buildFilesWithKeywordApplication( + keywordTokenType: KtKeywordToken, + prefixText: String, + psiFactory: KtPsiFactory + ): Sequence { return computeKeywordApplications(prefixText, keywordTokenType) - .map { application -> psiFactory.createFile(prefixText + application) } + .map { application -> psiFactory.createFile(prefixText + application) } } @@ -359,7 +366,7 @@ object KeywordCompletion { val elementAt = file.findElementAt(prefixText.length)!! val languageVersionSettings = ModuleUtilCore.findModuleForPsiElement(position)?.languageVersionSettings - ?: LanguageVersionSettingsImpl.DEFAULT + ?: LanguageVersionSettingsImpl.DEFAULT when { !elementAt.node!!.elementType.matchesKeyword(keywordTokenType) -> return false @@ -387,9 +394,29 @@ object KeywordCompletion { is KtEnumEntry -> listOf(ENUM_ENTRY) - is KtClassBody -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, MEMBER_FUNCTION, MEMBER_PROPERTY, FUNCTION, PROPERTY) + is KtClassBody -> listOf( + CLASS_ONLY, + INTERFACE, + OBJECT, + ENUM_CLASS, + ANNOTATION_CLASS, + MEMBER_FUNCTION, + MEMBER_PROPERTY, + FUNCTION, + PROPERTY + ) - is KtFile -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, FUNCTION, PROPERTY) + is KtFile -> listOf( + CLASS_ONLY, + INTERFACE, + OBJECT, + ENUM_CLASS, + ANNOTATION_CLASS, + TOP_LEVEL_FUNCTION, + TOP_LEVEL_PROPERTY, + FUNCTION, + PROPERTY + ) else -> listOf() } @@ -397,22 +424,22 @@ object KeywordCompletion { if (modifierTargets != null && possibleTargets.isNotEmpty() && modifierTargets.none { isModifierTargetSupportedAtLanguageLevel(keywordTokenType, it, languageVersionSettings) - }) return false + } + ) return false - val ownerDeclaration = container?.getParentOfType(strict = true) - val parentTarget = when (ownerDeclaration) { - null -> KotlinTarget.FILE + val parentTarget = when (val ownerDeclaration = container?.getParentOfType(strict = true)) { + null -> FILE is KtClass -> { when { - ownerDeclaration.isInterface() -> KotlinTarget.INTERFACE - ownerDeclaration.isEnum() -> KotlinTarget.ENUM_CLASS - ownerDeclaration.isAnnotation() -> KotlinTarget.ANNOTATION_CLASS - else -> KotlinTarget.CLASS_ONLY + ownerDeclaration.isInterface() -> INTERFACE + ownerDeclaration.isEnum() -> ENUM_CLASS + ownerDeclaration.isAnnotation() -> ANNOTATION_CLASS + else -> CLASS_ONLY } } - is KtObjectDeclaration -> if (ownerDeclaration.isObjectLiteral()) KotlinTarget.OBJECT_LITERAL else KotlinTarget.OBJECT + is KtObjectDeclaration -> if (ownerDeclaration.isObjectLiteral()) OBJECT_LITERAL else OBJECT else -> return keywordTokenType != CONST_KEYWORD } @@ -421,8 +448,8 @@ object KeywordCompletion { if (keywordTokenType == CONST_KEYWORD) { return when (parentTarget) { - KotlinTarget.OBJECT -> true - KotlinTarget.FILE -> { + OBJECT -> true + FILE -> { val prevSiblings = elementAt.parent.siblings(withItself = false, forward = false) val hasLineBreak = prevSiblings .takeWhile { it is PsiWhiteSpace || it.isSemicolon() } @@ -440,25 +467,25 @@ object KeywordCompletion { } } - return fun (keywordTokenType): Boolean { + return fun(keywordTokenType): Boolean { val files = buildFilesWithKeywordApplication(keywordTokenType, prefixText, psiFactory) return files.any { file -> isKeywordCorrectlyApplied(keywordTokenType, file); } } } - private fun PsiElement.isSemicolon() = node.elementType == KtTokens.SEMICOLON + private fun PsiElement.isSemicolon() = node.elementType == SEMICOLON private fun isErrorElementBefore(token: PsiElement): Boolean { for (leaf in token.prevLeafs) { if (leaf is PsiWhiteSpace || leaf is PsiComment) continue - if (leaf.parentsWithSelf.any { it is PsiErrorElement } ) return true + if (leaf.parentsWithSelf.any { it is PsiErrorElement }) return true if (leaf.textLength != 0) break } return false } private fun IElementType.matchesKeyword(keywordType: KtKeywordToken): Boolean { - return when(this) { + return when (this) { keywordType -> true NOT_IN -> keywordType == IN_KEYWORD NOT_IS -> keywordType == IS_KEYWORD @@ -468,29 +495,28 @@ object KeywordCompletion { private fun isModifierSupportedAtLanguageLevel(keyword: KtKeywordToken, languageVersionSettings: LanguageVersionSettings): Boolean { val feature = when (keyword) { - KtTokens.TYPE_ALIAS_KEYWORD -> LanguageFeature.TypeAliases - KtTokens.HEADER_KEYWORD, KtTokens.IMPL_KEYWORD -> return false - KtTokens.EXPECT_KEYWORD, KtTokens.ACTUAL_KEYWORD -> LanguageFeature.MultiPlatformProjects - KtTokens.SUSPEND_KEYWORD -> LanguageFeature.Coroutines + TYPE_ALIAS_KEYWORD -> LanguageFeature.TypeAliases + HEADER_KEYWORD, IMPL_KEYWORD -> return false + EXPECT_KEYWORD, ACTUAL_KEYWORD -> LanguageFeature.MultiPlatformProjects + SUSPEND_KEYWORD -> LanguageFeature.Coroutines else -> return true } return languageVersionSettings.supportsFeature(feature) } private fun isModifierTargetSupportedAtLanguageLevel( - keyword: KtKeywordToken, - target: KotlinTarget, - languageVersionSettings: LanguageVersionSettings + keyword: KtKeywordToken, + target: KotlinTarget, + languageVersionSettings: LanguageVersionSettings ): Boolean { - if (keyword == KtTokens.LATEINIT_KEYWORD) { + if (keyword == LATEINIT_KEYWORD) { val feature = when (target) { TOP_LEVEL_PROPERTY -> LanguageFeature.LateinitTopLevelProperties LOCAL_VARIABLE -> LanguageFeature.LateinitLocalVariables else -> return true } return languageVersionSettings.supportsFeature(feature) - } - else { + } else { return true } } @@ -519,8 +545,7 @@ object KeywordCompletion { if (child == prevDeclaration) { builder.appendReducedText(child) } - } - else { + } else { builder.append(child!!.text) } @@ -532,8 +557,7 @@ object KeywordCompletion { var child = element.firstChild if (child == null) { append(element.text!!) - } - else { + } else { while (child != null) { when (child) { is KtBlockExpression, is KtClassBody -> append("{}") @@ -550,14 +574,11 @@ object KeywordCompletion { return parent!!.getStartOffsetInAncestor(ancestor) + startOffsetInParent } - private fun PsiElement.goUpWhileIsLastChild(): Sequence { - return generateSequence(this) { - if (it is PsiFile) - null - else if (it != it.parent.lastChild) - null - else - it.parent + private fun PsiElement.goUpWhileIsLastChild(): Sequence = generateSequence(this) { + when { + it is PsiFile -> null + it != it.parent.lastChild -> null + else -> it.parent } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt index 71b1ac38b0e..ff4a221b948 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt @@ -115,11 +115,13 @@ class OverridesCompletion( val override = KtTokens.OVERRIDE_KEYWORD.value tailrec fun calcStartOffset(startOffset: Int, diff: Int = 0): Int { - if (context.document.text[startOffset - 1].isWhitespace()) { - return calcStartOffset(startOffset - 1, diff + 1) - } else if (context.document.text.substring(startOffset - override.length, startOffset) == override) { - return startOffset - override.length - } else return diff + startOffset + return when { + context.document.text[startOffset - 1].isWhitespace() -> calcStartOffset(startOffset - 1, diff + 1) + context.document.text.substring(startOffset - override.length, startOffset) == override -> { + startOffset - override.length + } + else -> diff + startOffset + } } val startOffset = calcStartOffset(context.startOffset) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/AbstractKeywordCompletionTest.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/AbstractKeywordCompletionTest.kt index 25356704a7b..321bef33521 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/AbstractKeywordCompletionTest.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/AbstractKeywordCompletionTest.kt @@ -22,12 +22,10 @@ abstract class AbstractKeywordCompletionTest : KotlinFixtureCompletionBaseTestCa return items.filter { it.`object` is KeywordLookupObject }.toTypedArray() } - override fun getProjectDescriptor(): KotlinLightProjectDescriptor { - when { - "LangLevel10" in fileName() -> return KotlinProjectDescriptorWithFacet.KOTLIN_10 - "LangLevel11" in fileName() -> return KotlinProjectDescriptorWithFacet.KOTLIN_11 - else -> return KotlinProjectDescriptorWithFacet.KOTLIN_STABLE_WITH_MULTIPLATFORM - } + override fun getProjectDescriptor(): KotlinLightProjectDescriptor = when { + "LangLevel10" in fileName() -> KotlinProjectDescriptorWithFacet.KOTLIN_10 + "LangLevel11" in fileName() -> KotlinProjectDescriptorWithFacet.KOTLIN_11 + else -> KotlinProjectDescriptorWithFacet.KOTLIN_STABLE_WITH_MULTIPLATFORM } override fun defaultInvocationCount() = 1 diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index a1e0affba02..2f64e033be3 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -60,20 +60,20 @@ import java.lang.reflect.Modifier import java.util.* class KotlinIndicesHelper( - private val resolutionFacade: ResolutionFacade, - private val scope: GlobalSearchScope, - visibilityFilter: (DeclarationDescriptor) -> Boolean, - private val declarationTranslator: (KtDeclaration) -> KtDeclaration? = { it }, - applyExcludeSettings: Boolean = true, - private val filterOutPrivate: Boolean = true, - private val file: KtFile? = null + private val resolutionFacade: ResolutionFacade, + private val scope: GlobalSearchScope, + visibilityFilter: (DeclarationDescriptor) -> Boolean, + private val declarationTranslator: (KtDeclaration) -> KtDeclaration? = { it }, + applyExcludeSettings: Boolean = true, + private val filterOutPrivate: Boolean = true, + private val file: KtFile? = null ) { private val moduleDescriptor = resolutionFacade.moduleDescriptor private val project = resolutionFacade.project private val scopeWithoutKotlin = scope.excludeKotlinSources() as GlobalSearchScope - private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@ { + private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@{ if (resolutionFacade.frontendService().isHiddenInResolution(it)) return@filter false if (!visibilityFilter(it)) return@filter false if (applyExcludeSettings && it.isExcludedFromAutoImport(project, file)) return@filter false @@ -85,31 +85,32 @@ class KotlinIndicesHelper( declarations.addTopLevelNonExtensionCallablesByName(KotlinFunctionShortNameIndex.getInstance(), name) declarations.addTopLevelNonExtensionCallablesByName(KotlinPropertyShortNameIndex.getInstance(), name) return declarations - .flatMap { it.resolveToDescriptors() } - .filter { descriptorFilter(it) } + .flatMap { it.resolveToDescriptors() } + .filter { descriptorFilter(it) } } private fun MutableSet.addTopLevelNonExtensionCallablesByName( - index: StringStubIndexExtension, - name: String + index: StringStubIndexExtension, + name: String ) { - index.get(name, project, scope).filterTo(this) { it.parent is KtFile && it is KtCallableDeclaration && it.receiverTypeReference == null } + index.get(name, project, scope) + .filterTo(this) { it.parent is KtFile && it is KtCallableDeclaration && it.receiverTypeReference == null } } fun getTopLevelExtensionOperatorsByName(name: String): Collection { return KotlinFunctionShortNameIndex.getInstance().get(name, project, scope) - .filter { it.parent is KtFile && it.receiverTypeReference != null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) } - .flatMap { it.resolveToDescriptors() } - .filter { descriptorFilter(it) && it.extensionReceiverParameter != null } - .distinct() + .filter { it.parent is KtFile && it.receiverTypeReference != null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) } + .flatMap { it.resolveToDescriptors() } + .filter { descriptorFilter(it) && it.extensionReceiverParameter != null } + .distinct() } fun getMemberOperatorsByName(name: String): Collection { return KotlinFunctionShortNameIndex.getInstance().get(name, project, scope) - .filter { it.parent is KtClassBody && it.receiverTypeReference == null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) } - .flatMap { it.resolveToDescriptors() } - .filter { descriptorFilter(it) && it.extensionReceiverParameter == null } - .distinct() + .filter { it.parent is KtClassBody && it.receiverTypeReference == null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) } + .flatMap { it.resolveToDescriptors() } + .filter { descriptorFilter(it) && it.extensionReceiverParameter == null } + .distinct() } fun processTopLevelCallables(nameFilter: (String) -> Boolean, processor: (CallableDescriptor) -> Unit) { @@ -135,21 +136,22 @@ class KotlinIndicesHelper( } fun getCallableTopLevelExtensions( - callTypeAndReceiver: CallTypeAndReceiver<*, *>, - position: KtExpression, - bindingContext: BindingContext, - nameFilter: (String) -> Boolean + callTypeAndReceiver: CallTypeAndReceiver<*, *>, + position: KtExpression, + bindingContext: BindingContext, + nameFilter: (String) -> Boolean ): Collection { - val receiverTypes = callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false) - ?: return emptyList() + val receiverTypes = + callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false) + ?: return emptyList() return getCallableTopLevelExtensions(callTypeAndReceiver, receiverTypes, nameFilter) } fun getCallableTopLevelExtensions( - callTypeAndReceiver: CallTypeAndReceiver<*, *>, - receiverTypes: Collection, - nameFilter: (String) -> Boolean, - declarationFilter: (KtDeclaration) -> Boolean = { true } + callTypeAndReceiver: CallTypeAndReceiver<*, *>, + receiverTypes: Collection, + nameFilter: (String) -> Boolean, + declarationFilter: (KtDeclaration) -> Boolean = { true } ): Collection { if (receiverTypes.isEmpty()) return emptyList() @@ -159,13 +161,13 @@ class KotlinIndicesHelper( val index = KotlinTopLevelExtensionsByReceiverTypeIndex.INSTANCE val declarations = index.getAllKeys(project) - .asSequence() - .filter { - ProgressManager.checkCanceled() - KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames - && nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it)) - } - .flatMap { index.get(it, project, scope).asSequence() }.filter(declarationFilter) + .asSequence() + .filter { + ProgressManager.checkCanceled() + KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames + && nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it)) + } + .flatMap { index.get(it, project, scope).asSequence() }.filter(declarationFilter) val suitableExtensions = findSuitableExtensions(declarations, receiverTypes, callTypeAndReceiver.callType) @@ -234,9 +236,9 @@ class KotlinIndicesHelper( * Check that function or property with the given qualified name can be resolved in given scope and called on given receiver */ private fun findSuitableExtensions( - declarations: Sequence, - receiverTypes: Collection, - callType: CallType<*> + declarations: Sequence, + receiverTypes: Collection, + callType: CallType<*> ): Collection { val result = LinkedHashSet() @@ -253,24 +255,24 @@ class KotlinIndicesHelper( fun getJvmClassesByName(name: String): Collection { return PsiShortNamesCache.getInstance(project).getClassesByName(name, scope) - .filter { it in scope && it.containingFile != null } - .mapNotNull { it.resolveToDescriptor(resolutionFacade) } - .filter(descriptorFilter) - .toSet() + .filter { it in scope && it.containingFile != null } + .mapNotNull { it.resolveToDescriptor(resolutionFacade) } + .filter(descriptorFilter) + .toSet() } fun getKotlinEnumsByName(name: String): Collection { return KotlinClassShortNameIndex.getInstance()[name, project, scope] - .filter { it is KtEnumEntry && it in scope } - .mapNotNull { it.unsafeResolveToDescriptor() } - .filter(descriptorFilter) - .toSet() + .filter { it is KtEnumEntry && it in scope } + .mapNotNull { it.unsafeResolveToDescriptor() } + .filter(descriptorFilter) + .toSet() } fun processJvmCallablesByName( - name: String, - filter: (PsiMember) -> Boolean, - processor: (CallableDescriptor) -> Unit + name: String, + filter: (PsiMember) -> Boolean, + processor: (CallableDescriptor) -> Unit ) { val javaDeclarations = getJavaCallables(name, PsiShortNamesCache.getInstance(project)) val processed = HashSet() @@ -295,16 +297,13 @@ class KotlinIndicesHelper( val shortNamesCache = PsiShortNamesCache.getInstance(project) if (shortNamesCache is CompositeShortNamesCache) { try { - fun getMyCachesField(clazz: Class): Field { - try { - return clazz.getDeclaredField("myCaches") - } - catch (e: NoSuchFieldException) { - // In case the class is proguarded - return clazz.declaredFields.first { - Modifier.isPrivate(it.modifiers) && Modifier.isFinal(it.modifiers) && !Modifier.isStatic(it.modifiers) - && it.type.isArray && it.type.componentType == PsiShortNamesCache::class.java - } + fun getMyCachesField(clazz: Class): Field = try { + clazz.getDeclaredField("myCaches") + } catch (e: NoSuchFieldException) { + // In case the class is proguarded + clazz.declaredFields.first { + Modifier.isPrivate(it.modifiers) && Modifier.isFinal(it.modifiers) && !Modifier.isStatic(it.modifiers) + && it.type.isArray && it.type.componentType == PsiShortNamesCache::class.java } } @@ -315,26 +314,25 @@ class KotlinIndicesHelper( @Suppress("UNCHECKED_CAST") return@lazy (myCachesField.get(shortNamesCache) as Array).filter { it !is KotlinShortNamesCache - && it::class.java.name != "com.android.tools.idea.databinding.BrShortNamesCache" - && it::class.java.name != "com.android.tools.idea.databinding.DataBindingComponentShortNamesCache" - && it::class.java.name != "com.android.tools.idea.databinding.DataBindingShortNamesCache" + && it::class.java.name != "com.android.tools.idea.databinding.BrShortNamesCache" + && it::class.java.name != "com.android.tools.idea.databinding.DataBindingComponentShortNamesCache" + && it::class.java.name != "com.android.tools.idea.databinding.DataBindingShortNamesCache" } - } - finally { + } finally { myCachesField.isAccessible = previousIsAccessible } - } - catch (thr: Throwable) { + } catch (thr: Throwable) { // Our dirty hack isn't working } } return@lazy null } + private fun getJavaCallables(name: String, shortNamesCache: PsiShortNamesCache): Sequence { filteredShortNamesCaches?.let { caches -> return getCallablesByName(name, scopeWithoutKotlin, caches) } return shortNamesCache.getFieldsByNameUnfiltered(name, scopeWithoutKotlin).asSequence() + - shortNamesCache.getMethodsByNameUnfiltered(name, scopeWithoutKotlin).asSequence() + shortNamesCache.getMethodsByNameUnfiltered(name, scopeWithoutKotlin).asSequence() } private fun getCallablesByName(name: String, scope: GlobalSearchScope, caches: List): Sequence { @@ -359,9 +357,9 @@ class KotlinIndicesHelper( } fun processKotlinCallablesByName( - name: String, - filter: (KtNamedDeclaration) -> Boolean, - processor: (CallableDescriptor) -> Unit + name: String, + filter: (KtNamedDeclaration) -> Boolean, + processor: (CallableDescriptor) -> Unit ) { val functions: Sequence = KotlinFunctionShortNameIndex.getInstance().get(name, project, scope).asSequence() val properties: Sequence = KotlinPropertyShortNameIndex.getInstance().get(name, project, scope).asSequence() @@ -377,45 +375,46 @@ class KotlinIndicesHelper( } fun getKotlinClasses( - nameFilter: (String) -> Boolean, - psiFilter: (KtDeclaration) -> Boolean = { true }, - kindFilter: (ClassKind) -> Boolean = { true }): Collection { + nameFilter: (String) -> Boolean, + psiFilter: (KtDeclaration) -> Boolean = { true }, + kindFilter: (ClassKind) -> Boolean = { true } + ): Collection { val index = KotlinFullClassNameIndex.getInstance() return index.getAllKeys(project).asSequence() - .filter { fqName -> - ProgressManager.checkCanceled() - nameFilter(fqName.substringAfterLast('.')) + .filter { fqName -> + ProgressManager.checkCanceled() + nameFilter(fqName.substringAfterLast('.')) + } + .toList() + .flatMap { fqName -> + index[fqName, project, scope].flatMap { classOrObject -> + classOrObject.resolveToDescriptorsWithHack(psiFilter).filterIsInstance() } - .toList() - .flatMap { fqName -> - index[fqName, project, scope].flatMap { classOrObject -> - classOrObject.resolveToDescriptorsWithHack(psiFilter).filterIsInstance() - } - } - .filter { kindFilter(it.kind) && descriptorFilter(it) } + } + .filter { kindFilter(it.kind) && descriptorFilter(it) } } fun getTopLevelTypeAliases(nameFilter: (String) -> Boolean): Collection { val index = KotlinTopLevelTypeAliasFqNameIndex.getInstance() return index.getAllKeys(project).asSequence() - .filter { - ProgressManager.checkCanceled() - nameFilter(it.substringAfterLast('.')) - } - .toList() - .flatMap { fqName -> - index[fqName, project, scope] - .flatMap { it.resolveToDescriptors() } + .filter { + ProgressManager.checkCanceled() + nameFilter(it.substringAfterLast('.')) + } + .toList() + .flatMap { fqName -> + index[fqName, project, scope] + .flatMap { it.resolveToDescriptors() } - } - .filter(descriptorFilter) + } + .filter(descriptorFilter) } fun processObjectMembers( - descriptorKindFilter: DescriptorKindFilter, - nameFilter: (String) -> Boolean, - filter: (KtNamedDeclaration, KtObjectDeclaration) -> Boolean, - processor: (DeclarationDescriptor) -> Unit + descriptorKindFilter: DescriptorKindFilter, + nameFilter: (String) -> Boolean, + filter: (KtNamedDeclaration, KtObjectDeclaration) -> Boolean, + processor: (DeclarationDescriptor) -> Unit ) { fun processIndex(index: StringStubIndexExtension) { for (name in index.getAllKeys(project)) { @@ -445,15 +444,19 @@ class KotlinIndicesHelper( } fun processJavaStaticMembers( - descriptorKindFilter: DescriptorKindFilter, - nameFilter: (String) -> Boolean, - processor: (DeclarationDescriptor) -> Unit + descriptorKindFilter: DescriptorKindFilter, + nameFilter: (String) -> Boolean, + processor: (DeclarationDescriptor) -> Unit ) { val idFilter = IdFilter.getProjectIdFilter(resolutionFacade.project, false) val shortNamesCache = PsiShortNamesCache.getInstance(project) val allMethodNames = hashSetOf() - shortNamesCache.processAllMethodNames({ name -> if (nameFilter(name)) allMethodNames.add(name); true }, scopeWithoutKotlin, idFilter) + shortNamesCache.processAllMethodNames( + { name -> if (nameFilter(name)) allMethodNames.add(name); true }, + scopeWithoutKotlin, + idFilter + ) for (name in allMethodNames) { ProgressManager.checkCanceled() @@ -469,9 +472,9 @@ class KotlinIndicesHelper( // SAM-adapter val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters() syntheticScopes.collectSyntheticStaticFunctions(container.staticScope, descriptor.name, NoLookupLocation.FROM_IDE) - .filterIsInstance>() - .firstOrNull { it.baseDescriptorForSynthetic.original == descriptor.original } - ?.let { processor(it) } + .filterIsInstance>() + .firstOrNull { it.baseDescriptorForSynthetic.original == descriptor.original } + ?.let { processor(it) } } } } @@ -493,15 +496,15 @@ class KotlinIndicesHelper( } private inline fun KtNamedDeclaration.resolveToDescriptors(): Collection { - return resolveToDescriptorsWithHack({ true }).filterIsInstance() + return resolveToDescriptorsWithHack { true }.filterIsInstance() } private fun KtNamedDeclaration.resolveToDescriptorsWithHack( - psiFilter: (KtDeclaration) -> Boolean): Collection { + psiFilter: (KtDeclaration) -> Boolean + ): Collection { if (containingKtFile.isCompiled) { //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations return resolutionFacade.resolveImportReference(moduleDescriptor, fqName!!) - } - else { + } else { val translatedDeclaration = declarationTranslator(this) ?: return emptyList() if (!psiFilter(translatedDeclaration)) return emptyList() diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinBreadcrumbsInfoProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinBreadcrumbsInfoProvider.kt index 168a0da42ff..9cff63b4f57 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinBreadcrumbsInfoProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinBreadcrumbsInfoProvider.kt @@ -43,21 +43,21 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { } private val handlers = listOf>( - LambdaHandler, - AnonymousObjectHandler, - AnonymousFunctionHandler, - PropertyAccessorHandler, - DeclarationHandler, - IfThenHandler, - ElseHandler, - TryHandler, - CatchHandler, - FinallyHandler, - WhileHandler, - DoWhileHandler, - WhenHandler, - WhenEntryHandler, - ForHandler + LambdaHandler, + AnonymousObjectHandler, + AnonymousFunctionHandler, + PropertyAccessorHandler, + DeclarationHandler, + IfThenHandler, + ElseHandler, + TryHandler, + CatchHandler, + FinallyHandler, + WhileHandler, + DoWhileHandler, + WhenHandler, + WhenEntryHandler, + ForHandler ) private object LambdaHandler : ElementHandler(KtFunctionLiteral::class) { @@ -83,8 +83,7 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { if (callExpression.valueArgumentList != null) { appendCallArguments(callExpression) - } - else { + } else { if (label.isNotEmpty()) append(" ") } append(lambdaText) @@ -149,8 +148,7 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { append(",$ellipsis") } } - } - else { + } else { append(superTypeEntries.joinToString(separator = ", ") { it.typeReference?.text ?: "" }.truncateEnd(kind)) } } @@ -166,8 +164,10 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { private fun KtNamedFunction.buildText(kind: TextKind): String { return "fun(" + - valueParameters.joinToString(separator = ", ") { if (kind == TextKind.INFO) it.name ?: "" else it.text }.truncateEnd(kind) + - ")" + valueParameters.joinToString(separator = ", ") { if (kind == TextKind.INFO) it.name ?: "" else it.text }.truncateEnd( + kind + ) + + ")" } } @@ -211,19 +211,16 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { } - override fun elementTooltip(element: KtDeclaration): String { - try { - return ElementDescriptionUtil.getElementDescription(element, RefactoringDescriptionLocation.WITH_PARENT) - } - catch (e: IndexNotReadyException) { - return "Indexing..." - } + override fun elementTooltip(element: KtDeclaration): String = try { + ElementDescriptionUtil.getElementDescription(element, RefactoringDescriptionLocation.WITH_PARENT) + } catch (e: IndexNotReadyException) { + "Indexing..." } } private abstract class ConstructWithExpressionHandler( - private val constructName: String, - type: KClass + private val constructName: String, + type: KClass ) : ElementHandler(type) { protected abstract fun extractExpression(element: TElement): KtExpression? @@ -273,7 +270,7 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { private object ElseHandler : ElementHandler(KtContainerNode::class) { override fun accepts(element: KtContainerNode): Boolean { return element.node.elementType == KtNodeTypes.ELSE - && (element.parent as KtIfExpression).`else` !is KtIfExpression // filter out "else if" + && (element.parent as KtIfExpression).`else` !is KtIfExpression // filter out "else if" } override fun elementInfo(element: KtContainerNode): String { @@ -357,20 +354,18 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { override fun elementTooltip(element: KtExpression) = element.buildText(TextKind.TOOLTIP) private fun KtExpression.buildText(kind: TextKind): String { - with (parent as KtWhenEntry) { + with(parent as KtWhenEntry) { if (isElse) { return "else ->" - } - else { + } else { val condition = conditions.firstOrNull() ?: return "->" val firstConditionText = condition.buildText(kind) return if (conditions.size == 1) { - firstConditionText + " ->" - } - else { + "$firstConditionText ->" + } else { //TODO: show all conditions for tooltip - (if (firstConditionText.endsWith(ellipsis)) firstConditionText else firstConditionText + ",$ellipsis") + " ->" + (if (firstConditionText.endsWith(ellipsis)) firstConditionText else "$firstConditionText,$ellipsis") + " ->" } } } @@ -402,10 +397,10 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { override fun elementTooltip(element: KtContainerNode) = element.buildText(TextKind.TOOLTIP) private fun KtContainerNode.buildText(kind: TextKind): String { - with (bodyOwner() as KtForExpression) { + with(bodyOwner() as KtForExpression) { val parameterText = loopParameter?.nameAsName?.render() ?: destructuringDeclaration?.text ?: return "for" val collectionText = loopRange?.text ?: "" - val text = (parameterText + " in " + collectionText).truncateEnd(kind) + val text = ("$parameterText in $collectionText").truncateEnd(kind) return labelText() + "for($text)" } } @@ -468,7 +463,7 @@ class KotlinBreadcrumbsInfoProvider : BreadcrumbsInfoProvider() { return if (length > maxLength) ellipsis + substring(length - maxLength - 1) else this } - val ellipsis = "${Typography.ellipsis}" + const val ellipsis = "${Typography.ellipsis}" fun KtContainerNode.bodyOwner(): KtExpression? { return if (node.elementType == KtNodeTypes.BODY) parent as KtExpression else null diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/elementSelectionUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/elementSelectionUtils.kt index 5126f845423..27ae0684790 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/elementSelectionUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/elementSelectionUtils.kt @@ -45,18 +45,20 @@ import kotlin.math.min @Throws(IntroduceRefactoringException::class) fun selectElement( - editor: Editor, - file: KtFile, - elementKinds: Collection, - callback: (PsiElement?) -> Unit + editor: Editor, + file: KtFile, + elementKinds: Collection, + callback: (PsiElement?) -> Unit ) = selectElement(editor, file, true, elementKinds, callback) @Throws(IntroduceRefactoringException::class) -fun selectElement(editor: Editor, - file: KtFile, - failOnEmptySuggestion: Boolean, - elementKinds: Collection, - callback: (PsiElement?) -> Unit) { +fun selectElement( + editor: Editor, + file: KtFile, + failOnEmptySuggestion: Boolean, + elementKinds: Collection, + callback: (PsiElement?) -> Unit +) { if (editor.selectionModel.hasSelection()) { var selectionStart = editor.selectionModel.selectionStart var selectionEnd = editor.selectionModel.selectionEnd @@ -64,8 +66,17 @@ fun selectElement(editor: Editor, var firstElement: PsiElement = file.findElementAt(selectionStart)!! var lastElement: PsiElement = file.findElementAt(selectionEnd - 1)!! - if (PsiTreeUtil.getParentOfType(firstElement, KtLiteralStringTemplateEntry::class.java, KtEscapeStringTemplateEntry::class.java) == null - && PsiTreeUtil.getParentOfType(lastElement, KtLiteralStringTemplateEntry::class.java, KtEscapeStringTemplateEntry::class.java) == null) { + if (PsiTreeUtil.getParentOfType( + firstElement, + KtLiteralStringTemplateEntry::class.java, + KtEscapeStringTemplateEntry::class.java + ) == null + && PsiTreeUtil.getParentOfType( + lastElement, + KtLiteralStringTemplateEntry::class.java, + KtEscapeStringTemplateEntry::class.java + ) == null + ) { firstElement = firstElement.getNextSiblingIgnoringWhitespaceAndComments(true)!! lastElement = lastElement.getPrevSiblingIgnoringWhitespaceAndComments(true)!! selectionStart = firstElement.textRange.startOffset @@ -73,11 +84,10 @@ fun selectElement(editor: Editor, } val element = elementKinds.asSequence() - .mapNotNull { findElement(file, selectionStart, selectionEnd, failOnEmptySuggestion, it) } - .firstOrNull() + .mapNotNull { findElement(file, selectionStart, selectionEnd, failOnEmptySuggestion, it) } + .firstOrNull() callback(element) - } - else { + } else { val offset = editor.caretModel.offset smartSelectElement(editor, file, offset, failOnEmptySuggestion, elementKinds, callback) } @@ -85,9 +95,9 @@ fun selectElement(editor: Editor, @Throws(IntroduceRefactoringException::class) fun getSmartSelectSuggestions( - file: PsiFile, - offset: Int, - elementKind: CodeInsightUtils.ElementKind + file: PsiFile, + offset: Int, + elementKind: CodeInsightUtils.ElementKind ): List { if (offset < 0) return emptyList() @@ -97,41 +107,38 @@ fun getSmartSelectSuggestions( val elements = ArrayList() while (element != null && !(element is KtBlockExpression && element.parent !is KtFunctionLiteral) && - element !is KtNamedFunction - && element !is KtClassBody) { + element !is KtNamedFunction + && element !is KtClassBody + ) { var addElement = false var keepPrevious = true if (element is KtTypeElement) { addElement = - elementKind == CodeInsightUtils.ElementKind.TYPE_ELEMENT - && element.getParentOfTypeAndBranch(true) { qualifier } == null + elementKind == CodeInsightUtils.ElementKind.TYPE_ELEMENT + && element.getParentOfTypeAndBranch(true) { qualifier } == null if (!addElement) { keepPrevious = false } - } - else if (element is KtExpression && element !is KtStatementExpression) { + } else if (element is KtExpression && element !is KtStatementExpression) { addElement = elementKind == CodeInsightUtils.ElementKind.EXPRESSION if (addElement) { if (element is KtParenthesizedExpression) { addElement = false - } - else if (KtPsiUtil.isLabelIdentifierExpression(element)) { + } else if (KtPsiUtil.isLabelIdentifierExpression(element)) { addElement = false - } - else if (element.parent is KtQualifiedExpression) { + } else if (element.parent is KtQualifiedExpression) { val qualifiedExpression = element.parent as KtQualifiedExpression if (qualifiedExpression.receiverExpression !== element) { addElement = false } - } - else if (element.parent is KtCallElement - || element.parent is KtThisExpression - || PsiTreeUtil.getParentOfType(element, KtSuperExpression::class.java) != null) { + } else if (element.parent is KtCallElement + || element.parent is KtThisExpression + || PsiTreeUtil.getParentOfType(element, KtSuperExpression::class.java) != null + ) { addElement = false - } - else if (element.parent is KtOperationExpression) { + } else if (element.parent is KtOperationExpression) { val operationExpression = element.parent as KtOperationExpression if (operationExpression.operationReference === element) { addElement = false @@ -162,12 +169,12 @@ fun getSmartSelectSuggestions( @Throws(IntroduceRefactoringException::class) private fun smartSelectElement( - editor: Editor, - file: PsiFile, - offset: Int, - failOnEmptySuggestion: Boolean, - elementKinds: Collection, - callback: (PsiElement?) -> Unit + editor: Editor, + file: PsiFile, + offset: Int, + failOnEmptySuggestion: Boolean, + elementKinds: Collection, + callback: (PsiElement?) -> Unit ) { val elements = elementKinds.flatMap { getSmartSelectSuggestions(file, offset, it) } if (elements.isEmpty()) { @@ -189,7 +196,13 @@ private fun smartSelectElement( val list = JBList(model) list.cellRenderer = object : DefaultListCellRenderer() { - override fun getListCellRendererComponent(list: JList<*>, value: Any?, index: Int, isSelected: Boolean, cellHasFocus: Boolean): Component { + override fun getListCellRendererComponent( + list: JList<*>, + value: Any?, + index: Int, + isSelected: Boolean, + cellHasFocus: Boolean + ): Component { val rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus) val element = value as KtElement? if (element!!.isValid) { @@ -210,28 +223,28 @@ private fun smartSelectElement( var title = "Elements" if (elementKinds.size == 1) { - when (elementKinds.iterator().next()) { - CodeInsightUtils.ElementKind.EXPRESSION -> title = "Expressions" - CodeInsightUtils.ElementKind.TYPE_ELEMENT, CodeInsightUtils.ElementKind.TYPE_CONSTRUCTOR -> title = "Types" + title = when (elementKinds.iterator().next()) { + CodeInsightUtils.ElementKind.EXPRESSION -> "Expressions" + CodeInsightUtils.ElementKind.TYPE_ELEMENT, CodeInsightUtils.ElementKind.TYPE_CONSTRUCTOR -> "Types" } } JBPopupFactory.getInstance() - .createListPopupBuilder(list) - .setTitle(title) - .setMovable(false) - .setResizable(false) - .setRequestFocus(true) - .setItemChoosenCallback { callback(list.selectedValue as KtElement) } - .addListener( - object : JBPopupAdapter() { - override fun onClosed(event: LightweightWindowEvent) { - highlighter.dropHighlight() - } - } - ) - .createPopup() - .showInBestPositionFor(editor) + .createListPopupBuilder(list) + .setTitle(title) + .setMovable(false) + .setResizable(false) + .setRequestFocus(true) + .setItemChoosenCallback { callback(list.selectedValue as KtElement) } + .addListener( + object : JBPopupAdapter() { + override fun onClosed(event: LightweightWindowEvent) { + highlighter.dropHighlight() + } + } + ) + .createPopup() + .showInBestPositionFor(editor) } fun getExpressionShortText(element: KtElement): String { @@ -244,11 +257,11 @@ fun getExpressionShortText(element: KtElement): String { @Throws(IntroduceRefactoringException::class) private fun findElement( - file: KtFile, - startOffset: Int, - endOffset: Int, - failOnNoExpression: Boolean, - elementKind: CodeInsightUtils.ElementKind + file: KtFile, + startOffset: Int, + endOffset: Int, + failOnNoExpression: Boolean, + elementKind: CodeInsightUtils.ElementKind ): PsiElement? { var element = CodeInsightUtils.findElement(file, startOffset, endOffset, elementKind) if (element == null && elementKind == CodeInsightUtils.ElementKind.EXPRESSION) {