diff --git a/.idea/runConfigurations/Smart_Completion_Tests.xml b/.idea/runConfigurations/Smart_Completion_Tests.xml
new file mode 100644
index 00000000000..54c15f73475
--- /dev/null
+++ b/.idea/runConfigurations/Smart_Completion_Tests.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java
index a9bdd23920e..510d438603b 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java
+++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java
@@ -136,13 +136,23 @@ public class JetCompletionContributor extends CompletionContributor {
}
int expressionEnd = expression.getTextRange().getEndOffset();
+ String text = context.getFile().getText();
+ while (expressionEnd > 0 && Character.isWhitespace(text.charAt(expressionEnd - 1))) {
+ expressionEnd--;
+ }
+
+ int suggestedReplacementOffset;
if (expression instanceof JetCallExpression) {
JetExpression calleeExpression = ((JetCallExpression) expression).getCalleeExpression();
- context.setReplacementOffset(calleeExpression != null ? calleeExpression.getTextRange().getEndOffset() : expressionEnd);
+ suggestedReplacementOffset = calleeExpression != null ? calleeExpression.getTextRange().getEndOffset() : expressionEnd;
}
- else{
- context.setReplacementOffset(expressionEnd);
+ else {
+ suggestedReplacementOffset = expressionEnd;
}
+ if (suggestedReplacementOffset > context.getReplacementOffset()) {
+ context.setReplacementOffset(suggestedReplacementOffset);
+ }
+
context.getOffsetMap().addOffset(SmartCompletion.OLD_ARGUMENTS_REPLACEMENT_OFFSET, expressionEnd);
}
}
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 35070f1f4b4..7b2eec710eb 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/smart/SmartCompletion.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/SmartCompletion.kt
@@ -31,6 +31,7 @@ import org.jetbrains.jet.plugin.util.makeNotNullable
import org.jetbrains.jet.plugin.util.makeNullable
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession
+import org.jetbrains.jet.renderer.DescriptorRenderer
class SmartCompletion(val expression: JetSimpleNameExpression,
val resolveSession: ResolveSessionForBodies,
@@ -64,6 +65,9 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
}
private fun buildLookupElementsInternal(referenceVariants: Iterable): Collection? {
+ val elements = buildForAsTypePosition()
+ if (elements != null) return elements
+
val parent = expression.getParent()
val expressionWithType: JetExpression
val receiver: JetExpression?
@@ -254,6 +258,61 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
return null
}
+ private fun buildForAsTypePosition(): Collection? {
+ 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
+
+ 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
+ }
+ }
+ return null
+ }
+
+ private fun lookupElementForType(jetType: JetType): LookupElement? {
+ if (jetType.isError()) return null
+ val classifier = jetType.getConstructor().getDeclarationDescriptor() ?: return null
+
+ val lookupElement = createLookupElement(classifier, resolveSession)
+ val lookupString = lookupElement.getLookupString()
+
+ val typeArgs = jetType.getArguments()
+ var itemText = lookupString + DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderTypeArguments(typeArgs)
+ val typeText = DescriptorUtils.getFqName(classifier).toString() + DescriptorRenderer.SOURCE_CODE.renderTypeArguments(typeArgs)
+
+ val insertHandler: InsertHandler = object : InsertHandler {
+ override fun handleInsert(context: InsertionContext, item: LookupElement) {
+ context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), typeText)
+ context.setTailOffset(context.getStartOffset() + typeText.length)
+ shortenReferences(context, context.getStartOffset(), context.getTailOffset())
+ }
+ }
+
+ return object: LookupElementDecorator(lookupElement) {
+ override fun getLookupString() = lookupString
+
+ override fun renderElement(presentation: LookupElementPresentation) {
+ getDelegate().renderElement(presentation)
+ presentation.setItemText(itemText)
+ }
+
+ override fun handleInsert(context: InsertionContext) {
+ insertHandler.handleInsert(context, getDelegate())
+ }
+ }
+ }
+
class object {
public val OLD_ARGUMENTS_REPLACEMENT_OFFSET: OffsetKey = OffsetKey.create("nonFunctionReplacementOffset")
}
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/smart/TypeInstantiationItems.kt b/idea/src/org/jetbrains/jet/plugin/completion/smart/TypeInstantiationItems.kt
index 6e9b34527db..d6a0dc25a01 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/smart/TypeInstantiationItems.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/TypeInstantiationItems.kt
@@ -41,8 +41,8 @@ import org.jetbrains.jet.plugin.util.makeNotNullable
class TypeInstantiationItems(val resolveSession: ResolveSessionForBodies, val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
public fun addToCollection(collection: MutableCollection, expectedInfos: Collection) {
val expectedInfosGrouped: Map> = expectedInfos.groupBy { it.`type`.makeNotNullable() }
- for ((jetType, types) in expectedInfosGrouped) {
- val tail = mergeTails(types.map { it.tail })
+ for ((jetType, infos) in expectedInfosGrouped) {
+ val tail = mergeTails(infos.map { it.tail })
addToCollection(collection, jetType, tail)
}
}
@@ -51,7 +51,7 @@ class TypeInstantiationItems(val resolveSession: ResolveSessionForBodies, val vi
if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(jetType)) return // do not show "object: ..." for function types
val classifier = jetType.getConstructor().getDeclarationDescriptor()
- if (!(classifier is ClassDescriptor)) return
+ if (classifier !is ClassDescriptor) return
val isAbstract = classifier.getModality() == Modality.ABSTRACT
val allConstructors = classifier.getConstructors()
diff --git a/idea/testData/completion/handlers/smart/AfterAs.kt b/idea/testData/completion/handlers/smart/AfterAs.kt
new file mode 100644
index 00000000000..5fd1712b8f1
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterAs.kt
@@ -0,0 +1,5 @@
+fun foo(p1: String, p2: Int){ }
+
+fun bar(o: Any){
+ foo(o as )
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/smart/AfterAs.kt.after b/idea/testData/completion/handlers/smart/AfterAs.kt.after
new file mode 100644
index 00000000000..9d6c6b47d79
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterAs.kt.after
@@ -0,0 +1,5 @@
+fun foo(p1: String, p2: Int){ }
+
+fun bar(o: Any){
+ foo(o as String, )
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/smart/AfterAs2.kt b/idea/testData/completion/handlers/smart/AfterAs2.kt
new file mode 100644
index 00000000000..92431c6ee9d
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterAs2.kt
@@ -0,0 +1,5 @@
+fun foo(p: java.util.HashMap){ }
+
+fun bar(o: Any){
+ foo(o as )
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/smart/AfterAs2.kt.after b/idea/testData/completion/handlers/smart/AfterAs2.kt.after
new file mode 100644
index 00000000000..df05411f580
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterAs2.kt.after
@@ -0,0 +1,8 @@
+import java.io.File
+import java.util.HashMap
+
+fun foo(p: java.util.HashMap){ }
+
+fun bar(o: Any){
+ foo(o as HashMap)
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/smart/AfterAs3.kt b/idea/testData/completion/handlers/smart/AfterAs3.kt
new file mode 100644
index 00000000000..b1e553dda24
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterAs3.kt
@@ -0,0 +1,6 @@
+fun foo(l: List){}
+fun foo(l: List, p: Int){}
+
+fun bar(o: Any) {
+ foo(o as )
+}
diff --git a/idea/testData/completion/handlers/smart/AfterAs3.kt.after b/idea/testData/completion/handlers/smart/AfterAs3.kt.after
new file mode 100644
index 00000000000..bdfd3afe2c7
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterAs3.kt.after
@@ -0,0 +1,6 @@
+fun foo(l: List){}
+fun foo(l: List, p: Int){}
+
+fun bar(o: Any) {
+ foo(o as List)
+}
diff --git a/idea/testData/completion/handlers/smart/AfterSafeAs.kt b/idea/testData/completion/handlers/smart/AfterSafeAs.kt
new file mode 100644
index 00000000000..0a43c9a4b22
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterSafeAs.kt
@@ -0,0 +1,5 @@
+fun foo(p: java.io.File?){ }
+
+fun bar(o: Any){
+ foo(o as? )
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/smart/AfterSafeAs.kt.after b/idea/testData/completion/handlers/smart/AfterSafeAs.kt.after
new file mode 100644
index 00000000000..ccb10a6c4b9
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AfterSafeAs.kt.after
@@ -0,0 +1,7 @@
+import java.io.File
+
+fun foo(p: java.io.File?){ }
+
+fun bar(o: Any){
+ foo(o as? File)
+}
\ No newline at end of file
diff --git a/idea/testData/completion/handlers/smart/AutoCompleteAfterAs1.kt b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs1.kt
new file mode 100644
index 00000000000..25eae583e01
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs1.kt
@@ -0,0 +1,6 @@
+fun foo(i: Int){}
+fun foo(i: Int, c: Char){}
+
+fun bar(o: Any) {
+ foo(o as )
+}
diff --git a/idea/testData/completion/handlers/smart/AutoCompleteAfterAs1.kt.after b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs1.kt.after
new file mode 100644
index 00000000000..fdfc6c6b16d
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs1.kt.after
@@ -0,0 +1,6 @@
+fun foo(i: Int){}
+fun foo(i: Int, c: Char){}
+
+fun bar(o: Any) {
+ foo(o as Int)
+}
diff --git a/idea/testData/completion/handlers/smart/AutoCompleteAfterAs2.kt b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs2.kt
new file mode 100644
index 00000000000..f853db31c10
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs2.kt
@@ -0,0 +1,3 @@
+fun bar(o: Any): String {
+ return o as
+}
diff --git a/idea/testData/completion/handlers/smart/AutoCompleteAfterAs2.kt.after b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs2.kt.after
new file mode 100644
index 00000000000..d3debae7ed1
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/AutoCompleteAfterAs2.kt.after
@@ -0,0 +1,3 @@
+fun bar(o: Any): String {
+ return o as String
+}
diff --git a/idea/testData/completion/smart/AfterAs.kt b/idea/testData/completion/smart/AfterAs.kt
new file mode 100644
index 00000000000..684e30a721a
--- /dev/null
+++ b/idea/testData/completion/smart/AfterAs.kt
@@ -0,0 +1,11 @@
+fun foo(s: String?){}
+
+fun foo(i: Int){}
+
+fun bar(o: Any) {
+ foo(o as )
+}
+
+// NUMBER: 2
+// EXIST: String
+// EXIST: Int
diff --git a/idea/testData/completion/smart/AfterAs2.kt b/idea/testData/completion/smart/AfterAs2.kt
new file mode 100644
index 00000000000..a8364373756
--- /dev/null
+++ b/idea/testData/completion/smart/AfterAs2.kt
@@ -0,0 +1,11 @@
+fun foo(s: List){}
+
+fun foo(i: Map){}
+
+fun bar(o: Any) {
+ foo(o as )
+}
+
+// NUMBER: 2
+// EXIST: { lookupString:"List", itemText:"List" }
+// EXIST: { lookupString:"Map", itemText:"Map" }
diff --git a/idea/testData/completion/smart/AfterAs3.kt b/idea/testData/completion/smart/AfterAs3.kt
new file mode 100644
index 00000000000..d4b41a67aff
--- /dev/null
+++ b/idea/testData/completion/smart/AfterAs3.kt
@@ -0,0 +1,12 @@
+fun foo(l: List){}
+fun foo(l: List, p: Int){}
+
+fun foo(s: String?){}
+
+fun bar(o: Any) {
+ foo(o as )
+}
+
+// NUMBER: 2
+// EXIST: { lookupString:"List", itemText:"List" }
+// EXIST: { lookupString:"String", itemText:"String" }
diff --git a/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java
index eb0e230ee24..f763a52c0fe 100644
--- a/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java
+++ b/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java
@@ -32,6 +32,21 @@ import org.jetbrains.jet.completion.AbstractJvmSmartCompletionTest;
@SuppressWarnings("all")
@TestMetadata("idea/testData/completion/smart")
public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionTest {
+ @TestMetadata("AfterAs.kt")
+ public void testAfterAs() throws Exception {
+ doTest("idea/testData/completion/smart/AfterAs.kt");
+ }
+
+ @TestMetadata("AfterAs2.kt")
+ public void testAfterAs2() throws Exception {
+ doTest("idea/testData/completion/smart/AfterAs2.kt");
+ }
+
+ @TestMetadata("AfterAs3.kt")
+ public void testAfterAs3() throws Exception {
+ doTest("idea/testData/completion/smart/AfterAs3.kt");
+ }
+
@TestMetadata("AfterExclSign.kt")
public void testAfterExclSign() throws Exception {
doTest("idea/testData/completion/smart/AfterExclSign.kt");
diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionHandlerTestBase.kt b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionHandlerTestBase.kt
index 05d8a96e892..448981d219a 100644
--- a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionHandlerTestBase.kt
+++ b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionHandlerTestBase.kt
@@ -18,8 +18,6 @@ package org.jetbrains.jet.completion.handlers
import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase
import com.intellij.codeInsight.completion.CompletionType
-import com.intellij.psi.codeStyle.CodeStyleSettingsManager
-import org.jetbrains.jet.plugin.formatter.JetCodeStyleSettings
import com.intellij.codeInsight.lookup.LookupElement
import java.io.File
import org.jetbrains.jet.plugin.PluginTestCaseBase
@@ -31,8 +29,6 @@ import com.intellij.codeInsight.lookup.LookupElementPresentation
import org.junit.Assert
import com.intellij.openapi.application.Result
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
-import kotlin.properties.Delegates
-import com.intellij.openapi.util.io.FileUtil
public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTestCase() {
protected abstract val completionType : CompletionType
@@ -41,28 +37,27 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
protected val fixture: JavaCodeInsightTestFixture
get() = myFixture
- protected fun doTest() : Unit = doTest(2, null, null, null, '\n')
+ protected fun doTest() : Unit = doTest(2, "*", null, null, '\n')
- protected fun doTest(time : Int, lookupString : String?, tailText : String?, completionChar : Char) {
+ protected fun doTest(time: Int, lookupString: String?, tailText: String?, completionChar: Char) {
doTest(time, lookupString, null, tailText, completionChar)
}
- protected fun doTest(time : Int, lookupString : String?, itemText: String?, tailText : String?, completionChar : Char) {
+ protected fun doTest(time: Int, lookupString: String?, itemText: String?, tailText: String?, completionChar: Char) {
fixture.configureByFile(fileName())
doTestWithTextLoaded(time, lookupString, itemText, tailText, completionChar)
}
- protected fun doTestWithTextLoaded(time : Int, lookupString : String?, itemText: String?, tailText : String?, completionChar : Char) {
+ protected fun doTestWithTextLoaded(time: Int, lookupString: String?, itemText: String?, tailText: String?, completionChar: Char) {
+ fixture.complete(completionType, time)
+
if (lookupString != null || itemText != null || tailText != null) {
- fixture.complete(completionType, time)
val item = getExistentLookupElement(lookupString, itemText, tailText)
if (item != null) {
selectItem(item, completionChar)
}
}
- else {
- forceCompleteFirst(completionType, time)
- }
+
checkResult()
}
@@ -70,13 +65,20 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
fixture.checkResultByFile(afterFileName())
}
- private fun getExistentLookupElement(lookupString : String?, itemText: String?, tailText : String?) : LookupElement? {
+ private fun getExistentLookupElement(lookupString: String?, itemText: String?, tailText: String?): LookupElement? {
val lookup = LookupManager.getInstance(getProject())?.getActiveLookup() as LookupImpl?
if (lookup == null) return null
+ val items = lookup.getItems()
+
+ if (lookupString == "*") {
+ assert(itemText == null)
+ assert(tailText == null)
+ return items.firstOrNull()
+ }
var foundElement : LookupElement? = null
val presentation = LookupElementPresentation()
- for (lookupElement in lookup.getItems()) {
+ for (lookupElement in items) {
val lookupOk = if (lookupString != null) lookupElement.getLookupString().contains(lookupString) else true
if (lookupOk) {
@@ -116,21 +118,13 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
protected fun afterFileName(): String = getTestName(false) + ".kt.after"
- private fun forceCompleteFirst(`type` : CompletionType, time : Int) {
- fixture.complete(`type`, time)
- val items : Array? = fixture.getLookupElements()
- if (items != null && items.isNotEmpty()) {
- selectItem(items[0])
- }
- }
-
protected override fun getTestDataPath() : String = File(PluginTestCaseBase.getTestDataPathBase(), testDataRelativePath).getPath() + File.separator
- protected fun selectItem(item : LookupElement?) {
+ protected fun selectItem(item: LookupElement?) {
selectItem(item, 0.toChar())
}
- protected fun selectItem(item : LookupElement?, completionChar : Char) {
+ protected fun selectItem(item: LookupElement?, completionChar: Char) {
val lookup = (fixture.getLookup() as LookupImpl)
lookup.setCurrentItem(item)
if (LookupEvent.isSpecialCompletionChar(completionChar)) {
diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java
index 54d04511369..ea4d2939b5b 100644
--- a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java
+++ b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java
@@ -32,6 +32,26 @@ import org.jetbrains.jet.completion.handlers.AbstractSmartCompletionHandlerTest;
@SuppressWarnings("all")
@TestMetadata("idea/testData/completion/handlers/smart")
public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletionHandlerTest {
+ @TestMetadata("AfterAs.kt")
+ public void testAfterAs() throws Exception {
+ doTest("idea/testData/completion/handlers/smart/AfterAs.kt");
+ }
+
+ @TestMetadata("AfterAs2.kt")
+ public void testAfterAs2() throws Exception {
+ doTest("idea/testData/completion/handlers/smart/AfterAs2.kt");
+ }
+
+ @TestMetadata("AfterAs3.kt")
+ public void testAfterAs3() throws Exception {
+ doTest("idea/testData/completion/handlers/smart/AfterAs3.kt");
+ }
+
+ @TestMetadata("AfterSafeAs.kt")
+ public void testAfterSafeAs() throws Exception {
+ doTest("idea/testData/completion/handlers/smart/AfterSafeAs.kt");
+ }
+
public void testAllFilesPresentInSmart() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/completion/handlers/smart"), Pattern.compile("^(.+)\\.kt$"), true);
}
@@ -56,6 +76,16 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest("idea/testData/completion/handlers/smart/AnonymousObjectInsertsImport.kt");
}
+ @TestMetadata("AutoCompleteAfterAs1.kt")
+ public void testAutoCompleteAfterAs1() throws Exception {
+ doTest("idea/testData/completion/handlers/smart/AutoCompleteAfterAs1.kt");
+ }
+
+ @TestMetadata("AutoCompleteAfterAs2.kt")
+ public void testAutoCompleteAfterAs2() throws Exception {
+ doTest("idea/testData/completion/handlers/smart/AutoCompleteAfterAs2.kt");
+ }
+
@TestMetadata("ClassObjectMethod1.kt")
public void testClassObjectMethod1() throws Exception {
doTest("idea/testData/completion/handlers/smart/ClassObjectMethod1.kt");