mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
position caret to the next probable editing location after inserting type arguments (IDEA-26763)
This commit is contained in:
+11
-5
@@ -26,6 +26,7 @@ import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -147,8 +148,16 @@ class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<L
|
||||
}
|
||||
|
||||
final PsiElement place = context.getFile().findElementAt(context.getStartOffset());
|
||||
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
|
||||
assert place != null;
|
||||
boolean hasParams = hasConstructorParameters(psiClass, place);
|
||||
|
||||
JavaCompletionUtil.insertParentheses(context, delegate, false, hasParams, forAnonymous);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean hasConstructorParameters(PsiClass psiClass, @NotNull PsiElement place) {
|
||||
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(place.getProject()).getResolveHelper();
|
||||
boolean hasParams = false;
|
||||
for (PsiMethod constructor : psiClass.getConstructors()) {
|
||||
if (!resolveHelper.isAccessible(constructor, place, null)) continue;
|
||||
@@ -157,10 +166,7 @@ class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<L
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JavaCompletionUtil.insertParentheses(context, delegate, false, hasParams, forAnonymous);
|
||||
|
||||
return true;
|
||||
return hasParams;
|
||||
}
|
||||
|
||||
private static Runnable generateAnonymousBody(final Editor editor, final PsiFile file) {
|
||||
|
||||
+6
-1
@@ -353,6 +353,11 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
|
||||
@NotNull
|
||||
public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) {
|
||||
return getExpectedTypes(parameters, parameters.getCompletionType() == CompletionType.SMART);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters, boolean voidable) {
|
||||
final PsiElement position = parameters.getPosition();
|
||||
if (psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)).accepts(position)) {
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(position.getProject()).getElementFactory();
|
||||
@@ -372,7 +377,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
PsiExpression expression = PsiTreeUtil.getContextOfType(position, PsiExpression.class, true);
|
||||
if (expression == null) return ExpectedTypeInfo.EMPTY_ARRAY;
|
||||
|
||||
return ExpectedTypesProvider.getExpectedTypes(expression, true, parameters.getCompletionType() == CompletionType.SMART, false);
|
||||
return ExpectedTypesProvider.getExpectedTypes(expression, true, voidable, false);
|
||||
}
|
||||
|
||||
static Set<LookupElement> completeReference(final PsiElement element,
|
||||
|
||||
+90
-31
@@ -16,12 +16,16 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.CharTailType;
|
||||
import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
|
||||
import com.intellij.codeInsight.lookup.TailTypeDecorator;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.filters.getters.ExpectedTypesGetter;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
@@ -36,6 +40,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
@@ -47,11 +53,12 @@ class TypeArgumentCompletionProvider extends CompletionProvider<CompletionParame
|
||||
final Pair<PsiClass, Integer> pair = getTypeParameterInfo(context);
|
||||
if (pair == null) return;
|
||||
|
||||
final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(context, false);
|
||||
if (psiTypes.length > 0) {
|
||||
for (PsiType type : psiTypes) {
|
||||
ExpectedTypeInfo[] types = JavaSmartCompletionContributor.getExpectedTypes(parameters, false);
|
||||
if (types.length > 0) {
|
||||
for (ExpectedTypeInfo info : types) {
|
||||
PsiType type = info.getType();
|
||||
if (type instanceof PsiClassType) {
|
||||
fillExpectedTypeArgs(resultSet, context, pair.first, pair.second, ((PsiClassType)type).resolveGenerics());
|
||||
fillExpectedTypeArgs(resultSet, context, pair.first, pair.second, ((PsiClassType)type).resolveGenerics(), info.getTailType());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -63,7 +70,7 @@ class TypeArgumentCompletionProvider extends CompletionProvider<CompletionParame
|
||||
PsiElement context,
|
||||
final PsiClass actualClass,
|
||||
final int index,
|
||||
PsiClassType.ClassResolveResult expectedType) {
|
||||
PsiClassType.ClassResolveResult expectedType, TailType globalTail) {
|
||||
final PsiClass expectedClass = expectedType.getElement();
|
||||
|
||||
if (!InheritanceUtil.isInheritorOrSelf(actualClass, expectedClass, true)) return;
|
||||
@@ -86,30 +93,7 @@ class TypeArgumentCompletionProvider extends CompletionProvider<CompletionParame
|
||||
typeItems.add(PsiTypeLookupItem.createLookupItem(arg, context));
|
||||
}
|
||||
|
||||
resultSet.addElement(LookupElementBuilder.create(typeItems.get(0).getObject(), typeItems.get(0).getLookupString()).setRenderer(new LookupElementRenderer<LookupElement>() {
|
||||
@Override
|
||||
public void renderElement(LookupElement element, LookupElementPresentation presentation) {
|
||||
typeItems.get(0).renderElement(presentation);
|
||||
presentation.setItemText(StringUtil.join(typeItems, new Function<PsiTypeLookupItem, String>() {
|
||||
@Override
|
||||
public String fun(PsiTypeLookupItem item) {
|
||||
return item.getLookupString();
|
||||
}
|
||||
}, ", "));
|
||||
presentation.setTailText(null);
|
||||
presentation.setTypeText(null);
|
||||
}
|
||||
}).setInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
|
||||
for (int i = 0; i < typeItems.size(); i++) {
|
||||
CompletionUtil.emulateInsertion(context, context.getTailOffset(), typeItems.get(i));
|
||||
getTail(i == typeItems.size() - 1).processTail(context.getEditor(), context.getTailOffset());
|
||||
}
|
||||
context.setAddCompletionChar(false);
|
||||
}
|
||||
}));
|
||||
resultSet.addElement(new TypeArgsLookupElement(typeItems, globalTail, ConstructorInsertHandler.hasConstructorParameters(actualClass, context)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -184,4 +168,79 @@ class TypeArgumentCompletionProvider extends CompletionProvider<CompletionParame
|
||||
|
||||
return Pair.create(referencedClass, parameterIndex);
|
||||
}
|
||||
|
||||
private static class TypeArgsLookupElement extends LookupElement {
|
||||
private String myLookupString;
|
||||
private final List<PsiTypeLookupItem> myTypeItems;
|
||||
private final TailType myGlobalTail;
|
||||
private final boolean myHasParameters;
|
||||
|
||||
public TypeArgsLookupElement(List<PsiTypeLookupItem> typeItems, TailType globalTail, boolean hasParameters) {
|
||||
myTypeItems = typeItems;
|
||||
myGlobalTail = globalTail;
|
||||
myHasParameters = hasParameters;
|
||||
myLookupString = StringUtil.join(myTypeItems, new Function<PsiTypeLookupItem, String>() {
|
||||
@Override
|
||||
public String fun(PsiTypeLookupItem item) {
|
||||
return item.getLookupString();
|
||||
}
|
||||
}, ", ");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object getObject() {
|
||||
return myTypeItems.get(0).getObject();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getLookupString() {
|
||||
return myLookupString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderElement(LookupElementPresentation presentation) {
|
||||
myTypeItems.get(0).renderElement(presentation);
|
||||
presentation.setItemText(getLookupString());
|
||||
presentation.setTailText(null);
|
||||
presentation.setTypeText(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context) {
|
||||
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
|
||||
for (int i = 0; i < myTypeItems.size(); i++) {
|
||||
CompletionUtil.emulateInsertion(context, context.getTailOffset(), myTypeItems.get(i));
|
||||
context.setTailOffset(getTail(i == myTypeItems.size() - 1).processTail(context.getEditor(), context.getTailOffset()));
|
||||
}
|
||||
context.setAddCompletionChar(false);
|
||||
|
||||
context.commitDocument();
|
||||
|
||||
PsiElement leaf = context.getFile().findElementAt(context.getTailOffset() - 1);
|
||||
if (psiElement().withParents(PsiReferenceParameterList.class, PsiJavaCodeReferenceElement.class, PsiNewExpression.class)
|
||||
.accepts(leaf)) {
|
||||
ParenthesesInsertHandler.getInstance(myHasParameters).handleInsert(context, this);
|
||||
myGlobalTail.processTail(context.getEditor(), context.getTailOffset());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
TypeArgsLookupElement element = (TypeArgsLookupElement)o;
|
||||
|
||||
if (!myTypeItems.equals(element.myTypeItems)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myTypeItems.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
class HashMap<T,V> {}
|
||||
import java.util.HashMap;
|
||||
|
||||
public class A {
|
||||
private HashMap<String, String> m = new HashMap<String, String><caret>();
|
||||
private HashMap<String, String> m = new HashMap<String, String>(<caret>);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class HashMap<T,V> {}
|
||||
import java.util.HashMap;
|
||||
|
||||
public class A {
|
||||
private HashMap<String, String> m = new HashMap<<caret>>();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
class Test<T> {
|
||||
Test<String> test = new Test<String><caret>
|
||||
Test<String> test = new Test<String>();<caret>
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
class AAAAA<K,V>{
|
||||
AAAAA<K,V> asd = new AAAAA<K, V><caret>
|
||||
AAAAA<K,V> asd = new AAAAA<K, V>();<caret>
|
||||
}
|
||||
Reference in New Issue
Block a user