Apply LiftReturnOrAssignmentInspection on idea
This commit is contained in:
+98
-82
@@ -39,11 +39,11 @@ import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.platform.isCommon
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.platform.isCommon
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -53,28 +53,28 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import java.util.*
|
||||
|
||||
class CompletionSessionConfiguration(
|
||||
val useBetterPrefixMatcherForNonImportedClasses: Boolean,
|
||||
val nonAccessibleDeclarations: Boolean,
|
||||
val javaGettersAndSetters: Boolean,
|
||||
val javaClassesNotToBeUsed: Boolean,
|
||||
val staticMembers: Boolean,
|
||||
val dataClassComponentFunctions: Boolean
|
||||
val useBetterPrefixMatcherForNonImportedClasses: Boolean,
|
||||
val nonAccessibleDeclarations: Boolean,
|
||||
val javaGettersAndSetters: Boolean,
|
||||
val javaClassesNotToBeUsed: Boolean,
|
||||
val staticMembers: Boolean,
|
||||
val dataClassComponentFunctions: Boolean
|
||||
)
|
||||
|
||||
fun CompletionSessionConfiguration(parameters: CompletionParameters) = CompletionSessionConfiguration(
|
||||
useBetterPrefixMatcherForNonImportedClasses = parameters.invocationCount < 2,
|
||||
nonAccessibleDeclarations = parameters.invocationCount >= 2,
|
||||
javaGettersAndSetters = parameters.invocationCount >= 2,
|
||||
javaClassesNotToBeUsed = parameters.invocationCount >= 2,
|
||||
staticMembers = parameters.invocationCount >= 2,
|
||||
dataClassComponentFunctions = parameters.invocationCount >= 2
|
||||
useBetterPrefixMatcherForNonImportedClasses = parameters.invocationCount < 2,
|
||||
nonAccessibleDeclarations = parameters.invocationCount >= 2,
|
||||
javaGettersAndSetters = parameters.invocationCount >= 2,
|
||||
javaClassesNotToBeUsed = parameters.invocationCount >= 2,
|
||||
staticMembers = parameters.invocationCount >= 2,
|
||||
dataClassComponentFunctions = parameters.invocationCount >= 2
|
||||
)
|
||||
|
||||
abstract class CompletionSession(
|
||||
protected val configuration: CompletionSessionConfiguration,
|
||||
protected val parameters: CompletionParameters,
|
||||
protected val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
resultSet: CompletionResultSet
|
||||
protected val configuration: CompletionSessionConfiguration,
|
||||
protected val parameters: CompletionParameters,
|
||||
protected val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
resultSet: CompletionResultSet
|
||||
) {
|
||||
init {
|
||||
CompletionBenchmarkSink.instance.onCompletionStarted(this)
|
||||
@@ -97,13 +97,11 @@ abstract class CompletionSession(
|
||||
if (reference.expression is KtLabelReferenceExpression) {
|
||||
this.nameExpression = null
|
||||
this.expression = reference.expression.parent.parent as? KtExpressionWithLabel
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.nameExpression = reference.expression
|
||||
this.expression = nameExpression
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.nameExpression = null
|
||||
this.expression = null
|
||||
}
|
||||
@@ -116,29 +114,36 @@ abstract class CompletionSession(
|
||||
private val kotlinIdentifierPartPattern = StandardPatterns.character().javaIdentifierPart().andNot(singleCharPattern('$'))
|
||||
|
||||
protected val prefix = CompletionUtil.findIdentifierPrefix(
|
||||
parameters.position.containingFile,
|
||||
parameters.offset,
|
||||
kotlinIdentifierPartPattern or singleCharPattern('@'),
|
||||
kotlinIdentifierStartPattern)!!
|
||||
parameters.position.containingFile,
|
||||
parameters.offset,
|
||||
kotlinIdentifierPartPattern or singleCharPattern('@'),
|
||||
kotlinIdentifierStartPattern
|
||||
)!!
|
||||
|
||||
protected val prefixMatcher = CamelHumpMatcher(prefix)
|
||||
|
||||
protected val descriptorNameFilter: (String) -> Boolean = prefixMatcher.asStringNameFilter()
|
||||
|
||||
protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = configuration.nonAccessibleDeclarations) }
|
||||
protected val isVisibleFilterCheckAlways: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = false) }
|
||||
protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean =
|
||||
{ isVisibleDescriptor(it, completeNonAccessible = configuration.nonAccessibleDeclarations) }
|
||||
protected val isVisibleFilterCheckAlways: (DeclarationDescriptor) -> Boolean =
|
||||
{ isVisibleDescriptor(it, completeNonAccessible = false) }
|
||||
|
||||
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext,
|
||||
resolutionFacade,
|
||||
moduleDescriptor,
|
||||
isVisibleFilter,
|
||||
NotPropertiesService.getNotProperties(position))
|
||||
protected val referenceVariantsHelper = ReferenceVariantsHelper(
|
||||
bindingContext,
|
||||
resolutionFacade,
|
||||
moduleDescriptor,
|
||||
isVisibleFilter,
|
||||
NotPropertiesService.getNotProperties(position)
|
||||
)
|
||||
|
||||
protected val callTypeAndReceiver = if (nameExpression == null) CallTypeAndReceiver.UNKNOWN else CallTypeAndReceiver.detect(nameExpression)
|
||||
protected val callTypeAndReceiver =
|
||||
if (nameExpression == null) CallTypeAndReceiver.UNKNOWN else CallTypeAndReceiver.detect(nameExpression)
|
||||
protected val receiverTypes = nameExpression?.let { detectReceiverTypes(bindingContext, nameExpression, callTypeAndReceiver) }
|
||||
|
||||
|
||||
protected val basicLookupElementFactory = BasicLookupElementFactory(project, InsertHandlerProvider(callTypeAndReceiver.callType) { expectedInfos })
|
||||
protected val basicLookupElementFactory =
|
||||
BasicLookupElementFactory(project, InsertHandlerProvider(callTypeAndReceiver.callType) { expectedInfos })
|
||||
|
||||
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
||||
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
|
||||
@@ -155,12 +160,14 @@ abstract class CompletionSession(
|
||||
|
||||
protected fun indicesHelper(mayIncludeInaccessible: Boolean): KotlinIndicesHelper {
|
||||
val filter = if (mayIncludeInaccessible) isVisibleFilter else isVisibleFilterCheckAlways
|
||||
return KotlinIndicesHelper(resolutionFacade,
|
||||
searchScope,
|
||||
filter,
|
||||
filterOutPrivate = !mayIncludeInaccessible,
|
||||
declarationTranslator = { toFromOriginalFileMapper.toSyntheticFile(it) },
|
||||
file = file)
|
||||
return KotlinIndicesHelper(
|
||||
resolutionFacade,
|
||||
searchScope,
|
||||
filter,
|
||||
filterOutPrivate = !mayIncludeInaccessible,
|
||||
declarationTranslator = { toFromOriginalFileMapper.toSyntheticFile(it) },
|
||||
file = file
|
||||
)
|
||||
}
|
||||
|
||||
private fun isVisibleDescriptor(descriptor: DeclarationDescriptor, completeNonAccessible: Boolean): Boolean {
|
||||
@@ -253,20 +260,22 @@ abstract class CompletionSession(
|
||||
protected open fun createSorter(): CompletionSorter {
|
||||
var sorter = CompletionSorter.defaultSorter(parameters, prefixMatcher)!!
|
||||
|
||||
sorter = sorter.weighBefore("stats", DeprecatedWeigher, PriorityWeigher, PreferGetSetMethodsToPropertyWeigher,
|
||||
NotImportedWeigher(importableFqNameClassifier),
|
||||
NotImportedStaticMemberWeigher(importableFqNameClassifier),
|
||||
KindWeigher, CallableWeigher)
|
||||
sorter = sorter.weighBefore(
|
||||
"stats", DeprecatedWeigher, PriorityWeigher, PreferGetSetMethodsToPropertyWeigher,
|
||||
NotImportedWeigher(importableFqNameClassifier),
|
||||
NotImportedStaticMemberWeigher(importableFqNameClassifier),
|
||||
KindWeigher, CallableWeigher
|
||||
)
|
||||
|
||||
sorter = sorter.weighAfter("stats", VariableOrFunctionWeigher, ImportedWeigher(importableFqNameClassifier))
|
||||
|
||||
val preferContextElementsWeigher = PreferContextElementsWeigher(inDescriptor)
|
||||
sorter = if (callTypeAndReceiver is CallTypeAndReceiver.SUPER_MEMBERS) { // for completion after "super." strictly prefer the current member
|
||||
sorter.weighBefore("kotlin.deprecated", preferContextElementsWeigher)
|
||||
}
|
||||
else {
|
||||
sorter.weighBefore("kotlin.proximity", preferContextElementsWeigher)
|
||||
}
|
||||
sorter =
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.SUPER_MEMBERS) { // for completion after "super." strictly prefer the current member
|
||||
sorter.weighBefore("kotlin.deprecated", preferContextElementsWeigher)
|
||||
} else {
|
||||
sorter.weighBefore("kotlin.proximity", preferContextElementsWeigher)
|
||||
}
|
||||
|
||||
sorter = sorter.weighBefore("middleMatching", PreferMatchingItemWeigher)
|
||||
|
||||
@@ -275,10 +284,10 @@ abstract class CompletionSession(
|
||||
|
||||
sorter = sorter.weighAfter("kotlin.proximity", ByNameAlphabeticalWeigher, PreferLessParametersWeigher)
|
||||
|
||||
if (expectedInfos.all { it.fuzzyType?.type?.isUnit() == true }) {
|
||||
sorter = sorter.weighBefore("prefix", PreferDslMembers)
|
||||
sorter = if (expectedInfos.all { it.fuzzyType?.type?.isUnit() == true }) {
|
||||
sorter.weighBefore("prefix", PreferDslMembers)
|
||||
} else {
|
||||
sorter = sorter.weighAfter("kotlin.preferContextElements", PreferDslMembers)
|
||||
sorter.weighAfter("kotlin.preferContextElements", PreferDslMembers)
|
||||
}
|
||||
|
||||
return sorter
|
||||
@@ -288,28 +297,29 @@ abstract class CompletionSession(
|
||||
if (expectedInfos.isEmpty()) return null
|
||||
|
||||
var context = expectedInfos
|
||||
.mapNotNull { it.fuzzyType?.type?.constructor?.declarationDescriptor?.importableFqName }
|
||||
.distinct()
|
||||
.singleOrNull()
|
||||
?.let { "expectedType=$it" }
|
||||
.mapNotNull { it.fuzzyType?.type?.constructor?.declarationDescriptor?.importableFqName }
|
||||
.distinct()
|
||||
.singleOrNull()
|
||||
?.let { "expectedType=$it" }
|
||||
|
||||
if (context == null) {
|
||||
context = expectedInfos
|
||||
.mapNotNull { it.expectedName }
|
||||
.distinct()
|
||||
.singleOrNull()
|
||||
?.let { "expectedName=$it" }
|
||||
.mapNotNull { it.expectedName }
|
||||
.distinct()
|
||||
.singleOrNull()
|
||||
?.let { "expectedName=$it" }
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
protected val referenceVariantsCollector = if (nameExpression != null) {
|
||||
ReferenceVariantsCollector(referenceVariantsHelper, indicesHelper(true), prefixMatcher,
|
||||
nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext,
|
||||
importableFqNameClassifier, configuration)
|
||||
}
|
||||
else {
|
||||
ReferenceVariantsCollector(
|
||||
referenceVariantsHelper, indicesHelper(true), prefixMatcher,
|
||||
nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext,
|
||||
importableFqNameClassifier, configuration
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@@ -319,7 +329,9 @@ abstract class CompletionSession(
|
||||
|
||||
protected fun referenceVariantsWithSingleFunctionTypeParameter(): ReferenceVariants? {
|
||||
val variants = referenceVariantsCollector?.allCollected ?: return null
|
||||
val filter = { descriptor: DeclarationDescriptor -> descriptor is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(descriptor) }
|
||||
val filter = { descriptor: DeclarationDescriptor ->
|
||||
descriptor is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(descriptor)
|
||||
}
|
||||
return ReferenceVariants(variants.imported.filter(filter), variants.notImportedExtensions.filter(filter))
|
||||
}
|
||||
|
||||
@@ -336,20 +348,21 @@ abstract class CompletionSession(
|
||||
|
||||
val expressionReceiver = ExpressionReceiver.create(explicitReceiver, runtimeType, bindingContext)
|
||||
val (variants, notImportedExtensions) = ReferenceVariantsCollector(
|
||||
referenceVariantsHelper, indicesHelper(true), prefixMatcher,
|
||||
nameExpression!!, callTypeAndReceiver, resolutionFacade, bindingContext,
|
||||
importableFqNameClassifier, configuration, runtimeReceiver = expressionReceiver
|
||||
referenceVariantsHelper, indicesHelper(true), prefixMatcher,
|
||||
nameExpression!!, callTypeAndReceiver, resolutionFacade, bindingContext,
|
||||
importableFqNameClassifier, configuration, runtimeReceiver = expressionReceiver
|
||||
).collectReferenceVariants(descriptorKindFilter!!)
|
||||
val filteredVariants = filterVariantsForRuntimeReceiverType(variants, referenceVariants.imported)
|
||||
val filteredNotImportedExtensions = filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants.notImportedExtensions)
|
||||
val filteredNotImportedExtensions =
|
||||
filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants.notImportedExtensions)
|
||||
|
||||
val runtimeVariants = ReferenceVariants(filteredVariants, filteredNotImportedExtensions)
|
||||
return Pair(runtimeVariants, lookupElementFactory.copy(receiverTypes = listOf(ReceiverType(runtimeType, 0))))
|
||||
}
|
||||
|
||||
private fun <TDescriptor : DeclarationDescriptor> filterVariantsForRuntimeReceiverType(
|
||||
runtimeVariants: Collection<TDescriptor>,
|
||||
baseVariants: Collection<TDescriptor>
|
||||
runtimeVariants: Collection<TDescriptor>,
|
||||
baseVariants: Collection<TDescriptor>
|
||||
): Collection<TDescriptor> {
|
||||
val baseVariantsByName = baseVariants.groupBy { it.name }
|
||||
val result = ArrayList<TDescriptor>()
|
||||
@@ -371,12 +384,11 @@ abstract class CompletionSession(
|
||||
|
||||
protected fun processTopLevelCallables(processor: (CallableDescriptor) -> Unit) {
|
||||
val shadowedFilter = ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression!!, callTypeAndReceiver)
|
||||
?.createNonImportedDeclarationsFilter<CallableDescriptor>(referenceVariantsCollector!!.allCollected.imported)
|
||||
?.createNonImportedDeclarationsFilter<CallableDescriptor>(referenceVariantsCollector!!.allCollected.imported)
|
||||
indicesHelper(true).processTopLevelCallables({ prefixMatcher.prefixMatches(it) }) {
|
||||
if (shadowedFilter != null) {
|
||||
shadowedFilter(listOf(it)).singleOrNull()?.let(processor)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
@@ -395,13 +407,17 @@ abstract class CompletionSession(
|
||||
}
|
||||
|
||||
protected open fun createLookupElementFactory(contextVariablesProvider: ContextVariablesProvider): LookupElementFactory {
|
||||
return LookupElementFactory(basicLookupElementFactory, receiverTypes,
|
||||
callTypeAndReceiver.callType, inDescriptor, contextVariablesProvider)
|
||||
return LookupElementFactory(
|
||||
basicLookupElementFactory, receiverTypes,
|
||||
callTypeAndReceiver.callType, inDescriptor, contextVariablesProvider
|
||||
)
|
||||
}
|
||||
|
||||
protected fun detectReceiverTypes(bindingContext: BindingContext,
|
||||
nameExpression: KtSimpleNameExpression,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection<ReceiverType>? {
|
||||
protected fun detectReceiverTypes(
|
||||
bindingContext: BindingContext,
|
||||
nameExpression: KtSimpleNameExpression,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>
|
||||
): Collection<ReceiverType>? {
|
||||
var receiverTypes = callTypeAndReceiver.receiverTypesWithIndex(
|
||||
bindingContext, nameExpression, moduleDescriptor, resolutionFacade,
|
||||
stableSmartCastsOnly = true, /* we don't include smart cast receiver types for "unstable" receiver value to mark members grayed */
|
||||
|
||||
+40
-30
@@ -46,16 +46,23 @@ import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
|
||||
|
||||
class KDocCompletionContributor : CompletionContributor() {
|
||||
init {
|
||||
extend(CompletionType.BASIC, psiElement().inside(KDocName::class.java),
|
||||
KDocNameCompletionProvider)
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement().inside(KDocName::class.java),
|
||||
KDocNameCompletionProvider
|
||||
)
|
||||
|
||||
extend(CompletionType.BASIC,
|
||||
psiElement().afterLeaf(
|
||||
StandardPatterns.or(psiElement(KDocTokens.LEADING_ASTERISK), psiElement(KDocTokens.START))),
|
||||
KDocTagCompletionProvider)
|
||||
extend(
|
||||
CompletionType.BASIC,
|
||||
psiElement().afterLeaf(
|
||||
StandardPatterns.or(psiElement(KDocTokens.LEADING_ASTERISK), psiElement(KDocTokens.START))
|
||||
),
|
||||
KDocTagCompletionProvider
|
||||
)
|
||||
|
||||
extend(CompletionType.BASIC,
|
||||
psiElement(KDocTokens.TAG_NAME), KDocTagCompletionProvider)
|
||||
extend(
|
||||
CompletionType.BASIC,
|
||||
psiElement(KDocTokens.TAG_NAME), KDocTagCompletionProvider
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +73,9 @@ object KDocNameCompletionProvider : CompletionProvider<CompletionParameters>() {
|
||||
}
|
||||
|
||||
class KDocNameCompletionSession(
|
||||
parameters: CompletionParameters,
|
||||
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
resultSet: CompletionResultSet
|
||||
parameters: CompletionParameters,
|
||||
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
resultSet: CompletionResultSet
|
||||
) : CompletionSession(CompletionSessionConfiguration(parameters), parameters, toFromOriginalFileMapper, resultSet) {
|
||||
|
||||
override val descriptorKindFilter: DescriptorKindFilter? get() = null
|
||||
@@ -81,39 +88,42 @@ class KDocNameCompletionSession(
|
||||
val declarationDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] ?: return
|
||||
if (kdocLink.getTagIfSubject()?.knownTag == KDocKnownTag.PARAM) {
|
||||
addParamCompletions(position, declarationDescriptor)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addLinkCompletions(declarationDescriptor, kdocLink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun addParamCompletions(position: KDocName,
|
||||
declarationDescriptor: DeclarationDescriptor) {
|
||||
private fun addParamCompletions(
|
||||
position: KDocName,
|
||||
declarationDescriptor: DeclarationDescriptor
|
||||
) {
|
||||
val section = position.getContainingSection()
|
||||
val documentedParameters = section.findTagsByName("param").map { it.getSubjectName() }.toSet()
|
||||
getParamDescriptors(declarationDescriptor)
|
||||
.filter { it.name.asString() !in documentedParameters }
|
||||
.forEach {
|
||||
collector.addElement(basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true))
|
||||
}
|
||||
.filter { it.name.asString() !in documentedParameters }
|
||||
.forEach {
|
||||
collector.addElement(basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true))
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectDescriptorsForLinkCompletion(declarationDescriptor: DeclarationDescriptor, kDocLink: KDocLink): Collection<DeclarationDescriptor> {
|
||||
private fun collectDescriptorsForLinkCompletion(
|
||||
declarationDescriptor: DeclarationDescriptor,
|
||||
kDocLink: KDocLink
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val contextScope = getKDocLinkResolutionScope(resolutionFacade, declarationDescriptor)
|
||||
|
||||
val qualifiedLink = kDocLink.getLinkText().split('.').dropLast(1)
|
||||
val nameFilter = descriptorNameFilter.toNameFilter()
|
||||
if (qualifiedLink.isNotEmpty()) {
|
||||
val parentDescriptors = resolveKDocLink(bindingContext, resolutionFacade, declarationDescriptor, kDocLink.getTagIfSubject(), qualifiedLink)
|
||||
return parentDescriptors
|
||||
.flatMap {
|
||||
val scope = getKDocLinkMemberScope(it, contextScope)
|
||||
scope.getContributedDescriptors(nameFilter = nameFilter)
|
||||
}
|
||||
}
|
||||
else {
|
||||
return contextScope.collectDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter, changeNamesForAliased = true)
|
||||
return if (qualifiedLink.isNotEmpty()) {
|
||||
val parentDescriptors =
|
||||
resolveKDocLink(bindingContext, resolutionFacade, declarationDescriptor, kDocLink.getTagIfSubject(), qualifiedLink)
|
||||
parentDescriptors.flatMap {
|
||||
val scope = getKDocLinkMemberScope(it, contextScope)
|
||||
scope.getContributedDescriptors(nameFilter = nameFilter)
|
||||
}
|
||||
} else {
|
||||
contextScope.collectDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter, changeNamesForAliased = true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+132
-111
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.idea.completion.handlers.createKeywordConstructLooku
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -52,46 +51,49 @@ open class KeywordLookupObject
|
||||
|
||||
object KeywordCompletion {
|
||||
private val ALL_KEYWORDS = (KEYWORDS.types + SOFT_KEYWORDS.types)
|
||||
.map { it as KtKeywordToken }
|
||||
.map { it as KtKeywordToken }
|
||||
|
||||
private val KEYWORDS_TO_IGNORE_PREFIX = TokenSet.create(OVERRIDE_KEYWORD /* it's needed to complete overrides that should be work by member name too */)
|
||||
private val KEYWORDS_TO_IGNORE_PREFIX =
|
||||
TokenSet.create(OVERRIDE_KEYWORD /* it's needed to complete overrides that should be work by member name too */)
|
||||
|
||||
private val COMPOUND_KEYWORDS = mapOf<KtKeywordToken, KtKeywordToken>(
|
||||
COMPANION_KEYWORD to OBJECT_KEYWORD,
|
||||
DATA_KEYWORD to CLASS_KEYWORD,
|
||||
ENUM_KEYWORD to CLASS_KEYWORD,
|
||||
ANNOTATION_KEYWORD to CLASS_KEYWORD,
|
||||
SEALED_KEYWORD to CLASS_KEYWORD,
|
||||
LATEINIT_KEYWORD to VAR_KEYWORD,
|
||||
CONST_KEYWORD to VAL_KEYWORD,
|
||||
SUSPEND_KEYWORD to FUN_KEYWORD
|
||||
COMPANION_KEYWORD to OBJECT_KEYWORD,
|
||||
DATA_KEYWORD to CLASS_KEYWORD,
|
||||
ENUM_KEYWORD to CLASS_KEYWORD,
|
||||
ANNOTATION_KEYWORD to CLASS_KEYWORD,
|
||||
SEALED_KEYWORD to CLASS_KEYWORD,
|
||||
LATEINIT_KEYWORD to VAR_KEYWORD,
|
||||
CONST_KEYWORD to VAL_KEYWORD,
|
||||
SUSPEND_KEYWORD to FUN_KEYWORD
|
||||
)
|
||||
|
||||
private val KEYWORD_CONSTRUCTS = mapOf<KtKeywordToken, String>(
|
||||
IF_KEYWORD to "fun foo() { if (caret)",
|
||||
WHILE_KEYWORD to "fun foo() { while(caret)",
|
||||
FOR_KEYWORD to "fun foo() { for(caret)",
|
||||
TRY_KEYWORD to "fun foo() { try {\ncaret\n}",
|
||||
CATCH_KEYWORD to "fun foo() { try {} catch (caret)",
|
||||
FINALLY_KEYWORD to "fun foo() { try {\n}\nfinally{\ncaret\n}",
|
||||
DO_KEYWORD to "fun foo() { do {\ncaret\n}",
|
||||
INIT_KEYWORD to "class C { init {\ncaret\n}",
|
||||
CONSTRUCTOR_KEYWORD to "class C { constructor(caret)"
|
||||
IF_KEYWORD to "fun foo() { if (caret)",
|
||||
WHILE_KEYWORD to "fun foo() { while(caret)",
|
||||
FOR_KEYWORD to "fun foo() { for(caret)",
|
||||
TRY_KEYWORD to "fun foo() { try {\ncaret\n}",
|
||||
CATCH_KEYWORD to "fun foo() { try {} catch (caret)",
|
||||
FINALLY_KEYWORD to "fun foo() { try {\n}\nfinally{\ncaret\n}",
|
||||
DO_KEYWORD to "fun foo() { do {\ncaret\n}",
|
||||
INIT_KEYWORD to "class C { init {\ncaret\n}",
|
||||
CONSTRUCTOR_KEYWORD to "class C { constructor(caret)"
|
||||
)
|
||||
|
||||
private val NO_SPACE_AFTER = listOf(THIS_KEYWORD,
|
||||
SUPER_KEYWORD,
|
||||
NULL_KEYWORD,
|
||||
TRUE_KEYWORD,
|
||||
FALSE_KEYWORD,
|
||||
BREAK_KEYWORD,
|
||||
CONTINUE_KEYWORD,
|
||||
ELSE_KEYWORD,
|
||||
WHEN_KEYWORD,
|
||||
FILE_KEYWORD,
|
||||
DYNAMIC_KEYWORD,
|
||||
GET_KEYWORD,
|
||||
SET_KEYWORD).map { it.value} + "companion object"
|
||||
private val NO_SPACE_AFTER = listOf(
|
||||
THIS_KEYWORD,
|
||||
SUPER_KEYWORD,
|
||||
NULL_KEYWORD,
|
||||
TRUE_KEYWORD,
|
||||
FALSE_KEYWORD,
|
||||
BREAK_KEYWORD,
|
||||
CONTINUE_KEYWORD,
|
||||
ELSE_KEYWORD,
|
||||
WHEN_KEYWORD,
|
||||
FILE_KEYWORD,
|
||||
DYNAMIC_KEYWORD,
|
||||
GET_KEYWORD,
|
||||
SET_KEYWORD
|
||||
).map { it.value } + "companion object"
|
||||
|
||||
fun complete(position: PsiElement, prefix: String, isJvmModule: Boolean, consumer: (LookupElement) -> Unit) {
|
||||
if (!GENERAL_FILTER.isAcceptable(position, position)) return
|
||||
@@ -187,40 +189,40 @@ object KeywordCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
private val GENERAL_FILTER = NotFilter(OrFilter(
|
||||
private val GENERAL_FILTER = NotFilter(
|
||||
OrFilter(
|
||||
CommentFilter(),
|
||||
ParentFilter(ClassFilter(KtLiteralStringTemplateEntry::class.java)),
|
||||
ParentFilter(ClassFilter(KtConstantExpression::class.java)),
|
||||
FileFilter(ClassFilter(KtTypeCodeFragment::class.java)),
|
||||
LeftNeighbour(TextFilter(".")),
|
||||
LeftNeighbour(TextFilter("?."))
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
private class CommentFilter() : ElementFilter {
|
||||
override fun isAcceptable(element : Any?, context : PsiElement?)
|
||||
= (element is PsiElement) && KtPsiUtil.isInComment(element)
|
||||
override fun isAcceptable(element: Any?, context: PsiElement?) = (element is PsiElement) && KtPsiUtil.isInComment(element)
|
||||
|
||||
override fun isClassAcceptable(hintClass: Class<out Any?>)
|
||||
= true
|
||||
override fun isClassAcceptable(hintClass: Class<out Any?>) = true
|
||||
}
|
||||
|
||||
private class ParentFilter(filter : ElementFilter) : PositionElementFilter() {
|
||||
private class ParentFilter(filter: ElementFilter) : PositionElementFilter() {
|
||||
init {
|
||||
setFilter(filter)
|
||||
}
|
||||
|
||||
override fun isAcceptable(element : Any?, context : PsiElement?) : Boolean {
|
||||
override fun isAcceptable(element: Any?, context: PsiElement?): Boolean {
|
||||
val parent = (element as? PsiElement)?.parent
|
||||
return parent != null && (filter?.isAcceptable(parent, context) ?: true)
|
||||
}
|
||||
}
|
||||
|
||||
private class FileFilter(filter : ElementFilter) : PositionElementFilter() {
|
||||
private class FileFilter(filter: ElementFilter) : PositionElementFilter() {
|
||||
init {
|
||||
setFilter(filter)
|
||||
}
|
||||
|
||||
override fun isAcceptable(element : Any?, context : PsiElement?) : Boolean {
|
||||
override fun isAcceptable(element: Any?, context: PsiElement?): Boolean {
|
||||
val file = (element as? PsiElement)?.containingFile
|
||||
return file != null && (filter?.isAcceptable(file, context) ?: true)
|
||||
}
|
||||
@@ -241,20 +243,20 @@ object KeywordCompletion {
|
||||
|
||||
var isAfterTry = false
|
||||
var isAfterCatch = false
|
||||
if (prevLeaf.node.elementType == KtTokens.RBRACE) {
|
||||
val blockParent = (prevLeaf.parent as? KtBlockExpression)?.parent
|
||||
when (blockParent) {
|
||||
if (prevLeaf.node.elementType == RBRACE) {
|
||||
when ((prevLeaf.parent as? KtBlockExpression)?.parent) {
|
||||
is KtTryExpression -> isAfterTry = true
|
||||
is KtCatchClause -> { isAfterTry = true; isAfterCatch = true }
|
||||
is KtCatchClause -> {
|
||||
isAfterTry = true; isAfterCatch = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAfterThen) {
|
||||
if (isAfterTry) {
|
||||
prefixText += "if (a)\n"
|
||||
}
|
||||
else {
|
||||
prefixText += "if (a) {}\n"
|
||||
prefixText += if (isAfterTry) {
|
||||
"if (a)\n"
|
||||
} else {
|
||||
"if (a) {}\n"
|
||||
}
|
||||
}
|
||||
if (isAfterTry) {
|
||||
@@ -266,16 +268,15 @@ object KeywordCompletion {
|
||||
}
|
||||
|
||||
return buildFilterWithContext(prefixText, prevParent, position)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val lastExpression = prevParent
|
||||
.siblings(forward = false, withItself = false)
|
||||
.firstIsInstanceOrNull<KtExpression>()
|
||||
.siblings(forward = false, withItself = false)
|
||||
.firstIsInstanceOrNull<KtExpression>()
|
||||
if (lastExpression != null) {
|
||||
val contextAfterExpression = lastExpression
|
||||
.siblings(forward = true, withItself = false)
|
||||
.takeWhile { it != prevParent }
|
||||
.joinToString { it.text }
|
||||
.siblings(forward = true, withItself = false)
|
||||
.takeWhile { it != prevParent }
|
||||
.joinToString { it.text }
|
||||
return buildFilterWithContext(prefixText + "x" + contextAfterExpression, prevParent, position)
|
||||
}
|
||||
}
|
||||
@@ -296,13 +297,11 @@ object KeywordCompletion {
|
||||
}
|
||||
|
||||
is KtDeclaration -> {
|
||||
val scope = parent.parent
|
||||
when (scope) {
|
||||
when (parent.parent) {
|
||||
is KtClassOrObject -> {
|
||||
return if (parent is KtPrimaryConstructor) {
|
||||
buildFilterWithReducedContext("class X ", parent, position)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buildFilterWithReducedContext("class X { ", parent, position)
|
||||
}
|
||||
}
|
||||
@@ -330,26 +329,34 @@ object KeywordCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildFilterWithContext(prefixText: String,
|
||||
contextElement: PsiElement,
|
||||
position: PsiElement): (KtKeywordToken) -> Boolean {
|
||||
private fun buildFilterWithContext(
|
||||
prefixText: String,
|
||||
contextElement: PsiElement,
|
||||
position: PsiElement
|
||||
): (KtKeywordToken) -> Boolean {
|
||||
val offset = position.getStartOffsetInAncestor(contextElement)
|
||||
val truncatedContext = contextElement.text!!.substring(0, offset)
|
||||
return buildFilterByText(prefixText + truncatedContext, position)
|
||||
}
|
||||
|
||||
private fun buildFilterWithReducedContext(prefixText: String,
|
||||
contextElement: PsiElement?,
|
||||
position: PsiElement): (KtKeywordToken) -> Boolean {
|
||||
private fun buildFilterWithReducedContext(
|
||||
prefixText: String,
|
||||
contextElement: PsiElement?,
|
||||
position: PsiElement
|
||||
): (KtKeywordToken) -> Boolean {
|
||||
val builder = StringBuilder()
|
||||
buildReducedContextBefore(builder, position, contextElement)
|
||||
return buildFilterByText(prefixText + builder.toString(), position)
|
||||
}
|
||||
|
||||
|
||||
private fun buildFilesWithKeywordApplication(keywordTokenType: KtKeywordToken, prefixText: String, psiFactory: KtPsiFactory): Sequence<KtFile> {
|
||||
private fun buildFilesWithKeywordApplication(
|
||||
keywordTokenType: KtKeywordToken,
|
||||
prefixText: String,
|
||||
psiFactory: KtPsiFactory
|
||||
): Sequence<KtFile> {
|
||||
return computeKeywordApplications(prefixText, keywordTokenType)
|
||||
.map { application -> psiFactory.createFile(prefixText + application) }
|
||||
.map { application -> psiFactory.createFile(prefixText + application) }
|
||||
}
|
||||
|
||||
|
||||
@@ -359,7 +366,7 @@ object KeywordCompletion {
|
||||
val elementAt = file.findElementAt(prefixText.length)!!
|
||||
|
||||
val languageVersionSettings = ModuleUtilCore.findModuleForPsiElement(position)?.languageVersionSettings
|
||||
?: LanguageVersionSettingsImpl.DEFAULT
|
||||
?: LanguageVersionSettingsImpl.DEFAULT
|
||||
|
||||
when {
|
||||
!elementAt.node!!.elementType.matchesKeyword(keywordTokenType) -> return false
|
||||
@@ -387,9 +394,29 @@ object KeywordCompletion {
|
||||
|
||||
is KtEnumEntry -> listOf(ENUM_ENTRY)
|
||||
|
||||
is KtClassBody -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, MEMBER_FUNCTION, MEMBER_PROPERTY, FUNCTION, PROPERTY)
|
||||
is KtClassBody -> listOf(
|
||||
CLASS_ONLY,
|
||||
INTERFACE,
|
||||
OBJECT,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION,
|
||||
MEMBER_PROPERTY,
|
||||
FUNCTION,
|
||||
PROPERTY
|
||||
)
|
||||
|
||||
is KtFile -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, FUNCTION, PROPERTY)
|
||||
is KtFile -> listOf(
|
||||
CLASS_ONLY,
|
||||
INTERFACE,
|
||||
OBJECT,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
TOP_LEVEL_FUNCTION,
|
||||
TOP_LEVEL_PROPERTY,
|
||||
FUNCTION,
|
||||
PROPERTY
|
||||
)
|
||||
|
||||
else -> listOf()
|
||||
}
|
||||
@@ -397,22 +424,22 @@ object KeywordCompletion {
|
||||
if (modifierTargets != null && possibleTargets.isNotEmpty() &&
|
||||
modifierTargets.none {
|
||||
isModifierTargetSupportedAtLanguageLevel(keywordTokenType, it, languageVersionSettings)
|
||||
}) return false
|
||||
}
|
||||
) return false
|
||||
|
||||
val ownerDeclaration = container?.getParentOfType<KtDeclaration>(strict = true)
|
||||
val parentTarget = when (ownerDeclaration) {
|
||||
null -> KotlinTarget.FILE
|
||||
val parentTarget = when (val ownerDeclaration = container?.getParentOfType<KtDeclaration>(strict = true)) {
|
||||
null -> FILE
|
||||
|
||||
is KtClass -> {
|
||||
when {
|
||||
ownerDeclaration.isInterface() -> KotlinTarget.INTERFACE
|
||||
ownerDeclaration.isEnum() -> KotlinTarget.ENUM_CLASS
|
||||
ownerDeclaration.isAnnotation() -> KotlinTarget.ANNOTATION_CLASS
|
||||
else -> KotlinTarget.CLASS_ONLY
|
||||
ownerDeclaration.isInterface() -> INTERFACE
|
||||
ownerDeclaration.isEnum() -> ENUM_CLASS
|
||||
ownerDeclaration.isAnnotation() -> ANNOTATION_CLASS
|
||||
else -> CLASS_ONLY
|
||||
}
|
||||
}
|
||||
|
||||
is KtObjectDeclaration -> if (ownerDeclaration.isObjectLiteral()) KotlinTarget.OBJECT_LITERAL else KotlinTarget.OBJECT
|
||||
is KtObjectDeclaration -> if (ownerDeclaration.isObjectLiteral()) OBJECT_LITERAL else OBJECT
|
||||
|
||||
else -> return keywordTokenType != CONST_KEYWORD
|
||||
}
|
||||
@@ -421,8 +448,8 @@ object KeywordCompletion {
|
||||
|
||||
if (keywordTokenType == CONST_KEYWORD) {
|
||||
return when (parentTarget) {
|
||||
KotlinTarget.OBJECT -> true
|
||||
KotlinTarget.FILE -> {
|
||||
OBJECT -> true
|
||||
FILE -> {
|
||||
val prevSiblings = elementAt.parent.siblings(withItself = false, forward = false)
|
||||
val hasLineBreak = prevSiblings
|
||||
.takeWhile { it is PsiWhiteSpace || it.isSemicolon() }
|
||||
@@ -440,25 +467,25 @@ object KeywordCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
return fun (keywordTokenType): Boolean {
|
||||
return fun(keywordTokenType): Boolean {
|
||||
val files = buildFilesWithKeywordApplication(keywordTokenType, prefixText, psiFactory)
|
||||
return files.any { file -> isKeywordCorrectlyApplied(keywordTokenType, file); }
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.isSemicolon() = node.elementType == KtTokens.SEMICOLON
|
||||
private fun PsiElement.isSemicolon() = node.elementType == SEMICOLON
|
||||
|
||||
private fun isErrorElementBefore(token: PsiElement): Boolean {
|
||||
for (leaf in token.prevLeafs) {
|
||||
if (leaf is PsiWhiteSpace || leaf is PsiComment) continue
|
||||
if (leaf.parentsWithSelf.any { it is PsiErrorElement } ) return true
|
||||
if (leaf.parentsWithSelf.any { it is PsiErrorElement }) return true
|
||||
if (leaf.textLength != 0) break
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun IElementType.matchesKeyword(keywordType: KtKeywordToken): Boolean {
|
||||
return when(this) {
|
||||
return when (this) {
|
||||
keywordType -> true
|
||||
NOT_IN -> keywordType == IN_KEYWORD
|
||||
NOT_IS -> keywordType == IS_KEYWORD
|
||||
@@ -468,29 +495,28 @@ object KeywordCompletion {
|
||||
|
||||
private fun isModifierSupportedAtLanguageLevel(keyword: KtKeywordToken, languageVersionSettings: LanguageVersionSettings): Boolean {
|
||||
val feature = when (keyword) {
|
||||
KtTokens.TYPE_ALIAS_KEYWORD -> LanguageFeature.TypeAliases
|
||||
KtTokens.HEADER_KEYWORD, KtTokens.IMPL_KEYWORD -> return false
|
||||
KtTokens.EXPECT_KEYWORD, KtTokens.ACTUAL_KEYWORD -> LanguageFeature.MultiPlatformProjects
|
||||
KtTokens.SUSPEND_KEYWORD -> LanguageFeature.Coroutines
|
||||
TYPE_ALIAS_KEYWORD -> LanguageFeature.TypeAliases
|
||||
HEADER_KEYWORD, IMPL_KEYWORD -> return false
|
||||
EXPECT_KEYWORD, ACTUAL_KEYWORD -> LanguageFeature.MultiPlatformProjects
|
||||
SUSPEND_KEYWORD -> LanguageFeature.Coroutines
|
||||
else -> return true
|
||||
}
|
||||
return languageVersionSettings.supportsFeature(feature)
|
||||
}
|
||||
|
||||
private fun isModifierTargetSupportedAtLanguageLevel(
|
||||
keyword: KtKeywordToken,
|
||||
target: KotlinTarget,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
keyword: KtKeywordToken,
|
||||
target: KotlinTarget,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): Boolean {
|
||||
if (keyword == KtTokens.LATEINIT_KEYWORD) {
|
||||
if (keyword == LATEINIT_KEYWORD) {
|
||||
val feature = when (target) {
|
||||
TOP_LEVEL_PROPERTY -> LanguageFeature.LateinitTopLevelProperties
|
||||
LOCAL_VARIABLE -> LanguageFeature.LateinitLocalVariables
|
||||
else -> return true
|
||||
}
|
||||
return languageVersionSettings.supportsFeature(feature)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -519,8 +545,7 @@ object KeywordCompletion {
|
||||
if (child == prevDeclaration) {
|
||||
builder.appendReducedText(child)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
builder.append(child!!.text)
|
||||
}
|
||||
|
||||
@@ -532,8 +557,7 @@ object KeywordCompletion {
|
||||
var child = element.firstChild
|
||||
if (child == null) {
|
||||
append(element.text!!)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
while (child != null) {
|
||||
when (child) {
|
||||
is KtBlockExpression, is KtClassBody -> append("{}")
|
||||
@@ -550,14 +574,11 @@ object KeywordCompletion {
|
||||
return parent!!.getStartOffsetInAncestor(ancestor) + startOffsetInParent
|
||||
}
|
||||
|
||||
private fun PsiElement.goUpWhileIsLastChild(): Sequence<PsiElement> {
|
||||
return generateSequence(this) {
|
||||
if (it is PsiFile)
|
||||
null
|
||||
else if (it != it.parent.lastChild)
|
||||
null
|
||||
else
|
||||
it.parent
|
||||
private fun PsiElement.goUpWhileIsLastChild(): Sequence<PsiElement> = generateSequence(this) {
|
||||
when {
|
||||
it is PsiFile -> null
|
||||
it != it.parent.lastChild -> null
|
||||
else -> it.parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -115,11 +115,13 @@ class OverridesCompletion(
|
||||
val override = KtTokens.OVERRIDE_KEYWORD.value
|
||||
|
||||
tailrec fun calcStartOffset(startOffset: Int, diff: Int = 0): Int {
|
||||
if (context.document.text[startOffset - 1].isWhitespace()) {
|
||||
return calcStartOffset(startOffset - 1, diff + 1)
|
||||
} else if (context.document.text.substring(startOffset - override.length, startOffset) == override) {
|
||||
return startOffset - override.length
|
||||
} else return diff + startOffset
|
||||
return when {
|
||||
context.document.text[startOffset - 1].isWhitespace() -> calcStartOffset(startOffset - 1, diff + 1)
|
||||
context.document.text.substring(startOffset - override.length, startOffset) == override -> {
|
||||
startOffset - override.length
|
||||
}
|
||||
else -> diff + startOffset
|
||||
}
|
||||
}
|
||||
|
||||
val startOffset = calcStartOffset(context.startOffset)
|
||||
|
||||
+4
-6
@@ -22,12 +22,10 @@ abstract class AbstractKeywordCompletionTest : KotlinFixtureCompletionBaseTestCa
|
||||
return items.filter { it.`object` is KeywordLookupObject }.toTypedArray()
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): KotlinLightProjectDescriptor {
|
||||
when {
|
||||
"LangLevel10" in fileName() -> return KotlinProjectDescriptorWithFacet.KOTLIN_10
|
||||
"LangLevel11" in fileName() -> return KotlinProjectDescriptorWithFacet.KOTLIN_11
|
||||
else -> return KotlinProjectDescriptorWithFacet.KOTLIN_STABLE_WITH_MULTIPLATFORM
|
||||
}
|
||||
override fun getProjectDescriptor(): KotlinLightProjectDescriptor = when {
|
||||
"LangLevel10" in fileName() -> KotlinProjectDescriptorWithFacet.KOTLIN_10
|
||||
"LangLevel11" in fileName() -> KotlinProjectDescriptorWithFacet.KOTLIN_11
|
||||
else -> KotlinProjectDescriptorWithFacet.KOTLIN_STABLE_WITH_MULTIPLATFORM
|
||||
}
|
||||
|
||||
override fun defaultInvocationCount() = 1
|
||||
|
||||
Reference in New Issue
Block a user