KT-4914 Smart completion should work after 'as' and 'as?'

#KT-4914 Fixed
This commit is contained in:
Valentin Kipyatkov
2014-07-23 18:34:52 +02:00
parent 32dbed602a
commit 7546a17539
22 changed files with 278 additions and 30 deletions
@@ -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);
}
}
@@ -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<DeclarationDescriptor>): Collection<LookupElement>? {
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<LookupElement>? {
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<JetType, List<ExpectedInfo>> = expectedInfos.groupBy { it.`type`.makeNotNullable() }
val result = ArrayList<LookupElement>()
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<LookupElement> = object : InsertHandler<LookupElement> {
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>(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")
}
@@ -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<LookupElement>, expectedInfos: Collection<ExpectedInfo>) {
val expectedInfosGrouped: Map<JetType, List<ExpectedInfo>> = 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()