IDEA-105093 Eclipse-way getter/setter completion

This commit is contained in:
peter
2013-07-18 17:09:32 +02:00
parent 61b5e0c7fa
commit 7839f1c478
5 changed files with 105 additions and 136 deletions
@@ -22,14 +22,19 @@ import com.intellij.codeInsight.generation.PsiGenerationInfo;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.ui.RowIcon;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.ContainerUtil;
import javax.swing.*;
import java.util.Arrays;
import java.util.List;
import static com.intellij.patterns.PlatformPatterns.psiElement;
@@ -51,6 +56,7 @@ public class JavaGenerateMemberCompletionContributor {
andNot(psiElement().afterLeaf(psiElement().inside(PsiModifierList.class))).accepts(position)) {
final PsiClass parent = CompletionUtil.getOriginalElement((PsiClass)position.getParent().getParent().getParent());
if (parent != null) {
addGetterSetterElements(result, parent);
addSuperSignatureElements(parent, true, result);
addSuperSignatureElements(parent, false, result);
}
@@ -58,9 +64,38 @@ public class JavaGenerateMemberCompletionContributor {
}
private static void addGetterSetterElements(CompletionResultSet result, PsiClass parent) {
List<PsiMethod> prototypes = ContainerUtil.newArrayList();
for (PsiField field : parent.getFields()) {
if (!(field instanceof PsiEnumConstant)) {
prototypes.add(PropertyUtil.generateGetterPrototype(field));
prototypes.add(PropertyUtil.generateSetterPrototype(field));
}
}
for (final PsiMethod prototype : prototypes) {
if (parent.findMethodBySignature(prototype, false) == null) {
Icon icon = prototype.getIcon(Iconable.ICON_FLAG_VISIBILITY);
result.addElement(createGenerateMethodElement(prototype, PsiSubstitutor.EMPTY, icon, "", new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
removeLookupString(context);
insertGenerationInfos(context, Arrays.asList(new PsiGenerationInfo<PsiMethod>(prototype)));
}
}));
}
}
}
private static void removeLookupString(InsertionContext context) {
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
context.commitDocument();
}
private static void addSuperSignatureElements(final PsiClass parent, boolean implemented, CompletionResultSet result) {
for (CandidateInfo candidate : OverrideImplementExploreUtil.getMethodsToOverrideImplement(parent, implemented)) {
PsiMethod baseMethod = (PsiMethod)candidate.getElement();
assert baseMethod != null;
PsiClass baseClass = baseMethod.getContainingClass();
if (!baseMethod.isConstructor() && baseClass != null) {
result.addElement(createOverridingLookupElement(parent, implemented, baseMethod, baseClass, candidate.getSubstitutor()));
@@ -72,38 +107,47 @@ public class JavaGenerateMemberCompletionContributor {
boolean implemented,
final PsiMethod baseMethod,
PsiClass baseClass, PsiSubstitutor substitutor) {
String methodName = baseMethod.getName();
String visibility = VisibilityUtil.getVisibilityModifier(baseMethod.getModifierList());
String modifiers = (visibility == PsiModifier.PACKAGE_LOCAL ? "" : visibility + " ");
PsiType type = substitutor.substitute(baseMethod.getReturnType());
String signature = modifiers + (type == null ? "" : type.getPresentableText() + " ") + methodName;
String parameters = PsiFormatUtil.formatMethod(baseMethod, substitutor, PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_NAME);
InsertHandler<LookupElement> insertHandler = new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
context.commitDocument();
List<PsiMethod> prototypes = OverrideImplementUtil.overrideOrImplementMethod(parent, baseMethod, false);
List<PsiGenerationInfo<PsiMethod>> infos = OverrideImplementUtil.convert2GenerationInfos(prototypes);
List<PsiGenerationInfo<PsiMethod>> newInfos = GenerateMembersUtil.insertMembersAtOffset(context.getFile(), context.getStartOffset(), infos);
if (!newInfos.isEmpty()) {
newInfos.get(0).positionCaret(context.getEditor(), true);
}
}
};
RowIcon icon = new RowIcon(2);
icon.setIcon(baseMethod.getIcon(0), 0);
icon.setIcon(implemented ? AllIcons.Gutter.ImplementingMethod : AllIcons.Gutter.OverridingMethod, 1);
LookupElementBuilder element = LookupElementBuilder.create(baseMethod, signature).withLookupString(methodName).
return createGenerateMethodElement(baseMethod, substitutor, icon, baseClass.getName(), new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
removeLookupString(context);
List<PsiMethod> prototypes = OverrideImplementUtil.overrideOrImplementMethod(parent, baseMethod, false);
insertGenerationInfos(context, OverrideImplementUtil.convert2GenerationInfos(prototypes));
}
});
}
private static void insertGenerationInfos(InsertionContext context, List<PsiGenerationInfo<PsiMethod>> infos) {
List<PsiGenerationInfo<PsiMethod>> newInfos = GenerateMembersUtil
.insertMembersAtOffset(context.getFile(), context.getStartOffset(), infos);
if (!newInfos.isEmpty()) {
newInfos.get(0).positionCaret(context.getEditor(), true);
}
}
private static LookupElementBuilder createGenerateMethodElement(PsiMethod prototype,
PsiSubstitutor substitutor,
Icon icon,
String typeText, InsertHandler<LookupElement> insertHandler) {
String methodName = prototype.getName();
String visibility = VisibilityUtil.getVisibilityModifier(prototype.getModifierList());
String modifiers = (visibility == PsiModifier.PACKAGE_LOCAL ? "" : visibility + " ");
PsiType type = substitutor.substitute(prototype.getReturnType());
String signature = modifiers + (type == null ? "" : type.getPresentableText() + " ") + methodName;
String parameters = PsiFormatUtil.formatMethod(prototype, substitutor, PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_NAME);
LookupElementBuilder element = LookupElementBuilder.create(prototype, signature).withLookupString(methodName).
withLookupString(signature).withInsertHandler(insertHandler).
appendTailText(parameters, false).appendTailText(" {...}", true).withTypeText(baseClass.getName()).withIcon(icon);
appendTailText(parameters, false).appendTailText(" {...}", true).withTypeText(typeText).withIcon(icon);
element.putUserData(GENERATE_ELEMENT, true);
return element;
}
@@ -1,110 +0,0 @@
/*
* Copyright 2000-2013 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 com.intellij.codeInsight.completion;
import com.intellij.codeInsight.generation.GenerateMembersUtil;
import com.intellij.codeInsight.generation.OverrideImplementExploreUtil;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.codeInsight.generation.PsiGenerationInfo;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.ui.RowIcon;
import com.intellij.util.VisibilityUtil;
import java.util.List;
import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* @author peter
*/
public class JavaOverrideCompletionContributor {
static final Key<Boolean> OVERRIDE_ELEMENT = Key.create("OVERRIDE_ELEMENT");
public static void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
if (parameters.getCompletionType() != CompletionType.BASIC && parameters.getCompletionType() != CompletionType.SMART) {
return;
}
PsiElement position = parameters.getPosition();
if (psiElement(PsiIdentifier.class).withParents(PsiJavaCodeReferenceElement.class, PsiTypeElement.class, PsiClass.class).
andNot(JavaCompletionData.AFTER_DOT).
andNot(psiElement().afterLeaf(psiElement().inside(PsiModifierList.class))).accepts(position)) {
final PsiClass parent = CompletionUtil.getOriginalElement((PsiClass)position.getParent().getParent().getParent());
if (parent != null) {
addSuperSignatureElements(parent, true, result);
addSuperSignatureElements(parent, false, result);
}
}
}
private static void addSuperSignatureElements(final PsiClass parent, boolean implemented, CompletionResultSet result) {
for (CandidateInfo candidate : OverrideImplementExploreUtil.getMethodsToOverrideImplement(parent, implemented)) {
PsiMethod baseMethod = (PsiMethod)candidate.getElement();
PsiClass baseClass = baseMethod.getContainingClass();
if (!baseMethod.isConstructor() && baseClass != null) {
result.addElement(createOverridingLookupElement(parent, implemented, baseMethod, baseClass, candidate.getSubstitutor()));
}
}
}
private static LookupElementBuilder createOverridingLookupElement(final PsiClass parent,
boolean implemented,
final PsiMethod baseMethod,
PsiClass baseClass, PsiSubstitutor substitutor) {
String methodName = baseMethod.getName();
String visibility = VisibilityUtil.getVisibilityModifier(baseMethod.getModifierList());
String modifiers = (visibility == PsiModifier.PACKAGE_LOCAL ? "" : visibility + " ");
PsiType type = substitutor.substitute(baseMethod.getReturnType());
String signature = modifiers + (type == null ? "" : type.getPresentableText() + " ") + methodName;
String parameters = PsiFormatUtil.formatMethod(baseMethod, substitutor, PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_NAME);
InsertHandler<LookupElement> insertHandler = new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
context.commitDocument();
List<PsiMethod> prototypes = OverrideImplementUtil.overrideOrImplementMethod(parent, baseMethod, false);
List<PsiGenerationInfo<PsiMethod>> infos = OverrideImplementUtil.convert2GenerationInfos(prototypes);
List<PsiGenerationInfo<PsiMethod>> newInfos = GenerateMembersUtil.insertMembersAtOffset(context.getFile(), context.getStartOffset(), infos);
if (!newInfos.isEmpty()) {
newInfos.get(0).positionCaret(context.getEditor(), true);
}
}
};
RowIcon icon = new RowIcon(2);
icon.setIcon(baseMethod.getIcon(0), 0);
icon.setIcon(implemented ? AllIcons.Gutter.ImplementingMethod : AllIcons.Gutter.OverridingMethod, 1);
LookupElementBuilder element = LookupElementBuilder.create(baseMethod, signature).withLookupString(methodName).
withLookupString(signature).withInsertHandler(insertHandler).
appendTailText(parameters, false).appendTailText(" {...}", true).withTypeText(baseClass.getName()).withIcon(icon);
element.putUserData(OVERRIDE_ELEMENT, true);
return element;
}
}
@@ -0,0 +1,5 @@
public class A {
int field;
publ<caret>
}
@@ -0,0 +1,7 @@
public class A {
int field;
public int getField() {
<caret><selection>return field;</selection>
}
}
@@ -1325,6 +1325,29 @@ class XInternalError {}
checkResult()
}
public void testAccessorViaCompletion() {
configure()
def getter = myFixture.lookupElements.find { it.lookupString == 'public int getField' }
def setter = myFixture.lookupElements.find { it.lookupString == 'public void setField' }
assert getter : myFixture.lookupElementStrings
assert setter : myFixture.lookupElementStrings
def p = LookupElementPresentation.renderElement(getter)
assert p.itemText == getter.lookupString
assert p.tailText == '() {...}'
assert !p.typeText
p = LookupElementPresentation.renderElement(setter)
assert p.itemText == setter.lookupString
assert p.tailText == '(field) {...}'
assert !p.typeText
lookup.currentItem = getter
myFixture.type('\n')
checkResult()
}
public void testBraceOnNextLine() {
codeStyleSettings.BRACE_STYLE = CommonCodeStyleSettings.NEXT_LINE
doTest()