Java tutorial
/* * Copyright 2000-2009 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.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.LangBundle; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.*; import com.intellij.psi.filters.ClassFilter; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.filters.element.ExcludeDeclaredFilter; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import java.util.List; import static com.intellij.patterns.PsiJavaPatterns.psiElement; /** * @author peter */ public class JavaClassNameCompletionContributor extends CompletionContributor { public static final PsiElementPattern.Capture<PsiElement> AFTER_NEW = psiElement().afterLeaf(PsiKeyword.NEW); private static final PsiElementPattern.Capture<PsiElement> IN_TYPE_PARAMETER = psiElement() .afterLeaf(PsiKeyword.EXTENDS, PsiKeyword.SUPER, "&") .withParent(psiElement(PsiReferenceList.class).withParent(PsiTypeParameter.class)); @Override public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet _result) { if (parameters.getCompletionType() == CompletionType.CLASS_NAME || parameters.isExtendedCompletion() && mayContainClassName(parameters)) { addAllClasses(parameters, _result); } } static void addAllClasses(CompletionParameters parameters, final CompletionResultSet _result) { CompletionResultSet result = _result .withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters)); addAllClasses(parameters, parameters.getInvocationCount() <= 1, result.getPrefixMatcher(), _result); } private static boolean mayContainClassName(CompletionParameters parameters) { PsiElement position = parameters.getPosition(); PsiFile file = position.getContainingFile(); if (file instanceof PsiPlainTextFile || file.getFileType() instanceof CustomSyntaxTableFileType) { return true; } if (SkipAutopopupInStrings.isInStringLiteral(position)) { return true; } if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) { return true; } return false; } public static void addAllClasses(CompletionParameters parameters, final boolean filterByScope, @NotNull final PrefixMatcher matcher, @NotNull final Consumer<LookupElement> consumer) { final PsiElement insertedElement = parameters.getPosition(); final ElementFilter filter = IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : TrueFilter.INSTANCE; final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; final boolean afterNew = AFTER_NEW.accepts(insertedElement); if (afterNew) { final PsiExpression expr = PsiTreeUtil.getContextOfType(insertedElement, PsiExpression.class, true); for (final ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(expr, true)) { final PsiType type = info.getType(); final PsiClass psiClass = PsiUtil.resolveClassInType(type); if (psiClass != null) { consumer.consume(createClassLookupItem(psiClass, inJavaContext)); } final PsiType defaultType = info.getDefaultType(); if (!defaultType.equals(type)) { final PsiClass defClass = PsiUtil.resolveClassInType(defaultType); if (defClass != null) { consumer.consume(createClassLookupItem(defClass, true)); } } } } final boolean pkgContext = JavaCompletionUtil.inSomePackage(insertedElement); AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer<PsiClass>() { @Override public void consume(PsiClass psiClass) { if (filter.isAcceptable(psiClass, insertedElement)) { if (!inJavaContext) { consumer.consume( AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING)); } else { for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew, JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition<PsiClass>() { @Override public boolean value(PsiClass psiClass) { return filter.isAcceptable(psiClass, insertedElement) && AllClassesGetter.isAcceptableInContext(insertedElement, psiClass, filterByScope, pkgContext); } })) { consumer.consume(element); } } } } }); } public static JavaPsiClassReferenceElement createClassLookupItem(final PsiClass psiClass, final boolean inJavaContext) { return AllClassesGetter.createLookupItem(psiClass, inJavaContext ? JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER : AllClassesGetter.TRY_SHORTENING); } public static List<JavaPsiClassReferenceElement> createClassLookupItems(final PsiClass psiClass, boolean withInners, InsertHandler<JavaPsiClassReferenceElement> insertHandler, Condition<PsiClass> condition) { List<JavaPsiClassReferenceElement> result = new SmartList<JavaPsiClassReferenceElement>(); if (condition.value(psiClass)) { result.add(AllClassesGetter.createLookupItem(psiClass, insertHandler)); } String name = psiClass.getName(); if (withInners && name != null) { for (PsiClass inner : psiClass.getInnerClasses()) { if (inner.hasModifierProperty(PsiModifier.STATIC)) { for (JavaPsiClassReferenceElement lookupInner : createClassLookupItems(inner, withInners, insertHandler, condition)) { String forced = lookupInner.getForcedPresentableName(); lookupInner .setForcedPresentableName(name + "." + (forced != null ? forced : inner.getName())); result.add(lookupInner); } } } } return result; } @Override public String handleEmptyLookup(@NotNull final CompletionParameters parameters, final Editor editor) { if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null; if (shouldShowSecondSmartCompletionHint(parameters)) { return LangBundle.message("completion.no.suggestions") + "; " + StringUtil.decapitalize(CompletionBundle .message("completion.class.name.hint.2", getActionShortcut(IdeActions.ACTION_CODE_COMPLETION))); } return null; } private static boolean shouldShowSecondSmartCompletionHint(final CompletionParameters parameters) { return parameters.getCompletionType() == CompletionType.BASIC && parameters.getInvocationCount() == 2 && parameters.getOriginalFile().getLanguage().isKindOf(JavaLanguage.INSTANCE); } }