idea: cleanup code
This commit is contained in:
+14
-27
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -34,19 +23,20 @@ import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
|
||||
class AllClassesCompletion(private val parameters: CompletionParameters,
|
||||
private val kotlinIndicesHelper: KotlinIndicesHelper,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val kindFilter: (ClassKind) -> Boolean,
|
||||
private val includeTypeAliases: Boolean,
|
||||
private val includeJavaClassesNotToBeUsed: Boolean
|
||||
class AllClassesCompletion(
|
||||
private val parameters: CompletionParameters,
|
||||
private val kotlinIndicesHelper: KotlinIndicesHelper,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val kindFilter: (ClassKind) -> Boolean,
|
||||
private val includeTypeAliases: Boolean,
|
||||
private val includeJavaClassesNotToBeUsed: Boolean
|
||||
) {
|
||||
fun collect(classifierDescriptorCollector: (ClassifierDescriptorWithTypeParameters) -> Unit, javaClassCollector: (PsiClass) -> Unit) {
|
||||
|
||||
@@ -60,14 +50,11 @@ class AllClassesCompletion(private val parameters: CompletionParameters,
|
||||
}
|
||||
}
|
||||
|
||||
kotlinIndicesHelper
|
||||
.getKotlinClasses({ prefixMatcher.prefixMatches(it) }, kindFilter = kindFilter)
|
||||
.forEach { classifierDescriptorCollector(it) }
|
||||
kotlinIndicesHelper.getKotlinClasses({ prefixMatcher.prefixMatches(it) }, kindFilter = kindFilter)
|
||||
.forEach { classifierDescriptorCollector(it) }
|
||||
|
||||
if (includeTypeAliases) {
|
||||
kotlinIndicesHelper
|
||||
.getTopLevelTypeAliases(prefixMatcher.asStringNameFilter())
|
||||
.forEach { classifierDescriptorCollector(it) }
|
||||
kotlinIndicesHelper.getTopLevelTypeAliases(prefixMatcher.asStringNameFilter()).forEach { classifierDescriptorCollector(it) }
|
||||
}
|
||||
|
||||
if (TargetPlatformDetector.getPlatform(parameters.originalFile as KtFile).isJvm()) {
|
||||
|
||||
+12
-19
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -55,12 +44,12 @@ import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptorKindExclude
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
@@ -206,7 +195,9 @@ class BasicCompletionSession(
|
||||
// no auto-popup on typing after "val", "var" and "fun" because it's likely the name of the declaration which is being typed by user
|
||||
if (parameters.invocationCount == 0) {
|
||||
val suppressOtherCompletion = when (declaration) {
|
||||
is KtNamedFunction, is KtProperty -> prefixMatcher.prefix.let { it.isEmpty() || it[0].isLowerCase() /* function name usually starts with lower case letter */ }
|
||||
is KtNamedFunction, is KtProperty -> prefixMatcher.prefix.let {
|
||||
it.isEmpty() || it[0].isLowerCase() /* function name usually starts with lower case letter */
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
if (suppressOtherCompletion) return
|
||||
@@ -263,7 +254,9 @@ class BasicCompletionSession(
|
||||
}
|
||||
|
||||
// getting root packages from scope is very slow so we do this in alternative way
|
||||
if (callTypeAndReceiver.receiver == null && callTypeAndReceiver.callType.descriptorKindFilter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0) {
|
||||
if (callTypeAndReceiver.receiver == null &&
|
||||
callTypeAndReceiver.callType.descriptorKindFilter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0
|
||||
) {
|
||||
//TODO: move this code somewhere else?
|
||||
val packageNames = PackageIndexUtil.getSubPackageFqNames(FqName.ROOT, searchScope, project, prefixMatcher.asNameFilter())
|
||||
.toMutableSet()
|
||||
@@ -471,7 +464,7 @@ class BasicCompletionSession(
|
||||
if (file != null) {
|
||||
val receiverInFile =
|
||||
file.findElementAt(receiver.startOffset)?.getParentOfType<KtSimpleNameExpression>(false)
|
||||
?: return
|
||||
?: return
|
||||
receiverInFile.mainReference.bindToFqName(fqNameToImport, FORCED_SHORTENING)
|
||||
}
|
||||
}
|
||||
@@ -570,7 +563,7 @@ class BasicCompletionSession(
|
||||
if (keyword in keywordsToSkip) return@complete
|
||||
|
||||
when (keyword) {
|
||||
// if "this" is parsed correctly in the current context - insert it and all this@xxx items
|
||||
// if "this" is parsed correctly in the current context - insert it and all this@xxx items
|
||||
"this" -> {
|
||||
if (expression != null) {
|
||||
collector.addElements(
|
||||
@@ -586,7 +579,7 @@ class BasicCompletionSession(
|
||||
}
|
||||
}
|
||||
|
||||
// if "return" is parsed correctly in the current context - insert it and all return@xxx items
|
||||
// if "return" is parsed correctly in the current context - insert it and all return@xxx items
|
||||
"return" -> {
|
||||
if (expression != null) {
|
||||
collector.addElements(returnExpressionItems(bindingContext, expression))
|
||||
|
||||
+43
-49
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -31,7 +20,6 @@ import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||
import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject
|
||||
import org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -46,8 +34,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import java.awt.Font
|
||||
|
||||
class BasicLookupElementFactory(
|
||||
private val project: Project,
|
||||
val insertHandlerProvider: InsertHandlerProvider
|
||||
private val project: Project,
|
||||
val insertHandlerProvider: InsertHandlerProvider
|
||||
) {
|
||||
companion object {
|
||||
// we skip parameter names in functional types in most of cases for shortness
|
||||
@@ -58,10 +46,10 @@ class BasicLookupElementFactory(
|
||||
}
|
||||
|
||||
fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor,
|
||||
qualifyNestedClasses: Boolean = false,
|
||||
includeClassTypeArguments: Boolean = true,
|
||||
parametersAndTypeGrayed: Boolean = false
|
||||
descriptor: DeclarationDescriptor,
|
||||
qualifyNestedClasses: Boolean = false,
|
||||
includeClassTypeArguments: Boolean = true,
|
||||
parametersAndTypeGrayed: Boolean = false
|
||||
): LookupElement {
|
||||
val _descriptor = if (descriptor is CallableMemberDescriptor)
|
||||
DescriptorUtils.unwrapFakeOverride(descriptor)
|
||||
@@ -70,14 +58,18 @@ class BasicLookupElementFactory(
|
||||
return createLookupElementUnwrappedDescriptor(_descriptor, qualifyNestedClasses, includeClassTypeArguments, parametersAndTypeGrayed)
|
||||
}
|
||||
|
||||
fun createLookupElementForJavaClass(psiClass: PsiClass, qualifyNestedClasses: Boolean = false, includeClassTypeArguments: Boolean = true): LookupElement {
|
||||
fun createLookupElementForJavaClass(
|
||||
psiClass: PsiClass,
|
||||
qualifyNestedClasses: Boolean = false,
|
||||
includeClassTypeArguments: Boolean = true
|
||||
): LookupElement {
|
||||
val lookupObject = object : DeclarationLookupObjectImpl(null) {
|
||||
override val psiElement: PsiElement?
|
||||
get() = psiClass
|
||||
|
||||
override fun getIcon(flags: Int) = psiClass.getIcon(flags)
|
||||
}
|
||||
var element = LookupElementBuilder.create(lookupObject, psiClass.name!!)
|
||||
.withInsertHandler(KotlinClassifierInsertHandler)
|
||||
var element = LookupElementBuilder.create(lookupObject, psiClass.name!!).withInsertHandler(KotlinClassifierInsertHandler)
|
||||
|
||||
val typeParams = psiClass.typeParameters
|
||||
if (includeClassTypeArguments && typeParams.isNotEmpty()) {
|
||||
@@ -123,10 +115,10 @@ class BasicLookupElementFactory(
|
||||
}
|
||||
|
||||
private fun createLookupElementUnwrappedDescriptor(
|
||||
descriptor: DeclarationDescriptor,
|
||||
qualifyNestedClasses: Boolean,
|
||||
includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean
|
||||
descriptor: DeclarationDescriptor,
|
||||
qualifyNestedClasses: Boolean,
|
||||
includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean
|
||||
): LookupElement {
|
||||
if (descriptor is JavaClassDescriptor) {
|
||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
|
||||
@@ -168,8 +160,10 @@ class BasicLookupElementFactory(
|
||||
else -> {
|
||||
lookupObject = object : DeclarationLookupObjectImpl(descriptor) {
|
||||
override val psiElement by lazy {
|
||||
DescriptorToSourceUtils.getSourceFromDescriptor(descriptor)
|
||||
?: DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
|
||||
DescriptorToSourceUtils.getSourceFromDescriptor(descriptor) ?: DescriptorToSourceUtilsIde.getAnyDeclaration(
|
||||
project,
|
||||
descriptor
|
||||
)
|
||||
}
|
||||
|
||||
override fun getIcon(flags: Int) = KotlinDescriptorIconProvider.getIcon(descriptor, psiElement, flags)
|
||||
@@ -186,14 +180,20 @@ class BasicLookupElementFactory(
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor -> {
|
||||
val returnType = descriptor.returnType
|
||||
element = element.withTypeText(if (returnType != null) SHORT_NAMES_RENDERER.renderType(returnType) else "", parametersAndTypeGrayed)
|
||||
element = element.withTypeText(
|
||||
if (returnType != null) SHORT_NAMES_RENDERER.renderType(returnType) else "",
|
||||
parametersAndTypeGrayed
|
||||
)
|
||||
|
||||
val insertsLambda = (insertHandler as? KotlinFunctionInsertHandler.Normal)?.lambdaInfo != null
|
||||
if (insertsLambda) {
|
||||
element = element.appendTailText(" {...} ", parametersAndTypeGrayed)
|
||||
}
|
||||
|
||||
element = element.appendTailText(SHORT_NAMES_RENDERER.renderFunctionParameters(descriptor), parametersAndTypeGrayed || insertsLambda)
|
||||
element = element.appendTailText(
|
||||
SHORT_NAMES_RENDERER.renderFunctionParameters(descriptor),
|
||||
parametersAndTypeGrayed || insertsLambda
|
||||
)
|
||||
}
|
||||
|
||||
is VariableDescriptor -> {
|
||||
@@ -210,8 +210,7 @@ class BasicLookupElementFactory(
|
||||
|
||||
if (descriptor.isArtificialImportAliasedDescriptor) {
|
||||
container = descriptor.original // we show original descriptor instead of container for import aliased descriptors
|
||||
}
|
||||
else if (qualifyNestedClasses) {
|
||||
} else if (qualifyNestedClasses) {
|
||||
element = element.withPresentableText(SHORT_NAMES_RENDERER.renderClassifierName(descriptor))
|
||||
|
||||
while (container is ClassDescriptor) {
|
||||
@@ -287,19 +286,17 @@ class BasicLookupElementFactory(
|
||||
|
||||
val extensionReceiver = descriptor.original.extensionReceiverParameter
|
||||
if (extensionReceiver != null) {
|
||||
when {
|
||||
descriptor is SamAdapterExtensionFunctionDescriptor -> {
|
||||
when (descriptor) {
|
||||
is SamAdapterExtensionFunctionDescriptor -> {
|
||||
// no need to show them as extensions
|
||||
return
|
||||
}
|
||||
|
||||
descriptor is SyntheticJavaPropertyDescriptor -> {
|
||||
is SyntheticJavaPropertyDescriptor -> {
|
||||
var from = descriptor.getMethod.name.asString() + "()"
|
||||
descriptor.setMethod?.let { from += "/" + it.name.asString() + "()" }
|
||||
appendTailText(" (from $from)")
|
||||
return
|
||||
}
|
||||
|
||||
else -> {
|
||||
val receiverPresentation = SHORT_NAMES_RENDERER.renderType(extensionReceiver.type)
|
||||
appendTailText(" for $receiverPresentation")
|
||||
@@ -321,8 +318,7 @@ class BasicLookupElementFactory(
|
||||
}
|
||||
|
||||
descriptor.isExtension -> {
|
||||
val container = descriptor.containingDeclaration
|
||||
val containerPresentation = when (container) {
|
||||
val containerPresentation = when (val container = descriptor.containingDeclaration) {
|
||||
is ClassDescriptor -> DescriptorUtils.getFqNameFromTopLevelClass(container).toString()
|
||||
is PackageFragmentDescriptor -> container.fqName.toString()
|
||||
else -> return null
|
||||
@@ -332,21 +328,19 @@ class BasicLookupElementFactory(
|
||||
|
||||
else -> {
|
||||
val container = descriptor.containingDeclaration as? PackageFragmentDescriptor
|
||||
// we show container only for global functions and properties
|
||||
?: return null
|
||||
// we show container only for global functions and properties
|
||||
?: return null
|
||||
//TODO: it would be probably better to show it also for static declarations which are not from the current class (imported)
|
||||
return "(${container.fqName})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LookupElement.withIconFromLookupObject(): LookupElement {
|
||||
// add icon in renderElement only to pass presentation.isReal()
|
||||
return object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.icon = DefaultLookupItemRenderer.getRawIcon(this@withIconFromLookupObject, presentation.isReal)
|
||||
}
|
||||
// add icon in renderElement only to pass presentation.isReal()
|
||||
private fun LookupElement.withIconFromLookupObject(): LookupElement = object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.icon = DefaultLookupItemRenderer.getRawIcon(this@withIconFromLookupObject, presentation.isReal)
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
-40
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -56,21 +45,21 @@ class CompletionBindingContextProvider(project: Project) {
|
||||
internal var TEST_LOG: StringBuilder? = null
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): CompletionBindingContextProvider
|
||||
= project.getComponent(CompletionBindingContextProvider::class.java)
|
||||
fun getInstance(project: Project): CompletionBindingContextProvider =
|
||||
project.getComponent(CompletionBindingContextProvider::class.java)
|
||||
|
||||
var ENABLED = true
|
||||
}
|
||||
|
||||
private class CompletionData(
|
||||
val block: KtBlockExpression,
|
||||
val prevStatement: KtExpression?,
|
||||
val psiElementsBeforeAndAfter: List<PsiElementData>,
|
||||
val bindingContext: BindingContext,
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val statementResolutionScope: LexicalScope,
|
||||
val statementDataFlowInfo: DataFlowInfo,
|
||||
val debugText: String
|
||||
val block: KtBlockExpression,
|
||||
val prevStatement: KtExpression?,
|
||||
val psiElementsBeforeAndAfter: List<PsiElementData>,
|
||||
val bindingContext: BindingContext,
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val statementResolutionScope: LexicalScope,
|
||||
val statementDataFlowInfo: DataFlowInfo,
|
||||
val debugText: String
|
||||
)
|
||||
|
||||
private data class PsiElementData(val element: PsiElement, val level: Int)
|
||||
@@ -80,7 +69,9 @@ class CompletionBindingContextProvider(project: Project) {
|
||||
|
||||
var data: CompletionData?
|
||||
get() = reference?.get()
|
||||
set(value) { reference = value?.let { SoftReference(it) } }
|
||||
set(value) {
|
||||
reference = value?.let { SoftReference(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private var prevCompletionDataCache: CachedValue<DataHolder> = CachedValuesManager.getManager(project).createCachedValue(
|
||||
@@ -94,13 +85,10 @@ class CompletionBindingContextProvider(project: Project) {
|
||||
)
|
||||
|
||||
|
||||
fun getBindingContext(position: PsiElement, resolutionFacade: ResolutionFacade): BindingContext {
|
||||
return if (ENABLED) {
|
||||
_getBindingContext(position, resolutionFacade)
|
||||
}
|
||||
else {
|
||||
resolutionFacade.analyze(position.parentsWithSelf.firstIsInstance<KtElement>(), BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
||||
}
|
||||
fun getBindingContext(position: PsiElement, resolutionFacade: ResolutionFacade): BindingContext = if (ENABLED) {
|
||||
_getBindingContext(position, resolutionFacade)
|
||||
} else {
|
||||
resolutionFacade.analyze(position.parentsWithSelf.firstIsInstance<KtElement>(), BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
||||
}
|
||||
|
||||
private fun _getBindingContext(position: PsiElement, resolutionFacade: ResolutionFacade): BindingContext {
|
||||
@@ -130,23 +118,33 @@ class CompletionBindingContextProvider(project: Project) {
|
||||
LOG.debug("Reusing data from completion of \"${prevCompletionData.debugText}\"")
|
||||
|
||||
//TODO: expected type?
|
||||
val statementContext = inStatement.analyzeInContext(scope = prevCompletionData.statementResolutionScope,
|
||||
contextExpression = block,
|
||||
dataFlowInfo = prevCompletionData.statementDataFlowInfo,
|
||||
isStatement = true)
|
||||
val statementContext = inStatement.analyzeInContext(
|
||||
scope = prevCompletionData.statementResolutionScope,
|
||||
contextExpression = block,
|
||||
dataFlowInfo = prevCompletionData.statementDataFlowInfo,
|
||||
isStatement = true
|
||||
)
|
||||
// we do not update prevCompletionDataCache because the same data should work
|
||||
return CompositeBindingContext.create(listOf(statementContext, prevCompletionData.bindingContext))
|
||||
}
|
||||
}
|
||||
|
||||
val bindingContext = resolutionFacade.analyze(position.parentsWithSelf.firstIsInstance<KtElement>(), BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
||||
val bindingContext =
|
||||
resolutionFacade.analyze(position.parentsWithSelf.firstIsInstance<KtElement>(), BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
||||
prevCompletionDataCache.value.data = if (block != null && modificationScope != null) {
|
||||
val resolutionScope = inStatement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(inStatement)
|
||||
CompletionData(block, prevStatement, psiElementsBeforeAndAfter!!, bindingContext, resolutionFacade.moduleDescriptor, resolutionScope, dataFlowInfo,
|
||||
debugText = position.text)
|
||||
}
|
||||
else {
|
||||
CompletionData(
|
||||
block,
|
||||
prevStatement,
|
||||
psiElementsBeforeAndAfter!!,
|
||||
bindingContext,
|
||||
resolutionFacade.moduleDescriptor,
|
||||
resolutionScope,
|
||||
dataFlowInfo,
|
||||
debugText = position.text
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
+11
-18
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -34,8 +23,8 @@ interface ContextVariablesProvider {
|
||||
}
|
||||
|
||||
class RealContextVariablesProvider(
|
||||
private val referenceVariantsHelper: ReferenceVariantsHelper,
|
||||
private val contextElement: PsiElement
|
||||
private val referenceVariantsHelper: ReferenceVariantsHelper,
|
||||
private val contextElement: PsiElement
|
||||
) : ContextVariablesProvider {
|
||||
|
||||
val allFunctionTypeVariables by lazy {
|
||||
@@ -43,9 +32,13 @@ class RealContextVariablesProvider(
|
||||
}
|
||||
|
||||
private fun collectVariables(): Collection<VariableDescriptor> {
|
||||
val descriptorFilter = DescriptorKindFilter.VARIABLES exclude DescriptorKindExclude.Extensions // we exclude extensions by performance reasons
|
||||
return referenceVariantsHelper.getReferenceVariants(contextElement, CallTypeAndReceiver.DEFAULT, descriptorFilter, nameFilter = { true })
|
||||
.map { it as VariableDescriptor }
|
||||
val descriptorFilter =
|
||||
DescriptorKindFilter.VARIABLES exclude DescriptorKindExclude.Extensions // we exclude extensions by performance reasons
|
||||
return referenceVariantsHelper.getReferenceVariants(
|
||||
contextElement,
|
||||
CallTypeAndReceiver.DEFAULT,
|
||||
descriptorFilter,
|
||||
nameFilter = { true }).map { it as VariableDescriptor }
|
||||
}
|
||||
|
||||
override fun functionTypeVariables(requiredType: FuzzyType): Collection<Pair<VariableDescriptor, TypeSubstitutor>> {
|
||||
|
||||
+4
-15
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -32,8 +21,8 @@ import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||
* Position will be used for sorting
|
||||
*/
|
||||
abstract class DeclarationLookupObjectImpl(
|
||||
final override val descriptor: DeclarationDescriptor?
|
||||
): DeclarationLookupObject {
|
||||
final override val descriptor: DeclarationDescriptor?
|
||||
) : DeclarationLookupObject {
|
||||
override val name: Name?
|
||||
get() = descriptor?.name ?: (psiElement as? PsiNamedElement)?.name?.let { Name.identifier(it) }
|
||||
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -37,8 +37,9 @@ class DslMembersCompletion(
|
||||
val extensionDescriptors = indicesHelper.getCallableTopLevelExtensions(
|
||||
nameFilter = { prefixMatcher.prefixMatches(it) },
|
||||
declarationFilter = {
|
||||
(it as KtModifierListOwner).modifierList?.collectAnnotationEntriesFromStubOrPsi()?.any { it.shortName in receiverMarkersShortNames }
|
||||
?: false
|
||||
(it as KtModifierListOwner).modifierList?.collectAnnotationEntriesFromStubOrPsi()
|
||||
?.any { it.shortName in receiverMarkersShortNames }
|
||||
?: false
|
||||
},
|
||||
callTypeAndReceiver = callTypeAndReceiver,
|
||||
receiverTypes = listOf(nearestReceiver.type)
|
||||
|
||||
+15
-22
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -32,9 +21,9 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import java.util.*
|
||||
|
||||
class ExtensionFunctionTypeValueCompletion(
|
||||
private val receiverTypes: Collection<ReceiverType>,
|
||||
private val callType: CallType<*>,
|
||||
private val lookupElementFactory: LookupElementFactory
|
||||
private val receiverTypes: Collection<ReceiverType>,
|
||||
private val callType: CallType<*>,
|
||||
private val lookupElementFactory: LookupElementFactory
|
||||
) {
|
||||
data class Result(val invokeDescriptor: FunctionDescriptor, val factory: AbstractLookupElementFactory)
|
||||
|
||||
@@ -51,7 +40,10 @@ class ExtensionFunctionTypeValueCompletion(
|
||||
for (invoke in createSynthesizedInvokes(invokes)) {
|
||||
for (substituted in invoke.substituteExtensionIfCallable(receiverTypes.map { it.type }, callType)) {
|
||||
val factory = object : AbstractLookupElementFactory {
|
||||
override fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||
override fun createStandardLookupElementsForDescriptor(
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean
|
||||
): Collection<LookupElement> {
|
||||
if (!useReceiverTypes) return emptyList()
|
||||
descriptor as FunctionDescriptor // should be descriptor for "invoke"
|
||||
|
||||
@@ -82,11 +74,12 @@ class ExtensionFunctionTypeValueCompletion(
|
||||
}
|
||||
|
||||
override fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean,
|
||||
includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean): LookupElement? = null
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean,
|
||||
includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean
|
||||
): LookupElement? = null
|
||||
}
|
||||
|
||||
results.add(Result(substituted, factory))
|
||||
|
||||
+10
-19
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -31,8 +20,8 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import java.util.*
|
||||
|
||||
class FromUnresolvedNamesCompletion(
|
||||
private val collector: LookupElementsCollector,
|
||||
private val prefixMatcher: PrefixMatcher
|
||||
private val collector: LookupElementsCollector,
|
||||
private val prefixMatcher: PrefixMatcher
|
||||
) {
|
||||
fun addNameSuggestions(scope: KtElement, afterOffset: Int?, sampleDescriptor: DeclarationDescriptor?) {
|
||||
val names = HashSet<String>()
|
||||
@@ -50,7 +39,10 @@ class FromUnresolvedNamesCompletion(
|
||||
val canBeUsage = when (sampleDescriptor) {
|
||||
is FunctionDescriptor -> isCall // cannot use simply function name without arguments
|
||||
is VariableDescriptor -> true // variable can as well be used with arguments when it has invoke()
|
||||
is ClassDescriptor -> if (isCall) sampleDescriptor.kind == ClassKind.CLASS else sampleDescriptor.kind.isSingleton
|
||||
is ClassDescriptor -> if (isCall)
|
||||
sampleDescriptor.kind == ClassKind.CLASS
|
||||
else
|
||||
sampleDescriptor.kind.isSingleton
|
||||
else -> false // what else it can be?
|
||||
}
|
||||
if (!canBeUsage) return@forEachDescendantOfType
|
||||
@@ -69,9 +61,8 @@ class FromUnresolvedNamesCompletion(
|
||||
}
|
||||
|
||||
for (name in names.sorted()) {
|
||||
val lookupElement = LookupElementBuilder.create(name)
|
||||
.suppressAutoInsertion()
|
||||
.assignPriority(ItemPriority.FROM_UNRESOLVED_NAME_SUGGESTION)
|
||||
val lookupElement =
|
||||
LookupElementBuilder.create(name).suppressAutoInsertion().assignPriority(ItemPriority.FROM_UNRESOLVED_NAME_SUGGESTION)
|
||||
lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit)
|
||||
collector.addElement(lookupElement)
|
||||
}
|
||||
|
||||
+10
-18
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -32,8 +21,8 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
class InsertHandlerProvider(
|
||||
private val callType: CallType<*>,
|
||||
expectedInfosCalculator: () -> Collection<ExpectedInfo>
|
||||
private val callType: CallType<*>,
|
||||
expectedInfosCalculator: () -> Collection<ExpectedInfo>
|
||||
) {
|
||||
private val expectedInfos by lazy(LazyThreadSafetyMode.NONE) { expectedInfosCalculator() }
|
||||
|
||||
@@ -55,8 +44,8 @@ class InsertHandlerProvider(
|
||||
if (getValueParametersCountFromFunctionType(parameterType) <= 1 && !parameter.hasDefaultValue()) {
|
||||
// otherwise additional item with lambda template is to be added
|
||||
return KotlinFunctionInsertHandler.Normal(
|
||||
callType, needTypeArguments, inputValueArguments = false,
|
||||
lambdaInfo = GenerateLambdaInfo(parameterType, false)
|
||||
callType, needTypeArguments, inputValueArguments = false,
|
||||
lambdaInfo = GenerateLambdaInfo(parameterType, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -126,7 +115,10 @@ class InsertHandlerProvider(
|
||||
if (returnType != null) {
|
||||
addPotentiallyInferred(returnType)
|
||||
|
||||
if (allTypeParametersPotentiallyInferred() && expectedInfos.any { it.fuzzyType?.checkIsSuperTypeOf(originalFunction.fuzzyReturnType()!!) != null }) {
|
||||
if (allTypeParametersPotentiallyInferred() && expectedInfos.any {
|
||||
it.fuzzyType?.checkIsSuperTypeOf(originalFunction.fuzzyReturnType()!!) != null
|
||||
}
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -40,22 +29,23 @@ import org.jetbrains.kotlin.types.typeUtil.isBooleanOrNullableBoolean
|
||||
object KeywordValues {
|
||||
interface Consumer {
|
||||
fun consume(
|
||||
lookupString: String,
|
||||
expectedInfoMatcher: (ExpectedInfo) -> ExpectedInfoMatch,
|
||||
priority: SmartCompletionItemPriority,
|
||||
factory: () -> LookupElement)
|
||||
lookupString: String,
|
||||
expectedInfoMatcher: (ExpectedInfo) -> ExpectedInfoMatch,
|
||||
priority: SmartCompletionItemPriority,
|
||||
factory: () -> LookupElement
|
||||
)
|
||||
}
|
||||
|
||||
fun process(
|
||||
consumer: Consumer,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
isJvmModule: Boolean
|
||||
consumer: Consumer,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
isJvmModule: Boolean
|
||||
) {
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
|
||||
val booleanInfoMatcher = matcher@ { info: ExpectedInfo ->
|
||||
val booleanInfoMatcher = matcher@{ info: ExpectedInfo ->
|
||||
// no sense in true or false as if-condition or when entry for when with no subject
|
||||
val additionalData = info.additionalData
|
||||
val skipTrueFalse = when (additionalData) {
|
||||
@@ -72,10 +62,10 @@ object KeywordValues {
|
||||
else
|
||||
ExpectedInfoMatch.noMatch
|
||||
}
|
||||
consumer.consume("true", booleanInfoMatcher, SmartCompletionItemPriority.TRUE) {
|
||||
consumer.consume("true", booleanInfoMatcher, SmartCompletionItemPriority.TRUE) {
|
||||
LookupElementBuilder.create(KeywordLookupObject(), "true").bold()
|
||||
}
|
||||
consumer.consume("false", booleanInfoMatcher, SmartCompletionItemPriority.FALSE) {
|
||||
consumer.consume("false", booleanInfoMatcher, SmartCompletionItemPriority.FALSE) {
|
||||
LookupElementBuilder.create(KeywordLookupObject(), "false").bold()
|
||||
}
|
||||
|
||||
@@ -97,7 +87,8 @@ object KeywordValues {
|
||||
val qualifierType = bindingContext.get(BindingContext.DOUBLE_COLON_LHS, callTypeAndReceiver.receiver!!)?.type
|
||||
if (qualifierType != null) {
|
||||
val kClassDescriptor = resolutionFacade.getFrontendService(ReflectionTypes::class.java).kClass
|
||||
val classLiteralType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, kClassDescriptor, listOf(TypeProjectionImpl(qualifierType)))
|
||||
val classLiteralType =
|
||||
KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, kClassDescriptor, listOf(TypeProjectionImpl(qualifierType)))
|
||||
val kClassTypes = listOf(classLiteralType.toFuzzyType(emptyList()))
|
||||
val kClassMatcher = { info: ExpectedInfo -> kClassTypes.matchExpectedInfo(info) }
|
||||
consumer.consume("class", kClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) {
|
||||
@@ -106,17 +97,21 @@ object KeywordValues {
|
||||
|
||||
if (isJvmModule) {
|
||||
val javaLangClassDescriptor = resolutionFacade.resolveImportReference(moduleDescriptor, FqName("java.lang.Class"))
|
||||
.singleOrNull() as? ClassDescriptor
|
||||
.singleOrNull() as? ClassDescriptor
|
||||
|
||||
if (javaLangClassDescriptor != null) {
|
||||
val javaLangClassType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, javaLangClassDescriptor, listOf(TypeProjectionImpl(qualifierType)))
|
||||
val javaLangClassType = KotlinTypeFactory.simpleNotNullType(
|
||||
Annotations.EMPTY,
|
||||
javaLangClassDescriptor,
|
||||
listOf(TypeProjectionImpl(qualifierType))
|
||||
)
|
||||
val javaClassTypes = listOf(javaLangClassType.toFuzzyType(emptyList()))
|
||||
val javaClassMatcher = { info: ExpectedInfo -> javaClassTypes.matchExpectedInfo(info) }
|
||||
consumer.consume("class", javaClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) {
|
||||
LookupElementBuilder.create(KeywordLookupObject(), "class.java")
|
||||
.withPresentableText("class")
|
||||
.withTailText(".java")
|
||||
.bold()
|
||||
.withPresentableText("class")
|
||||
.withTailText(".java")
|
||||
.bold()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-15
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -26,13 +15,14 @@ class KotlinCompletionCharFilter() : CharFilter() {
|
||||
companion object {
|
||||
val ACCEPT_OPENING_BRACE: Key<Unit> = Key("KotlinCompletionCharFilter.ACCEPT_OPENING_BRACE")
|
||||
|
||||
val SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING: Key<Unit> = Key("KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING")
|
||||
val SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING: Key<Unit> =
|
||||
Key("KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING")
|
||||
val HIDE_LOOKUP_ON_COLON: Key<Unit> = Key("KotlinCompletionCharFilter.HIDE_LOOKUP_ON_COLON")
|
||||
|
||||
val JUST_TYPING_PREFIX: Key<String> = Key("KotlinCompletionCharFilter.JUST_TYPING_PREFIX")
|
||||
}
|
||||
|
||||
override fun acceptChar(c : Char, prefixLength : Int, lookup : Lookup) : Result? {
|
||||
override fun acceptChar(c: Char, prefixLength: Int, lookup: Lookup): Result? {
|
||||
if (lookup.psiFile !is KtFile) return null
|
||||
if (!lookup.isCompletion) return null
|
||||
val isAutopopup = CompletionService.getCompletionService().currentCompletion?.isAutopopupCompletion ?: return null
|
||||
|
||||
+57
-53
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -50,11 +39,18 @@ import kotlin.math.max
|
||||
var KtFile.doNotComplete: Boolean? by UserDataProperty(Key.create("DO_NOT_COMPLETE"))
|
||||
|
||||
class KotlinCompletionContributor : CompletionContributor() {
|
||||
private val AFTER_NUMBER_LITERAL = psiElement().afterLeafSkipping(psiElement().withText(""), psiElement().withElementType(elementType().oneOf(KtTokens.FLOAT_LITERAL, KtTokens.INTEGER_LITERAL)))
|
||||
private val AFTER_INTEGER_LITERAL_AND_DOT = psiElement().afterLeafSkipping(psiElement().withText("."), psiElement().withElementType(elementType().oneOf(KtTokens.INTEGER_LITERAL)))
|
||||
private val AFTER_NUMBER_LITERAL = psiElement().afterLeafSkipping(
|
||||
psiElement().withText(""),
|
||||
psiElement().withElementType(elementType().oneOf(KtTokens.FLOAT_LITERAL, KtTokens.INTEGER_LITERAL))
|
||||
)
|
||||
private val AFTER_INTEGER_LITERAL_AND_DOT = psiElement().afterLeafSkipping(
|
||||
psiElement().withText("."),
|
||||
psiElement().withElementType(elementType().oneOf(KtTokens.INTEGER_LITERAL))
|
||||
)
|
||||
|
||||
companion object {
|
||||
val DEFAULT_DUMMY_IDENTIFIER: String = CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED + "$" // add '$' to ignore context after the caret
|
||||
val DEFAULT_DUMMY_IDENTIFIER: String =
|
||||
CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED + "$" // add '$' to ignore context after the caret
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -102,15 +98,16 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
isInSimpleStringTemplate(tokenBefore) -> CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED
|
||||
|
||||
else -> specialLambdaSignatureDummyIdentifier(tokenBefore)
|
||||
?: specialExtensionReceiverDummyIdentifier(tokenBefore)
|
||||
?: specialInTypeArgsDummyIdentifier(tokenBefore)
|
||||
?: specialInArgumentListDummyIdentifier(tokenBefore)
|
||||
?: DEFAULT_DUMMY_IDENTIFIER
|
||||
?: specialExtensionReceiverDummyIdentifier(tokenBefore)
|
||||
?: specialInTypeArgsDummyIdentifier(tokenBefore)
|
||||
?: specialInArgumentListDummyIdentifier(tokenBefore)
|
||||
?: DEFAULT_DUMMY_IDENTIFIER
|
||||
}
|
||||
|
||||
val tokenAt = psiFile.findElementAt(max(0, offset))
|
||||
if (tokenAt != null) {
|
||||
if (context.completionType == CompletionType.SMART && !isAtEndOfLine(offset, context.editor.document) /* do not use parent expression if we are at the end of line - it's probably parsed incorrectly */) {
|
||||
/* do not use parent expression if we are at the end of line - it's probably parsed incorrectly */
|
||||
if (context.completionType == CompletionType.SMART && !isAtEndOfLine(offset, context.editor.document)) {
|
||||
var parent = tokenAt.parent
|
||||
if (parent is KtExpression && parent !is KtBlockExpression) {
|
||||
// search expression to be replaced - go up while we are the first child of parent expression
|
||||
@@ -130,8 +127,10 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
|
||||
val argumentList = (expression.parent as? KtValueArgument)?.parent as? KtValueArgumentList
|
||||
if (argumentList != null) {
|
||||
context.offsetMap.addOffset(SmartCompletion.MULTIPLE_ARGUMENTS_REPLACEMENT_OFFSET,
|
||||
argumentList.rightParenthesis?.textRange?.startOffset ?: argumentList.endOffset)
|
||||
context.offsetMap.addOffset(
|
||||
SmartCompletion.MULTIPLE_ARGUMENTS_REPLACEMENT_OFFSET,
|
||||
argumentList.rightParenthesis?.textRange?.startOffset ?: argumentList.endOffset
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,12 +192,16 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
}
|
||||
|
||||
private val declarationKeywords = TokenSet.create(KtTokens.FUN_KEYWORD, KtTokens.VAL_KEYWORD, KtTokens.VAR_KEYWORD)
|
||||
private val declarationTokens = TokenSet.orSet(TokenSet.create(KtTokens.IDENTIFIER, KtTokens.LT, KtTokens.GT,
|
||||
KtTokens.COMMA, KtTokens.DOT, KtTokens.QUEST, KtTokens.COLON,
|
||||
KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD,
|
||||
KtTokens.LPAR, KtTokens.RPAR, KtTokens.ARROW,
|
||||
TokenType.ERROR_ELEMENT),
|
||||
KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET)
|
||||
private val declarationTokens = TokenSet.orSet(
|
||||
TokenSet.create(
|
||||
KtTokens.IDENTIFIER, KtTokens.LT, KtTokens.GT,
|
||||
KtTokens.COMMA, KtTokens.DOT, KtTokens.QUEST, KtTokens.COLON,
|
||||
KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD,
|
||||
KtTokens.LPAR, KtTokens.RPAR, KtTokens.ARROW,
|
||||
TokenType.ERROR_ELEMENT
|
||||
),
|
||||
KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET
|
||||
)
|
||||
|
||||
private fun specialExtensionReceiverDummyIdentifier(tokenBefore: PsiElement?): String? {
|
||||
var token = tokenBefore ?: return null
|
||||
@@ -223,8 +226,8 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
val file = KtPsiFactory(tokenBefore.project).createFile(text)
|
||||
val declaration = file.declarations.singleOrNull() ?: return null
|
||||
if (declaration.textLength != text.length) return null
|
||||
val containsErrorElement = !PsiTreeUtil.processElements(file, PsiElementProcessor<PsiElement>{ it !is PsiErrorElement })
|
||||
return if (containsErrorElement) null else tail + "$"
|
||||
val containsErrorElement = !PsiTreeUtil.processElements(file, PsiElementProcessor<PsiElement> { it !is PsiErrorElement })
|
||||
return if (containsErrorElement) null else "$tail$"
|
||||
}
|
||||
if (tokenType !in declarationTokens) return null
|
||||
if (tokenType == KtTokens.LT) ltCount++
|
||||
@@ -266,10 +269,10 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
}
|
||||
|
||||
private fun doComplete(
|
||||
parameters: CompletionParameters,
|
||||
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
result: CompletionResultSet,
|
||||
lookupElementPostProcessor: ((LookupElement) -> LookupElement)? = null
|
||||
parameters: CompletionParameters,
|
||||
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
result: CompletionResultSet,
|
||||
lookupElementPostProcessor: ((LookupElement) -> LookupElement)? = null
|
||||
) {
|
||||
val name = parameters.originalFile.virtualFile?.name ?: "default.kts"
|
||||
completionStatsData = completionStatsData?.copy(
|
||||
@@ -328,20 +331,19 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
if (!somethingAdded && parameters.invocationCount < 2) {
|
||||
// Rerun completion if nothing was found
|
||||
val newConfiguration = CompletionSessionConfiguration(
|
||||
useBetterPrefixMatcherForNonImportedClasses = false,
|
||||
nonAccessibleDeclarations = false,
|
||||
javaGettersAndSetters = true,
|
||||
javaClassesNotToBeUsed = false,
|
||||
staticMembers = parameters.invocationCount > 0,
|
||||
dataClassComponentFunctions = true
|
||||
useBetterPrefixMatcherForNonImportedClasses = false,
|
||||
nonAccessibleDeclarations = false,
|
||||
javaGettersAndSetters = true,
|
||||
javaClassesNotToBeUsed = false,
|
||||
staticMembers = parameters.invocationCount > 0,
|
||||
dataClassComponentFunctions = true
|
||||
)
|
||||
|
||||
val newSession = BasicCompletionSession(newConfiguration, parameters, toFromOriginalFileMapper, result)
|
||||
addPostProcessor(newSession)
|
||||
newSession.complete()
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val session = SmartCompletionSession(configuration, parameters, toFromOriginalFileMapper, result)
|
||||
addPostProcessor(session)
|
||||
session.complete()
|
||||
@@ -421,8 +423,7 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
val targets = nameRef.getReferenceTargets(bindingContext)
|
||||
return if (targets.isNotEmpty() && targets.all { it is FunctionDescriptor || it is ClassDescriptor && it.kind == ClassKind.CLASS }) {
|
||||
CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED + ">".repeat(balance) + "$"
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -432,16 +433,19 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
val pair = unclosedTypeArgListNameAndBalance(nameToken)
|
||||
return if (pair == null) {
|
||||
Pair(nameToken, 1)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Pair(pair.first, pair.second + 1)
|
||||
}
|
||||
}
|
||||
|
||||
private val callTypeArgsTokens = TokenSet.orSet(TokenSet.create(KtTokens.IDENTIFIER, KtTokens.LT, KtTokens.GT,
|
||||
KtTokens.COMMA, KtTokens.DOT, KtTokens.QUEST, KtTokens.COLON,
|
||||
KtTokens.LPAR, KtTokens.RPAR, KtTokens.ARROW),
|
||||
KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET)
|
||||
private val callTypeArgsTokens = TokenSet.orSet(
|
||||
TokenSet.create(
|
||||
KtTokens.IDENTIFIER, KtTokens.LT, KtTokens.GT,
|
||||
KtTokens.COMMA, KtTokens.DOT, KtTokens.QUEST, KtTokens.COLON,
|
||||
KtTokens.LPAR, KtTokens.RPAR, KtTokens.ARROW
|
||||
),
|
||||
KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET
|
||||
)
|
||||
|
||||
// if the leaf could be located inside type argument list of a call (if parsed properly)
|
||||
// then it returns the call name reference this type argument list would belong to
|
||||
@@ -479,7 +483,7 @@ class KotlinCompletionContributor : CompletionContributor() {
|
||||
|
||||
private fun isInUnclosedSuperQualifier(tokenBefore: PsiElement?): Boolean {
|
||||
if (tokenBefore == null) return false
|
||||
val tokensToSkip = TokenSet.orSet(TokenSet.create(KtTokens.IDENTIFIER, KtTokens.DOT ), KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET)
|
||||
val tokensToSkip = TokenSet.orSet(TokenSet.create(KtTokens.IDENTIFIER, KtTokens.DOT), KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET)
|
||||
val tokens = generateSequence(tokenBefore) { it.prevLeaf() }
|
||||
val ltToken = tokens.firstOrNull { it.node.elementType !in tokensToSkip } ?: return false
|
||||
if (ltToken.node.elementType != KtTokens.LT) return false
|
||||
@@ -497,6 +501,6 @@ abstract class KotlinCompletionExtension {
|
||||
|
||||
companion object {
|
||||
val EP_NAME: ExtensionPointName<KotlinCompletionExtension> =
|
||||
ExtensionPointName.create<KotlinCompletionExtension>("org.jetbrains.kotlin.completionExtension")
|
||||
ExtensionPointName.create<KotlinCompletionExtension>("org.jetbrains.kotlin.completionExtension")
|
||||
}
|
||||
}
|
||||
|
||||
+4
-15
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
@@ -43,8 +32,8 @@ class KotlinExcludeFromCompletionLookupActionProvider : LookupActionProvider {
|
||||
}
|
||||
|
||||
private class ExcludeFromCompletionAction(
|
||||
private val project: Project,
|
||||
private val exclude: String
|
||||
private val project: Project,
|
||||
private val exclude: String
|
||||
) : LookupElementAction(null, "Exclude '$exclude' from completion") {
|
||||
override fun performLookupAction(): Result {
|
||||
AddImportAction.excludeFromImport(project, exclude)
|
||||
|
||||
+25
-36
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -46,11 +35,11 @@ import org.jetbrains.kotlin.types.TypeProjection
|
||||
|
||||
object LambdaSignatureTemplates {
|
||||
fun insertTemplate(
|
||||
context: InsertionContext,
|
||||
placeholderRange: TextRange,
|
||||
lambdaType: KotlinType,
|
||||
explicitParameterTypes: Boolean,
|
||||
signatureOnly: Boolean
|
||||
context: InsertionContext,
|
||||
placeholderRange: TextRange,
|
||||
lambdaType: KotlinType,
|
||||
explicitParameterTypes: Boolean,
|
||||
signatureOnly: Boolean
|
||||
) {
|
||||
// we start template later to not interfere with insertion of tail type
|
||||
val commandProcessor = CommandProcessor.getInstance()
|
||||
@@ -77,8 +66,7 @@ object LambdaSignatureTemplates {
|
||||
val template = buildTemplate(lambdaType, signatureOnly, explicitParameterTypes, context.project)
|
||||
TemplateManager.getInstance(context.project).startTemplate(context.editor, template)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
rangeMarker.dispose()
|
||||
}
|
||||
}
|
||||
@@ -114,16 +102,18 @@ object LambdaSignatureTemplates {
|
||||
|
||||
fun explicitParameterTypesRequired(file: KtFile, placeholderRange: TextRange, lambdaType: KotlinType): Boolean {
|
||||
PsiDocumentManager.getInstance(file.project).commitAllDocuments()
|
||||
val expression = PsiTreeUtil.findElementOfClassAtRange(file, placeholderRange.startOffset, placeholderRange.endOffset, KtExpression::class.java)
|
||||
?: return false
|
||||
val expression =
|
||||
PsiTreeUtil.findElementOfClassAtRange(file, placeholderRange.startOffset, placeholderRange.endOffset, KtExpression::class.java)
|
||||
?: return false
|
||||
|
||||
val resolutionFacade = file.getResolutionFacade()
|
||||
val bindingContext = resolutionFacade.analyze(expression, BodyResolveMode.PARTIAL)
|
||||
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, indicesHelper = null, useHeuristicSignatures = false).calculate(expression)
|
||||
val expectedInfos =
|
||||
ExpectedInfos(bindingContext, resolutionFacade, indicesHelper = null, useHeuristicSignatures = false).calculate(expression)
|
||||
val functionTypes = expectedInfos
|
||||
.mapNotNull { it.fuzzyType?.type }
|
||||
.filter(KotlinType::isFunctionOrSuspendFunctionType)
|
||||
.toSet()
|
||||
.mapNotNull { it.fuzzyType?.type }
|
||||
.filter(KotlinType::isFunctionOrSuspendFunctionType)
|
||||
.toSet()
|
||||
return explicitParameterTypesRequired(functionTypes, lambdaType)
|
||||
}
|
||||
|
||||
@@ -138,10 +128,10 @@ object LambdaSignatureTemplates {
|
||||
}
|
||||
|
||||
private fun buildTemplate(
|
||||
lambdaType: KotlinType,
|
||||
signatureOnly: Boolean,
|
||||
explicitParameterTypes: Boolean,
|
||||
project: Project
|
||||
lambdaType: KotlinType,
|
||||
signatureOnly: Boolean,
|
||||
explicitParameterTypes: Boolean,
|
||||
project: Project
|
||||
): Template {
|
||||
val parameterTypes = functionParameterTypes(lambdaType)
|
||||
|
||||
@@ -161,14 +151,13 @@ object LambdaSignatureTemplates {
|
||||
}
|
||||
//TODO: check for names in scope
|
||||
val parameterName = parameterType.extractParameterNameFromFunctionTypeArgument()?.render()
|
||||
val nameExpression = if (parameterName != null) {
|
||||
val nameExpression = if (parameterName != null) {
|
||||
object : Expression() {
|
||||
override fun calculateResult(context: ExpressionContext?) = TextResult(parameterName)
|
||||
override fun calculateQuickResult(context: ExpressionContext?): Result? = TextResult(parameterName)
|
||||
override fun calculateLookupItems(context: ExpressionContext?) = emptyArray<LookupElement>()
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val count = (noNameParameterCount[parameterType] ?: 0) + 1
|
||||
noNameParameterCount[parameterType] = count
|
||||
val suffix = if (count == 1) null else "$count"
|
||||
@@ -176,8 +165,8 @@ object LambdaSignatureTemplates {
|
||||
object : Expression() {
|
||||
override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0])
|
||||
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
|
||||
override fun calculateLookupItems(context: ExpressionContext?)
|
||||
= nameSuggestions.map { LookupElementBuilder.create(it) }.toTypedArray()
|
||||
override fun calculateLookupItems(context: ExpressionContext?) =
|
||||
nameSuggestions.map { LookupElementBuilder.create(it) }.toTypedArray()
|
||||
}
|
||||
}
|
||||
template.addVariable(nameExpression, true)
|
||||
@@ -201,7 +190,7 @@ object LambdaSignatureTemplates {
|
||||
val suggestions = KotlinNameSuggester.suggestNamesByType(parameterType, { true }, "p")
|
||||
return if (suffix != null) suggestions.map { "$it$suffix" } else suggestions
|
||||
}
|
||||
|
||||
|
||||
private fun nameSuggestion(parameterType: KotlinType) = nameSuggestions(parameterType)[0]
|
||||
|
||||
private fun functionParameterTypes(functionType: KotlinType): List<KotlinType> {
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -24,11 +13,9 @@ import com.intellij.psi.tree.IElementType
|
||||
|
||||
class LeafElementFilter(private val elementType: IElementType) : ElementFilter {
|
||||
|
||||
override fun isAcceptable(element: Any?, context: PsiElement?)
|
||||
= element is LeafPsiElement && element.elementType == elementType
|
||||
override fun isAcceptable(element: Any?, context: PsiElement?) = element is LeafPsiElement && element.elementType == elementType
|
||||
|
||||
override fun isClassAcceptable(hintClass: Class<*>)
|
||||
= LEAF_CLASS_FILTER.isClassAcceptable(hintClass)
|
||||
override fun isClassAcceptable(hintClass: Class<*>) = LEAF_CLASS_FILTER.isClassAcceptable(hintClass)
|
||||
|
||||
companion object {
|
||||
private val LEAF_CLASS_FILTER = ClassFilter(LeafPsiElement::class.java)
|
||||
|
||||
+83
-77
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -55,22 +44,22 @@ interface AbstractLookupElementFactory {
|
||||
fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement>
|
||||
|
||||
fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean = false,
|
||||
includeClassTypeArguments: Boolean = true,
|
||||
parametersAndTypeGrayed: Boolean = false
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean = false,
|
||||
includeClassTypeArguments: Boolean = true,
|
||||
parametersAndTypeGrayed: Boolean = false
|
||||
): LookupElement?
|
||||
}
|
||||
|
||||
data /* we need copy() */
|
||||
class LookupElementFactory(
|
||||
val basicFactory: BasicLookupElementFactory,
|
||||
private val receiverTypes: Collection<ReceiverType>?,
|
||||
private val callType: CallType<*>,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val contextVariablesProvider: ContextVariablesProvider,
|
||||
private val standardLookupElementsPostProcessor: (LookupElement) -> LookupElement = { it }
|
||||
val basicFactory: BasicLookupElementFactory,
|
||||
private val receiverTypes: Collection<ReceiverType>?,
|
||||
private val callType: CallType<*>,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val contextVariablesProvider: ContextVariablesProvider,
|
||||
private val standardLookupElementsPostProcessor: (LookupElement) -> LookupElement = { it }
|
||||
) : AbstractLookupElementFactory {
|
||||
companion object {
|
||||
fun hasSingleFunctionTypeParameter(descriptor: FunctionDescriptor): Boolean {
|
||||
@@ -84,18 +73,18 @@ class LookupElementFactory(
|
||||
val insertHandlerProvider = basicFactory.insertHandlerProvider
|
||||
|
||||
private val superFunctions: Set<FunctionDescriptor> by lazy {
|
||||
inDescriptor.parentsWithSelf
|
||||
.takeWhile { it !is ClassDescriptor }
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.toList()
|
||||
.flatMap { it.findOriginalTopMostOverriddenDescriptors() }
|
||||
.toSet()
|
||||
inDescriptor.parentsWithSelf.takeWhile { it !is ClassDescriptor }.filterIsInstance<FunctionDescriptor>().toList()
|
||||
.flatMap { it.findOriginalTopMostOverriddenDescriptors() }.toSet()
|
||||
}
|
||||
|
||||
override fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||
override fun createStandardLookupElementsForDescriptor(
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean
|
||||
): Collection<LookupElement> {
|
||||
val result = SmartList<LookupElement>()
|
||||
|
||||
val isNormalCall = callType == CallType.DEFAULT || callType == CallType.DOT || callType == CallType.SAFE || callType == CallType.SUPER_MEMBERS
|
||||
val isNormalCall =
|
||||
callType == CallType.DEFAULT || callType == CallType.DOT || callType == CallType.SAFE || callType == CallType.SUPER_MEMBERS
|
||||
|
||||
result.add(createLookupElement(descriptor, useReceiverTypes, parametersAndTypeGrayed = !isNormalCall && callType != CallType.INFIX))
|
||||
|
||||
@@ -103,8 +92,7 @@ class LookupElementFactory(
|
||||
if (descriptor is FunctionDescriptor && isNormalCall) {
|
||||
if (callType != CallType.SUPER_MEMBERS) {
|
||||
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
||||
}
|
||||
else if (useReceiverTypes) {
|
||||
} else if (useReceiverTypes) {
|
||||
result.addIfNotNull(createSuperFunctionCallWithArguments(descriptor))
|
||||
}
|
||||
}
|
||||
@@ -149,7 +137,14 @@ class LookupElementFactory(
|
||||
val insertHandler = insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal
|
||||
if (insertHandler.lambdaInfo == null) {
|
||||
val functionParameterCount = getValueParametersCountFromFunctionType(parameterType)
|
||||
add(createFunctionCallElementWithLambda(descriptor, parameterType, useReceiverTypes, explicitLambdaParameters = functionParameterCount > 1))
|
||||
add(
|
||||
createFunctionCallElementWithLambda(
|
||||
descriptor,
|
||||
parameterType,
|
||||
useReceiverTypes,
|
||||
explicitLambdaParameters = functionParameterCount > 1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (isSingleParameter) {
|
||||
@@ -165,10 +160,10 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
private fun createFunctionCallElementWithLambda(
|
||||
descriptor: FunctionDescriptor,
|
||||
parameterType: KotlinType,
|
||||
useReceiverTypes: Boolean,
|
||||
explicitLambdaParameters: Boolean
|
||||
descriptor: FunctionDescriptor,
|
||||
parameterType: KotlinType,
|
||||
useReceiverTypes: Boolean,
|
||||
explicitLambdaParameters: Boolean
|
||||
): LookupElement {
|
||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||
val inputTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal).inputTypeArguments
|
||||
@@ -182,14 +177,20 @@ class LookupElementFactory(
|
||||
var parametersRenderer = BasicLookupElementFactory.SHORT_NAMES_RENDERER
|
||||
if (descriptor.valueParameters.size > 1) {
|
||||
parametersRenderer = parametersRenderer.withOptions {
|
||||
valueParametersHandler = object: DescriptorRenderer.ValueParametersHandler by this.valueParametersHandler {
|
||||
override fun appendBeforeValueParameter(parameter: ValueParameterDescriptor, parameterIndex: Int, parameterCount: Int, builder: StringBuilder) {
|
||||
valueParametersHandler = object : DescriptorRenderer.ValueParametersHandler by this.valueParametersHandler {
|
||||
override fun appendBeforeValueParameter(
|
||||
parameter: ValueParameterDescriptor,
|
||||
parameterIndex: Int,
|
||||
parameterCount: Int,
|
||||
builder: StringBuilder
|
||||
) {
|
||||
builder.append("..., ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val parametersPresentation = parametersRenderer.renderValueParameters(listOf(descriptor.valueParameters.last()), descriptor.hasSynthesizedParameterNames())
|
||||
val parametersPresentation =
|
||||
parametersRenderer.renderValueParameters(listOf(descriptor.valueParameters.last()), descriptor.hasSynthesizedParameterNames())
|
||||
|
||||
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
@@ -202,7 +203,8 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
KotlinFunctionInsertHandler.Normal(callType, inputTypeArguments, inputValueArguments = false, lambdaInfo = lambdaInfo).handleInsert(context, this)
|
||||
KotlinFunctionInsertHandler.Normal(callType, inputTypeArguments, inputValueArguments = false, lambdaInfo = lambdaInfo)
|
||||
.handleInsert(context, this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +225,11 @@ class LookupElementFactory(
|
||||
return lookupElement
|
||||
}
|
||||
|
||||
private fun createFunctionCallElementWithArguments(descriptor: FunctionDescriptor, argumentText: String, useReceiverTypes: Boolean): LookupElement {
|
||||
private fun createFunctionCallElementWithArguments(
|
||||
descriptor: FunctionDescriptor,
|
||||
argumentText: String,
|
||||
useReceiverTypes: Boolean
|
||||
): LookupElement {
|
||||
val lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||
|
||||
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal).inputTypeArguments
|
||||
@@ -231,13 +237,15 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
private inner class FunctionCallWithArgumentsLookupElement(
|
||||
originalLookupElement: LookupElement,
|
||||
private val descriptor: FunctionDescriptor,
|
||||
private val argumentText: String,
|
||||
private val needTypeArguments: Boolean
|
||||
originalLookupElement: LookupElement,
|
||||
private val descriptor: FunctionDescriptor,
|
||||
private val argumentText: String,
|
||||
private val needTypeArguments: Boolean
|
||||
) : LookupElementDecorator<LookupElement>(originalLookupElement) {
|
||||
|
||||
override fun equals(other: Any?) = other is FunctionCallWithArgumentsLookupElement && delegate == other.delegate && argumentText == other.argumentText
|
||||
override fun equals(other: Any?) =
|
||||
other is FunctionCallWithArgumentsLookupElement && delegate == other.delegate && argumentText == other.argumentText
|
||||
|
||||
override fun hashCode() = delegate.hashCode() * 17 + argumentText.hashCode()
|
||||
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
@@ -249,17 +257,21 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
KotlinFunctionInsertHandler.Normal(callType, inputTypeArguments = needTypeArguments, inputValueArguments = false, argumentText = argumentText)
|
||||
.handleInsert(context, this)
|
||||
KotlinFunctionInsertHandler.Normal(
|
||||
callType,
|
||||
inputTypeArguments = needTypeArguments,
|
||||
inputValueArguments = false,
|
||||
argumentText = argumentText
|
||||
).handleInsert(context, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean,
|
||||
includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean,
|
||||
includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean
|
||||
): LookupElement {
|
||||
var element = basicFactory.createLookupElement(descriptor, qualifyNestedClasses, includeClassTypeArguments, parametersAndTypeGrayed)
|
||||
|
||||
@@ -286,8 +298,7 @@ class LookupElementFactory(
|
||||
super.renderElement(presentation)
|
||||
if (style == Style.BOLD) {
|
||||
presentation.isItemTextBold = true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
presentation.itemTextForeground = CAST_REQUIRED_COLOR
|
||||
// gray all tail fragments too:
|
||||
val fragments = presentation.tailFragments
|
||||
@@ -298,8 +309,7 @@ class LookupElementFactory(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
@@ -324,15 +334,11 @@ class LookupElementFactory(
|
||||
|
||||
if (descriptor.overriddenDescriptors.isNotEmpty()) {
|
||||
// Optimization: when one of direct overridden fits, then nothing can fit better
|
||||
descriptor.overriddenDescriptors
|
||||
.mapNotNull { it.callableWeightBasedOnReceiver(receiverTypes, onReceiverTypeMismatch = null) }
|
||||
.minBy { it.enum }
|
||||
?.let { return it }
|
||||
descriptor.overriddenDescriptors.mapNotNull { it.callableWeightBasedOnReceiver(receiverTypes, onReceiverTypeMismatch = null) }
|
||||
.minBy { it.enum }?.let { return it }
|
||||
|
||||
val overridden = descriptor.overriddenTreeUniqueAsSequence(useOriginal = false)
|
||||
return overridden
|
||||
.map { callableWeightBasic(it, receiverTypes)!! }
|
||||
.minBy { it.enum }!!
|
||||
return overridden.map { callableWeightBasic(it, receiverTypes)!! }.minBy { it.enum }!!
|
||||
}
|
||||
|
||||
return callableWeightBasic(descriptor, receiverTypes)
|
||||
@@ -348,8 +354,8 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
private fun CallableDescriptor.callableWeightBasedOnReceiver(
|
||||
receiverTypes: Collection<ReceiverType>,
|
||||
onReceiverTypeMismatch: CallableWeight?
|
||||
receiverTypes: Collection<ReceiverType>,
|
||||
onReceiverTypeMismatch: CallableWeight?
|
||||
): CallableWeight? {
|
||||
|
||||
val bothReceivers = listOfNotNull(extensionReceiverParameter, dispatchReceiverParameter)
|
||||
@@ -357,18 +363,18 @@ class LookupElementFactory(
|
||||
val receiverTypesForFirstReceiver = receiverTypes.filterNot { it.implicit }.ifEmpty { receiverTypes }
|
||||
|
||||
val weights = bothReceivers.zip(generateSequence(receiverTypesForFirstReceiver) { receiverTypes }.asIterable())
|
||||
.map { (receiverParameter, receiverTypes) ->
|
||||
callableWeightBasedOnReceiver(receiverTypes, onReceiverTypeMismatch, receiverParameter)
|
||||
}
|
||||
.map { (receiverParameter, receiverTypes) ->
|
||||
callableWeightBasedOnReceiver(receiverTypes, onReceiverTypeMismatch, receiverParameter)
|
||||
}
|
||||
|
||||
if (weights.any { it == onReceiverTypeMismatch }) return onReceiverTypeMismatch
|
||||
return weights.firstOrNull()
|
||||
}
|
||||
|
||||
private fun CallableDescriptor.callableWeightBasedOnReceiver(
|
||||
receiverTypes: Collection<ReceiverType>,
|
||||
onReceiverTypeMismatch: CallableWeight?,
|
||||
receiverParameter: ReceiverParameterDescriptor
|
||||
receiverTypes: Collection<ReceiverType>,
|
||||
onReceiverTypeMismatch: CallableWeight?,
|
||||
receiverParameter: ReceiverParameterDescriptor
|
||||
): CallableWeight? {
|
||||
if ((receiverParameter.value as? TransientReceiver)?.type?.isFunctionType == true) return null
|
||||
|
||||
@@ -403,8 +409,8 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
private fun CallableDescriptor.callableWeightForReceiverType(
|
||||
receiverType: KotlinType,
|
||||
receiverParameterType: KotlinType
|
||||
receiverType: KotlinType,
|
||||
receiverParameterType: KotlinType
|
||||
): CallableWeightEnum? = when {
|
||||
TypeUtils.equalTypes(receiverType, receiverParameterType) -> when {
|
||||
isExtensionForTypeParameter() -> CallableWeightEnum.typeParameterExtension
|
||||
|
||||
+10
-23
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -33,13 +22,13 @@ import java.util.*
|
||||
import kotlin.math.max
|
||||
|
||||
class LookupElementsCollector(
|
||||
private val onFlush: () -> Unit,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val completionParameters: CompletionParameters,
|
||||
resultSet: CompletionResultSet,
|
||||
sorter: CompletionSorter,
|
||||
private val filter: ((LookupElement) -> Boolean)?,
|
||||
private val allowExpectDeclarations: Boolean
|
||||
private val onFlush: () -> Unit,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val completionParameters: CompletionParameters,
|
||||
resultSet: CompletionResultSet,
|
||||
sorter: CompletionSorter,
|
||||
private val filter: ((LookupElement) -> Boolean)?,
|
||||
private val allowExpectDeclarations: Boolean
|
||||
) {
|
||||
|
||||
var bestMatchingDegree = Int.MIN_VALUE
|
||||
@@ -47,9 +36,7 @@ class LookupElementsCollector(
|
||||
|
||||
private val elements = ArrayList<LookupElement>()
|
||||
|
||||
private val resultSet = resultSet
|
||||
.withPrefixMatcher(prefixMatcher)
|
||||
.withRelevanceSorter(sorter)
|
||||
private val resultSet = resultSet.withPrefixMatcher(prefixMatcher).withRelevanceSorter(sorter)
|
||||
|
||||
private val postProcessors = ArrayList<(LookupElement) -> LookupElement>()
|
||||
private val processedCallables = mutableSetOf<CallableDescriptor>()
|
||||
|
||||
+7
-20
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -41,9 +30,7 @@ object NamedArgumentCompletion {
|
||||
|
||||
val callElement = thisArgument.getStrictParentOfType<KtCallElement>() ?: return false
|
||||
|
||||
return callElement.valueArguments
|
||||
.takeWhile { it != thisArgument }
|
||||
.any { it.isNamed() }
|
||||
return callElement.valueArguments.takeWhile { it != thisArgument }.any { it.isNamed() }
|
||||
}
|
||||
|
||||
fun complete(collector: LookupElementsCollector, expectedInfos: Collection<ExpectedInfo>, callType: CallType<*>) {
|
||||
@@ -61,10 +48,10 @@ object NamedArgumentCompletion {
|
||||
val typeText = types.singleOrNull()?.let { BasicLookupElementFactory.SHORT_NAMES_RENDERER.renderType(it) } ?: "..."
|
||||
val nameString = name.asString()
|
||||
val lookupElement = LookupElementBuilder.create("$nameString =")
|
||||
.withPresentableText("$nameString =")
|
||||
.withTailText(" $typeText")
|
||||
.withIcon(KotlinIcons.PARAMETER)
|
||||
.withInsertHandler(NamedArgumentInsertHandler(name))
|
||||
.withPresentableText("$nameString =")
|
||||
.withTailText(" $typeText")
|
||||
.withIcon(KotlinIcons.PARAMETER)
|
||||
.withInsertHandler(NamedArgumentInsertHandler(name))
|
||||
lookupElement.putUserData(SmartCompletionInBasicWeigher.NAMED_ARGUMENT_KEY, Unit)
|
||||
collector.addElement(lookupElement)
|
||||
}
|
||||
|
||||
+11
-24
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -31,28 +20,26 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.SET
|
||||
object OperatorNameCompletion {
|
||||
|
||||
private val additionalOperatorPresentation = mapOf(
|
||||
SET to "[...] = ...",
|
||||
GET to "[...]",
|
||||
CONTAINS to "in !in",
|
||||
COMPARE_TO to "< > <= >=",
|
||||
EQUALS to "== !=",
|
||||
INVOKE to "(...)"
|
||||
SET to "[...] = ...",
|
||||
GET to "[...]",
|
||||
CONTAINS to "in !in",
|
||||
COMPARE_TO to "< > <= >=",
|
||||
EQUALS to "== !=",
|
||||
INVOKE to "(...)"
|
||||
)
|
||||
|
||||
private fun buildLookupElement(opName: Name): LookupElement {
|
||||
val element = LookupElementBuilder.create(opName)
|
||||
|
||||
val symbol =
|
||||
(OperatorConventions.getOperationSymbolForName(opName) as? KtSingleValueToken)?.value ?:
|
||||
additionalOperatorPresentation[opName]
|
||||
(OperatorConventions.getOperationSymbolForName(opName) as? KtSingleValueToken)?.value ?: additionalOperatorPresentation[opName]
|
||||
|
||||
if (symbol != null) return element.withTypeText(symbol)
|
||||
return element
|
||||
}
|
||||
|
||||
fun doComplete(collector: LookupElementsCollector, descriptorNameFilter: (String) -> Boolean) {
|
||||
collector.addElements(OperatorConventions.CONVENTION_NAMES
|
||||
.filter { descriptorNameFilter(it.asString()) }
|
||||
.map(this::buildLookupElement))
|
||||
collector.addElements(OperatorConventions.CONVENTION_NAMES.filter { descriptorNameFilter(it.asString()) }
|
||||
.map(this::buildLookupElement))
|
||||
}
|
||||
}
|
||||
+6
-14
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -53,7 +42,10 @@ object PackageDirectiveCompletion {
|
||||
val packageMemberScope = resolutionFacade.moduleDescriptor.getPackage(file.packageFqName.parent()).memberScope
|
||||
|
||||
val variants = packageMemberScope.getContributedDescriptors(DescriptorKindFilter.PACKAGES, prefixMatcher.asNameFilter())
|
||||
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(callType = CallType.PACKAGE_DIRECTIVE, expectedInfosCalculator = { emptyList() }))
|
||||
val lookupElementFactory = BasicLookupElementFactory(
|
||||
resolutionFacade.project,
|
||||
InsertHandlerProvider(callType = CallType.PACKAGE_DIRECTIVE, expectedInfosCalculator = { emptyList() })
|
||||
)
|
||||
for (variant in variants) {
|
||||
val lookupElement = lookupElementFactory.createLookupElement(variant)
|
||||
if (!lookupElement.lookupString.contains(DUMMY_IDENTIFIER)) {
|
||||
|
||||
+55
-51
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -43,22 +32,24 @@ private operator fun ReferenceVariants.plus(other: ReferenceVariants): Reference
|
||||
}
|
||||
|
||||
class ReferenceVariantsCollector(
|
||||
private val referenceVariantsHelper: ReferenceVariantsHelper,
|
||||
private val indicesHelper: KotlinIndicesHelper,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val nameExpression: KtSimpleNameExpression,
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext,
|
||||
private val importableFqNameClassifier: ImportableFqNameClassifier,
|
||||
private val configuration: CompletionSessionConfiguration,
|
||||
private val runtimeReceiver: ExpressionReceiver? = null
|
||||
private val referenceVariantsHelper: ReferenceVariantsHelper,
|
||||
private val indicesHelper: KotlinIndicesHelper,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val nameExpression: KtSimpleNameExpression,
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext,
|
||||
private val importableFqNameClassifier: ImportableFqNameClassifier,
|
||||
private val configuration: CompletionSessionConfiguration,
|
||||
private val runtimeReceiver: ExpressionReceiver? = null
|
||||
) {
|
||||
|
||||
private data class FilterConfiguration internal constructor(val descriptorKindFilter: DescriptorKindFilter,
|
||||
val additionalPropertyNameFilter: ((String) -> Boolean)?,
|
||||
val shadowedDeclarationsFilter: ShadowedDeclarationsFilter?,
|
||||
val completeExtensionsFromIndices: Boolean)
|
||||
private data class FilterConfiguration internal constructor(
|
||||
val descriptorKindFilter: DescriptorKindFilter,
|
||||
val additionalPropertyNameFilter: ((String) -> Boolean)?,
|
||||
val shadowedDeclarationsFilter: ShadowedDeclarationsFilter?,
|
||||
val completeExtensionsFromIndices: Boolean
|
||||
)
|
||||
|
||||
private val prefix = prefixMatcher.prefix
|
||||
private val descriptorNameFilter = prefixMatcher.asStringNameFilter()
|
||||
@@ -111,8 +102,9 @@ class ReferenceVariantsCollector(
|
||||
|
||||
private fun configuration(descriptorKindFilter: DescriptorKindFilter): FilterConfiguration {
|
||||
val completeExtensionsFromIndices = descriptorKindFilter.kindMask.and(DescriptorKindFilter.CALLABLES_MASK) != 0
|
||||
&& DescriptorKindExclude.Extensions !in descriptorKindFilter.excludes
|
||||
&& callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE
|
||||
&& DescriptorKindExclude.Extensions !in descriptorKindFilter.excludes
|
||||
&& callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val descriptorKindFilter = if (completeExtensionsFromIndices)
|
||||
descriptorKindFilter exclude TopLevelExtensionsExclude // handled via indices
|
||||
@@ -120,27 +112,34 @@ class ReferenceVariantsCollector(
|
||||
descriptorKindFilter
|
||||
|
||||
val getOrSetPrefix = GET_SET_PREFIXES.firstOrNull { prefix.startsWith(it) }
|
||||
val additionalPropertyNameFilter: ((String) -> Boolean)? = getOrSetPrefix
|
||||
?.let { prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmartForCompiler()).asStringNameFilter() }
|
||||
val additionalPropertyNameFilter: ((String) -> Boolean)? = getOrSetPrefix?.let {
|
||||
prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmartForCompiler()).asStringNameFilter()
|
||||
}
|
||||
|
||||
val shadowedDeclarationsFilter = if (runtimeReceiver != null)
|
||||
ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, runtimeReceiver)
|
||||
else
|
||||
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression, callTypeAndReceiver)
|
||||
|
||||
return FilterConfiguration(descriptorKindFilter, additionalPropertyNameFilter, shadowedDeclarationsFilter, completeExtensionsFromIndices)
|
||||
return FilterConfiguration(
|
||||
descriptorKindFilter,
|
||||
additionalPropertyNameFilter,
|
||||
shadowedDeclarationsFilter,
|
||||
completeExtensionsFromIndices
|
||||
)
|
||||
}
|
||||
|
||||
private fun doCollectBasicVariants(filterConfiguration: FilterConfiguration): ReferenceVariants {
|
||||
fun getReferenceVariants(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||
return referenceVariantsHelper.getReferenceVariants(
|
||||
nameExpression,
|
||||
kindFilter,
|
||||
nameFilter,
|
||||
filterOutJavaGettersAndSetters = false,
|
||||
filterOutShadowed = false,
|
||||
excludeNonInitializedVariable = false,
|
||||
useReceiverType = runtimeReceiver?.type)
|
||||
nameExpression,
|
||||
kindFilter,
|
||||
nameFilter,
|
||||
filterOutJavaGettersAndSetters = false,
|
||||
filterOutShadowed = false,
|
||||
excludeNonInitializedVariable = false,
|
||||
useReceiverType = runtimeReceiver?.type
|
||||
)
|
||||
}
|
||||
|
||||
val basicNameFilter = descriptorNameFilter.toNameFilter()
|
||||
@@ -150,7 +149,10 @@ class ReferenceVariantsCollector(
|
||||
|
||||
var basicVariants = getReferenceVariants(descriptorKindFilter, basicNameFilter)
|
||||
if (additionalPropertyNameFilter != null) {
|
||||
basicVariants += getReferenceVariants(descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES), additionalPropertyNameFilter.toNameFilter())
|
||||
basicVariants += getReferenceVariants(
|
||||
descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES),
|
||||
additionalPropertyNameFilter.toNameFilter()
|
||||
)
|
||||
runDistinct = true
|
||||
}
|
||||
|
||||
@@ -183,18 +185,22 @@ class ReferenceVariantsCollector(
|
||||
else
|
||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, nameExpression, bindingContext, nameFilter)
|
||||
|
||||
val (extensionsVariants, notImportedExtensions) = extensions.partition { importableFqNameClassifier.isImportableDescriptorImported(it) }
|
||||
val (extensionsVariants, notImportedExtensions) = extensions.partition {
|
||||
importableFqNameClassifier.isImportableDescriptorImported(
|
||||
it
|
||||
)
|
||||
}
|
||||
|
||||
val notImportedDeclarationsFilter =
|
||||
shadowedDeclarationsFilter?.createNonImportedDeclarationsFilter<CallableDescriptor>(importedDeclarations = basicVariants.imported + extensionsVariants)
|
||||
shadowedDeclarationsFilter?.createNonImportedDeclarationsFilter<CallableDescriptor>(importedDeclarations = basicVariants.imported + extensionsVariants)
|
||||
|
||||
val filteredImported = filterConfiguration.filterVariants(extensionsVariants + basicVariants.imported)
|
||||
|
||||
val importedExtensionsVariants = filteredImported.filter { it !in basicVariants.imported }
|
||||
|
||||
return ReferenceVariants(
|
||||
importedExtensionsVariants,
|
||||
notImportedExtensions.let { variants -> notImportedDeclarationsFilter?.invoke(variants) ?: variants }
|
||||
importedExtensionsVariants,
|
||||
notImportedExtensions.let { variants -> notImportedDeclarationsFilter?.invoke(variants) ?: variants }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -226,17 +232,15 @@ class ReferenceVariantsCollector(
|
||||
if (descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION) return false /* do not filter out synthetic extensions */
|
||||
if (descriptor.isArtificialImportAliasedDescriptor) return false // do not exclude aliased descriptors - they cannot be completed via indices
|
||||
val containingPackage = descriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||
if (containingPackage.fqName.asString().startsWith("kotlinx.android.synthetic.")) return false // TODO: temporary solution for Android synthetic extensions
|
||||
// TODO: temporary solution for Android synthetic extensions
|
||||
if (containingPackage.fqName.asString().startsWith("kotlinx.android.synthetic.")) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int get() = 0
|
||||
}
|
||||
|
||||
private fun isDataClassComponentFunction(descriptor: DeclarationDescriptor): Boolean {
|
||||
return descriptor is FunctionDescriptor &&
|
||||
descriptor.isOperator &&
|
||||
DataClassDescriptorResolver.isComponentLike(descriptor.name) &&
|
||||
descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
}
|
||||
private fun isDataClassComponentFunction(descriptor: DeclarationDescriptor): Boolean =
|
||||
descriptor is FunctionDescriptor && descriptor.isOperator && DataClassDescriptorResolver.isComponentLike(descriptor.name) && descriptor.kind == CallableMemberDescriptor.Kind
|
||||
.SYNTHESIZED
|
||||
}
|
||||
|
||||
+37
-47
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -39,43 +28,42 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
class StaticMembersCompletion(
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val lookupElementFactory: LookupElementFactory,
|
||||
alreadyAdded: Collection<DeclarationDescriptor>,
|
||||
private val isJvmModule: Boolean
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val lookupElementFactory: LookupElementFactory,
|
||||
alreadyAdded: Collection<DeclarationDescriptor>,
|
||||
private val isJvmModule: Boolean
|
||||
) {
|
||||
private val alreadyAdded = alreadyAdded.mapTo(HashSet()) {
|
||||
if (it is ImportedFromObjectCallableDescriptor<*>) it.callableFromObject else it
|
||||
}
|
||||
|
||||
fun decoratedLookupElementFactory(itemPriority: ItemPriority): AbstractLookupElementFactory {
|
||||
return object : AbstractLookupElementFactory {
|
||||
override fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||
if (!useReceiverTypes) return emptyList()
|
||||
return lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false)
|
||||
.decorateAsStaticMember(descriptor, classNameAsLookupString = false)
|
||||
?.assignPriority(itemPriority)
|
||||
?.suppressAutoInsertion()
|
||||
.let(::listOfNotNull)
|
||||
}
|
||||
|
||||
override fun createLookupElement(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean, includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean) = null
|
||||
fun decoratedLookupElementFactory(itemPriority: ItemPriority): AbstractLookupElementFactory = object : AbstractLookupElementFactory {
|
||||
override fun createStandardLookupElementsForDescriptor(
|
||||
descriptor: DeclarationDescriptor,
|
||||
useReceiverTypes: Boolean
|
||||
): Collection<LookupElement> {
|
||||
if (!useReceiverTypes) return emptyList()
|
||||
return lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false)
|
||||
.decorateAsStaticMember(descriptor, classNameAsLookupString = false)
|
||||
?.assignPriority(itemPriority)
|
||||
?.suppressAutoInsertion()
|
||||
.let(::listOfNotNull)
|
||||
}
|
||||
|
||||
override fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor, useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean, includeClassTypeArguments: Boolean,
|
||||
parametersAndTypeGrayed: Boolean
|
||||
) = null
|
||||
}
|
||||
|
||||
fun membersFromImports(file: KtFile): Collection<DeclarationDescriptor> {
|
||||
val containers = file.importDirectives
|
||||
.filter { !it.isAllUnder }
|
||||
.mapNotNull {
|
||||
it.targetDescriptors(resolutionFacade)
|
||||
.map { it.containingDeclaration }
|
||||
.distinct()
|
||||
.singleOrNull() as? ClassDescriptor
|
||||
}
|
||||
.toSet()
|
||||
val containers = file.importDirectives.filter { !it.isAllUnder }.mapNotNull {
|
||||
it.targetDescriptors(resolutionFacade).map { descriptor ->
|
||||
descriptor.containingDeclaration
|
||||
}.distinct().singleOrNull() as? ClassDescriptor
|
||||
}.toSet()
|
||||
|
||||
val result = ArrayList<DeclarationDescriptor>()
|
||||
|
||||
@@ -84,8 +72,11 @@ class StaticMembersCompletion(
|
||||
for (container in containers) {
|
||||
val memberScope = if (container.kind == ClassKind.OBJECT) container.unsubstitutedMemberScope else container.staticScope
|
||||
val members =
|
||||
memberScope.getDescriptorsFiltered(kindFilter, nameFilter) +
|
||||
memberScope.collectSyntheticStaticMembersAndConstructors(resolutionFacade, kindFilter, nameFilter)
|
||||
memberScope.getDescriptorsFiltered(kindFilter, nameFilter) + memberScope.collectSyntheticStaticMembersAndConstructors(
|
||||
resolutionFacade,
|
||||
kindFilter,
|
||||
nameFilter
|
||||
)
|
||||
members.filterTo(result) { it is CallableDescriptor && it !in alreadyAdded }
|
||||
}
|
||||
return result
|
||||
@@ -109,7 +100,7 @@ class StaticMembersCompletion(
|
||||
}
|
||||
|
||||
if (isJvmModule) {
|
||||
indicesHelper.processJavaStaticMembers(descriptorKindFilter, nameFilter){
|
||||
indicesHelper.processJavaStaticMembers(descriptorKindFilter, nameFilter) {
|
||||
if (it !in alreadyAdded) {
|
||||
processor(it)
|
||||
}
|
||||
@@ -132,9 +123,8 @@ class StaticMembersCompletion(
|
||||
|
||||
fun completeFromImports(file: KtFile, collector: LookupElementsCollector) {
|
||||
val factory = decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER_FROM_IMPORTS)
|
||||
membersFromImports(file)
|
||||
.flatMap { factory.createStandardLookupElementsForDescriptor(it, useReceiverTypes = true) }
|
||||
.forEach { collector.addElement(it) }
|
||||
membersFromImports(file).flatMap { factory.createStandardLookupElementsForDescriptor(it, useReceiverTypes = true) }
|
||||
.forEach { collector.addElement(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -42,8 +31,7 @@ class KotlinCompletionStatistician : CompletionStatistician() {
|
||||
|
||||
if (o.descriptor != null) {
|
||||
return KotlinStatisticsInfo.forDescriptor(o.descriptor!!.original, context)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val fqName = o.importableFqName ?: return StatisticsInfo.EMPTY
|
||||
return StatisticsInfo(context, fqName.asString())
|
||||
}
|
||||
@@ -74,13 +62,12 @@ object KotlinStatisticsInfo {
|
||||
return descriptor.importableFqName?.let { StatisticsInfo("", it.asString()) } ?: StatisticsInfo.EMPTY
|
||||
}
|
||||
|
||||
val container = descriptor.containingDeclaration
|
||||
val containerFqName = when (container) {
|
||||
is ClassDescriptor -> container.importableFqName?.asString()
|
||||
is PackageFragmentDescriptor -> container.fqName.asString()
|
||||
is ModuleDescriptor -> ""
|
||||
else -> null
|
||||
} ?: return StatisticsInfo.EMPTY
|
||||
val containerFqName = when (val container = descriptor.containingDeclaration) {
|
||||
is ClassDescriptor -> container.importableFqName?.asString()
|
||||
is PackageFragmentDescriptor -> container.fqName.asString()
|
||||
is ModuleDescriptor -> ""
|
||||
else -> null
|
||||
} ?: return StatisticsInfo.EMPTY
|
||||
val signature = SIGNATURE_RENDERER.render(descriptor)
|
||||
return StatisticsInfo(context, "$containerFqName###$signature")
|
||||
}
|
||||
|
||||
+6
-17
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -25,9 +14,9 @@ import org.jetbrains.kotlin.utils.checkWithAttachment
|
||||
import kotlin.math.min
|
||||
|
||||
class ToFromOriginalFileMapper private constructor(
|
||||
val originalFile: KtFile,
|
||||
val syntheticFile: KtFile,
|
||||
val completionOffset: Int
|
||||
val originalFile: KtFile,
|
||||
val syntheticFile: KtFile,
|
||||
val completionOffset: Int
|
||||
) {
|
||||
companion object {
|
||||
fun create(parameters: CompletionParameters): ToFromOriginalFileMapper {
|
||||
@@ -60,7 +49,7 @@ class ToFromOriginalFileMapper private constructor(
|
||||
syntheticLength = syntheticText.length
|
||||
originalLength = originalText.length
|
||||
val minLength = min(originalLength, syntheticLength)
|
||||
tailLength = (0..minLength-1).firstOrNull {
|
||||
tailLength = (0 until minLength).firstOrNull {
|
||||
syntheticText[syntheticLength - it - 1] != originalText[originalLength - it - 1]
|
||||
} ?: minLength
|
||||
shift = syntheticLength - originalLength
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
@@ -39,8 +28,7 @@ import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
|
||||
object PriorityWeigher : LookupElementWeigher("kotlin.priority") {
|
||||
override fun weigh(element: LookupElement, context: WeighingContext)
|
||||
= element.getUserData(ITEM_PRIORITY_KEY) ?: ItemPriority.DEFAULT
|
||||
override fun weigh(element: LookupElement, context: WeighingContext) = element.getUserData(ITEM_PRIORITY_KEY) ?: ItemPriority.DEFAULT
|
||||
}
|
||||
|
||||
object PreferDslMembers : LookupElementWeigher("kotlin.preferDsl") {
|
||||
@@ -71,7 +59,8 @@ class NotImportedWeigher(private val classifier: ImportableFqNameClassifier) : L
|
||||
}
|
||||
}
|
||||
|
||||
class NotImportedStaticMemberWeigher(private val classifier: ImportableFqNameClassifier) : LookupElementWeigher("kotlin.notImportedMember") {
|
||||
class NotImportedStaticMemberWeigher(private val classifier: ImportableFqNameClassifier) :
|
||||
LookupElementWeigher("kotlin.notImportedMember") {
|
||||
override fun weigh(element: LookupElement): Comparable<*>? {
|
||||
if (element.getUserData(ITEM_PRIORITY_KEY) != ItemPriority.STATIC_MEMBER) return null
|
||||
val fqName = (element.`object` as DeclarationLookupObject).importableFqName ?: return null
|
||||
@@ -109,8 +98,8 @@ object KotlinLookupElementProximityWeigher : CompletionWeigher() {
|
||||
}
|
||||
|
||||
object SmartCompletionPriorityWeigher : LookupElementWeigher("kotlin.smartCompletionPriority") {
|
||||
override fun weigh(element: LookupElement, context: WeighingContext)
|
||||
= element.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) ?: SmartCompletionItemPriority.DEFAULT
|
||||
override fun weigh(element: LookupElement, context: WeighingContext) =
|
||||
element.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) ?: SmartCompletionItemPriority.DEFAULT
|
||||
}
|
||||
|
||||
object KindWeigher : LookupElementWeigher("kotlin.kind") {
|
||||
@@ -197,7 +186,7 @@ object CallableWeigher : LookupElementWeigher("kotlin.callableWeight") {
|
||||
}
|
||||
}
|
||||
|
||||
object VariableOrFunctionWeigher : LookupElementWeigher("kotlin.variableOrFunction"){
|
||||
object VariableOrFunctionWeigher : LookupElementWeigher("kotlin.variableOrFunction") {
|
||||
private enum class Weight {
|
||||
variable,
|
||||
function
|
||||
@@ -216,7 +205,7 @@ object VariableOrFunctionWeigher : LookupElementWeigher("kotlin.variableOrFuncti
|
||||
/**
|
||||
* Decreases priority of properties when prefix starts with "get" or "set" (and the property name does not)
|
||||
*/
|
||||
object PreferGetSetMethodsToPropertyWeigher : LookupElementWeigher("kotlin.preferGetSetMethodsToProperty", false, true){
|
||||
object PreferGetSetMethodsToPropertyWeigher : LookupElementWeigher("kotlin.preferGetSetMethodsToProperty", false, true) {
|
||||
override fun weigh(element: LookupElement, context: WeighingContext): Int {
|
||||
val property = (element.`object` as? DeclarationLookupObject)?.descriptor as? PropertyDescriptor ?: return 0
|
||||
val prefixMatcher = context.itemMatcher(element)
|
||||
@@ -247,8 +236,7 @@ object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMatching",
|
||||
val prefix = context.itemPattern(element)
|
||||
if (element.lookupString != prefix) {
|
||||
return Weight.notExactMatch
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val o = element.`object`
|
||||
return when (o) {
|
||||
is KeywordLookupObject -> Weight.keywordExactMatch
|
||||
@@ -270,10 +258,10 @@ object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMatching",
|
||||
}
|
||||
|
||||
class SmartCompletionInBasicWeigher(
|
||||
private val smartCompletion: SmartCompletion,
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext
|
||||
private val smartCompletion: SmartCompletion,
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext
|
||||
) : LookupElementWeigher("kotlin.smartInBasic", true, false) {
|
||||
|
||||
companion object {
|
||||
@@ -286,8 +274,8 @@ class SmartCompletionInBasicWeigher(
|
||||
|
||||
private val PRIORITY_COUNT = SmartCompletionItemPriority.values().size
|
||||
|
||||
private fun itemWeight(priority: SmartCompletionItemPriority, nameSimilarity: Int)
|
||||
= (nameSimilarity.toLong() shl 32) + PRIORITY_COUNT - priority.ordinal
|
||||
private fun itemWeight(priority: SmartCompletionItemPriority, nameSimilarity: Int) =
|
||||
(nameSimilarity.toLong() shl 32) + PRIORITY_COUNT - priority.ordinal
|
||||
|
||||
private val NAMED_ARGUMENT_WEIGHT = 1L
|
||||
|
||||
@@ -316,7 +304,12 @@ class SmartCompletionInBasicWeigher(
|
||||
val (fuzzyTypes, name) = when (o) {
|
||||
is DeclarationLookupObject -> {
|
||||
val descriptor = o.descriptor ?: return NO_MATCH_WEIGHT
|
||||
descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callTypeAndReceiver, resolutionFacade, bindingContext) to descriptor.name
|
||||
descriptor.fuzzyTypesForSmartCompletion(
|
||||
smartCastCalculator,
|
||||
callTypeAndReceiver,
|
||||
resolutionFacade,
|
||||
bindingContext
|
||||
) to descriptor.name
|
||||
}
|
||||
|
||||
is ThisItemLookupObject -> smartCastCalculator.types(o.receiverParameter).map { it.toFuzzyType(emptyList()) } to null
|
||||
@@ -332,8 +325,7 @@ class SmartCompletionInBasicWeigher(
|
||||
val nameSimilarity = if (name != null) {
|
||||
val matchingInfos = matched.filter { it.second != ExpectedInfoMatch.noMatch }.map { it.first }
|
||||
calcNameSimilarity(name.asString(), matchingInfos)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
@@ -346,10 +338,10 @@ class SmartCompletionInBasicWeigher(
|
||||
|
||||
class PreferContextElementsWeigher(context: DeclarationDescriptor) : LookupElementWeigher("kotlin.preferContextElements", true, false) {
|
||||
private val contextElements = context.parentsWithSelf
|
||||
.takeWhile { it !is PackageFragmentDescriptor }
|
||||
.toList()
|
||||
.flatMap { if (it is CallableDescriptor) it.findOriginalTopMostOverriddenDescriptors() else listOf(it) }
|
||||
.toSet()
|
||||
.takeWhile { it !is PackageFragmentDescriptor }
|
||||
.toList()
|
||||
.flatMap { if (it is CallableDescriptor) it.findOriginalTopMostOverriddenDescriptors() else listOf(it) }
|
||||
.toSet()
|
||||
private val contextElementNames = contextElements.map { it.name }.toSet()
|
||||
|
||||
override fun weigh(element: LookupElement): Boolean {
|
||||
|
||||
+4
-14
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.confidence
|
||||
@@ -29,7 +18,8 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
class EnableAutopopupInStringTemplate : CompletionConfidence() {
|
||||
override fun shouldSkipAutopopup(contextElement: PsiElement, psiFile: PsiFile, offset: Int): ThreeState {
|
||||
val stringTemplate = contextElement.prevLeaf()?.getParentOfType<KtSimpleNameStringTemplateEntry>(strict = false) ?: return ThreeState.UNSURE
|
||||
val stringTemplate =
|
||||
contextElement.prevLeaf()?.getParentOfType<KtSimpleNameStringTemplateEntry>(strict = false) ?: return ThreeState.UNSURE
|
||||
|
||||
// "$<caret>nameRef" stringTemplate here is "$nameRef", so offset are inside template, we should show lookup
|
||||
if (offset in stringTemplate.startOffset until stringTemplate.endOffset) return ThreeState.NO
|
||||
|
||||
+2
-1
@@ -45,7 +45,8 @@ object KotlinClassifierInsertHandler : BaseDeclarationInsertHandler() {
|
||||
val document = context.document
|
||||
|
||||
val lookupObject = item.`object` as DeclarationLookupObject
|
||||
if (lookupObject.descriptor?.isArtificialImportAliasedDescriptor == true) return // never need to insert import or use qualified name for import-aliased class
|
||||
// never need to insert import or use qualified name for import-aliased class
|
||||
if (lookupObject.descriptor?.isArtificialImportAliasedDescriptor == true) return
|
||||
|
||||
val qualifiedName = qualifiedName(lookupObject)
|
||||
|
||||
|
||||
+2
-1
@@ -117,7 +117,8 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
val token = context.file.findElementAt(offset1)!!
|
||||
if (token.node.elementType == KtTokens.LT) {
|
||||
val parent = token.parent
|
||||
if (parent is KtTypeArgumentList && parent.getText().indexOf('\n') < 0/* if type argument list is on multiple lines this is more likely wrong parsing*/) {
|
||||
/* if type argument list is on multiple lines this is more likely wrong parsing*/
|
||||
if (parent is KtTypeArgumentList && parent.getText().indexOf('\n') < 0) {
|
||||
offset = parent.endOffset
|
||||
insertTypeArguments = false
|
||||
}
|
||||
|
||||
+22
-33
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -30,18 +19,22 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
|
||||
object ArrayLiteralsInAnnotationItems {
|
||||
|
||||
private fun MutableCollection<LookupElement>.addForUsage(expectedInfos: Collection<ExpectedInfo>,
|
||||
position: PsiElement) {
|
||||
private fun MutableCollection<LookupElement>.addForUsage(
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
position: PsiElement
|
||||
) {
|
||||
if (position.getParentOfType<KtAnnotationEntry>(false) != null) {
|
||||
expectedInfos.asSequence()
|
||||
.filter { it.fuzzyType?.type?.let { type -> KotlinBuiltIns.isArray(type) } == true }
|
||||
.filterNot { it.itemOptions.starPrefix }
|
||||
.mapTo(this) { createLookupElement() }
|
||||
.filter { it.fuzzyType?.type?.let { type -> KotlinBuiltIns.isArray(type) } == true }
|
||||
.filterNot { it.itemOptions.starPrefix }
|
||||
.mapTo(this) { createLookupElement() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableCollection<LookupElement>.addForDefaultArguments(expectedInfos: Collection<ExpectedInfo>,
|
||||
position: PsiElement) {
|
||||
private fun MutableCollection<LookupElement>.addForDefaultArguments(
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
position: PsiElement
|
||||
) {
|
||||
|
||||
// CLASS [MODIFIER_LIST, PRIMARY_CONSTRUCTOR [VALUE_PARAMETER_LIST [VALUE_PARAMETER [..., REFERENCE_EXPRESSION=position]]]]
|
||||
val valueParameter = position.parent as? KtParameter ?: return
|
||||
@@ -50,24 +43,20 @@ object ArrayLiteralsInAnnotationItems {
|
||||
val primaryConstructor = klass.primaryConstructor ?: return
|
||||
|
||||
if (primaryConstructor.valueParameterList == valueParameter.parent) {
|
||||
expectedInfos
|
||||
.filter { it.fuzzyType?.type?.let { type -> KotlinBuiltIns.isArray(type) } == true }
|
||||
.mapTo(this) { createLookupElement() }
|
||||
expectedInfos.filter { it.fuzzyType?.type?.let { type -> KotlinBuiltIns.isArray(type) } == true }
|
||||
.mapTo(this) { createLookupElement() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLookupElement(): LookupElement {
|
||||
return LookupElementBuilder.create("[]")
|
||||
.withInsertHandler { context, _ ->
|
||||
context.editor.caretModel.moveToOffset(context.tailOffset - 1)
|
||||
}
|
||||
.apply { putUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY, SmartCompletionItemPriority.ARRAY_LITERAL_IN_ANNOTATION) }
|
||||
}
|
||||
private fun createLookupElement(): LookupElement = LookupElementBuilder.create("[]")
|
||||
.withInsertHandler { context, _ ->
|
||||
context.editor.caretModel.moveToOffset(context.tailOffset - 1)
|
||||
}
|
||||
.apply { putUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY, SmartCompletionItemPriority.ARRAY_LITERAL_IN_ANNOTATION) }
|
||||
|
||||
fun collect(expectedInfos: Collection<ExpectedInfo>, position: PsiElement): Collection<LookupElement> {
|
||||
return mutableListOf<LookupElement>().apply {
|
||||
fun collect(expectedInfos: Collection<ExpectedInfo>, position: PsiElement): Collection<LookupElement> =
|
||||
mutableListOf<LookupElement>().apply {
|
||||
addForUsage(expectedInfos, position)
|
||||
addForDefaultArguments(expectedInfos, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-20
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -27,8 +16,8 @@ import org.jetbrains.kotlin.idea.completion.BasicLookupElementFactory
|
||||
import org.jetbrains.kotlin.idea.completion.createLookupElementForType
|
||||
import org.jetbrains.kotlin.idea.core.ExpectedInfo
|
||||
import org.jetbrains.kotlin.idea.core.fuzzyType
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
@@ -36,10 +25,10 @@ import java.util.*
|
||||
|
||||
object ClassLiteralItems {
|
||||
fun addToCollection(
|
||||
collection: MutableCollection<LookupElement>,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
lookupElementFactory: BasicLookupElementFactory,
|
||||
isJvmModule: Boolean
|
||||
collection: MutableCollection<LookupElement>,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
lookupElementFactory: BasicLookupElementFactory,
|
||||
isJvmModule: Boolean
|
||||
) {
|
||||
val typeAndSuffixToExpectedInfos = LinkedHashMap<Pair<KotlinType, String>, MutableList<ExpectedInfo>>()
|
||||
|
||||
@@ -64,8 +53,7 @@ object ClassLiteralItems {
|
||||
val (type, suffix) = pair
|
||||
val typeToUse = if (KotlinBuiltIns.isArray(type)) {
|
||||
type.makeNotNullable()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val classifier = (type.constructor.declarationDescriptor as? ClassDescriptor) ?: continue
|
||||
classifier.defaultType
|
||||
}
|
||||
|
||||
+20
-28
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -39,46 +28,49 @@ object LambdaItems {
|
||||
val functionExpectedInfos = expectedInfos.filter { it.fuzzyType?.type?.isFunctionOrSuspendFunctionType == true }
|
||||
if (functionExpectedInfos.isEmpty()) return
|
||||
|
||||
val functionTypes = functionExpectedInfos
|
||||
.mapNotNull { it.fuzzyType?.type }
|
||||
.toSet()
|
||||
val functionTypes = functionExpectedInfos.mapNotNull { it.fuzzyType?.type }.toSet()
|
||||
|
||||
val singleType = if (functionTypes.size == 1) functionTypes.single() else null
|
||||
val singleSignatureLength = singleType?.let(::getValueParametersCountFromFunctionType)
|
||||
val offerNoParametersLambda = singleSignatureLength == 0 || singleSignatureLength == 1
|
||||
if (offerNoParametersLambda) {
|
||||
val lookupElement = LookupElementBuilder.create(LambdaSignatureTemplates.DEFAULT_LAMBDA_PRESENTATION)
|
||||
.withInsertHandler(ArtificialElementInsertHandler("{ ", " }", false))
|
||||
.suppressAutoInsertion()
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.LAMBDA_NO_PARAMS)
|
||||
.addTailAndNameSimilarity(functionExpectedInfos)
|
||||
.withInsertHandler(ArtificialElementInsertHandler("{ ", " }", false))
|
||||
.suppressAutoInsertion()
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.LAMBDA_NO_PARAMS)
|
||||
.addTailAndNameSimilarity(functionExpectedInfos)
|
||||
collection.add(lookupElement)
|
||||
}
|
||||
|
||||
if (singleSignatureLength != 0) {
|
||||
for (functionType in functionTypes) {
|
||||
if (LambdaSignatureTemplates.explicitParameterTypesRequired(functionTypes, functionType)) {
|
||||
collection.add(createLookupElement(
|
||||
collection.add(
|
||||
createLookupElement(
|
||||
functionType,
|
||||
functionExpectedInfos,
|
||||
LambdaSignatureTemplates.SignaturePresentation.NAMES_OR_TYPES,
|
||||
explicitParameterTypes = true
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
else {
|
||||
collection.add(createLookupElement(
|
||||
} else {
|
||||
collection.add(
|
||||
createLookupElement(
|
||||
functionType,
|
||||
functionExpectedInfos,
|
||||
LambdaSignatureTemplates.SignaturePresentation.NAMES_AND_TYPES,
|
||||
explicitParameterTypes = true
|
||||
))
|
||||
collection.add(createLookupElement(
|
||||
)
|
||||
)
|
||||
collection.add(
|
||||
createLookupElement(
|
||||
functionType,
|
||||
functionExpectedInfos,
|
||||
LambdaSignatureTemplates.SignaturePresentation.NAMES,
|
||||
explicitParameterTypes = false
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-25
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -35,10 +24,10 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
object LambdaSignatureItems {
|
||||
fun addToCollection(
|
||||
collection: MutableCollection<LookupElement>,
|
||||
position: KtExpression,
|
||||
bindingContext: BindingContext,
|
||||
resolutionFacade: ResolutionFacade
|
||||
collection: MutableCollection<LookupElement>,
|
||||
position: KtExpression,
|
||||
bindingContext: BindingContext,
|
||||
resolutionFacade: ResolutionFacade
|
||||
) {
|
||||
val block = position.parent as? KtBlockExpression ?: return
|
||||
if (position != block.statements.first()) return
|
||||
@@ -47,18 +36,35 @@ object LambdaSignatureItems {
|
||||
val literalExpression = functionLiteral.parent as KtLambdaExpression
|
||||
|
||||
val expectedFunctionTypes = ExpectedInfos(bindingContext, resolutionFacade, null).calculate(literalExpression)
|
||||
.mapNotNull { it.fuzzyType?.type }
|
||||
.filter { it.isFunctionOrSuspendFunctionType }
|
||||
.toSet()
|
||||
.mapNotNull { it.fuzzyType?.type }
|
||||
.filter { it.isFunctionOrSuspendFunctionType }
|
||||
.toSet()
|
||||
for (functionType in expectedFunctionTypes) {
|
||||
if (functionType.getValueParameterTypesFromFunctionType().isEmpty()) continue
|
||||
|
||||
if (LambdaSignatureTemplates.explicitParameterTypesRequired(expectedFunctionTypes, functionType)) {
|
||||
collection.add(createLookupElement(functionType, LambdaSignatureTemplates.SignaturePresentation.NAMES_OR_TYPES, explicitParameterTypes = true))
|
||||
}
|
||||
else {
|
||||
collection.add(createLookupElement(functionType, LambdaSignatureTemplates.SignaturePresentation.NAMES, explicitParameterTypes = false))
|
||||
collection.add(createLookupElement(functionType, LambdaSignatureTemplates.SignaturePresentation.NAMES_AND_TYPES, explicitParameterTypes = true))
|
||||
collection.add(
|
||||
createLookupElement(
|
||||
functionType,
|
||||
LambdaSignatureTemplates.SignaturePresentation.NAMES_OR_TYPES,
|
||||
explicitParameterTypes = true
|
||||
)
|
||||
)
|
||||
} else {
|
||||
collection.add(
|
||||
createLookupElement(
|
||||
functionType,
|
||||
LambdaSignatureTemplates.SignaturePresentation.NAMES,
|
||||
explicitParameterTypes = false
|
||||
)
|
||||
)
|
||||
collection.add(
|
||||
createLookupElement(
|
||||
functionType,
|
||||
LambdaSignatureTemplates.SignaturePresentation.NAMES_AND_TYPES,
|
||||
explicitParameterTypes = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-33
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -45,14 +34,16 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import java.util.*
|
||||
|
||||
class MultipleArgumentsItemProvider(
|
||||
private val bindingContext: BindingContext,
|
||||
private val smartCastCalculator: SmartCastCalculator,
|
||||
private val resolutionFacade: ResolutionFacade
|
||||
private val bindingContext: BindingContext,
|
||||
private val smartCastCalculator: SmartCastCalculator,
|
||||
private val resolutionFacade: ResolutionFacade
|
||||
) {
|
||||
|
||||
fun addToCollection(collection: MutableCollection<LookupElement>,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
context: KtExpression) {
|
||||
fun addToCollection(
|
||||
collection: MutableCollection<LookupElement>,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
context: KtExpression
|
||||
) {
|
||||
val resolutionScope = context.getResolutionScope(bindingContext, resolutionFacade)
|
||||
|
||||
val added = HashSet<String>()
|
||||
@@ -69,7 +60,8 @@ class MultipleArgumentsItemProvider(
|
||||
for ((i, parameter) in parameters.withIndex()) {
|
||||
variables.add(variableInScope(parameter, resolutionScope) ?: break)
|
||||
|
||||
if (i > 0 && parameters.asSequence().drop(i + 1).all { it.hasDefaultValue() }) { // this is the last parameter or all others have default values
|
||||
// this is the last parameter or all others have default values
|
||||
if (i > 0 && parameters.asSequence().drop(i + 1).all { it.hasDefaultValue() }) {
|
||||
val lookupElement = createParametersLookupElement(variables, tail)
|
||||
if (added.add(lookupElement.lookupString)) { // check that we don't already have item with the same text
|
||||
collection.add(lookupElement)
|
||||
@@ -88,27 +80,26 @@ class MultipleArgumentsItemProvider(
|
||||
compoundIcon.setIcon(lastIcon, 0, 2 * firstIcon.iconWidth / 5, 0)
|
||||
compoundIcon.setIcon(firstIcon, 1, 0, 0)
|
||||
|
||||
return LookupElementBuilder
|
||||
.create(variables.joinToString(", ") { it.name.render() }) //TODO: use code formatting settings
|
||||
.withInsertHandler { context, _ ->
|
||||
if (context.completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||
val offset = context.offsetMap.tryGetOffset(SmartCompletion.MULTIPLE_ARGUMENTS_REPLACEMENT_OFFSET)
|
||||
if (offset != null) {
|
||||
context.document.deleteString(context.tailOffset, offset)
|
||||
}
|
||||
return LookupElementBuilder.create(variables.joinToString(", ") { it.name.render() }) //TODO: use code formatting settings
|
||||
.withInsertHandler { context, _ ->
|
||||
if (context.completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||
val offset = context.offsetMap.tryGetOffset(SmartCompletion.MULTIPLE_ARGUMENTS_REPLACEMENT_OFFSET)
|
||||
if (offset != null) {
|
||||
context.document.deleteString(context.tailOffset, offset)
|
||||
}
|
||||
|
||||
}
|
||||
.withIcon(compoundIcon)
|
||||
.addTail(tail)
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.MULTIPLE_ARGUMENTS_ITEM)
|
||||
|
||||
}
|
||||
.withIcon(compoundIcon)
|
||||
.addTail(tail)
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.MULTIPLE_ARGUMENTS_ITEM)
|
||||
}
|
||||
|
||||
private fun variableInScope(parameter: ValueParameterDescriptor, scope: LexicalScope): VariableDescriptor? {
|
||||
val name = parameter.name
|
||||
//TODO: there can be more than one property with such name in scope and we should be able to select one (but we need API for this)
|
||||
val variable = scope.findVariable(name, NoLookupLocation.FROM_IDE) { !it.isExtension }
|
||||
?: scope.getVariableFromImplicitReceivers(name) ?: return null
|
||||
?: scope.getVariableFromImplicitReceivers(name) ?: return null
|
||||
return if (smartCastCalculator.types(variable).any { KotlinTypeChecker.DEFAULT.isSubtypeOf(it, parameter.type) })
|
||||
variable
|
||||
else
|
||||
|
||||
+7
-23
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -27,16 +16,11 @@ import kotlin.math.min
|
||||
val NAME_SIMILARITY_KEY = Key<Int>("NAME_SIMILARITY_KEY")
|
||||
|
||||
object NameSimilarityWeigher : LookupElementWeigher("kotlin.nameSimilarity") {
|
||||
override fun weigh(element: LookupElement, context: WeighingContext)
|
||||
= -(element.getUserData(NAME_SIMILARITY_KEY) ?: 0)
|
||||
override fun weigh(element: LookupElement, context: WeighingContext) = -(element.getUserData(NAME_SIMILARITY_KEY) ?: 0)
|
||||
}
|
||||
|
||||
fun calcNameSimilarity(name: String, expectedInfos: Collection<ExpectedInfo>): Int {
|
||||
return expectedInfos
|
||||
.mapNotNull { it.expectedName }
|
||||
.map { calcNameSimilarity(name, it) }
|
||||
.max() ?: 0
|
||||
}
|
||||
fun calcNameSimilarity(name: String, expectedInfos: Collection<ExpectedInfo>): Int =
|
||||
expectedInfos.mapNotNull { it.expectedName }.map { calcNameSimilarity(name, it) }.max() ?: 0
|
||||
|
||||
private fun calcNameSimilarity(name: String, expectedName: String): Int {
|
||||
val words1 = NameUtil.nameToWordsLowerCase(name)
|
||||
@@ -51,8 +35,8 @@ private fun calcNameSimilarity(name: String, expectedName: String): Int {
|
||||
|
||||
// count number of words matched at the end (but ignore number words - they are less important)
|
||||
val minWords = min(nonNumberWords1.size, nonNumberWords2.size)
|
||||
val matchedTailLength = (0..minWords-1).firstOrNull {
|
||||
i -> nonNumberWords1[nonNumberWords1.size - i - 1] != nonNumberWords2[nonNumberWords2.size - i - 1]
|
||||
val matchedTailLength = (0 until minWords).firstOrNull { i ->
|
||||
nonNumberWords1[nonNumberWords1.size - i - 1] != nonNumberWords2[nonNumberWords2.size - i - 1]
|
||||
} ?: minWords
|
||||
|
||||
return matchedWords.size * 1000 + matchedTailLength
|
||||
|
||||
+99
-66
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -54,18 +43,18 @@ interface InheritanceItemsSearcher {
|
||||
}
|
||||
|
||||
class SmartCompletion(
|
||||
private val expression: KtExpression,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
private val indicesHelper: KotlinIndicesHelper,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val inheritorSearchScope: GlobalSearchScope,
|
||||
private val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val isJvmModule: Boolean,
|
||||
private val forBasicCompletion: Boolean = false
|
||||
private val expression: KtExpression,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
private val indicesHelper: KotlinIndicesHelper,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val inheritorSearchScope: GlobalSearchScope,
|
||||
private val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val isJvmModule: Boolean,
|
||||
private val forBasicCompletion: Boolean = false
|
||||
) {
|
||||
private val expressionWithType = when (callTypeAndReceiver) {
|
||||
is CallTypeAndReceiver.DEFAULT ->
|
||||
@@ -87,13 +76,19 @@ class SmartCompletion(
|
||||
private val callableTypeExpectedInfo = expectedInfos.filterCallableExpected()
|
||||
|
||||
val smartCastCalculator: SmartCastCalculator by lazy(LazyThreadSafetyMode.NONE) {
|
||||
SmartCastCalculator(bindingContext, resolutionFacade.moduleDescriptor, expression, callTypeAndReceiver.receiver as? KtExpression, resolutionFacade)
|
||||
SmartCastCalculator(
|
||||
bindingContext,
|
||||
resolutionFacade.moduleDescriptor,
|
||||
expression,
|
||||
callTypeAndReceiver.receiver as? KtExpression,
|
||||
resolutionFacade
|
||||
)
|
||||
}
|
||||
|
||||
val descriptorFilter: ((DeclarationDescriptor, AbstractLookupElementFactory) -> Collection<LookupElement>)? =
|
||||
{ descriptor: DeclarationDescriptor, factory: AbstractLookupElementFactory ->
|
||||
filterDescriptor(descriptor, factory).map { postProcess(it) }
|
||||
}.takeIf { expectedInfos.isNotEmpty() }
|
||||
{ descriptor: DeclarationDescriptor, factory: AbstractLookupElementFactory ->
|
||||
filterDescriptor(descriptor, factory).map { postProcess(it) }
|
||||
}.takeIf { expectedInfos.isNotEmpty() }
|
||||
|
||||
fun additionalItems(lookupElementFactory: LookupElementFactory): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
|
||||
val (items, inheritanceSearcher) = additionalItemsNoPostProcess(lookupElementFactory)
|
||||
@@ -142,12 +137,11 @@ class SmartCompletion(
|
||||
val subjectType = bindingContext.getType(subject) ?: return@lazy emptySet()
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(subjectType)
|
||||
if (classDescriptor != null && DescriptorUtils.isEnumClass(classDescriptor)) {
|
||||
val conditions = whenExpression.entries
|
||||
.flatMap { it.conditions.toList() }
|
||||
.filterIsInstance<KtWhenConditionWithExpression>()
|
||||
val conditions =
|
||||
whenExpression.entries.flatMap { it.conditions.toList() }.filterIsInstance<KtWhenConditionWithExpression>()
|
||||
for (condition in conditions) {
|
||||
val selectorExpr = (condition.expression as? KtDotQualifiedExpression)
|
||||
?.selectorExpression as? KtReferenceExpression ?: continue
|
||||
val selectorExpr =
|
||||
(condition.expression as? KtDotQualifiedExpression)?.selectorExpression as? KtReferenceExpression ?: continue
|
||||
val target = bindingContext[BindingContext.REFERENCE_TARGET, selectorExpr] as? ClassDescriptor ?: continue
|
||||
if (DescriptorUtils.isEnumEntry(target)) {
|
||||
descriptorsToSkip.add(target)
|
||||
@@ -161,7 +155,10 @@ class SmartCompletion(
|
||||
return@lazy emptySet()
|
||||
}
|
||||
|
||||
private fun filterDescriptor(descriptor: DeclarationDescriptor, lookupElementFactory: AbstractLookupElementFactory): Collection<LookupElement> {
|
||||
private fun filterDescriptor(
|
||||
descriptor: DeclarationDescriptor,
|
||||
lookupElementFactory: AbstractLookupElementFactory
|
||||
): Collection<LookupElement> {
|
||||
ProgressManager.checkCanceled()
|
||||
if (descriptor in descriptorsToSkip) return emptyList()
|
||||
|
||||
@@ -169,7 +166,12 @@ class SmartCompletion(
|
||||
val types = descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callTypeAndReceiver, resolutionFacade, bindingContext)
|
||||
val infoMatcher = { expectedInfo: ExpectedInfo -> types.matchExpectedInfo(expectedInfo) }
|
||||
|
||||
result.addLookupElements(descriptor, expectedInfos, infoMatcher, noNameSimilarityForReturnItself = callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { declarationDescriptor ->
|
||||
result.addLookupElements(
|
||||
descriptor,
|
||||
expectedInfos,
|
||||
infoMatcher,
|
||||
noNameSimilarityForReturnItself = callTypeAndReceiver is CallTypeAndReceiver.DEFAULT
|
||||
) { declarationDescriptor ->
|
||||
lookupElementFactory.createStandardLookupElementsForDescriptor(declarationDescriptor, useReceiverTypes = true)
|
||||
}
|
||||
|
||||
@@ -192,7 +194,12 @@ class SmartCompletion(
|
||||
|
||||
if (!forBasicCompletion) { // basic completion adds keyword values on its own
|
||||
val keywordValueConsumer = object : KeywordValues.Consumer {
|
||||
override fun consume(lookupString: String, expectedInfoMatcher: (ExpectedInfo) -> ExpectedInfoMatch, priority: SmartCompletionItemPriority, factory: () -> LookupElement) {
|
||||
override fun consume(
|
||||
lookupString: String,
|
||||
expectedInfoMatcher: (ExpectedInfo) -> ExpectedInfoMatch,
|
||||
priority: SmartCompletionItemPriority,
|
||||
factory: () -> LookupElement
|
||||
) {
|
||||
items.addLookupElements(null, expectedInfos, expectedInfoMatcher) {
|
||||
val lookupElement = factory()
|
||||
lookupElement.putUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY, priority)
|
||||
@@ -200,7 +207,14 @@ class SmartCompletion(
|
||||
}
|
||||
}
|
||||
}
|
||||
KeywordValues.process(keywordValueConsumer, callTypeAndReceiver, bindingContext, resolutionFacade, moduleDescriptor, isJvmModule)
|
||||
KeywordValues.process(
|
||||
keywordValueConsumer,
|
||||
callTypeAndReceiver,
|
||||
bindingContext,
|
||||
resolutionFacade,
|
||||
moduleDescriptor,
|
||||
isJvmModule
|
||||
)
|
||||
}
|
||||
|
||||
if (expectedInfos.isNotEmpty()) {
|
||||
@@ -211,12 +225,24 @@ class SmartCompletion(
|
||||
}
|
||||
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
|
||||
TypeInstantiationItems(resolutionFacade, bindingContext, visibilityFilter, toFromOriginalFileMapper, inheritorSearchScope, lookupElementFactory, forBasicCompletion, indicesHelper)
|
||||
.addTo(items, inheritanceSearchers, expectedInfos)
|
||||
TypeInstantiationItems(
|
||||
resolutionFacade,
|
||||
bindingContext,
|
||||
visibilityFilter,
|
||||
toFromOriginalFileMapper,
|
||||
inheritorSearchScope,
|
||||
lookupElementFactory,
|
||||
forBasicCompletion,
|
||||
indicesHelper
|
||||
).addTo(items, inheritanceSearchers, expectedInfos)
|
||||
|
||||
if (expression is KtSimpleNameExpression) {
|
||||
StaticMembers(bindingContext, lookupElementFactory, resolutionFacade, moduleDescriptor)
|
||||
.addToCollection(items, expectedInfos, expression, descriptorsToSkip)
|
||||
StaticMembers(bindingContext, lookupElementFactory, resolutionFacade, moduleDescriptor).addToCollection(
|
||||
items,
|
||||
expectedInfos,
|
||||
expression,
|
||||
descriptorsToSkip
|
||||
)
|
||||
}
|
||||
|
||||
ClassLiteralItems.addToCollection(items, expectedInfos, lookupElementFactory.basicFactory, isJvmModule)
|
||||
@@ -235,7 +261,7 @@ class SmartCompletion(
|
||||
val entries = whenExpression.entries
|
||||
if (whenExpression.elseExpression == null && entry == entries.last() && entries.size != 1) {
|
||||
val lookupElement = LookupElementBuilder.create("else").bold().withTailText(" ->")
|
||||
items.add(object: LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
items.add(object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler("->", spaceBefore = true, spaceAfter = true).handleInsert(context, delegate)
|
||||
}
|
||||
@@ -244,8 +270,11 @@ class SmartCompletion(
|
||||
}
|
||||
}
|
||||
|
||||
MultipleArgumentsItemProvider(bindingContext, smartCastCalculator, resolutionFacade)
|
||||
.addToCollection(items, expectedInfos, expression)
|
||||
MultipleArgumentsItemProvider(bindingContext, smartCastCalculator, resolutionFacade).addToCollection(
|
||||
items,
|
||||
expectedInfos,
|
||||
expression
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,13 +306,16 @@ class SmartCompletion(
|
||||
super.handleInsert(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableCollection<LookupElement>.addThisItems(place: KtExpression, expectedInfos: Collection<ExpectedInfo>, smartCastCalculator: SmartCastCalculator) {
|
||||
private fun MutableCollection<LookupElement>.addThisItems(
|
||||
place: KtExpression,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
smartCastCalculator: SmartCastCalculator
|
||||
) {
|
||||
if (shouldCompleteThisItems(prefixMatcher)) {
|
||||
val items = thisExpressionItems(bindingContext, place, prefixMatcher.prefix, resolutionFacade)
|
||||
for (item in items) {
|
||||
@@ -330,8 +362,10 @@ class SmartCompletion(
|
||||
|
||||
private fun createNamedArgumentWithValueLookupElement(name: Name, value: String, priority: SmartCompletionItemPriority): LookupElement {
|
||||
val lookupElement = LookupElementBuilder.create("${name.asString()} = $value")
|
||||
.withIcon(KotlinIcons.PARAMETER)
|
||||
.withInsertHandler({ context, _ -> context.document.replaceString(context.startOffset, context.tailOffset, "${name.render()} = $value") })
|
||||
.withIcon(KotlinIcons.PARAMETER)
|
||||
.withInsertHandler { context, _ ->
|
||||
context.document.replaceString(context.startOffset, context.tailOffset, "${name.render()} = $value")
|
||||
}
|
||||
lookupElement.putUserData(SmartCompletionInBasicWeigher.NAMED_ARGUMENT_KEY, Unit)
|
||||
lookupElement.assignSmartCompletionPriority(priority)
|
||||
return lookupElement
|
||||
@@ -354,8 +388,8 @@ class SmartCompletion(
|
||||
// if expected types are too general, try to use expected type from outer calls
|
||||
var count = 0
|
||||
while (true) {
|
||||
val infos = ExpectedInfos(bindingContext, resolutionFacade, indicesHelper, useOuterCallsExpectedTypeCount = count)
|
||||
.calculate(expression)
|
||||
val infos =
|
||||
ExpectedInfos(bindingContext, resolutionFacade, indicesHelper, useOuterCallsExpectedTypeCount = count).calculate(expression)
|
||||
if (count == 2 /* use two outer calls maximum */ || infos.none { it.fuzzyType?.isAlmostEverything() ?: false }) {
|
||||
return if (forBasicCompletion)
|
||||
infos.map { it.copy(tail = null) }
|
||||
@@ -376,7 +410,10 @@ class SmartCompletion(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun MutableCollection<LookupElement>.addCallableReferenceLookupElements(descriptor: DeclarationDescriptor, lookupElementFactory: AbstractLookupElementFactory) {
|
||||
private fun MutableCollection<LookupElement>.addCallableReferenceLookupElements(
|
||||
descriptor: DeclarationDescriptor,
|
||||
lookupElementFactory: AbstractLookupElementFactory
|
||||
) {
|
||||
if (callableTypeExpectedInfo.isEmpty()) return
|
||||
|
||||
fun toLookupElement(descriptor: CallableDescriptor): LookupElement? {
|
||||
@@ -385,9 +422,10 @@ class SmartCompletion(
|
||||
val matchedExpectedInfos = callableTypeExpectedInfo.filter { it.matchingSubstitutor(callableReferenceType) != null }
|
||||
if (matchedExpectedInfos.isEmpty()) return null
|
||||
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false, parametersAndTypeGrayed = true)
|
||||
?: return null
|
||||
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
var lookupElement =
|
||||
lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false, parametersAndTypeGrayed = true)
|
||||
?: return null
|
||||
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun getLookupString() = "::" + delegate.lookupString
|
||||
override fun getAllLookupStrings() = setOf(lookupString)
|
||||
|
||||
@@ -400,9 +438,8 @@ class SmartCompletion(
|
||||
}
|
||||
}
|
||||
|
||||
return lookupElement
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.CALLABLE_REFERENCE)
|
||||
.addTailAndNameSimilarity(matchedExpectedInfos)
|
||||
return lookupElement.assignSmartCompletionPriority(SmartCompletionItemPriority.CALLABLE_REFERENCE)
|
||||
.addTailAndNameSimilarity(matchedExpectedInfos)
|
||||
}
|
||||
|
||||
when (descriptor) {
|
||||
@@ -415,19 +452,15 @@ class SmartCompletion(
|
||||
|
||||
is ClassDescriptor -> {
|
||||
if (descriptor.modality != Modality.ABSTRACT && !descriptor.isInner) {
|
||||
descriptor.constructors
|
||||
.filter(visibilityFilter)
|
||||
.mapNotNullTo(this, ::toLookupElement)
|
||||
descriptor.constructors.filter(visibilityFilter).mapNotNullTo(this, ::toLookupElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildForAsTypePosition(lookupElementFactory: BasicLookupElementFactory): Collection<LookupElement>? {
|
||||
val binaryExpression = ((expression.parent as? KtUserType)
|
||||
?.parent as? KtTypeReference)
|
||||
?.parent as? KtBinaryExpressionWithTypeRHS
|
||||
?: return null
|
||||
val binaryExpression =
|
||||
((expression.parent as? KtUserType)?.parent as? KtTypeReference)?.parent as? KtBinaryExpressionWithTypeRHS ?: return null
|
||||
val elementType = binaryExpression.operationReference.getReferencedNameElementType()
|
||||
if (elementType != KtTokens.AS_KEYWORD && elementType != KtTokens.AS_SAFE) return null
|
||||
val expectedInfos = calcExpectedInfos(binaryExpression)
|
||||
|
||||
+45
-43
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -39,10 +28,10 @@ import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
|
||||
class SmartCompletionSession(
|
||||
configuration: CompletionSessionConfiguration,
|
||||
parameters: CompletionParameters,
|
||||
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
resultSet: CompletionResultSet
|
||||
configuration: CompletionSessionConfiguration,
|
||||
parameters: CompletionParameters,
|
||||
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
resultSet: CompletionResultSet
|
||||
) : CompletionSession(configuration, parameters, toFromOriginalFileMapper, resultSet) {
|
||||
|
||||
override val descriptorKindFilter: DescriptorKindFilter by lazy {
|
||||
@@ -62,9 +51,11 @@ class SmartCompletionSession(
|
||||
|
||||
private val smartCompletion by lazy(LazyThreadSafetyMode.NONE) {
|
||||
expression?.let {
|
||||
SmartCompletion(it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter, indicesHelper(false),
|
||||
prefixMatcher, searchScope, toFromOriginalFileMapper,
|
||||
callTypeAndReceiver, isJvmModule)
|
||||
SmartCompletion(
|
||||
it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter, indicesHelper(false),
|
||||
prefixMatcher, searchScope, toFromOriginalFileMapper,
|
||||
callTypeAndReceiver, isJvmModule
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +83,8 @@ class SmartCompletionSession(
|
||||
val contextVariableTypesForReferenceVariants = filter?.let {
|
||||
withCollectRequiredContextVariableTypes { lookupElementFactory ->
|
||||
if (referenceVariantsCollector != null) {
|
||||
val (imported, notImported) = referenceVariantsCollector.collectReferenceVariants(descriptorKindFilter).excludeNonInitializedVariable()
|
||||
val (imported, notImported) = referenceVariantsCollector.collectReferenceVariants(descriptorKindFilter)
|
||||
.excludeNonInitializedVariable()
|
||||
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
|
||||
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
|
||||
referenceVariantsCollector.collectingFinished()
|
||||
@@ -105,8 +97,11 @@ class SmartCompletionSession(
|
||||
val contextVariablesProvider = RealContextVariablesProvider(referenceVariantsHelper, position)
|
||||
withContextVariablesProvider(contextVariablesProvider) { lookupElementFactory ->
|
||||
if (filter != null && receiverTypes != null) {
|
||||
val results = ExtensionFunctionTypeValueCompletion(receiverTypes, callTypeAndReceiver.callType, lookupElementFactory)
|
||||
.processVariables(contextVariablesProvider)
|
||||
val results = ExtensionFunctionTypeValueCompletion(
|
||||
receiverTypes,
|
||||
callTypeAndReceiver.callType,
|
||||
lookupElementFactory
|
||||
).processVariables(contextVariablesProvider)
|
||||
for ((invokeDescriptor, factory) in results) {
|
||||
collector.addElements(filter(invokeDescriptor, factory))
|
||||
}
|
||||
@@ -117,7 +112,9 @@ class SmartCompletionSession(
|
||||
collector.addElements(additionalItems)
|
||||
}
|
||||
|
||||
if (filter != null && contextVariableTypesForReferenceVariants!!.any { contextVariablesProvider.functionTypeVariables(it).isNotEmpty() }) {
|
||||
if (filter != null &&
|
||||
contextVariableTypesForReferenceVariants!!.any { contextVariablesProvider.functionTypeVariables(it).isNotEmpty() }
|
||||
) {
|
||||
val (imported, notImported) = referenceVariantsWithSingleFunctionTypeParameter()!!
|
||||
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
|
||||
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
|
||||
@@ -129,13 +126,12 @@ class SmartCompletionSession(
|
||||
val staticMembersCompletion: StaticMembersCompletion?
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
|
||||
val alreadyCollected = referenceVariantsCollector!!.allCollected.imported
|
||||
staticMembersCompletion = StaticMembersCompletion(prefixMatcher, resolutionFacade, lookupElementFactory, alreadyCollected, isJvmModule)
|
||||
staticMembersCompletion =
|
||||
StaticMembersCompletion(prefixMatcher, resolutionFacade, lookupElementFactory, alreadyCollected, isJvmModule)
|
||||
val decoratedFactory = staticMembersCompletion.decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER_FROM_IMPORTS)
|
||||
staticMembersCompletion.membersFromImports(file)
|
||||
.flatMap { filter(it, decoratedFactory) }
|
||||
.forEach { collector.addElement(it) }
|
||||
}
|
||||
else {
|
||||
staticMembersCompletion.membersFromImports(file).flatMap { filter(it, decoratedFactory) }
|
||||
.forEach { collector.addElement(it) }
|
||||
} else {
|
||||
staticMembersCompletion = null
|
||||
}
|
||||
|
||||
@@ -152,7 +148,12 @@ class SmartCompletionSession(
|
||||
val variants = variantsAndFactory.first
|
||||
@Suppress("NAME_SHADOWING") val lookupElementFactory = variantsAndFactory.second
|
||||
variants.imported.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }) }
|
||||
variants.notImportedExtensions.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }, notImported = true) }
|
||||
variants.notImportedExtensions.forEach {
|
||||
collector.addElements(
|
||||
filter(it, lookupElementFactory).map { element -> element.withReceiverCast() },
|
||||
notImported = true
|
||||
)
|
||||
}
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
@@ -160,8 +161,8 @@ class SmartCompletionSession(
|
||||
if (staticMembersCompletion != null && configuration.staticMembers) {
|
||||
val decoratedFactory = staticMembersCompletion.decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER)
|
||||
staticMembersCompletion.processMembersFromIndices(indicesHelper(false)) {
|
||||
filter(it, decoratedFactory).forEach {
|
||||
collector.addElement(it)
|
||||
filter(it, decoratedFactory).forEach { element ->
|
||||
collector.addElement(element)
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
@@ -199,23 +200,24 @@ class SmartCompletionSession(
|
||||
override fun getValueArgumentList() = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, indicesHelper(false))
|
||||
.calculateForArgument(dummyCall, dummyArgument)
|
||||
val expectedInfos =
|
||||
ExpectedInfos(bindingContext, resolutionFacade, indicesHelper(false)).calculateForArgument(dummyCall, dummyArgument)
|
||||
collector.addElements(LambdaItems.collect(expectedInfos))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createSorter(): CompletionSorter {
|
||||
return super.createSorter()
|
||||
.weighBefore(KindWeigher.toString(), NameSimilarityWeigher, SmartCompletionPriorityWeigher, CallableReferenceWeigher(callTypeAndReceiver.callType))
|
||||
}
|
||||
override fun createSorter(): CompletionSorter = super.createSorter().weighBefore(
|
||||
KindWeigher.toString(),
|
||||
NameSimilarityWeigher,
|
||||
SmartCompletionPriorityWeigher,
|
||||
CallableReferenceWeigher(callTypeAndReceiver.callType)
|
||||
)
|
||||
|
||||
override fun createLookupElementFactory(contextVariablesProvider: ContextVariablesProvider): LookupElementFactory {
|
||||
return super.createLookupElementFactory(contextVariablesProvider).copy(
|
||||
standardLookupElementsPostProcessor = { wrapStandardLookupElement(it) }
|
||||
override fun createLookupElementFactory(contextVariablesProvider: ContextVariablesProvider): LookupElementFactory =
|
||||
super.createLookupElementFactory(contextVariablesProvider).copy(
|
||||
standardLookupElementsPostProcessor = { wrapStandardLookupElement(it) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun wrapStandardLookupElement(lookupElement: LookupElement): LookupElement {
|
||||
val descriptor = (lookupElement.`object` as DeclarationLookupObject).descriptor
|
||||
|
||||
+74
-68
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -58,19 +47,19 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
class TypeInstantiationItems(
|
||||
val resolutionFacade: ResolutionFacade,
|
||||
val bindingContext: BindingContext,
|
||||
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
val inheritorSearchScope: GlobalSearchScope,
|
||||
val lookupElementFactory: LookupElementFactory,
|
||||
val forOrdinaryCompletion: Boolean,
|
||||
val indicesHelper: KotlinIndicesHelper
|
||||
val resolutionFacade: ResolutionFacade,
|
||||
val bindingContext: BindingContext,
|
||||
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
val inheritorSearchScope: GlobalSearchScope,
|
||||
val lookupElementFactory: LookupElementFactory,
|
||||
val forOrdinaryCompletion: Boolean,
|
||||
val indicesHelper: KotlinIndicesHelper
|
||||
) {
|
||||
fun addTo(
|
||||
items: MutableCollection<LookupElement>,
|
||||
inheritanceSearchers: MutableCollection<InheritanceItemsSearcher>,
|
||||
expectedInfos: Collection<ExpectedInfo>
|
||||
items: MutableCollection<LookupElement>,
|
||||
inheritanceSearchers: MutableCollection<InheritanceItemsSearcher>,
|
||||
expectedInfos: Collection<ExpectedInfo>
|
||||
) {
|
||||
val expectedInfosGrouped = LinkedHashMap<FuzzyType, MutableList<ExpectedInfo>>()
|
||||
for (expectedInfo in expectedInfos) {
|
||||
@@ -86,10 +75,10 @@ class TypeInstantiationItems(
|
||||
}
|
||||
|
||||
private fun addTo(
|
||||
items: MutableCollection<LookupElement>,
|
||||
inheritanceSearchers: MutableCollection<InheritanceItemsSearcher>,
|
||||
fuzzyType: FuzzyType,
|
||||
tail: Tail?
|
||||
items: MutableCollection<LookupElement>,
|
||||
inheritanceSearchers: MutableCollection<InheritanceItemsSearcher>,
|
||||
fuzzyType: FuzzyType,
|
||||
tail: Tail?
|
||||
) {
|
||||
if (fuzzyType.type.isFunctionType) return // do not show "object: ..." for function types
|
||||
|
||||
@@ -115,7 +104,8 @@ class TypeInstantiationItems(
|
||||
|
||||
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(DescriptorUtils.getFqName(classifier))
|
||||
if (javaClassId != null) {
|
||||
val javaAnalog = resolutionFacade.moduleDescriptor.resolveTopLevelClass(javaClassId.asSingleFqName(), NoLookupLocation.FROM_IDE)
|
||||
val javaAnalog =
|
||||
resolutionFacade.moduleDescriptor.resolveTopLevelClass(javaClassId.asSingleFqName(), NoLookupLocation.FROM_IDE)
|
||||
if (javaAnalog != null) {
|
||||
inheritanceSearchers.addInheritorSearcher(javaAnalog, classDescriptor, typeArgs, fuzzyType.freeParameters, tail)
|
||||
}
|
||||
@@ -124,7 +114,11 @@ class TypeInstantiationItems(
|
||||
}
|
||||
|
||||
private fun MutableCollection<InheritanceItemsSearcher>.addInheritorSearcher(
|
||||
descriptor: ClassDescriptor, kotlinClassDescriptor: ClassDescriptor, typeArgs: List<TypeProjection>, freeParameters: Collection<TypeParameterDescriptor>, tail: Tail?
|
||||
descriptor: ClassDescriptor,
|
||||
kotlinClassDescriptor: ClassDescriptor,
|
||||
typeArgs: List<TypeProjection>,
|
||||
freeParameters: Collection<TypeParameterDescriptor>,
|
||||
tail: Tail?
|
||||
) {
|
||||
val _declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(resolutionFacade.project, descriptor) ?: return
|
||||
val declaration = if (_declaration is KtDeclaration)
|
||||
@@ -176,11 +170,11 @@ class TypeInstantiationItems(
|
||||
// drop "in" and "out" from type arguments - they cannot be used in constructor call
|
||||
val typeArgsToUse = typeArgs.map { TypeProjectionImpl(Variance.INVARIANT, it.type) }
|
||||
|
||||
val allTypeArgsKnown = fuzzyType.freeParameters.isEmpty() || typeArgs.none { it.type.areTypeParametersUsedInside(fuzzyType.freeParameters) }
|
||||
val allTypeArgsKnown =
|
||||
fuzzyType.freeParameters.isEmpty() || typeArgs.none { it.type.areTypeParametersUsedInside(fuzzyType.freeParameters) }
|
||||
itemText += if (allTypeArgsKnown) {
|
||||
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderTypeArguments(typeArgsToUse)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
"<...>"
|
||||
}
|
||||
|
||||
@@ -210,8 +204,7 @@ class TypeInstantiationItems(
|
||||
shortenReferences(context, startOffset, startOffset + text.length)
|
||||
|
||||
ImplementMembersHandler().invoke(context.project, context.editor, context.file, true)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
context.editor.caretModel.moveToOffset(startOffset + text1.length + 1) // put caret into "<>"
|
||||
|
||||
shortenReferences(context, startOffset, startOffset + text.length)
|
||||
@@ -219,8 +212,7 @@ class TypeInstantiationItems(
|
||||
}
|
||||
lookupElement = lookupElement.suppressAutoInsertion()
|
||||
lookupElement = lookupElement.assignSmartCompletionPriority(SmartCompletionItemPriority.ANONYMOUS_OBJECT)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//TODO: when constructor has one parameter of lambda type with more than one parameter, generate special additional item
|
||||
signatureText = when (visibleConstructors.size) {
|
||||
0 -> "()"
|
||||
@@ -228,7 +220,8 @@ class TypeInstantiationItems(
|
||||
1 -> {
|
||||
val constructor = visibleConstructors.single()
|
||||
val substitutor = TypeSubstitutor.create(fuzzyType.presentationType())
|
||||
val substitutedConstructor = constructor.substitute(substitutor) ?: constructor // render original signature if failed to substitute
|
||||
val substitutedConstructor = constructor.substitute(substitutor)
|
||||
?: constructor // render original signature if failed to substitute
|
||||
BasicLookupElementFactory.SHORT_NAMES_RENDERER.renderFunctionParameters(substitutedConstructor)
|
||||
}
|
||||
|
||||
@@ -236,24 +229,33 @@ class TypeInstantiationItems(
|
||||
}
|
||||
|
||||
val baseInsertHandler = when (visibleConstructors.size) {
|
||||
0 -> KotlinFunctionInsertHandler.Normal(CallType.DEFAULT, inputTypeArguments = false, inputValueArguments = false, argumentsOnly = true)
|
||||
0 -> KotlinFunctionInsertHandler.Normal(
|
||||
CallType.DEFAULT,
|
||||
inputTypeArguments = false,
|
||||
inputValueArguments = false,
|
||||
argumentsOnly = true
|
||||
)
|
||||
|
||||
1 -> (lookupElementFactory.insertHandlerProvider.insertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler.Normal)
|
||||
.copy(argumentsOnly = true)
|
||||
1 -> (lookupElementFactory.insertHandlerProvider
|
||||
.insertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler.Normal).copy(argumentsOnly = true)
|
||||
|
||||
else -> KotlinFunctionInsertHandler.Normal(CallType.DEFAULT, inputTypeArguments = false, inputValueArguments = true, argumentsOnly = true)
|
||||
else -> KotlinFunctionInsertHandler.Normal(
|
||||
CallType.DEFAULT,
|
||||
inputTypeArguments = false,
|
||||
inputValueArguments = true,
|
||||
argumentsOnly = true
|
||||
)
|
||||
}
|
||||
|
||||
insertHandler = object : InsertHandler<LookupElement> {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
context.document.replaceString(context.startOffset, context.tailOffset, typeText)
|
||||
context.tailOffset = context.startOffset + typeText.length
|
||||
insertHandler = InsertHandler { context, item ->
|
||||
context.document.replaceString(context.startOffset, context.tailOffset, typeText)
|
||||
context.tailOffset = context.startOffset + typeText.length
|
||||
|
||||
baseInsertHandler.handleInsert(context, item)
|
||||
baseInsertHandler.handleInsert(context, item)
|
||||
|
||||
shortenReferences(context, context.startOffset, context.tailOffset)
|
||||
}
|
||||
shortenReferences(context, context.startOffset, context.tailOffset)
|
||||
}
|
||||
|
||||
if (baseInsertHandler.inputValueArguments) {
|
||||
lookupElement = lookupElement.keepOldArgumentListOnTab()
|
||||
}
|
||||
@@ -304,34 +306,39 @@ class TypeInstantiationItems(
|
||||
return FuzzyType(this, freeParameters).freeParameters.isNotEmpty()
|
||||
}
|
||||
|
||||
private fun addSamConstructorItem(collection: MutableCollection<LookupElement>,
|
||||
classifier: ClassifierDescriptorWithTypeParameters,
|
||||
classDescriptor: ClassDescriptor?,
|
||||
tail: Tail?) {
|
||||
private fun addSamConstructorItem(
|
||||
collection: MutableCollection<LookupElement>,
|
||||
classifier: ClassifierDescriptorWithTypeParameters,
|
||||
classDescriptor: ClassDescriptor?,
|
||||
tail: Tail?
|
||||
) {
|
||||
if (classDescriptor?.kind == ClassKind.INTERFACE) {
|
||||
val samConstructor = run {
|
||||
val container = classifier.containingDeclaration
|
||||
val scope = when (container) {
|
||||
val scope = when (val container = classifier.containingDeclaration) {
|
||||
is PackageFragmentDescriptor -> container.getMemberScope()
|
||||
is ClassDescriptor -> container.unsubstitutedMemberScope
|
||||
else -> return
|
||||
}
|
||||
scope.collectSyntheticStaticMembersAndConstructors(resolutionFacade, DescriptorKindFilter.FUNCTIONS, { classifier.name == it })
|
||||
.filterIsInstance<SamConstructorDescriptor>()
|
||||
.singleOrNull() ?: return
|
||||
scope.collectSyntheticStaticMembersAndConstructors(
|
||||
resolutionFacade,
|
||||
DescriptorKindFilter.FUNCTIONS
|
||||
) { classifier.name == it }
|
||||
.filterIsInstance<SamConstructorDescriptor>()
|
||||
.singleOrNull() ?: return
|
||||
}
|
||||
lookupElementFactory
|
||||
.createStandardLookupElementsForDescriptor(samConstructor, useReceiverTypes = false)
|
||||
.mapTo(collection) { it.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION).addTail(tail) }
|
||||
.createStandardLookupElementsForDescriptor(samConstructor, useReceiverTypes = false)
|
||||
.mapTo(collection) { it.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION).addTail(tail) }
|
||||
}
|
||||
}
|
||||
|
||||
private inner class InheritanceSearcher(
|
||||
private val psiClass: PsiClass,
|
||||
classDescriptor: ClassDescriptor,
|
||||
typeArgs: List<TypeProjection>,
|
||||
private val freeParameters: Collection<TypeParameterDescriptor>,
|
||||
private val tail: Tail?) : InheritanceItemsSearcher {
|
||||
private val psiClass: PsiClass,
|
||||
classDescriptor: ClassDescriptor,
|
||||
typeArgs: List<TypeProjection>,
|
||||
private val freeParameters: Collection<TypeParameterDescriptor>,
|
||||
private val tail: Tail?
|
||||
) : InheritanceItemsSearcher {
|
||||
|
||||
private val baseHasTypeArgs = classDescriptor.declaredTypeParameters.isNotEmpty()
|
||||
private val expectedType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, classDescriptor, typeArgs)
|
||||
@@ -341,9 +348,8 @@ class TypeInstantiationItems(
|
||||
val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter)
|
||||
for (inheritor in ClassInheritorsSearch.search(parameters)) {
|
||||
val descriptor = inheritor.resolveToDescriptor(
|
||||
resolutionFacade,
|
||||
{ toFromOriginalFileMapper.toSyntheticFile(it) }
|
||||
) ?: continue
|
||||
resolutionFacade
|
||||
) { toFromOriginalFileMapper.toSyntheticFile(it) } ?: continue
|
||||
if (!visibilityFilter(descriptor)) continue
|
||||
|
||||
var inheritorFuzzyType = descriptor.defaultType.toFuzzyType(descriptor.typeConstructor.parameters)
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
@@ -23,7 +12,6 @@ import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithExpressionPrefixInsertHandler
|
||||
@@ -46,10 +34,10 @@ import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||
import java.util.*
|
||||
|
||||
class ArtificialElementInsertHandler(
|
||||
private val textBeforeCaret: String,
|
||||
private val textAfterCaret: String,
|
||||
private val shortenRefs: Boolean
|
||||
) : InsertHandler<LookupElement>{
|
||||
private val textBeforeCaret: String,
|
||||
private val textAfterCaret: String,
|
||||
private val shortenRefs: Boolean
|
||||
) : InsertHandler<LookupElement> {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
val offset = context.editor.caretModel.offset
|
||||
val startOffset = offset - item.lookupString.length
|
||||
@@ -67,38 +55,36 @@ fun mergeTails(tails: Collection<Tail?>): Tail? {
|
||||
return tails.singleOrNull() ?: tails.toSet().singleOrNull()
|
||||
}
|
||||
|
||||
fun LookupElement.addTail(tail: Tail?): LookupElement {
|
||||
return when (tail) {
|
||||
null -> this
|
||||
fun LookupElement.addTail(tail: Tail?): LookupElement = when (tail) {
|
||||
null -> this
|
||||
|
||||
Tail.COMMA -> object: LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.COMMA.handleInsert(context, delegate)
|
||||
}
|
||||
Tail.COMMA -> object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.COMMA.handleInsert(context, delegate)
|
||||
}
|
||||
}
|
||||
|
||||
Tail.RPARENTH -> object: LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.RPARENTH.handleInsert(context, delegate)
|
||||
}
|
||||
Tail.RPARENTH -> object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.RPARENTH.handleInsert(context, delegate)
|
||||
}
|
||||
}
|
||||
|
||||
Tail.RBRACKET -> object: LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.RBRACKET.handleInsert(context, delegate)
|
||||
}
|
||||
Tail.RBRACKET -> object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.RBRACKET.handleInsert(context, delegate)
|
||||
}
|
||||
}
|
||||
|
||||
Tail.ELSE -> object: LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.ELSE.handleInsert(context, delegate)
|
||||
}
|
||||
Tail.ELSE -> object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.ELSE.handleInsert(context, delegate)
|
||||
}
|
||||
}
|
||||
|
||||
Tail.RBRACE -> object: LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.RBRACE.handleInsert(context, delegate)
|
||||
}
|
||||
Tail.RBRACE -> object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler.RBRACE.handleInsert(context, delegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,8 +107,8 @@ fun LookupElement.withOptions(options: ItemOptions): LookupElement {
|
||||
}
|
||||
|
||||
fun LookupElement.addTailAndNameSimilarity(
|
||||
matchedExpectedInfos: Collection<ExpectedInfo>,
|
||||
nameSimilarityExpectedInfos: Collection<ExpectedInfo> = matchedExpectedInfos
|
||||
matchedExpectedInfos: Collection<ExpectedInfo>,
|
||||
nameSimilarityExpectedInfos: Collection<ExpectedInfo> = matchedExpectedInfos
|
||||
): LookupElement {
|
||||
val lookupElement = addTail(mergeTails(matchedExpectedInfos.map { it.tail }))
|
||||
val similarity = calcNameSimilarity(lookupElement.lookupString, nameSimilarityExpectedInfos)
|
||||
@@ -134,8 +120,8 @@ fun LookupElement.addTailAndNameSimilarity(
|
||||
|
||||
class ExpectedInfoMatch
|
||||
private constructor(
|
||||
val substitutor: TypeSubstitutor?,
|
||||
val makeNotNullable: Boolean
|
||||
val substitutor: TypeSubstitutor?,
|
||||
val makeNotNullable: Boolean
|
||||
) {
|
||||
fun isMatch() = substitutor != null && !makeNotNullable
|
||||
|
||||
@@ -165,18 +151,20 @@ fun Collection<FuzzyType>.matchExpectedInfo(expectedInfo: ExpectedInfo): Expecte
|
||||
|
||||
fun FuzzyType.matchExpectedInfo(expectedInfo: ExpectedInfo) = listOf(this).matchExpectedInfo(expectedInfo)
|
||||
|
||||
fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLookupElements(
|
||||
descriptor: TDescriptor,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
infoMatcher: (ExpectedInfo) -> ExpectedInfoMatch,
|
||||
noNameSimilarityForReturnItself: Boolean = false,
|
||||
lookupElementFactory: (TDescriptor) -> Collection<LookupElement>
|
||||
fun <TDescriptor : DeclarationDescriptor?> MutableCollection<LookupElement>.addLookupElements(
|
||||
descriptor: TDescriptor,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
infoMatcher: (ExpectedInfo) -> ExpectedInfoMatch,
|
||||
noNameSimilarityForReturnItself: Boolean = false,
|
||||
lookupElementFactory: (TDescriptor) -> Collection<LookupElement>
|
||||
) {
|
||||
class ItemData(val descriptor: TDescriptor, val itemOptions: ItemOptions) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun equals(other: Any?)
|
||||
= descriptorsEqualWithSubstitution(this.descriptor, (other as? ItemData)?.descriptor) && itemOptions ==
|
||||
(other as? ItemData)?.itemOptions
|
||||
override fun equals(other: Any?) = descriptorsEqualWithSubstitution(
|
||||
this.descriptor,
|
||||
(other as? ItemData)?.descriptor
|
||||
) && itemOptions == (other as? ItemData)?.itemOptions
|
||||
|
||||
override fun hashCode() = if (this.descriptor != null) this.descriptor.original.hashCode() else 0
|
||||
}
|
||||
|
||||
@@ -194,18 +182,16 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
}
|
||||
}
|
||||
|
||||
if (!matchedInfos.isEmpty()) {
|
||||
if (matchedInfos.isNotEmpty()) {
|
||||
for ((itemData, infos) in matchedInfos) {
|
||||
val lookupElements = itemData.createLookupElements()
|
||||
val nameSimilarityInfos = if (noNameSimilarityForReturnItself && descriptor is CallableDescriptor) {
|
||||
infos.filter { (it.additionalData as? ReturnValueAdditionalData)?.callable != descriptor } // do not calculate name similarity with function itself in its return
|
||||
}
|
||||
else
|
||||
} else
|
||||
infos
|
||||
lookupElements.mapTo(this) { it.addTailAndNameSimilarity(infos, nameSimilarityInfos) }
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for ((itemData, infos) in makeNullableInfos) {
|
||||
addLookupElementsForNullable({ itemData.createLookupElements() }, infos)
|
||||
}
|
||||
@@ -220,7 +206,10 @@ private fun <T : DeclarationDescriptor?> T.substituteFixed(substitutor: TypeSubs
|
||||
return this.substitute(substitutor) as T
|
||||
}
|
||||
|
||||
private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factory: () -> Collection<LookupElement>, matchedInfos: Collection<ExpectedInfo>) {
|
||||
private fun MutableCollection<LookupElement>.addLookupElementsForNullable(
|
||||
factory: () -> Collection<LookupElement>,
|
||||
matchedInfos: Collection<ExpectedInfo>
|
||||
) {
|
||||
fun LookupElement.postProcess(): LookupElement {
|
||||
var element = this
|
||||
element = element.suppressAutoInsertion()
|
||||
@@ -230,11 +219,12 @@ private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factor
|
||||
}
|
||||
|
||||
factory().mapTo(this) {
|
||||
object: LookupElementDecorator<LookupElement>(it) {
|
||||
object : LookupElementDecorator<LookupElement>(it) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.itemText = "!! " + presentation.itemText
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler("!!", spaceBefore = false, spaceAfter = false).handleInsert(context, delegate)
|
||||
}
|
||||
@@ -242,11 +232,12 @@ private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factor
|
||||
}
|
||||
|
||||
factory().mapTo(this) {
|
||||
object: LookupElementDecorator<LookupElement>(it) {
|
||||
object : LookupElementDecorator<LookupElement>(it) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.itemText = "?: " + presentation.itemText
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler("?:", spaceBefore = true, spaceAfter = true).handleInsert(context, delegate) //TODO: code style
|
||||
}
|
||||
@@ -258,10 +249,10 @@ fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade,
|
||||
if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references
|
||||
|
||||
return DoubleColonExpressionResolver.createKCallableTypeForReference(
|
||||
this,
|
||||
lhs,
|
||||
resolutionFacade.getFrontendService(ReflectionTypes::class.java),
|
||||
resolutionFacade.moduleDescriptor
|
||||
this,
|
||||
lhs,
|
||||
resolutionFacade.getFrontendService(ReflectionTypes::class.java),
|
||||
resolutionFacade.moduleDescriptor
|
||||
)?.toFuzzyType(emptyList())
|
||||
}
|
||||
|
||||
@@ -302,10 +293,10 @@ fun LookupElement.assignSmartCompletionPriority(priority: SmartCompletionItemPri
|
||||
var LookupElement.isProbableKeyword: Boolean by NotNullableUserDataProperty(Key.create("PROBABLE_KEYWORD_KEY"), false)
|
||||
|
||||
fun DeclarationDescriptor.fuzzyTypesForSmartCompletion(
|
||||
smartCastCalculator: SmartCastCalculator,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
bindingContext: BindingContext
|
||||
smartCastCalculator: SmartCastCalculator,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
bindingContext: BindingContext
|
||||
): Collection<FuzzyType> {
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.CALLABLE_REFERENCE) {
|
||||
val lhs = callTypeAndReceiver.receiver?.let { bindingContext[BindingContext.DOUBLE_COLON_LHS, it] }
|
||||
@@ -319,24 +310,22 @@ fun DeclarationDescriptor.fuzzyTypesForSmartCompletion(
|
||||
if (returnType.type.isNothing() ||
|
||||
returnType.type.isNullableNothing() ||
|
||||
returnType.type.isDynamic() ||
|
||||
returnType.isAlmostEverything()) {
|
||||
returnType.isAlmostEverything()
|
||||
) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return if (this is VariableDescriptor) { //TODO: generic properties!
|
||||
smartCastCalculator.types(this).map { it.toFuzzyType(emptyList()) }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
listOf(returnType)
|
||||
}
|
||||
}
|
||||
else if (this is ClassDescriptor && kind.isSingleton) {
|
||||
} else if (this is ClassDescriptor && kind.isSingleton) {
|
||||
return listOf(defaultType.toFuzzyType(emptyList()))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
fun Collection<ExpectedInfo>.filterCallableExpected()
|
||||
= filter { it.fuzzyType != null && ReflectionTypes.isCallableType(it.fuzzyType!!.type) }
|
||||
fun Collection<ExpectedInfo>.filterCallableExpected() =
|
||||
filter { it.fuzzyType != null && ReflectionTypes.isCallableType(it.fuzzyType!!.type) }
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ abstract class AbstractCompiledKotlinInJavaCompletionTest : KotlinFixtureComplet
|
||||
override fun getPlatform() = JvmPlatforms.unspecifiedJvmPlatform
|
||||
|
||||
override fun getProjectDescriptor() =
|
||||
SdkAndMockLibraryProjectDescriptor(COMPLETION_TEST_DATA_BASE_PATH + "/injava/mockLib", false)
|
||||
SdkAndMockLibraryProjectDescriptor("$COMPLETION_TEST_DATA_BASE_PATH/injava/mockLib", false)
|
||||
|
||||
override fun defaultCompletionType() = CompletionType.BASIC
|
||||
}
|
||||
|
||||
+12
-9
@@ -40,10 +40,12 @@ abstract class AbstractCompletionIncrementalResolveTest : KotlinLightCodeInsight
|
||||
assertTrue("\"$CHANGE_MARKER\" is missing in file \"$testPath\"", changeMarkerOffset >= 0)
|
||||
|
||||
val textToType = InTextDirectivesUtils.findArrayWithPrefixes(document.text, TYPE_DIRECTIVE_PREFIX).singleOrNull()
|
||||
?.let { StringUtil.unquoteString(it) }
|
||||
?.let { StringUtil.unquoteString(it) }
|
||||
val backspaceCount = InTextDirectivesUtils.getPrefixedInt(document.text, BACKSPACES_DIRECTIVE_PREFIX)
|
||||
assertTrue("At least one of \"$TYPE_DIRECTIVE_PREFIX\" and \"$BACKSPACES_DIRECTIVE_PREFIX\" should be defined",
|
||||
textToType != null || backspaceCount != null)
|
||||
assertTrue(
|
||||
"At least one of \"$TYPE_DIRECTIVE_PREFIX\" and \"$BACKSPACES_DIRECTIVE_PREFIX\" should be defined",
|
||||
textToType != null || backspaceCount != null
|
||||
)
|
||||
|
||||
val beforeMarker = document.createRangeMarker(beforeMarkerOffset, beforeMarkerOffset + BEFORE_MARKER.length)
|
||||
val changeMarker = document.createRangeMarker(changeMarkerOffset, changeMarkerOffset + CHANGE_MARKER.length)
|
||||
@@ -76,15 +78,16 @@ abstract class AbstractCompletionIncrementalResolveTest : KotlinLightCodeInsight
|
||||
|
||||
if (caretMarker != null) {
|
||||
editor.caretModel.moveToOffset(caretMarker.startOffset)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
editor.caretModel.moveToOffset(changeMarker.endOffset)
|
||||
}
|
||||
|
||||
testCompletion(FileUtil.loadFile(file, true),
|
||||
JvmPlatforms.unspecifiedJvmPlatform,
|
||||
{ completionType, count -> myFixture.complete(completionType, count) },
|
||||
additionalValidDirectives = listOf(TYPE_DIRECTIVE_PREFIX, BACKSPACES_DIRECTIVE_PREFIX))
|
||||
testCompletion(
|
||||
FileUtil.loadFile(file, true),
|
||||
JvmPlatforms.unspecifiedJvmPlatform,
|
||||
{ completionType, count -> myFixture.complete(completionType, count) },
|
||||
additionalValidDirectives = listOf(TYPE_DIRECTIVE_PREFIX, BACKSPACES_DIRECTIVE_PREFIX)
|
||||
)
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(File(file.parent, file.nameWithoutExtension + ".log"), testLog.toString())
|
||||
} finally {
|
||||
|
||||
+5
-3
@@ -36,7 +36,10 @@ fun testCompletion(
|
||||
val itemsNumber = ExpectedCompletionUtils.getExpectedNumber(fileText, platform)
|
||||
val nothingElse = ExpectedCompletionUtils.isNothingElseExpected(fileText)
|
||||
|
||||
Assert.assertTrue("Should be some assertions about completion", expected.size != 0 || unexpected.size != 0 || itemsNumber != null || nothingElse)
|
||||
Assert.assertTrue(
|
||||
"Should be some assertions about completion",
|
||||
expected.size != 0 || unexpected.size != 0 || itemsNumber != null || nothingElse
|
||||
)
|
||||
ExpectedCompletionUtils.assertContainsRenderedItems(expected, items, ExpectedCompletionUtils.isWithOrder(fileText), nothingElse)
|
||||
ExpectedCompletionUtils.assertNotContainsRenderedItems(unexpected, items)
|
||||
|
||||
@@ -57,8 +60,7 @@ private fun testWithAutoCompleteSetting(fileText: String, doTest: () -> Unit) {
|
||||
settings.AUTOCOMPLETE_ON_CODE_COMPLETION = autoComplete
|
||||
settings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION = autoComplete
|
||||
doTest()
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
settings.AUTOCOMPLETE_ON_CODE_COMPLETION = oldValue1
|
||||
settings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION = oldValue2
|
||||
}
|
||||
|
||||
+101
-108
@@ -63,8 +63,7 @@ object ExpectedCompletionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun matches(expectedProposal: CompletionProposal): Boolean
|
||||
= expectedProposal.map.entries.none { it.value != map[it.key] }
|
||||
fun matches(expectedProposal: CompletionProposal): Boolean = expectedProposal.map.entries.none { it.value != map[it.key] }
|
||||
|
||||
override fun toString(): String {
|
||||
val jsonObject = JsonObject()
|
||||
@@ -75,13 +74,13 @@ object ExpectedCompletionUtils {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOOKUP_STRING: String = "lookupString"
|
||||
val ALL_LOOKUP_STRINGS: String = "allLookupStrings"
|
||||
val PRESENTATION_ITEM_TEXT: String = "itemText"
|
||||
val PRESENTATION_TYPE_TEXT: String = "typeText"
|
||||
val PRESENTATION_TAIL_TEXT: String = "tailText"
|
||||
val PRESENTATION_TEXT_ATTRIBUTES: String = "attributes"
|
||||
val MODULE_NAME: String = "module"
|
||||
const val LOOKUP_STRING: String = "lookupString"
|
||||
const val ALL_LOOKUP_STRINGS: String = "allLookupStrings"
|
||||
const val PRESENTATION_ITEM_TEXT: String = "itemText"
|
||||
const val PRESENTATION_TYPE_TEXT: String = "typeText"
|
||||
const val PRESENTATION_TAIL_TEXT: String = "tailText"
|
||||
const val PRESENTATION_TEXT_ATTRIBUTES: String = "attributes"
|
||||
const val MODULE_NAME: String = "module"
|
||||
val validKeys: Set<String> = setOf(
|
||||
LOOKUP_STRING, ALL_LOOKUP_STRINGS, PRESENTATION_ITEM_TEXT, PRESENTATION_TYPE_TEXT,
|
||||
PRESENTATION_TAIL_TEXT, PRESENTATION_TEXT_ATTRIBUTES, MODULE_NAME
|
||||
@@ -89,69 +88,67 @@ object ExpectedCompletionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private val UNSUPPORTED_PLATFORM_MESSAGE = "Only ${JvmPlatforms.unspecifiedJvmPlatform} and ${JsPlatforms.defaultJsPlatform} platforms are supported"
|
||||
private val UNSUPPORTED_PLATFORM_MESSAGE =
|
||||
"Only ${JvmPlatforms.unspecifiedJvmPlatform} and ${JsPlatforms.defaultJsPlatform} platforms are supported"
|
||||
|
||||
private val EXIST_LINE_PREFIX = "EXIST:"
|
||||
private const val EXIST_LINE_PREFIX = "EXIST:"
|
||||
|
||||
private val ABSENT_LINE_PREFIX = "ABSENT:"
|
||||
private val ABSENT_JS_LINE_PREFIX = "ABSENT_JS:"
|
||||
private val ABSENT_JAVA_LINE_PREFIX = "ABSENT_JAVA:"
|
||||
private const val ABSENT_LINE_PREFIX = "ABSENT:"
|
||||
private const val ABSENT_JS_LINE_PREFIX = "ABSENT_JS:"
|
||||
private const val ABSENT_JAVA_LINE_PREFIX = "ABSENT_JAVA:"
|
||||
|
||||
private val EXIST_JAVA_ONLY_LINE_PREFIX = "EXIST_JAVA_ONLY:"
|
||||
private val EXIST_JS_ONLY_LINE_PREFIX = "EXIST_JS_ONLY:"
|
||||
private const val EXIST_JAVA_ONLY_LINE_PREFIX = "EXIST_JAVA_ONLY:"
|
||||
private const val EXIST_JS_ONLY_LINE_PREFIX = "EXIST_JS_ONLY:"
|
||||
|
||||
private val NUMBER_LINE_PREFIX = "NUMBER:"
|
||||
private val NUMBER_JS_LINE_PREFIX = "NUMBER_JS:"
|
||||
private val NUMBER_JAVA_LINE_PREFIX = "NUMBER_JAVA:"
|
||||
private const val NUMBER_LINE_PREFIX = "NUMBER:"
|
||||
private const val NUMBER_JS_LINE_PREFIX = "NUMBER_JS:"
|
||||
private const val NUMBER_JAVA_LINE_PREFIX = "NUMBER_JAVA:"
|
||||
|
||||
private val NOTHING_ELSE_PREFIX = "NOTHING_ELSE"
|
||||
private val RUN_HIGHLIGHTING_BEFORE_PREFIX = "RUN_HIGHLIGHTING_BEFORE"
|
||||
private const val NOTHING_ELSE_PREFIX = "NOTHING_ELSE"
|
||||
private const val RUN_HIGHLIGHTING_BEFORE_PREFIX = "RUN_HIGHLIGHTING_BEFORE"
|
||||
|
||||
private val INVOCATION_COUNT_PREFIX = "INVOCATION_COUNT:"
|
||||
private val WITH_ORDER_PREFIX = "WITH_ORDER"
|
||||
private val AUTOCOMPLETE_SETTING_PREFIX = "AUTOCOMPLETE_SETTING:"
|
||||
private const val INVOCATION_COUNT_PREFIX = "INVOCATION_COUNT:"
|
||||
private const val WITH_ORDER_PREFIX = "WITH_ORDER"
|
||||
private const val AUTOCOMPLETE_SETTING_PREFIX = "AUTOCOMPLETE_SETTING:"
|
||||
|
||||
val RUNTIME_TYPE: String = "RUNTIME_TYPE:"
|
||||
const val RUNTIME_TYPE: String = "RUNTIME_TYPE:"
|
||||
|
||||
private val COMPLETION_TYPE_PREFIX = "COMPLETION_TYPE:"
|
||||
private const val COMPLETION_TYPE_PREFIX = "COMPLETION_TYPE:"
|
||||
|
||||
val KNOWN_PREFIXES: List<String> = ImmutableList.of(
|
||||
"LANGUAGE_VERSION:",
|
||||
EXIST_LINE_PREFIX,
|
||||
ABSENT_LINE_PREFIX,
|
||||
ABSENT_JS_LINE_PREFIX,
|
||||
ABSENT_JAVA_LINE_PREFIX,
|
||||
EXIST_JAVA_ONLY_LINE_PREFIX,
|
||||
EXIST_JS_ONLY_LINE_PREFIX,
|
||||
NUMBER_LINE_PREFIX,
|
||||
NUMBER_JS_LINE_PREFIX,
|
||||
NUMBER_JAVA_LINE_PREFIX,
|
||||
INVOCATION_COUNT_PREFIX,
|
||||
WITH_ORDER_PREFIX,
|
||||
AUTOCOMPLETE_SETTING_PREFIX,
|
||||
NOTHING_ELSE_PREFIX,
|
||||
RUN_HIGHLIGHTING_BEFORE_PREFIX,
|
||||
RUNTIME_TYPE,
|
||||
COMPLETION_TYPE_PREFIX,
|
||||
LightClassComputationControl.LIGHT_CLASS_DIRECTIVE,
|
||||
AstAccessControl.ALLOW_AST_ACCESS_DIRECTIVE)
|
||||
"LANGUAGE_VERSION:",
|
||||
EXIST_LINE_PREFIX,
|
||||
ABSENT_LINE_PREFIX,
|
||||
ABSENT_JS_LINE_PREFIX,
|
||||
ABSENT_JAVA_LINE_PREFIX,
|
||||
EXIST_JAVA_ONLY_LINE_PREFIX,
|
||||
EXIST_JS_ONLY_LINE_PREFIX,
|
||||
NUMBER_LINE_PREFIX,
|
||||
NUMBER_JS_LINE_PREFIX,
|
||||
NUMBER_JAVA_LINE_PREFIX,
|
||||
INVOCATION_COUNT_PREFIX,
|
||||
WITH_ORDER_PREFIX,
|
||||
AUTOCOMPLETE_SETTING_PREFIX,
|
||||
NOTHING_ELSE_PREFIX,
|
||||
RUN_HIGHLIGHTING_BEFORE_PREFIX,
|
||||
RUNTIME_TYPE,
|
||||
COMPLETION_TYPE_PREFIX,
|
||||
LightClassComputationControl.LIGHT_CLASS_DIRECTIVE,
|
||||
AstAccessControl.ALLOW_AST_ACCESS_DIRECTIVE
|
||||
)
|
||||
|
||||
fun itemsShouldExist(fileText: String, platform: TargetPlatform?): Array<CompletionProposal> {
|
||||
return when {
|
||||
platform.isJvm() -> processProposalAssertions(fileText, EXIST_LINE_PREFIX, EXIST_JAVA_ONLY_LINE_PREFIX)
|
||||
platform.isJs() -> processProposalAssertions(fileText, EXIST_LINE_PREFIX, EXIST_JS_ONLY_LINE_PREFIX)
|
||||
platform == null -> processProposalAssertions(fileText, EXIST_LINE_PREFIX)
|
||||
else -> throw IllegalArgumentException(UNSUPPORTED_PLATFORM_MESSAGE)
|
||||
}
|
||||
fun itemsShouldExist(fileText: String, platform: TargetPlatform?): Array<CompletionProposal> = when {
|
||||
platform.isJvm() -> processProposalAssertions(fileText, EXIST_LINE_PREFIX, EXIST_JAVA_ONLY_LINE_PREFIX)
|
||||
platform.isJs() -> processProposalAssertions(fileText, EXIST_LINE_PREFIX, EXIST_JS_ONLY_LINE_PREFIX)
|
||||
platform == null -> processProposalAssertions(fileText, EXIST_LINE_PREFIX)
|
||||
else -> throw IllegalArgumentException(UNSUPPORTED_PLATFORM_MESSAGE)
|
||||
}
|
||||
|
||||
fun itemsShouldAbsent(fileText: String, platform: TargetPlatform?): Array<CompletionProposal> {
|
||||
return when {
|
||||
platform.isJvm() -> processProposalAssertions(fileText, ABSENT_LINE_PREFIX, ABSENT_JAVA_LINE_PREFIX, EXIST_JS_ONLY_LINE_PREFIX)
|
||||
platform.isJs() -> processProposalAssertions(fileText, ABSENT_LINE_PREFIX, ABSENT_JS_LINE_PREFIX, EXIST_JAVA_ONLY_LINE_PREFIX)
|
||||
platform == null -> processProposalAssertions(fileText, ABSENT_LINE_PREFIX)
|
||||
else -> throw IllegalArgumentException(UNSUPPORTED_PLATFORM_MESSAGE)
|
||||
}
|
||||
fun itemsShouldAbsent(fileText: String, platform: TargetPlatform?): Array<CompletionProposal> = when {
|
||||
platform.isJvm() -> processProposalAssertions(fileText, ABSENT_LINE_PREFIX, ABSENT_JAVA_LINE_PREFIX, EXIST_JS_ONLY_LINE_PREFIX)
|
||||
platform.isJs() -> processProposalAssertions(fileText, ABSENT_LINE_PREFIX, ABSENT_JS_LINE_PREFIX, EXIST_JAVA_ONLY_LINE_PREFIX)
|
||||
platform == null -> processProposalAssertions(fileText, ABSENT_LINE_PREFIX)
|
||||
else -> throw IllegalArgumentException(UNSUPPORTED_PLATFORM_MESSAGE)
|
||||
}
|
||||
|
||||
fun processProposalAssertions(fileText: String, vararg prefixes: String): Array<CompletionProposal> {
|
||||
@@ -161,16 +158,13 @@ object ExpectedCompletionUtils {
|
||||
val parser = JsonParser()
|
||||
val json: JsonElement? = try {
|
||||
parser.parse(proposalStr)
|
||||
}
|
||||
catch(t: Throwable) {
|
||||
} catch (t: Throwable) {
|
||||
throw RuntimeException("Error parsing '$proposalStr'", t)
|
||||
}
|
||||
proposals.add(CompletionProposal(json as JsonObject))
|
||||
}
|
||||
else if (proposalStr.startsWith("\"") && proposalStr.endsWith("\"")) {
|
||||
} else if (proposalStr.startsWith("\"") && proposalStr.endsWith("\"")) {
|
||||
proposals.add(CompletionProposal(proposalStr.substring(1, proposalStr.length - 1)))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (item in proposalStr.split(",")) {
|
||||
proposals.add(CompletionProposal(item.trim()))
|
||||
}
|
||||
@@ -180,50 +174,44 @@ object ExpectedCompletionUtils {
|
||||
return ArrayUtil.toObjectArray(proposals, CompletionProposal::class.java)
|
||||
}
|
||||
|
||||
fun getExpectedNumber(fileText: String, platform: TargetPlatform?): Int? {
|
||||
return when {
|
||||
platform == null -> InTextDirectivesUtils.getPrefixedInt(fileText, NUMBER_LINE_PREFIX)
|
||||
platform.isJvm() -> getPlatformExpectedNumber(fileText, NUMBER_JAVA_LINE_PREFIX)
|
||||
platform.isJs() -> getPlatformExpectedNumber(fileText, NUMBER_JS_LINE_PREFIX)
|
||||
else -> throw IllegalArgumentException(UNSUPPORTED_PLATFORM_MESSAGE)
|
||||
}
|
||||
fun getExpectedNumber(fileText: String, platform: TargetPlatform?): Int? = when {
|
||||
platform == null -> InTextDirectivesUtils.getPrefixedInt(fileText, NUMBER_LINE_PREFIX)
|
||||
platform.isJvm() -> getPlatformExpectedNumber(fileText, NUMBER_JAVA_LINE_PREFIX)
|
||||
platform.isJs() -> getPlatformExpectedNumber(fileText, NUMBER_JS_LINE_PREFIX)
|
||||
else -> throw IllegalArgumentException(UNSUPPORTED_PLATFORM_MESSAGE)
|
||||
}
|
||||
|
||||
fun isNothingElseExpected(fileText: String): Boolean {
|
||||
return InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, NOTHING_ELSE_PREFIX).isNotEmpty()
|
||||
}
|
||||
fun isNothingElseExpected(fileText: String): Boolean =
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, NOTHING_ELSE_PREFIX).isNotEmpty()
|
||||
|
||||
fun shouldRunHighlightingBeforeCompletion(fileText: String): Boolean {
|
||||
return InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, RUN_HIGHLIGHTING_BEFORE_PREFIX).isNotEmpty()
|
||||
}
|
||||
fun shouldRunHighlightingBeforeCompletion(fileText: String): Boolean =
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, RUN_HIGHLIGHTING_BEFORE_PREFIX).isNotEmpty()
|
||||
|
||||
fun getInvocationCount(fileText: String): Int? {
|
||||
return InTextDirectivesUtils.getPrefixedInt(fileText, INVOCATION_COUNT_PREFIX)
|
||||
}
|
||||
fun getInvocationCount(fileText: String): Int? = InTextDirectivesUtils.getPrefixedInt(fileText, INVOCATION_COUNT_PREFIX)
|
||||
|
||||
fun getCompletionType(fileText: String): CompletionType? {
|
||||
val completionTypeString = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_TYPE_PREFIX)
|
||||
return when (completionTypeString) {
|
||||
fun getCompletionType(fileText: String): CompletionType? =
|
||||
when (val completionTypeString = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_TYPE_PREFIX)) {
|
||||
"BASIC" -> CompletionType.BASIC
|
||||
"SMART" -> CompletionType.SMART
|
||||
null -> null
|
||||
else -> error("Unknown completion type: $completionTypeString")
|
||||
}
|
||||
}
|
||||
|
||||
fun getAutocompleteSetting(fileText: String): Boolean? {
|
||||
return InTextDirectivesUtils.getPrefixedBoolean(fileText, AUTOCOMPLETE_SETTING_PREFIX)
|
||||
}
|
||||
fun getAutocompleteSetting(fileText: String): Boolean? = InTextDirectivesUtils.getPrefixedBoolean(fileText, AUTOCOMPLETE_SETTING_PREFIX)
|
||||
|
||||
fun isWithOrder(fileText: String): Boolean {
|
||||
return !InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, WITH_ORDER_PREFIX).isEmpty()
|
||||
}
|
||||
fun isWithOrder(fileText: String): Boolean =
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, WITH_ORDER_PREFIX).isNotEmpty()
|
||||
|
||||
fun assertDirectivesValid(fileText: String, additionalValidDirectives: Collection<String> = emptyList()) {
|
||||
InTextDirectivesUtils.assertHasUnknownPrefixes(fileText, KNOWN_PREFIXES + additionalValidDirectives)
|
||||
}
|
||||
|
||||
fun assertContainsRenderedItems(expected: Array<CompletionProposal>, items: Array<LookupElement>, checkOrder: Boolean, nothingElse: Boolean) {
|
||||
fun assertContainsRenderedItems(
|
||||
expected: Array<CompletionProposal>,
|
||||
items: Array<LookupElement>,
|
||||
checkOrder: Boolean,
|
||||
nothingElse: Boolean
|
||||
) {
|
||||
val itemsInformation = getItemsInformation(items)
|
||||
val allItemsString = listToString(itemsInformation)
|
||||
|
||||
@@ -235,13 +223,15 @@ object ExpectedCompletionUtils {
|
||||
var isFound = false
|
||||
|
||||
for (index in itemsInformation.indices) {
|
||||
val proposal = itemsInformation.get(index)
|
||||
val proposal = itemsInformation[index]
|
||||
|
||||
if (proposal.matches(expectedProposal)) {
|
||||
isFound = true
|
||||
|
||||
Assert.assertTrue("Invalid order of existent elements in $allItemsString",
|
||||
!checkOrder || index > indexOfPrevious)
|
||||
Assert.assertTrue(
|
||||
"Invalid order of existent elements in $allItemsString",
|
||||
!checkOrder || index > indexOfPrevious
|
||||
)
|
||||
indexOfPrevious = index
|
||||
|
||||
leftItems?.remove(proposal)
|
||||
@@ -253,14 +243,13 @@ object ExpectedCompletionUtils {
|
||||
if (!isFound) {
|
||||
if (allItemsString.isEmpty()) {
|
||||
Assert.fail("Completion is empty but $expectedProposal is expected")
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Assert.fail("Expected $expectedProposal not found in:\n$allItemsString")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (leftItems != null && !leftItems.isEmpty()) {
|
||||
if (leftItems != null && leftItems.isNotEmpty()) {
|
||||
Assert.fail("No items not mentioned in EXIST directives expected but some found:\n" + listToString(leftItems))
|
||||
}
|
||||
}
|
||||
@@ -268,8 +257,10 @@ object ExpectedCompletionUtils {
|
||||
private fun getPlatformExpectedNumber(fileText: String, platformNumberPrefix: String): Int? {
|
||||
val prefixedInt = InTextDirectivesUtils.getPrefixedInt(fileText, platformNumberPrefix)
|
||||
if (prefixedInt != null) {
|
||||
Assert.assertNull("There shouldn't be $NUMBER_LINE_PREFIX and $platformNumberPrefix prefixes set in same time",
|
||||
InTextDirectivesUtils.getPrefixedInt(fileText, NUMBER_LINE_PREFIX))
|
||||
Assert.assertNull(
|
||||
"There shouldn't be $NUMBER_LINE_PREFIX and $platformNumberPrefix prefixes set in same time",
|
||||
InTextDirectivesUtils.getPrefixedInt(fileText, NUMBER_LINE_PREFIX)
|
||||
)
|
||||
return prefixedInt
|
||||
}
|
||||
|
||||
@@ -282,8 +273,10 @@ object ExpectedCompletionUtils {
|
||||
|
||||
for (unexpectedProposal in unexpected) {
|
||||
for (proposal in itemsInformation) {
|
||||
Assert.assertFalse("Unexpected '$unexpectedProposal' presented in $allItemsString",
|
||||
proposal.matches(unexpectedProposal))
|
||||
Assert.assertFalse(
|
||||
"Unexpected '$unexpectedProposal' presented in $allItemsString",
|
||||
proposal.matches(unexpectedProposal)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,21 +289,21 @@ object ExpectedCompletionUtils {
|
||||
item.renderElement(presentation)
|
||||
|
||||
val map = HashMap<String, String?>()
|
||||
map.put(CompletionProposal.LOOKUP_STRING, item.lookupString)
|
||||
map[CompletionProposal.LOOKUP_STRING] = item.lookupString
|
||||
|
||||
map.put(CompletionProposal.ALL_LOOKUP_STRINGS, item.allLookupStrings.sorted().joinToString())
|
||||
map[CompletionProposal.ALL_LOOKUP_STRINGS] = item.allLookupStrings.sorted().joinToString()
|
||||
|
||||
if (presentation.itemText != null) {
|
||||
map.put(CompletionProposal.PRESENTATION_ITEM_TEXT, presentation.itemText)
|
||||
map.put(CompletionProposal.PRESENTATION_TEXT_ATTRIBUTES, textAttributes(presentation))
|
||||
map[CompletionProposal.PRESENTATION_ITEM_TEXT] = presentation.itemText
|
||||
map[CompletionProposal.PRESENTATION_TEXT_ATTRIBUTES] = textAttributes(presentation)
|
||||
}
|
||||
|
||||
if (presentation.typeText != null) {
|
||||
map.put(CompletionProposal.PRESENTATION_TYPE_TEXT, presentation.typeText)
|
||||
map[CompletionProposal.PRESENTATION_TYPE_TEXT] = presentation.typeText
|
||||
}
|
||||
|
||||
if (presentation.tailText != null) {
|
||||
map.put(CompletionProposal.PRESENTATION_TAIL_TEXT, presentation.tailText)
|
||||
map[CompletionProposal.PRESENTATION_TAIL_TEXT] = presentation.tailText
|
||||
}
|
||||
item.moduleName?.let {
|
||||
map.put(CompletionProposal.MODULE_NAME, it)
|
||||
|
||||
+6
-7
@@ -20,7 +20,7 @@ import java.util.Collections.synchronizedList
|
||||
object LightClassComputationControl {
|
||||
fun testWithControl(project: Project, testText: String, testBody: () -> Unit) {
|
||||
val expectedLightClassFqNames = InTextDirectivesUtils.findLinesWithPrefixesRemoved(
|
||||
testText, "// $LIGHT_CLASS_DIRECTIVE"
|
||||
testText, "// $LIGHT_CLASS_DIRECTIVE"
|
||||
).map { it.trim() }
|
||||
|
||||
val actualFqNames = synchronizedList(ArrayList<String>())
|
||||
@@ -37,14 +37,14 @@ object LightClassComputationControl {
|
||||
|
||||
if (expectedLightClassFqNames.toSortedSet() != synchronized(actualFqNames) { actualFqNames.toSortedSet() }) {
|
||||
Assert.fail(
|
||||
"Expected to compute: ${expectedLightClassFqNames.prettyToString()}\n" +
|
||||
"Actually computed: ${actualFqNames.prettyToString()}\n" +
|
||||
"Use $LIGHT_CLASS_DIRECTIVE to specify expected light class computations"
|
||||
"Expected to compute: ${expectedLightClassFqNames.prettyToString()}\n" +
|
||||
"Actually computed: ${actualFqNames.prettyToString()}\n" +
|
||||
"Use $LIGHT_CLASS_DIRECTIVE to specify expected light class computations"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val LIGHT_CLASS_DIRECTIVE = "LIGHT_CLASS:"
|
||||
const val LIGHT_CLASS_DIRECTIVE = "LIGHT_CLASS:"
|
||||
|
||||
private fun List<String>.prettyToString() = if (isEmpty()) "<empty>" else joinToString()
|
||||
}
|
||||
@@ -56,8 +56,7 @@ inline fun <reified T : Any, R> ComponentManager.withServiceRegistered(instance:
|
||||
picoContainer.unregisterComponent(key)
|
||||
picoContainer.registerComponentInstance(key, instance)
|
||||
return body()
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
picoContainer.unregisterComponent(key)
|
||||
}
|
||||
}
|
||||
|
||||
+8
-4
@@ -14,8 +14,8 @@ import java.io.File
|
||||
|
||||
@Deprecated("All tests from here to be moved to the generated test")
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
|
||||
private fun checkResult(){
|
||||
class BasicCompletionHandlerTest : CompletionHandlerTestBase() {
|
||||
private fun checkResult() {
|
||||
fixture.checkResultByFile(getTestName(false) + ".kt.after")
|
||||
}
|
||||
|
||||
@@ -144,7 +144,11 @@ class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
|
||||
fun testInfixCall() = doTest(1, "to", null, null, '\n')
|
||||
fun testInfixCallOnSpace() = doTest(1, "to", null, null, ' ')
|
||||
|
||||
fun testImportedEnumMember() { doTest(1, "AAA", null, null, '\n') }
|
||||
fun testImportedEnumMember() {
|
||||
doTest(1, "AAA", null, null, '\n')
|
||||
}
|
||||
|
||||
fun testInnerClass() { doTest(1, "Inner", null, null, '\n') }
|
||||
fun testInnerClass() {
|
||||
doTest(1, "Inner", null, null, '\n')
|
||||
}
|
||||
}
|
||||
|
||||
+12
-8
@@ -82,7 +82,7 @@ abstract class CompletionHandlerTestBase : KotlinLightCodeInsightFixtureTestCase
|
||||
return items.firstOrNull()
|
||||
}
|
||||
|
||||
var foundElement : LookupElement? = null
|
||||
var foundElement: LookupElement? = null
|
||||
val presentation = LookupElementPresentation()
|
||||
for (lookupElement in items) {
|
||||
val lookupOk = if (lookupString != null) lookupElement.lookupString == lookupString else true
|
||||
@@ -93,8 +93,7 @@ abstract class CompletionHandlerTestBase : KotlinLightCodeInsightFixtureTestCase
|
||||
val textOk = if (itemText != null) {
|
||||
val itemItemText = presentation.itemText
|
||||
itemItemText != null && itemItemText == itemText
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
@@ -102,14 +101,20 @@ abstract class CompletionHandlerTestBase : KotlinLightCodeInsightFixtureTestCase
|
||||
val tailOk = if (tailText != null) {
|
||||
val itemTailText = presentation.tailText
|
||||
itemTailText != null && itemTailText == tailText
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
if (tailOk) {
|
||||
if (foundElement != null) {
|
||||
val dump = ExpectedCompletionUtils.listToString(ExpectedCompletionUtils.getItemsInformation(arrayOf(foundElement, lookupElement)))
|
||||
val dump = ExpectedCompletionUtils.listToString(
|
||||
ExpectedCompletionUtils.getItemsInformation(
|
||||
arrayOf(
|
||||
foundElement,
|
||||
lookupElement
|
||||
)
|
||||
)
|
||||
)
|
||||
fail("Several elements satisfy to completion restrictions:\n$dump")
|
||||
}
|
||||
|
||||
@@ -134,8 +139,7 @@ abstract class CompletionHandlerTestBase : KotlinLightCodeInsightFixtureTestCase
|
||||
lookup.focusDegree = LookupImpl.FocusDegree.FOCUSED
|
||||
if (LookupEvent.isSpecialCompletionChar(completionChar)) {
|
||||
lookup.finishLookup(completionChar)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fixture.type(completionChar)
|
||||
}
|
||||
}
|
||||
|
||||
+17
-7
@@ -16,15 +16,25 @@ import java.io.File
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class SmartCompletionMultifileHandlerTest : KotlinCompletionTestCase() {
|
||||
fun testImportExtensionFunction() { doTest() }
|
||||
fun testImportExtensionFunction() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testImportExtensionProperty() { doTest() }
|
||||
fun testImportExtensionProperty() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testAnonymousObjectGenericJava() { doTest() }
|
||||
fun testAnonymousObjectGenericJava() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testImportAnonymousObject() { doTest() }
|
||||
fun testImportAnonymousObject() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testNestedSamAdapter() { doTest(lookupString = "Nested") }
|
||||
fun testNestedSamAdapter() {
|
||||
doTest(lookupString = "Nested")
|
||||
}
|
||||
|
||||
override fun setUp() {
|
||||
setType(CompletionType.SMART)
|
||||
@@ -34,7 +44,7 @@ class SmartCompletionMultifileHandlerTest : KotlinCompletionTestCase() {
|
||||
private fun doTest(lookupString: String? = null, itemText: String? = null) {
|
||||
val fileName = getTestName(false)
|
||||
|
||||
val fileNames = listOf(fileName + "-1.kt", fileName + "-2.kt", fileName + ".java")
|
||||
val fileNames = listOf("$fileName-1.kt", "$fileName-2.kt", "$fileName.java")
|
||||
|
||||
configureByFiles(null, *fileNames.filter { File(testDataPath + it).exists() }.toTypedArray())
|
||||
|
||||
@@ -58,7 +68,7 @@ class SmartCompletionMultifileHandlerTest : KotlinCompletionTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
checkResultByFile(fileName + ".kt.after")
|
||||
checkResultByFile("$fileName.kt.after")
|
||||
}
|
||||
|
||||
override fun getTestDataPath() = File(COMPLETION_TEST_DATA_BASE_PATH, "/handlers/multifile/smart/").path + File.separator
|
||||
|
||||
+3
-4
@@ -15,12 +15,11 @@ fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraName
|
||||
|
||||
val noExtensionPath = FileUtil.getNameWithoutExtension(fileName)
|
||||
val extensions = arrayOf("kt", "java", "properties")
|
||||
val extraPaths: List<String> = extraNameParts
|
||||
.flatMap { extensions.map { ext -> "$noExtensionPath$it.$ext" } }
|
||||
.mapNotNull { File(testDataPath, it).takeIf { it.exists() }?.name }
|
||||
val extraPaths: List<String> = extraNameParts.flatMap { extensions.map { ext -> "$noExtensionPath$it.$ext" } }
|
||||
.mapNotNull { File(testDataPath, it).takeIf { file -> file.exists() }?.name }
|
||||
|
||||
configureByFiles(*(listOf(fileName) + extraPaths).toTypedArray())
|
||||
}
|
||||
|
||||
@Suppress("unused") // Used in kotlin-ultimate
|
||||
inline fun <reified T: Any> Any?.assertInstanceOf() = UsefulTestCase.assertInstanceOf(this, T::class.java)
|
||||
inline fun <reified T : Any> Any?.assertInstanceOf() = UsefulTestCase.assertInstanceOf(this, T::class.java)
|
||||
|
||||
+4
-3
@@ -15,9 +15,10 @@ import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.junit.Assert
|
||||
|
||||
abstract class AbstractCompletionWeigherTest(val completionType: CompletionType, val relativeTestDataPath: String) : KotlinLightCodeInsightFixtureTestCase() {
|
||||
abstract class AbstractCompletionWeigherTest(val completionType: CompletionType, val relativeTestDataPath: String) :
|
||||
KotlinLightCodeInsightFixtureTestCase() {
|
||||
fun doTest(path: String) {
|
||||
val pathPrefix = RELATIVE_COMPLETION_TEST_DATA_BASE_PATH + "/" + relativeTestDataPath
|
||||
val pathPrefix = "$RELATIVE_COMPLETION_TEST_DATA_BASE_PATH/$relativeTestDataPath"
|
||||
assert(path.startsWith(pathPrefix))
|
||||
val relativePath = path.removePrefix(pathPrefix)
|
||||
|
||||
@@ -28,7 +29,7 @@ abstract class AbstractCompletionWeigherTest(val completionType: CompletionType,
|
||||
val configured = configureCompilerOptions(text, project, module)
|
||||
|
||||
val items = InTextDirectivesUtils.findArrayWithPrefixes(text, "// ORDER:")
|
||||
Assert.assertTrue("""Some items should be defined with "// ORDER:" directive""", !items.isEmpty())
|
||||
Assert.assertTrue("""Some items should be defined with "// ORDER:" directive""", items.isNotEmpty())
|
||||
|
||||
try {
|
||||
myFixture.complete(completionType, InTextDirectivesUtils.getPrefixedInt(text, "// INVOCATION_COUNT:") ?: 1)
|
||||
|
||||
Reference in New Issue
Block a user