Smart completion: static members insertion reworked to support single lambda parameter, more correct reference shortening in range

This commit is contained in:
Valentin Kipyatkov
2014-04-23 17:58:46 +04:00
parent e8805f69bf
commit 7905d32c14
9 changed files with 98 additions and 32 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentF
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor
import com.intellij.openapi.util.TextRange
import com.intellij.psi.SmartPointerManager
import com.intellij.psi.PsiDocumentManager
import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession
public object ShortenReferences {
@@ -30,13 +31,19 @@ public object ShortenReferences {
}
public fun process(file: JetFile, startOffset: Int, endOffset: Int) {
val smartPointerManager = SmartPointerManager.getInstance(file.getProject())
val pointer = smartPointerManager.createSmartPsiFileRangePointer(file, TextRange(startOffset, endOffset))
val documentManager = PsiDocumentManager.getInstance(file.getProject())
val document = documentManager.getDocument(file)!!
if (!documentManager.isCommitted(document)) {
throw IllegalStateException("Document should be committed to shorten references in range")
}
val rangeMarker = document.createRangeMarker(startOffset, endOffset)
rangeMarker.setGreedyToLeft(true)
rangeMarker.setGreedyToRight(true)
try {
process(listOf(file), { element ->
val segment = pointer.getRange()
if (segment != null) {
val range = TextRange(segment.getStartOffset(), segment.getEndOffset())
if (rangeMarker.isValid()) {
val range = TextRange(rangeMarker.getStartOffset(), rangeMarker.getEndOffset())
val elementRange = element.getTextRange()!!
when {
range.contains(elementRange) -> FilterResult.PROCESS
@@ -50,7 +57,7 @@ public object ShortenReferences {
})
}
finally {
smartPointerManager.removePointer(pointer)
rangeMarker.dispose()
}
}
@@ -93,14 +93,6 @@ class StaticMembers(val bindingContext: BindingContext, val resolveSession: Reso
val lookupString = qualifierPresentation + "." + lookupElement.getLookupString()
val qualifierText = DescriptorUtils.getFqName(classDescriptor).asString() //TODO: escape keywords
val caretPosition: CaretPosition?
if (memberDescriptor is FunctionDescriptor) {
caretPosition = if (memberDescriptor.getValueParameters().empty) CaretPosition.AFTER_BRACKETS else CaretPosition.IN_BRACKETS
}
else {
caretPosition = null
}
return object: LookupElementDecorator<LookupElement>(lookupElement) {
override fun getLookupString() = lookupString
@@ -123,19 +115,16 @@ class StaticMembers(val bindingContext: BindingContext, val resolveSession: Reso
}
override fun handleInsert(context: InsertionContext) {
val editor = context.getEditor()
val startOffset = context.getStartOffset()
var text = qualifierText + "." + memberDescriptor.getName().asString() //TODO: escape
context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), text)
context.setTailOffset(context.getStartOffset() + text.length)
if (memberDescriptor is FunctionDescriptor) {
text += "()"
//TODO: auto-popup parameter info and other functionality from JetFunctionInsertHandler
getDelegate().handleInsert(context)
}
editor.getDocument().replaceString(startOffset, context.getTailOffset(), text)
val endOffset = startOffset + text.length
editor.getCaretModel().moveToOffset(if (caretPosition == CaretPosition.IN_BRACKETS) endOffset - 1 else endOffset)
shortenReferences(context, startOffset, startOffset + qualifierText.length)
shortenReferences(context, context.getStartOffset(), context.getTailOffset())
}
}
}
@@ -0,0 +1,13 @@
package sample
class K {
class object {
fun bar(p: () -> Unit): K = K()
}
}
fun foo(){
val k : K = <caret>
}
// ELEMENT: K.bar
@@ -0,0 +1,13 @@
package sample
class K {
class object {
fun bar(p: () -> Unit): K = K()
}
}
fun foo(){
val k : K = K.bar { <caret> }
}
// ELEMENT: K.bar
@@ -0,0 +1,13 @@
package sample
class K {
class object {
fun bar(p: (Int, String) -> Unit): K = K()
}
}
fun foo(){
val k : K = <caret>
}
// ELEMENT: K.bar
@@ -0,0 +1,13 @@
package sample
class K {
class object {
fun bar(p: (Int, String) -> Unit): K = K()
}
}
fun foo(){
val k : K = K.bar(<caret>)
}
// ELEMENT: K.bar
@@ -16,14 +16,17 @@
package org.jetbrains.jet.completion;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.completion.AbstractJvmBasicCompletionTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@@ -16,11 +16,17 @@
package org.jetbrains.jet.completion.handlers;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.TestMetadata;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.jetbrains.jet.completion.handlers.AbstractSmartCompletionHandlerTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@@ -60,6 +66,16 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest("idea/testData/completion/handlers/smart/ClassObjectMethod2.kt");
}
@TestMetadata("ClassObjectMethod3.kt")
public void testClassObjectMethod3() throws Exception {
doTest("idea/testData/completion/handlers/smart/ClassObjectMethod3.kt");
}
@TestMetadata("ClassObjectMethod4.kt")
public void testClassObjectMethod4() throws Exception {
doTest("idea/testData/completion/handlers/smart/ClassObjectMethod4.kt");
}
@TestMetadata("ClosingParenthesis1.kt")
public void testClosingParenthesis1() throws Exception {
doTest("idea/testData/completion/handlers/smart/ClosingParenthesis1.kt");
@@ -31,7 +31,7 @@ abstract class AbstractShortenRefsTest : LightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
protected fun doTest(testPath: String) {
val fixture = myFixture!!
val fixture = myFixture
val dependencyPath = testPath.replace(".kt", ".dependency.kt")
if (File(dependencyPath).exists()) {
fixture.configureByFile(dependencyPath)
@@ -44,13 +44,12 @@ abstract class AbstractShortenRefsTest : LightCodeInsightFixtureTestCase() {
fixture.configureByFile(testPath)
val file = fixture.getFile() as JetFile
val selectionModel = fixture.getEditor()!!.getSelectionModel()
val selectionModel = fixture.getEditor().getSelectionModel()
if (!selectionModel.hasSelection()) error("No selection in input file")
val element = PsiTreeUtil.findElementOfClassAtRange(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd(), javaClass<JetElement>())!!
CommandProcessor.getInstance()!!.executeCommand(getProject(), {
CommandProcessor.getInstance().executeCommand(getProject(), {
ApplicationManager.getApplication()!!.runWriteAction {
ShortenReferences.process(element)
ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())
}
}, null, null)
selectionModel.removeSelection()