blob: 456c06fe87567fbeba7c2b8e1d2e8c1087955e04 [file] [log] [blame]
/*
* Copyright 2000-2014 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.*;
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.MethodSignature;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.psi.util.PsiTreeUtil;
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.Collections;
import java.util.List;
import java.util.Set;
import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* @author peter
*/
public class JavaGenerateMemberCompletionContributor {
static final Key<Boolean> GENERATE_ELEMENT = Key.create("GENERATE_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) {
Set<MethodSignature> addedSignatures = ContainerUtil.newHashSet();
addGetterSetterElements(result, parent, addedSignatures);
addSuperSignatureElements(parent, true, result, addedSignatures);
addSuperSignatureElements(parent, false, result, addedSignatures);
}
}
}
private static void addGetterSetterElements(CompletionResultSet result, PsiClass parent, Set<MethodSignature> addedSignatures) {
List<PsiMethod> prototypes = ContainerUtil.newArrayList();
for (PsiField field : parent.getFields()) {
if (!(field instanceof PsiEnumConstant)) {
Collections.addAll(prototypes, GetterSetterPrototypeProvider.generateGetterSetters(field, true));
Collections.addAll(prototypes, GetterSetterPrototypeProvider.generateGetterSetters(field, false));
}
}
for (final PsiMethod prototype : prototypes) {
if (parent.findMethodBySignature(prototype, false) == null && addedSignatures.add(prototype.getSignature(PsiSubstitutor.EMPTY))) {
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, Set<MethodSignature> addedSignatures) {
for (CandidateInfo candidate : OverrideImplementExploreUtil.getMethodsToOverrideImplement(parent, implemented)) {
PsiMethod baseMethod = (PsiMethod)candidate.getElement();
PsiClass baseClass = baseMethod.getContainingClass();
PsiSubstitutor substitutor = candidate.getSubstitutor();
if (!baseMethod.isConstructor() && baseClass != null && addedSignatures.add(baseMethod.getSignature(substitutor))) {
result.addElement(createOverridingLookupElement(implemented, baseMethod, baseClass, substitutor));
}
}
}
private static LookupElementBuilder createOverridingLookupElement(boolean implemented,
final PsiMethod baseMethod,
PsiClass baseClass, PsiSubstitutor substitutor) {
RowIcon icon = new RowIcon(2);
icon.setIcon(baseMethod.getIcon(0), 0);
icon.setIcon(implemented ? AllIcons.Gutter.ImplementingMethod : AllIcons.Gutter.OverridingMethod, 1);
return createGenerateMethodElement(baseMethod, substitutor, icon, baseClass.getName(), new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
removeLookupString(context);
final PsiClass parent = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiClass.class, false);
if (parent == null) return;
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(typeText).withIcon(icon);
element.putUserData(GENERATE_ELEMENT, true);
return element;
}
}