diff --git a/.idea/runConfigurations/Smart_Completion_Tests.xml b/.idea/runConfigurations/Smart_Completion_Tests.xml
index 54c15f73475..421247549ac 100644
--- a/.idea/runConfigurations/Smart_Completion_Tests.xml
+++ b/.idea/runConfigurations/Smart_Completion_Tests.xml
@@ -27,6 +27,7 @@
+
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt
index 634594c16e5..1de9a220095 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt
@@ -31,7 +31,9 @@ import org.jetbrains.jet.plugin.completion.smart.SmartCompletion
import org.jetbrains.jet.plugin.references.JetSimpleNameReference
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import org.jetbrains.jet.plugin.caches.KotlinIndicesHelper
-import org.jetbrains.jet.plugin.search.searchScopeForSourceElementDependencies
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.module.ModuleUtilCore
+import com.intellij.openapi.module.Module
class CompletionSessionConfiguration(
val completeNonImportedDeclarations: Boolean,
@@ -44,7 +46,6 @@ fun CompletionSessionConfiguration(parameters: CompletionParameters) = Completio
abstract class CompletionSessionBase(protected val configuration: CompletionSessionConfiguration,
protected val parameters: CompletionParameters,
resultSet: CompletionResultSet) {
-
protected val position: PsiElement = parameters.getPosition()
protected val jetReference: JetSimpleNameReference? = position.getParent()?.getReferences()?.filterIsInstance(javaClass())?.firstOrNull()
protected val resolveSession: ResolveSessionForBodies = (position.getContainingFile() as JetFile).getLazyResolveSession()
@@ -59,6 +60,14 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
protected val prefixMatcher: PrefixMatcher = this.resultSet.getPrefixMatcher()
+ protected val collector: LookupElementsCollector = LookupElementsCollector(prefixMatcher, resolveSession, { isVisibleDescriptor(it) })
+ protected var anythingAdded: Boolean = false
+
+ protected val project: Project = position.getProject()
+ protected val indicesHelper: KotlinIndicesHelper = KotlinIndicesHelper(project)
+ protected val module: Module? = ModuleUtilCore.findModuleForPsiElement(parameters.getOriginalFile())
+ protected val searchScope: GlobalSearchScope = if (module != null) GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) else GlobalSearchScope.EMPTY_SCOPE
+
protected fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean {
if (configuration.completeNonAccessibleDeclarations) return true
@@ -68,6 +77,46 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
return true
}
+
+ protected fun flushToResultSet() {
+ if (!collector.isEmpty) {
+ anythingAdded = true
+ }
+ collector.flushToResultSet(resultSet)
+ }
+
+ public fun complete(): Boolean {
+ doComplete()
+ flushToResultSet()
+ return anythingAdded
+ }
+
+ protected abstract fun doComplete()
+
+ protected fun shouldRunTopLevelCompletion(): Boolean {
+ if (!configuration.completeNonImportedDeclarations) return false
+
+ if (position.getNode()!!.getElementType() == JetTokens.IDENTIFIER) {
+ val parent = position.getParent()
+ if (parent is JetSimpleNameExpression && !JetPsiUtil.isSelectorInQualified(parent)) return true
+ }
+
+ return false
+ }
+
+ protected fun shouldRunExtensionsCompletion(): Boolean {
+ return configuration.completeNonImportedDeclarations || prefixMatcher.getPrefix().length >= 3
+ }
+
+ protected fun getKotlinTopLevelDeclarations(): Collection {
+ val filter = { (name: String) -> prefixMatcher.prefixMatches(name) }
+ return indicesHelper.getTopLevelCallables(filter, jetReference!!.expression, resolveSession, searchScope) +
+ indicesHelper.getTopLevelObjects(filter, resolveSession, searchScope)
+ }
+
+ protected fun getKotlinExtensions(): Collection {
+ return indicesHelper.getCallableExtensions({ prefixMatcher.prefixMatches(it) }, jetReference!!.expression, resolveSession, searchScope)
+ }
}
class BasicCompletionSession(configuration: CompletionSessionConfiguration,
@@ -75,14 +124,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
resultSet: CompletionResultSet)
: CompletionSessionBase(configuration, parameters, resultSet) {
- private val collector = LookupElementsCollector(prefixMatcher, resolveSession, { isVisibleDescriptor(it) })
- private var anythingAdded = false
-
- private val project = position.getProject()
- private val indicesHelper = KotlinIndicesHelper(project)
- private val searchScope = searchScopeForSourceElementDependencies(parameters.getOriginalFile()) ?: GlobalSearchScope.EMPTY_SCOPE
-
- public fun complete(): Boolean {
+ override fun doComplete() {
assert(parameters.getCompletionType() == CompletionType.BASIC)
if (!NamedParametersCompletion.isOnlyNamedParameterExpected(position)) {
@@ -111,16 +153,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
}
NamedParametersCompletion.complete(position, collector)
-
- flushToResultSet()
- return anythingAdded
- }
-
- private fun flushToResultSet() {
- if (!collector.isEmpty) {
- anythingAdded = true
- }
- collector.flushToResultSet(resultSet)
}
private fun addNonImported() {
@@ -137,11 +169,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
if (shouldRunTopLevelCompletion()) {
TypesCompletion(parameters, resolveSession, prefixMatcher).addAllTypes(collector)
- addKotlinTopLevelDeclarations()
+ collector.addDescriptorElements(getKotlinTopLevelDeclarations())
}
if (shouldRunExtensionsCompletion()) {
- addKotlinExtensions()
+ collector.addDescriptorElements(getKotlinExtensions())
}
}
@@ -162,16 +194,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
}
}
- private fun addKotlinTopLevelDeclarations() {
- val filter = { (name: String) -> prefixMatcher.prefixMatches(name) }
- collector.addDescriptorElements(indicesHelper.getTopLevelCallables(filter, jetReference!!.expression, resolveSession, searchScope))
- collector.addDescriptorElements(indicesHelper.getTopLevelObjects(filter, resolveSession, searchScope))
- }
-
- private fun addKotlinExtensions() {
- collector.addDescriptorElements(indicesHelper.getCallableExtensions({ prefixMatcher.prefixMatches(it) }, jetReference!!.expression, resolveSession, searchScope))
- }
-
private fun shouldRunOnlyTypeCompletion(): Boolean {
// Check that completion in the type annotation context and if there's a qualified
// expression we are at first of it
@@ -184,21 +206,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
return false
}
- private fun shouldRunTopLevelCompletion(): Boolean {
- if (!configuration.completeNonImportedDeclarations) return false
-
- if (position.getNode()!!.getElementType() == JetTokens.IDENTIFIER) {
- val parent = position.getParent()
- if (parent is JetSimpleNameExpression && !JetPsiUtil.isSelectorInQualified(parent)) return true
- }
-
- return false
- }
-
- private fun shouldRunExtensionsCompletion(): Boolean {
- return configuration.completeNonImportedDeclarations || prefixMatcher.getPrefix().length >= 3
- }
-
private fun addReferenceVariants(filterCondition: (DeclarationDescriptor) -> Boolean = { true }) {
val descriptors = TipsManager.getReferenceVariants(jetReference!!.expression, bindingContext!!)
collector.addDescriptorElements(descriptors.filter { filterCondition(it) })
@@ -207,11 +214,43 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
class SmartCompletionSession(configuration: CompletionSessionConfiguration, parameters: CompletionParameters, resultSet: CompletionResultSet)
: CompletionSessionBase(configuration, parameters, resultSet) {
- public fun complete() {
+
+ override fun doComplete() {
if (jetReference != null) {
- val descriptors = TipsManager.getReferenceVariants(jetReference.expression, bindingContext!!)
val completion = SmartCompletion(jetReference.expression, resolveSession, { isVisibleDescriptor(it) }, parameters.getOriginalFile() as JetFile)
- completion.buildLookupElements(descriptors)?.forEach { resultSet.addElement(it) }
+ val result = completion.execute()
+ if (result != null) {
+ collector.addElements(result.additionalItems)
+
+ val filter = result.declarationFilter
+ if (filter != null) {
+ TipsManager.getReferenceVariants(jetReference.expression, bindingContext!!)
+ .forEach { collector.addElements(filter(it)) }
+
+ flushToResultSet()
+
+ processNonImported { collector.addElements(filter(it)) }
+ }
+ }
+ }
+ }
+
+ private fun processNonImported(processor: (DeclarationDescriptor) -> Unit) {
+ val prefix = prefixMatcher.getPrefix()
+
+ // Try to avoid computing not-imported descriptors for empty prefix
+ if (prefix.isEmpty()) {
+ if (!configuration.completeNonImportedDeclarations) return
+
+ if (PsiTreeUtil.getParentOfType(jetReference!!.expression, javaClass()) == null) return
+ }
+
+ if (shouldRunTopLevelCompletion()) {
+ getKotlinTopLevelDeclarations().forEach(processor)
+ }
+
+ if (shouldRunExtensionsCompletion()) {
+ getKotlinExtensions().forEach(processor)
}
}
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.kt b/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.kt
index bb94c491294..599596b2876 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.kt
@@ -33,6 +33,7 @@ import org.jetbrains.jet.plugin.completion.handlers.JetClassInsertHandler
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.plugin.completion.handlers.BaseDeclarationInsertHandler
+import org.jetbrains.jet.plugin.completion.handlers.JetPropertyInsertHandler
public object DescriptorLookupConverter {
public fun createLookupElement(analyzer: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor, declaration: PsiElement?): LookupElement {
@@ -100,6 +101,8 @@ public object DescriptorLookupConverter {
}
}
+ is PropertyDescriptor -> JetPropertyInsertHandler
+
is ClassDescriptor -> JetClassInsertHandler
else -> BaseDeclarationInsertHandler()
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt b/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt
index c2cbf34a0cd..a31c81e14e1 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt
@@ -83,4 +83,8 @@ class LookupElementsCollector(private val prefixMatcher: PrefixMatcher,
elements.add(element)
}
}
+
+ public fun addElements(elements: Iterable) {
+ elements.forEach { addElement(it) }
+ }
}
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.kt b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetCallableInsertHandler.kt
similarity index 76%
rename from idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.kt
rename to idea/src/org/jetbrains/jet/plugin/completion/handlers/JetCallableInsertHandler.kt
index 665e1490fcb..4115d8a2f31 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetCallableInsertHandler.kt
@@ -28,7 +28,6 @@ import com.intellij.openapi.project.Project
import org.jetbrains.jet.plugin.formatter.JetCodeStyleSettings
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.jet.lang.psi.JetFile
-import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.plugin.quickfix.ImportInsertHelper
@@ -36,6 +35,46 @@ import com.intellij.openapi.editor.Document
import org.jetbrains.jet.lang.types.JetType
import com.intellij.openapi.util.TextRange
import org.jetbrains.jet.plugin.completion.DeclarationLookupObject
+import org.jetbrains.jet.lang.descriptors.CallableDescriptor
+
+public abstract class JetCallableInsertHandler : BaseDeclarationInsertHandler() {
+ public override fun handleInsert(context: InsertionContext, item: LookupElement) {
+ super.handleInsert(context, item)
+
+ addImport(context, item)
+ }
+
+ private fun addImport(context : InsertionContext, item : LookupElement) {
+ PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
+
+ ApplicationManager.getApplication()?.runReadAction { () : Unit ->
+ val startOffset = context.getStartOffset()
+ val element = context.getFile().findElementAt(startOffset)
+
+ if (element == null) return@runReadAction
+
+ val file = context.getFile()
+ val o = item.getObject()
+ if (file is JetFile && o is DeclarationLookupObject) {
+ val descriptor = o.descriptor as? CallableDescriptor
+ if (descriptor != null) {
+ if (PsiTreeUtil.getParentOfType(element, javaClass()) != null &&
+ descriptor.getReceiverParameter() == null) {
+ return@runReadAction
+ }
+
+ if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
+ ApplicationManager.getApplication()?.runWriteAction {
+ ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+public object JetPropertyInsertHandler : JetCallableInsertHandler()
public enum class CaretPosition {
IN_BRACKETS
@@ -44,7 +83,7 @@ public enum class CaretPosition {
public data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
-public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : BaseDeclarationInsertHandler() {
+public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : JetCallableInsertHandler() {
{
if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) {
throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported")
@@ -54,7 +93,10 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
public override fun handleInsert(context: InsertionContext, item: LookupElement) {
super.handleInsert(context, item)
- PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
+ val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject())
+ psiDocumentManager.commitAllDocuments()
+ psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument())
+
if (context.getCompletionChar() == '(') {
context.setAddCompletionChar(false)
}
@@ -62,13 +104,9 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
val startOffset = context.getStartOffset()
val element = context.getFile().findElementAt(startOffset)
- if (element == null) return
-
- if (shouldAddBrackets(element)) {
+ if (element != null && shouldAddBrackets(element)) {
addBrackets(context, element)
}
-
- addImports(context, item)
}
private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) {
@@ -145,36 +183,8 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
return -1
}
- private open fun isInsertSpacesInOneLineFunctionEnabled(project : Project)
+ private fun isInsertSpacesInOneLineFunctionEnabled(project : Project)
= CodeStyleSettingsManager.getSettings(project)
.getCustomSettings(javaClass())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
-
- private open fun addImports(context : InsertionContext, item : LookupElement) {
- ApplicationManager.getApplication()?.runReadAction { () : Unit ->
- val startOffset = context.getStartOffset()
- val element = context.getFile().findElementAt(startOffset)
-
- if (element == null) return@runReadAction
-
- val file = context.getFile()
- val o = item.getObject()
- if (file is JetFile && o is DeclarationLookupObject) {
- val descriptor = o.descriptor as? SimpleFunctionDescriptor
- if (descriptor != null) {
- if (PsiTreeUtil.getParentOfType(element, javaClass()) != null &&
- descriptor.getReceiverParameter() == null) {
- return@runReadAction
- }
-
- if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
- ApplicationManager.getApplication()?.runWriteAction {
- val fqn = DescriptorUtils.getFqNameSafe(descriptor)
- ImportInsertHelper.addImportDirectiveIfNeeded(fqn, file)
- }
- }
- }
- }
- }
- }
}
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/smart/SmartCompletion.kt b/idea/src/org/jetbrains/jet/plugin/completion/smart/SmartCompletion.kt
index 7b2eec710eb..16fb066e09c 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/smart/SmartCompletion.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/SmartCompletion.kt
@@ -37,15 +37,17 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
val resolveSession: ResolveSessionForBodies,
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
val originalFile: JetFile) {
-
private val bindingContext = resolveSession.resolveToElement(expression)
private val moduleDescriptor = resolveSession.getModuleDescriptor()
private val project = expression.getProject()
- public fun buildLookupElements(referenceVariants: Iterable): Collection? {
- return buildLookupElementsInternal(referenceVariants)?.map {
- if (it.getUserData(KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY) == null) {
- object : LookupElementDecorator(it) {
+ public data class Result(val declarationFilter: ((DeclarationDescriptor) -> Collection)?,
+ val additionalItems: Collection)
+
+ public fun execute(): Result? {
+ fun postProcess(item: LookupElement): LookupElement {
+ return if (item.getUserData(KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY) == null) {
+ object : LookupElementDecorator(item) {
override fun handleInsert(context: InsertionContext) {
if (context.getCompletionChar() == Lookup.REPLACE_SELECT_CHAR) {
val offset = context.getOffsetMap().getOffset(SmartCompletion.OLD_ARGUMENTS_REPLACEMENT_OFFSET)
@@ -59,14 +61,23 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
}
}
else {
- it
+ item
}
}
+
+ val result = executeInternal() ?: return null
+ // TODO: code could be more simple, see KT-5726
+ val additionalItems = result.additionalItems.map(::postProcess)
+ val filter = result.declarationFilter
+ return if (filter != null)
+ Result({ filter(it).map(::postProcess) }, additionalItems)
+ else
+ Result(null, additionalItems)
}
- private fun buildLookupElementsInternal(referenceVariants: Iterable): Collection? {
- val elements = buildForAsTypePosition()
- if (elements != null) return elements
+ private fun executeInternal(): Result? {
+ val asTypePositionResult = buildForAsTypePosition()
+ if (asTypePositionResult != null) return asTypePositionResult
val parent = expression.getParent()
val expressionWithType: JetExpression
@@ -90,46 +101,47 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
else
filteredExpectedInfos
- val result = ArrayList()
-
val typesWithAutoCasts: (DeclarationDescriptor) -> Iterable = TypesWithAutoCasts(bindingContext).calculate(expressionWithType, receiver)
val itemsToSkip = calcItemsToSkip(expressionWithType)
val functionExpectedInfos = expectedInfos.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it.`type`) }
- for (descriptor in referenceVariants) {
- if (itemsToSkip.contains(descriptor)) continue
+ fun filterDeclaration(descriptor: DeclarationDescriptor): Collection {
+ val result = ArrayList()
+ if (!itemsToSkip.contains(descriptor)) {
+ val types = typesWithAutoCasts(descriptor)
+ val nonNullTypes = types.map { it.makeNotNullable() }
+ val classifier = { (expectedInfo: ExpectedInfo) ->
+ when {
+ types.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MATCHES
+ nonNullTypes.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MAKE_NOT_NULLABLE
+ else -> ExpectedInfoClassification.NOT_MATCHES
+ }
+ }
+ result.addLookupElements(expectedInfos, classifier, { createLookupElement(descriptor, resolveSession) })
- val types = typesWithAutoCasts(descriptor)
- val nonNullTypes = types.map { it.makeNotNullable() }
- val classifier = { (expectedInfo: ExpectedInfo) ->
- when {
- types.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MATCHES
- nonNullTypes.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MAKE_NOT_NULLABLE
- else -> ExpectedInfoClassification.NOT_MATCHES
+ if (receiver == null) {
+ toFunctionReferenceLookupElement(descriptor, functionExpectedInfos)?.let { result.add(it) }
}
}
- result.addLookupElements(expectedInfos, classifier, { createLookupElement(descriptor, resolveSession) })
-
- if (receiver == null) {
- toFunctionReferenceLookupElement(descriptor, functionExpectedInfos)?.let { result.add(it) }
- }
+ return result
}
+ val additionalItems = ArrayList()
if (receiver == null) {
- TypeInstantiationItems(resolveSession, visibilityFilter).addToCollection(result, expectedInfos)
+ TypeInstantiationItems(resolveSession, visibilityFilter).addToCollection(additionalItems, expectedInfos)
- StaticMembers(bindingContext, resolveSession).addToCollection(result, expectedInfos, expression, itemsToSkip)
+ StaticMembers(bindingContext, resolveSession).addToCollection(additionalItems, expectedInfos, expression, itemsToSkip)
- ThisItems(bindingContext).addToCollection(result, expressionWithType, expectedInfos)
+ ThisItems(bindingContext).addToCollection(additionalItems, expressionWithType, expectedInfos)
- LambdaItems.addToCollection(result, functionExpectedInfos)
+ LambdaItems.addToCollection(additionalItems, functionExpectedInfos)
- KeywordValues.addToCollection(result, filteredExpectedInfos/* use filteredExpectedInfos to not include null after == */, expressionWithType)
+ KeywordValues.addToCollection(additionalItems, filteredExpectedInfos/* use filteredExpectedInfos to not include null after == */, expressionWithType)
}
- return result
+ return Result(::filterDeclaration, additionalItems)
}
private fun calcExpectedInfos(expression: JetExpression): Collection? {
@@ -258,26 +270,23 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
return null
}
- private fun buildForAsTypePosition(): Collection? {
+ private fun buildForAsTypePosition(): Result? {
val binaryExpression = ((expression.getParent() as? JetUserType)
?.getParent() as? JetTypeReference)
?.getParent() as? JetBinaryExpressionWithTypeRHS
- if (binaryExpression != null) {
- val elementType = binaryExpression.getOperationReference().getReferencedNameElementType()
- if (elementType == JetTokens.AS_KEYWORD || elementType == JetTokens.AS_SAFE) {
- val expectedInfos = calcExpectedInfos(binaryExpression) ?: return null
+ ?: return null
+ val elementType = binaryExpression.getOperationReference().getReferencedNameElementType()
+ if (elementType != JetTokens.AS_KEYWORD && elementType != JetTokens.AS_SAFE) return null
+ val expectedInfos = calcExpectedInfos(binaryExpression) ?: return null
- val expectedInfosGrouped: Map> = expectedInfos.groupBy { it.`type`.makeNotNullable() }
+ val expectedInfosGrouped: Map> = expectedInfos.groupBy { it.`type`.makeNotNullable() }
- val result = ArrayList()
- for ((jetType, infos) in expectedInfosGrouped) {
- val lookupElement = lookupElementForType(jetType) ?: continue
- result.add(lookupElement.addTail(infos))
- }
- return result
- }
+ val items = ArrayList()
+ for ((jetType, infos) in expectedInfosGrouped) {
+ val lookupElement = lookupElementForType(jetType) ?: continue
+ items.add(lookupElement.addTail(infos))
}
- return null
+ return Result(null, items)
}
private fun lookupElementForType(jetType: JetType): LookupElement? {
diff --git a/idea/testData/completion/handlers/multifile/ExtensionFunctions-1.kt b/idea/testData/completion/handlers/multifile/ExtensionFunctionImport-1.kt
similarity index 100%
rename from idea/testData/completion/handlers/multifile/ExtensionFunctions-1.kt
rename to idea/testData/completion/handlers/multifile/ExtensionFunctionImport-1.kt
diff --git a/idea/testData/completion/handlers/multifile/ExtensionFunctions-2.kt b/idea/testData/completion/handlers/multifile/ExtensionFunctionImport-2.kt
similarity index 100%
rename from idea/testData/completion/handlers/multifile/ExtensionFunctions-2.kt
rename to idea/testData/completion/handlers/multifile/ExtensionFunctionImport-2.kt
diff --git a/idea/testData/completion/handlers/multifile/ExtensionFunctions.kt.after b/idea/testData/completion/handlers/multifile/ExtensionFunctionImport.kt.after
similarity index 100%
rename from idea/testData/completion/handlers/multifile/ExtensionFunctions.kt.after
rename to idea/testData/completion/handlers/multifile/ExtensionFunctionImport.kt.after
diff --git a/idea/testData/completion/handlers/multifile/ExtensionPropertyImport-1.kt b/idea/testData/completion/handlers/multifile/ExtensionPropertyImport-1.kt
new file mode 100644
index 00000000000..619eee40afc
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/ExtensionPropertyImport-1.kt
@@ -0,0 +1,5 @@
+package first
+
+fun foo() {
+ "".ext
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/multifile/ExtensionPropertyImport-2.kt b/idea/testData/completion/handlers/multifile/ExtensionPropertyImport-2.kt
new file mode 100644
index 00000000000..7584c805362
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/ExtensionPropertyImport-2.kt
@@ -0,0 +1,4 @@
+package second
+
+val String.extensionProp: Int
+ get() = 1
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/multifile/ExtensionPropertyImport.kt.after b/idea/testData/completion/handlers/multifile/ExtensionPropertyImport.kt.after
new file mode 100644
index 00000000000..a2b7cea67b6
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/ExtensionPropertyImport.kt.after
@@ -0,0 +1,7 @@
+package first
+
+import second.extensionProp
+
+fun foo() {
+ "".extensionProp
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/multifile/TopLevelPropertyImport-1.kt b/idea/testData/completion/handlers/multifile/TopLevelPropertyImport-1.kt
new file mode 100644
index 00000000000..4cd77425af1
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/TopLevelPropertyImport-1.kt
@@ -0,0 +1,5 @@
+package some
+
+fun other() {
+ somePr
+}
diff --git a/idea/testData/completion/handlers/multifile/TopLevelPropertyImport-2.kt b/idea/testData/completion/handlers/multifile/TopLevelPropertyImport-2.kt
new file mode 100644
index 00000000000..d8e3e859c44
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/TopLevelPropertyImport-2.kt
@@ -0,0 +1,3 @@
+package other
+
+val someProp: Int = 1
diff --git a/idea/testData/completion/handlers/multifile/TopLevelPropertyImport.kt.after b/idea/testData/completion/handlers/multifile/TopLevelPropertyImport.kt.after
new file mode 100644
index 00000000000..951975fd6a8
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/TopLevelPropertyImport.kt.after
@@ -0,0 +1,7 @@
+package some
+
+import other.someProp
+
+fun other() {
+ someProp
+}
diff --git a/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction-1.kt b/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction-1.kt
new file mode 100644
index 00000000000..67b6d088751
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction-1.kt
@@ -0,0 +1 @@
+fun foo(s: String): String = s.ext
diff --git a/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction-2.kt b/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction-2.kt
new file mode 100644
index 00000000000..7e0132bf254
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction-2.kt
@@ -0,0 +1,3 @@
+package other
+
+fun String.extensionFun() = ""
diff --git a/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction.kt.after b/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction.kt.after
new file mode 100644
index 00000000000..175b1db2cc3
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/smart/ImportExtensionFunction.kt.after
@@ -0,0 +1,3 @@
+import other.extensionFun
+
+fun foo(s: String): String = s.extensionFun()
diff --git a/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty-1.kt b/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty-1.kt
new file mode 100644
index 00000000000..565fe2852b0
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty-1.kt
@@ -0,0 +1 @@
+fun foo(s: String): Int = s.ext
diff --git a/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty-2.kt b/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty-2.kt
new file mode 100644
index 00000000000..e58bed27843
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty-2.kt
@@ -0,0 +1,3 @@
+package other
+
+val String.extensionProp: Int get() = this.size
diff --git a/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty.kt.after b/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty.kt.after
new file mode 100644
index 00000000000..f87f824a5fb
--- /dev/null
+++ b/idea/testData/completion/handlers/multifile/smart/ImportExtensionProperty.kt.after
@@ -0,0 +1,3 @@
+import other.extensionProp
+
+fun foo(s: String): Int = s.extensionProp
diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java
index 6156964863b..0b59c4faf16 100644
--- a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java
+++ b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java
@@ -22,7 +22,11 @@ import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
public class CompletionMultifileHandlerTest extends KotlinCompletionTestCase {
- public void testExtensionFunctions() throws Exception {
+ public void testExtensionFunctionImport() throws Exception {
+ doTest();
+ }
+
+ public void testExtensionPropertyImport() throws Exception {
doTest();
}
@@ -42,6 +46,10 @@ public class CompletionMultifileHandlerTest extends KotlinCompletionTestCase {
doTest();
}
+ public void testTopLevelPropertyImport() throws Exception {
+ doTest();
+ }
+
public void testNoParenthesisInImports() throws Exception {
doTest();
}
diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionMultifileHandlerTest.java b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionMultifileHandlerTest.java
new file mode 100644
index 00000000000..1cb67519697
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionMultifileHandlerTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2014 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.jet.completion.handlers;
+
+import com.intellij.codeInsight.completion.CompletionType;
+import org.jetbrains.jet.plugin.KotlinCompletionTestCase;
+import org.jetbrains.jet.plugin.PluginTestCaseBase;
+
+import java.io.File;
+
+public class SmartCompletionMultifileHandlerTest extends KotlinCompletionTestCase {
+ public void testImportExtensionFunction() throws Exception {
+ doTest();
+ }
+
+ public void testImportExtensionProperty() throws Exception {
+ doTest();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ setType(CompletionType.SMART);
+ super.setUp();
+ }
+
+ public void doTest() throws Exception {
+ String fileName = getTestName(false);
+
+ configureByFiles(null, fileName + "-1.kt", fileName + "-2.kt");
+ complete(1);
+ checkResultByFile(fileName + ".kt.after");
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/handlers/multifile/smart/").getPath() + File.separator;
+ }
+}