diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt index 3abd9ad648a..ca40ae721b6 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt @@ -28,6 +28,7 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.colors.CodeInsightColors import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.progress.ProcessCanceledException +import com.intellij.openapi.util.Key import com.intellij.openapi.util.TextRange import com.intellij.psi.MultiRangeReference import com.intellij.psi.PsiElement @@ -44,10 +45,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult import org.jetbrains.kotlin.idea.quickfix.QuickFixes import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.util.ProjectRootsUtil -import org.jetbrains.kotlin.psi.KtCodeFragment -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.KtReferenceExpression +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.utils.singletonOrEmptyList @@ -81,6 +79,12 @@ open class KotlinPsiChecker : Annotator, HighlightRangeExtension { fun annotateElement(element: PsiElement, holder: AnnotationHolder, diagnostics: Diagnostics) { val diagnosticsForElement = diagnostics.forElement(element) + + if (element is KtNameReferenceExpression) { + val unresolved = diagnostics.any { it.factory == Errors.UNRESOLVED_REFERENCE } + element.putUserData(UNRESOLVED_KEY, if (unresolved) Unit else null) + } + if (diagnosticsForElement.isEmpty()) return if (ProjectRootsUtil.isInProjectSource(element) || element.containingFile is KtCodeFragment) { @@ -98,6 +102,10 @@ open class KotlinPsiChecker : Annotator, HighlightRangeExtension { fun createQuickFixes(diagnostic: Diagnostic): Collection = createQuickFixes(diagnostic.singletonOrEmptyList())[diagnostic] + + private val UNRESOLVED_KEY = Key("KotlinPsiChecker.UNRESOLVED_KEY") + + fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index b2499fb0ee9..3bf9c3140f5 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -46,16 +46,18 @@ import org.jetbrains.kotlin.name.Name 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.scopes.DescriptorKindExclude import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.util.supertypesWithAny +import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.util.* class BasicCompletionSession( configuration: CompletionSessionConfiguration, parameters: CompletionParameters, - toFromOriginalFileMapper: ToFromOriginalFileMapper, + private val toFromOriginalFileMapper: ToFromOriginalFileMapper, resultSet: CompletionResultSet ) : CompletionSession(configuration, parameters, resultSet) { @@ -88,14 +90,9 @@ class BasicCompletionSession( private fun detectCompletionKind(): CompletionKind { if (nameExpression == null) { return when { - (position.parent as? KtParameter)?.nameIdentifier == position -> - PARAMETER_NAME + (position.parent as? KtNamedDeclaration)?.nameIdentifier == position -> DECLARATION_NAME - (position.parent as? KtClassOrObject)?.nameIdentifier == position && position.parent.parent is KtFile -> - TOP_LEVEL_CLASS_NAME - - else -> - KEYWORDS_ONLY + else -> KEYWORDS_ONLY } } @@ -158,6 +155,20 @@ class BasicCompletionSession( } override fun doComplete() { + val declaration = isStartOfExtensionReceiverFor() + if (declaration != null) { + completeDeclarationNameFromUnresolved(declaration) + + // 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 -> prefixMatcher.prefix.let { it.isEmpty() || it[0].isLowerCase() /* function name usually starts with lower case letter */ } + else -> true + } + if (suppressOtherCompletion) return + } + } + fun completeWithSmartCompletion(lookupElementFactory: LookupElementFactory) { if (smartCompletion != null) { val (additionalItems, @Suppress("UNUSED_VARIABLE") inheritanceSearcher) = smartCompletion.additionalItems(lookupElementFactory) @@ -276,6 +287,19 @@ class BasicCompletionSession( } } } + + private fun isStartOfExtensionReceiverFor(): KtCallableDeclaration? { + val userType = nameExpression!!.parent as? KtUserType ?: return null + if (userType.qualifier != null) return null + val typeRef = userType.parent as? KtTypeReference ?: return null + if (userType != typeRef.typeElement) return null + val parent = typeRef.parent + return when (parent) { + is KtNamedFunction -> parent.check { typeRef == it.receiverTypeReference } + is KtProperty -> parent.check { typeRef == it.receiverTypeReference } + else -> null + } + } } private val KEYWORDS_ONLY = object : CompletionKind { @@ -414,45 +438,42 @@ class BasicCompletionSession( } } - private val PARAMETER_NAME = object : CompletionKind { + private val DECLARATION_NAME = object : CompletionKind { override val descriptorKindFilter: DescriptorKindFilter? get() = null override fun doComplete() { + val declaration = declaration() + if (declaration is KtParameter && !shouldCompleteParameterNameAndType()) return // do not complete also keywords and from unresolved references in such case + + collector.addLookupElementPostProcessor { lookupElement -> + lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit) + lookupElement + } + KEYWORDS_ONLY.doComplete() - if (shouldCompleteParameterNameAndType()) { - val parameterNameAndTypeCompletion = ParameterNameAndTypeCompletion(collector, basicLookupElementFactory, prefixMatcher, resolutionFacade) + completeDeclarationNameFromUnresolved(declaration) - // if we are typing parameter name, restart completion each time we type an upper case letter because new suggestions will appear (previous words can be used as user prefix) - val prefixPattern = StandardPatterns.string().with(object : PatternCondition("Prefix ends with uppercase letter") { - override fun accepts(prefix: String, context: ProcessingContext?) = prefix.isNotEmpty() && prefix.last().isUpperCase() - }) - collector.restartCompletionOnPrefixChange(prefixPattern) + when (declaration) { + is KtParameter -> + completeParameterNameAndType() - collector.addLookupElementPostProcessor { lookupElement -> - lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit) - lookupElement.putUserData(KotlinCompletionCharFilter.HIDE_LOOKUP_ON_COLON, Unit) - lookupElement + is KtClassOrObject -> { + if (declaration.isTopLevel()) { + completeTopLevelClassName() + } } - - parameterNameAndTypeCompletion.addFromParametersInFile(position, resolutionFacade, isVisibleFilterCheckAlways) - flushToResultSet() - - parameterNameAndTypeCompletion.addFromImportedClasses(position, bindingContext, isVisibleFilterCheckAlways) - flushToResultSet() - - parameterNameAndTypeCompletion.addFromAllClasses(parameters, indicesHelper(false)) } } override fun shouldDisableAutoPopup(): Boolean { - if (!shouldCompleteParameterNameAndType() || TemplateManager.getInstance(project).getActiveTemplate(parameters.editor) != null) { - return true - } + if (TemplateManager.getInstance(project).getActiveTemplate(parameters.editor) != null) return true - if (LookupCancelWatcher.getInstance(project).wasAutoPopupRecentlyCancelled(parameters.editor, position.startOffset)) { - return true + if (declaration() is KtParameter) { + if (LookupCancelWatcher.getInstance(project).wasAutoPopupRecentlyCancelled(parameters.editor, position.startOffset)) { + return true + } } return false @@ -465,8 +486,41 @@ class BasicCompletionSession( return sorter } + private fun completeParameterNameAndType() { + val parameterNameAndTypeCompletion = ParameterNameAndTypeCompletion(collector, basicLookupElementFactory, prefixMatcher, resolutionFacade) + + // if we are typing parameter name, restart completion each time we type an upper case letter because new suggestions will appear (previous words can be used as user prefix) + val prefixPattern = StandardPatterns.string().with(object : PatternCondition("Prefix ends with uppercase letter") { + override fun accepts(prefix: String, context: ProcessingContext?) = prefix.isNotEmpty() && prefix.last().isUpperCase() + }) + collector.restartCompletionOnPrefixChange(prefixPattern) + + collector.addLookupElementPostProcessor { lookupElement -> + lookupElement.putUserData(KotlinCompletionCharFilter.HIDE_LOOKUP_ON_COLON, Unit) + lookupElement + } + + parameterNameAndTypeCompletion.addFromParametersInFile(position, resolutionFacade, isVisibleFilterCheckAlways) + flushToResultSet() + + parameterNameAndTypeCompletion.addFromImportedClasses(position, bindingContext, isVisibleFilterCheckAlways) + flushToResultSet() + + parameterNameAndTypeCompletion.addFromAllClasses(parameters, indicesHelper(false)) + } + + private fun completeTopLevelClassName() { + val name = parameters.originalFile.virtualFile.nameWithoutExtension + if (!(Name.isValidIdentifier(name) && Name.identifier(name).render() == name && name[0].isUpperCase())) return + if ((parameters.originalFile as KtFile).declarations.any { it is KtClassOrObject && it.name == name }) return + + collector.addElement(LookupElementBuilder.create(name)) + } + + private fun declaration() = position.parent as KtNamedDeclaration + private fun shouldCompleteParameterNameAndType(): Boolean { - val parameter = position.getNonStrictParentOfType()!! + val parameter = declaration() as? KtParameter ?: return false val list = parameter.parent as? KtParameterList ?: return false val owner = list.parent return when (owner) { @@ -478,21 +532,6 @@ class BasicCompletionSession( } } - private val TOP_LEVEL_CLASS_NAME = object : CompletionKind { - override val descriptorKindFilter: DescriptorKindFilter? - get() = null - - override fun doComplete() { - val name = parameters.originalFile.virtualFile.nameWithoutExtension - if (!(Name.isValidIdentifier(name) && Name.identifier(name).render() == name && name[0].isUpperCase())) return - if ((parameters.originalFile as KtFile).declarations.any { it is KtClassOrObject && it.name == name }) return - - val lookupElement = LookupElementBuilder.create(name) - lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit) - collector.addElement(lookupElement) - } - } - private val SUPER_QUALIFIER = object : CompletionKind { override val descriptorKindFilter: DescriptorKindFilter? get() = DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS @@ -513,4 +552,35 @@ class BasicCompletionSession( .forEach { collector.addElement(it) } } } + + private fun completeDeclarationNameFromUnresolved(declaration: KtNamedDeclaration) { + val referenceScope = referenceScope(declaration) ?: return + val originalScope = toFromOriginalFileMapper.toOriginalFile(referenceScope) ?: return + val afterOffset = if (referenceScope is KtBlockExpression) parameters.offset else null + val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] + FromUnresolvedNamesCompletion(collector, prefixMatcher).addNameSuggestions(originalScope, afterOffset, descriptor) + } + + private fun referenceScope(declaration: KtNamedDeclaration): KtElement? { + val parent = declaration.parent + when (parent) { + is KtParameterList -> return parent.parent as KtElement + + is KtClassBody -> { + val classOrObject = parent.parent as KtClassOrObject + if (classOrObject is KtObjectDeclaration && classOrObject.isCompanion()) { + return classOrObject.containingClassOrObject + } + else { + return classOrObject + } + } + + is KtFile -> return parent + + is KtBlockExpression -> return parent + + else -> return null + } + } } \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index 3589524ec8c..2df5a474a6e 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -64,6 +64,7 @@ tailrec fun LookupElement.getUserDataDeep(key: Key): T? { enum class ItemPriority { SUPER_METHOD_WITH_ARGUMENTS, + FROM_UNRESOLVED_NAME_SUGGESTION, DEFAULT, IMPLEMENT, OVERRIDE, diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt new file mode 100644 index 00000000000..46ad0bbf533 --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.idea.completion + +import com.intellij.codeInsight.completion.PrefixMatcher +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.progress.ProgressManager +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtNameReferenceExpression +import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType +import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import java.util.* + +class FromUnresolvedNamesCompletion( + private val collector: LookupElementsCollector, + private val prefixMatcher: PrefixMatcher +) { + fun addNameSuggestions(scope: KtElement, afterOffset: Int?, sampleDescriptor: DeclarationDescriptor?) { + val names = HashSet() + scope.forEachDescendantOfType { refExpr -> + ProgressManager.checkCanceled() + + if (KotlinPsiChecker.wasUnresolved(refExpr)) { + val callTypeAndReceiver = CallTypeAndReceiver.detect(refExpr) + if (callTypeAndReceiver.receiver != null) return@forEachDescendantOfType + if (sampleDescriptor != null) { + if (!callTypeAndReceiver.callType.descriptorKindFilter.accepts(sampleDescriptor)) return@forEachDescendantOfType + + if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { + val isCall = refExpr.parent is KtCallExpression + 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 + else -> false // what else it can be? + } + if (!canBeUsage) return@forEachDescendantOfType + } + } + + val name = refExpr.getReferencedName() + if (!prefixMatcher.prefixMatches(name)) return@forEachDescendantOfType + + if (afterOffset != null && refExpr.startOffset < afterOffset) return@forEachDescendantOfType + + if (refExpr.mainReference.resolveToDescriptors(refExpr.analyze(BodyResolveMode.PARTIAL)).isEmpty()) { + names.add(name) + } + } + } + + for (name in names.sorted()) { + 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) + } + } +} \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt index 87fb50df290..0ed45d99128 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt @@ -42,7 +42,6 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull var KtFile.doNotComplete: Boolean? by UserDataProperty(Key.create("DO_NOT_COMPLETE")) @@ -365,33 +364,9 @@ class KotlinCompletionContributor : CompletionContributor() { // no completion auto-popup after integer and dot if (invocationCount == 0 && prefixMatcher.prefix.isEmpty() && AFTER_INTEGER_LITERAL_AND_DOT.accepts(position)) return true - // 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 (invocationCount == 0) { - val callable = isInExtensionReceiverOf(position) - if (callable != null) { - return when (callable) { - is KtNamedFunction -> prefixMatcher.prefix.let { it.isEmpty() || it[0].isLowerCase() /* function name usually starts with lower case letter */ } - else -> true - } - } - } - return false } - private fun isInExtensionReceiverOf(position: PsiElement): KtCallableDeclaration? { - val nameRef = position.parent as? KtNameReferenceExpression ?: return null - val userType = nameRef.parent as? KtUserType ?: return null - val typeRef = userType.parent as? KtTypeReference ?: return null - if (userType != typeRef.typeElement) return null - val parent = typeRef.parent - return when (parent) { - is KtNamedFunction -> parent.check { typeRef == it.receiverTypeReference } - is KtProperty -> parent.check { typeRef == it.receiverTypeReference } - else -> null - } - } - private fun isAtEndOfLine(offset: Int, document: Document): Boolean { var i = offset val chars = document.charsSequence diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ToFromOriginalFileMapper.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ToFromOriginalFileMapper.kt index 7af9a8ffc69..d18eedea167 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ToFromOriginalFileMapper.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ToFromOriginalFileMapper.kt @@ -16,9 +16,9 @@ package org.jetbrains.kotlin.idea.completion -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtDeclaration +import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.startOffset class ToFromOriginalFileMapper( @@ -63,15 +63,15 @@ class ToFromOriginalFileMapper( } } - fun toOriginalFile(declaration: KtDeclaration): KtDeclaration? { - if (declaration.containingFile != syntheticFile) return declaration - val offset = toOriginalFile(declaration.startOffset) ?: return null - return PsiTreeUtil.findElementOfClassAtOffset(originalFile, offset, KtDeclaration::class.java, true) + fun toOriginalFile(element: TElement): TElement? { + if (element.containingFile != syntheticFile) return element + val offset = toOriginalFile(element.startOffset) ?: return null + return PsiTreeUtil.findElementOfClassAtOffset(originalFile, offset, element.javaClass, true) } - fun toSyntheticFile(declaration: KtDeclaration): KtDeclaration? { - if (declaration.containingFile != originalFile) return declaration - val offset = toSyntheticFile(declaration.startOffset) ?: return null - return PsiTreeUtil.findElementOfClassAtOffset(syntheticFile, offset, KtDeclaration::class.java, true) + fun toSyntheticFile(element: TElement): TElement? { + if (element.containingFile != originalFile) return element + val offset = toSyntheticFile(element.startOffset) ?: return null + return PsiTreeUtil.findElementOfClassAtOffset(syntheticFile, offset, element.javaClass, true) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt index c215eee4638..d062f079d78 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt @@ -264,6 +264,8 @@ class TypeInstantiationItems( other.renderElement(presentation2) return presentation1.itemText == presentation2.itemText && presentation1.tailText == presentation2.tailText } + + override fun hashCode() = lookupString.hashCode() } return InstantiationLookupElement(lookupElement).addTail(tail) @@ -307,7 +309,7 @@ class TypeInstantiationItems( for (inheritor in ClassInheritorsSearch.search(parameters)) { val descriptor = inheritor.resolveToDescriptor( resolutionFacade, - { toFromOriginalFileMapper.toSyntheticFile(it) as KtClassOrObject? } + { toFromOriginalFileMapper.toSyntheticFile(it) } ) ?: continue if (!visibilityFilter(descriptor)) continue diff --git a/idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInExtFunName.kt b/idea/idea-completion/testData/basic/common/autoPopup/InExtFunName.kt similarity index 70% rename from idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInExtFunName.kt rename to idea/idea-completion/testData/basic/common/autoPopup/InExtFunName.kt index f399f725fc6..a197de47724 100644 --- a/idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInExtFunName.kt +++ b/idea/idea-completion/testData/basic/common/autoPopup/InExtFunName.kt @@ -5,4 +5,5 @@ class Outer { fun Outer. // INVOCATION_COUNT: 0 -// NUMBER: 0 +// EXIST: Nested +// NOTHING_ELSE \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInGenericExtFunName.kt b/idea/idea-completion/testData/basic/common/autoPopup/InGenericExtFunName.kt similarity index 71% rename from idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInGenericExtFunName.kt rename to idea/idea-completion/testData/basic/common/autoPopup/InGenericExtFunName.kt index 802c9018722..3fd4c934e8a 100644 --- a/idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInGenericExtFunName.kt +++ b/idea/idea-completion/testData/basic/common/autoPopup/InGenericExtFunName.kt @@ -5,4 +5,5 @@ class Outer { fun Outer. // INVOCATION_COUNT: 0 -// NUMBER: 0 +// EXIST: Nested +// NOTHING_ELSE \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/FunctionInCompanionObject.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/FunctionInCompanionObject.kt new file mode 100644 index 00000000000..f39f84adabe --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/FunctionInCompanionObject.kt @@ -0,0 +1,32 @@ +// RUN_HIGHLIGHTING_BEFORE + +class C { + fun foo(p: Int) { + unresolvedInFoo1() + if (p > 0) { + unresolvedInFoo2() + } + } + + companion object { + fun + + fun bar() { + unresolvedInBar() + } + } + + fun zoo() { + unresolvedInZoo() + } +} + +fun f() { + unresolvedOutside() +} + +// EXIST: unresolvedInFoo1 +// EXIST: unresolvedInFoo2 +// EXIST: unresolvedInBar +// EXIST: unresolvedInZoo +// ABSENT: unresolvedOutside diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/LocalVal.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/LocalVal.kt new file mode 100644 index 00000000000..7533f886f5f --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/LocalVal.kt @@ -0,0 +1,32 @@ +// RUN_HIGHLIGHTING_BEFORE + +fun foo(p: Int) { + print(unresolved0) + + if (p > 0) { + print(unresolved1) + + val u + + print(unresolved2) + if (p > 0) { + print(unresolved3) + } + + unresolvedCall() + } + + print(unresolved4) +} + +fun bar() { + print(unresolvedInBar) +} + +// ABSENT: unresolved0 +// ABSENT: unresolved1 +// EXIST: unresolved2 +// EXIST: unresolved3 +// ABSENT: unresolved4 +// ABSENT: unresolvedInBar +// EXIST: unresolvedCall diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberFunction.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberFunction.kt new file mode 100644 index 00000000000..8ecabd2e89d --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberFunction.kt @@ -0,0 +1,27 @@ +// RUN_HIGHLIGHTING_BEFORE + +class C { + fun foo(p: Int) { + unresolvedInFoo1() + if (p > 0) { + unresolvedInFoo2() + } + } + + fun + + fun bar(s: String) { + unresolvedInBar() + s.unresolvedWithReceiver() + } +} + +fun f() { + unresolvedOutside() +} + +// EXIST: unresolvedInFoo1 +// EXIST: unresolvedInFoo2 +// EXIST: unresolvedInBar +// ABSENT: unresolvedWithReceiver +// ABSENT: unresolvedOutside diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberProperty.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberProperty.kt new file mode 100644 index 00000000000..a463a22c0a5 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberProperty.kt @@ -0,0 +1,24 @@ +// RUN_HIGHLIGHTING_BEFORE + +class C { + fun foo(p: Int) { + print(unresolvedInFoo) + } + + val + + fun bar(s: String, x: UnresolvedType) { + print(unresolvedInBar) + print(s.unresolvedWithReceiver) + } +} + +fun f() { + print(unresolvedOutside) +} + +// EXIST: unresolvedInFoo +// EXIST: unresolvedInBar +// ABSENT: unresolvedWithReceiver +// ABSENT: unresolvedOutside +// ABSENT: UnresolvedType diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/NotForExtensionFunction.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/NotForExtensionFunction.kt new file mode 100644 index 00000000000..7d3c60b4a20 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/NotForExtensionFunction.kt @@ -0,0 +1,9 @@ +// RUN_HIGHLIGHTING_BEFORE + +fun foo() { + unresolvedInFoo() +} + +fun String. + +// ABSENT: unresolvedInFoo diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/Parameter.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/Parameter.kt new file mode 100644 index 00000000000..7edd1659f69 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/Parameter.kt @@ -0,0 +1,16 @@ +// RUN_HIGHLIGHTING_BEFORE + +fun foo(p: Int, ) { + print(unresolvedInFoo1) + if (p > 0) { + print(unresolvedInFoo2) + } +} + +fun bar() { + print(unresolvedInBar) +} + +// EXIST: { lookupString: "unresolvedInFoo1", itemText: "unresolvedInFoo1" } +// EXIST: { lookupString: "unresolvedInFoo2", itemText: "unresolvedInFoo2" } +// ABSENT: unresolvedInBar diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelClass.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelClass.kt new file mode 100644 index 00000000000..ddba2d80484 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelClass.kt @@ -0,0 +1,13 @@ +// RUN_HIGHLIGHTING_BEFORE + +fun foo(p: UnresolvedClass1) { + val foo = UnresolvedClass2() + val bar = unresolvedValue +} + +class + +// EXIST: TopLevelClass +// EXIST: UnresolvedClass1 +// EXIST: UnresolvedClass2 +// ABSENT: unresolvedValue diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelFunction.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelFunction.kt new file mode 100644 index 00000000000..338e4aa5099 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelFunction.kt @@ -0,0 +1,31 @@ +// RUN_HIGHLIGHTING_BEFORE + +fun foo(p: Int, x: UnresolvedClassName) { + unresolvedInFoo1() + if (p > 0) { + unresolvedInFoo2() + } +} + +fun + +fun bar() { + unresolvedInBar() + val v = unresolvedValue + listOf(1).filter(::unresolvedFunctionRef) +} + +class C { + fun f() { + unresolvedInClass() + } +} + + +// EXIST: unresolvedInFoo1 +// EXIST: unresolvedInFoo2 +// EXIST: unresolvedInBar +// EXIST: unresolvedInClass +// ABSENT: UnresolvedClassName +// ABSENT: unresolvedValue +// EXIST: unresolvedFunctionRef diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelInterface.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelInterface.kt new file mode 100644 index 00000000000..1fea4f41aba --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelInterface.kt @@ -0,0 +1,13 @@ +// RUN_HIGHLIGHTING_BEFORE + +fun foo(p: UnresolvedClass1) { + val foo = UnresolvedClass2() + val bar = unresolvedValue +} + +interface + +// EXIST: TopLevelInterface +// EXIST: UnresolvedClass1 +// ABSENT: UnresolvedClass2 +// ABSENT: unresolvedValue diff --git a/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelObject.kt b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelObject.kt new file mode 100644 index 00000000000..80d2683d6c3 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelObject.kt @@ -0,0 +1,13 @@ +// RUN_HIGHLIGHTING_BEFORE + +fun foo(p: UnresolvedClass1) { + val foo = UnresolvedClass2() + val bar = unresolvedValue +} + +object + +// EXIST: TopLevelObject +// EXIST: UnresolvedClass1 +// ABSENT: UnresolvedClass2 +// EXIST: unresolvedValue diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/ExpectedCompletionUtils.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/ExpectedCompletionUtils.kt index fefc0d3a3b1..7e5f72c024f 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/ExpectedCompletionUtils.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/ExpectedCompletionUtils.kt @@ -108,6 +108,7 @@ object ExpectedCompletionUtils { private val NUMBER_JAVA_LINE_PREFIX = "NUMBER_JAVA:" private val NOTHING_ELSE_PREFIX = "NOTHING_ELSE" + private val RUN_HIGHLIGHTING_BEFORE_PREFIX = "RUN_HIGHLIGHTING_BEFORE" private val INVOCATION_COUNT_PREFIX = "INVOCATION_COUNT:" private val WITH_ORDER_PREFIX = "WITH_ORDER" @@ -131,6 +132,7 @@ object ExpectedCompletionUtils { WITH_ORDER_PREFIX, AUTOCOMPLETE_SETTING_PREFIX, NOTHING_ELSE_PREFIX, + RUN_HIGHLIGHTING_BEFORE_PREFIX, RUNTIME_TYPE, COMPLETION_TYPE_PREFIX, LightClassComputationControl.LIGHT_CLASS_DIRECTIVE, @@ -190,7 +192,11 @@ object ExpectedCompletionUtils { } fun isNothingElseExpected(fileText: String): Boolean { - return !InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, NOTHING_ELSE_PREFIX).isEmpty() + return InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, NOTHING_ELSE_PREFIX).isNotEmpty() + } + + fun shouldRunHighlightingBeforeCompletion(fileText: String): Boolean { + return InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, RUN_HIGHLIGHTING_BEFORE_PREFIX).isNotEmpty() } fun getInvocationCount(fileText: String): Int? { diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index f64c12ad222..474268df173 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -990,6 +990,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } + @TestMetadata("InExtFunName.kt") + public void testInExtFunName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/InExtFunName.kt"); + doTest(fileName); + } + + @TestMetadata("InGenericExtFunName.kt") + public void testInGenericExtFunName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/InGenericExtFunName.kt"); + doTest(fileName); + } + @TestMetadata("NoAutoPopupAfterNumberLiteral.kt") public void testNoAutoPopupAfterNumberLiteral() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutoPopupAfterNumberLiteral.kt"); @@ -1002,24 +1014,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } - @TestMetadata("NoAutopopupInExtFunName.kt") - public void testNoAutopopupInExtFunName() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInExtFunName.kt"); - doTest(fileName); - } - @TestMetadata("NoAutopopupInFunName.kt") public void testNoAutopopupInFunName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInFunName.kt"); doTest(fileName); } - @TestMetadata("NoAutopopupInGenericExtFunName.kt") - public void testNoAutopopupInGenericExtFunName() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInGenericExtFunName.kt"); - doTest(fileName); - } - @TestMetadata("NoAutopopupInGenericFunName.kt") public void testNoAutopopupInGenericFunName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInGenericFunName.kt"); @@ -1438,6 +1438,75 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes } } + @TestMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class FromUnresolvedNames extends AbstractJSBasicCompletionTest { + public void testAllFilesPresentInFromUnresolvedNames() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/fromUnresolvedNames"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("FunctionInCompanionObject.kt") + public void testFunctionInCompanionObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/FunctionInCompanionObject.kt"); + doTest(fileName); + } + + @TestMetadata("LocalVal.kt") + public void testLocalVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/LocalVal.kt"); + doTest(fileName); + } + + @TestMetadata("MemberFunction.kt") + public void testMemberFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberFunction.kt"); + doTest(fileName); + } + + @TestMetadata("MemberProperty.kt") + public void testMemberProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberProperty.kt"); + doTest(fileName); + } + + @TestMetadata("NotForExtensionFunction.kt") + public void testNotForExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/NotForExtensionFunction.kt"); + doTest(fileName); + } + + @TestMetadata("Parameter.kt") + public void testParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/Parameter.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelClass.kt") + public void testTopLevelClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelClass.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelFunction.kt") + public void testTopLevelFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelFunction.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelInterface.kt") + public void testTopLevelInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelInterface.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelObject.kt") + public void testTopLevelObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelObject.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index ccf4f62f667..5a1746844b2 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -990,6 +990,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } + @TestMetadata("InExtFunName.kt") + public void testInExtFunName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/InExtFunName.kt"); + doTest(fileName); + } + + @TestMetadata("InGenericExtFunName.kt") + public void testInGenericExtFunName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/InGenericExtFunName.kt"); + doTest(fileName); + } + @TestMetadata("NoAutoPopupAfterNumberLiteral.kt") public void testNoAutoPopupAfterNumberLiteral() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutoPopupAfterNumberLiteral.kt"); @@ -1002,24 +1014,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } - @TestMetadata("NoAutopopupInExtFunName.kt") - public void testNoAutopopupInExtFunName() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInExtFunName.kt"); - doTest(fileName); - } - @TestMetadata("NoAutopopupInFunName.kt") public void testNoAutopopupInFunName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInFunName.kt"); doTest(fileName); } - @TestMetadata("NoAutopopupInGenericExtFunName.kt") - public void testNoAutopopupInGenericExtFunName() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInGenericExtFunName.kt"); - doTest(fileName); - } - @TestMetadata("NoAutopopupInGenericFunName.kt") public void testNoAutopopupInGenericFunName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/autoPopup/NoAutopopupInGenericFunName.kt"); @@ -1438,6 +1438,75 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT } } + @TestMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class FromUnresolvedNames extends AbstractJvmBasicCompletionTest { + public void testAllFilesPresentInFromUnresolvedNames() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/fromUnresolvedNames"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("FunctionInCompanionObject.kt") + public void testFunctionInCompanionObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/FunctionInCompanionObject.kt"); + doTest(fileName); + } + + @TestMetadata("LocalVal.kt") + public void testLocalVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/LocalVal.kt"); + doTest(fileName); + } + + @TestMetadata("MemberFunction.kt") + public void testMemberFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberFunction.kt"); + doTest(fileName); + } + + @TestMetadata("MemberProperty.kt") + public void testMemberProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/MemberProperty.kt"); + doTest(fileName); + } + + @TestMetadata("NotForExtensionFunction.kt") + public void testNotForExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/NotForExtensionFunction.kt"); + doTest(fileName); + } + + @TestMetadata("Parameter.kt") + public void testParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/Parameter.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelClass.kt") + public void testTopLevelClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelClass.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelFunction.kt") + public void testTopLevelFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelFunction.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelInterface.kt") + public void testTopLevelInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelInterface.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelObject.kt") + public void testTopLevelObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromUnresolvedNames/TopLevelObject.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinFixtureCompletionBaseTestCase.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinFixtureCompletionBaseTestCase.kt index 4274335af09..3f6f8beae17 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinFixtureCompletionBaseTestCase.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinFixtureCompletionBaseTestCase.kt @@ -37,6 +37,11 @@ abstract class KotlinFixtureCompletionBaseTestCase : KotlinLightCodeInsightFixtu setUpFixture(testPath) val fileText = FileUtil.loadFile(File(testPath), true) + + if (ExpectedCompletionUtils.shouldRunHighlightingBeforeCompletion(fileText)) { + myFixture.doHighlighting() + } + testCompletion(fileText, getPlatform(), { completionType, count -> complete(completionType, count) }, defaultCompletionType(), defaultInvocationCount()) }