IDEA-89099 IDEA misses some types in code completion in "try" construct

This commit is contained in:
peter
2012-07-20 17:20:22 +02:00
parent b10a4f2471
commit 4dee0cff9d
7 changed files with 214 additions and 180 deletions
@@ -43,11 +43,9 @@ import com.intellij.psi.filters.classes.AssignableFromContextFilter;
import com.intellij.psi.filters.element.ExcludeDeclaredFilter;
import com.intellij.psi.filters.element.ModifierFilter;
import com.intellij.psi.filters.getters.ExpectedTypesGetter;
import com.intellij.psi.filters.types.AssignableFromFilter;
import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl;
import com.intellij.psi.impl.source.PsiLabelReference;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.scope.ElementClassFilter;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -106,21 +104,6 @@ public class JavaCompletionContributor extends CompletionContributor {
private static final ElementPattern<PsiElement> IMPORT_REFERENCE =
psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).withParent(PsiImportStatementBase.class));
static final ElementPattern<PsiElement> IN_CATCH_TYPE =
psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).
withParent(psiElement(PsiTypeElement.class).
withParent(or(psiElement(PsiCatchSection.class),
psiElement(PsiVariable.class).withParent(PsiCatchSection.class)))));
static final ElementPattern<PsiElement> IN_MULTI_CATCH_TYPE =
or(psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiCatchSection.class)),
psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiParameter.class).withSuperParent(3, PsiCatchSection.class)));
static final ElementPattern<PsiElement> INSIDE_METHOD_THROWS_CLAUSE =
psiElement().afterLeaf(PsiKeyword.THROWS, ",").inside(psiElement(JavaElementType.THROWS_LIST));
static final ElementPattern<PsiElement> IN_RESOURCE_TYPE =
psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).
withParent(psiElement(PsiTypeElement.class).
withParent(or(psiElement(PsiResourceVariable.class), psiElement(PsiResourceList.class)))));
@Nullable
public static ElementFilter getReferenceFilter(PsiElement position) {
// Completion after extends in interface, type parameter and implements in class
@@ -134,10 +117,6 @@ public class JavaCompletionContributor extends CompletionContributor {
return new OrFilter(ElementClassFilter.CLASS, ElementClassFilter.PACKAGE_FILTER);
}
if (INSIDE_METHOD_THROWS_CLAUSE.accepts(position)) {
return new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE);
}
if (psiElement().afterLeaf(PsiKeyword.INSTANCEOF).accepts(position)) {
return new ElementExtractorFilter(ElementClassFilter.CLASS);
}
@@ -157,18 +136,6 @@ public class JavaCompletionContributor extends CompletionContributor {
return new OrFilter(ElementClassFilter.CLASS, ElementClassFilter.VARIABLE);
}
if (IN_CATCH_TYPE.accepts(position) || IN_MULTI_CATCH_TYPE.accepts(position)) {
return new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE);
}
if (IN_RESOURCE_TYPE.accepts(position)) {
return new AssignableFromFilter(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE);
}
if (JavaSmartCompletionContributor.AFTER_THROW_NEW.accepts(position)) {
return new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE);
}
if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) {
return ElementClassFilter.CLASS;
}
@@ -62,7 +62,7 @@ public class JavaCompletionSorting {
ContainerUtil.addIfNotNull(afterNegativeStats, preferStatics(position, expectedTypes));
}
if (!JavaCompletionData.START_FOR.accepts(position)) {
afterNegativeStats.add(new PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(type, position));
afterNegativeStats.add(new PreferByKindWeigher(type, position));
}
ContainerUtil.addIfNotNull(afterNegativeStats, recursion(parameters, expectedTypes));
if (!smart && !afterNew) {
@@ -1,140 +1,179 @@
/*
* 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.completion.scope.JavaCompletionProcessor;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementWeigher;
import com.intellij.psi.*;
import com.intellij.psi.filters.getters.MembersGetter;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* @author peter
*/
public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupElementWeigher {
private final CompletionType myCompletionType;
private final PsiElement myPosition;
private final Set<PsiField> myNonInitializedFields;
public PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(CompletionType completionType, PsiElement position) {
super("local");
myCompletionType = completionType;
myPosition = position;
myNonInitializedFields = JavaCompletionProcessor.getNonInitializedFields(position);
}
enum MyResult {
annoMethod,
probableKeyword,
localOrParameter,
qualifiedWithField,
qualifiedWithGetter,
superMethodParameters,
normal,
collectionFactory,
expectedTypeMember,
nonInitialized,
classLiteral,
classNameOrGlobalStatic,
}
@NotNull
@Override
public MyResult weigh(@NotNull LookupElement item) {
final Object object = item.getObject();
if (object instanceof PsiKeyword) {
String keyword = ((PsiKeyword)object).getText();
if (PsiKeyword.RETURN.equals(keyword) && isLastStatement(PsiTreeUtil.getParentOfType(myPosition, PsiStatement.class))) {
return MyResult.probableKeyword;
}
if (PsiKeyword.ELSE.equals(keyword) || PsiKeyword.FINALLY.equals(keyword)) {
return MyResult.probableKeyword;
}
}
if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) {
return MyResult.localOrParameter;
}
if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) {
return MyResult.superMethodParameters;
}
if (myCompletionType == CompletionType.SMART) {
if (item.getUserData(CollectionsUtilityMethodsProvider.COLLECTION_FACTORY) != null) {
return MyResult.collectionFactory;
}
if (Boolean.TRUE.equals(item.getUserData(MembersGetter.EXPECTED_TYPE_INHERITOR_MEMBER))) {
return MyResult.expectedTypeMember;
}
final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY);
if (chain != null) {
Object qualifier = chain.getQualifier().getObject();
if (qualifier instanceof PsiLocalVariable || qualifier instanceof PsiParameter) {
return MyResult.localOrParameter;
}
if (qualifier instanceof PsiField) {
return MyResult.qualifiedWithField;
}
if (qualifier instanceof PsiMethod && PropertyUtil.isSimplePropertyGetter((PsiMethod)qualifier)) {
return MyResult.qualifiedWithGetter;
}
}
return MyResult.normal;
}
if (myCompletionType == CompletionType.BASIC) {
StaticallyImportable callElement = item.as(StaticallyImportable.CLASS_CONDITION_KEY);
if (callElement != null && callElement.canBeImported() && !callElement.willBeImported()) {
return MyResult.classNameOrGlobalStatic;
}
if (object instanceof PsiKeyword && PsiKeyword.CLASS.equals(item.getLookupString())) {
return MyResult.classLiteral;
}
if (object instanceof PsiAnnotationMethod && ((PsiAnnotationMethod)object).getContainingClass().isAnnotationType()) {
return MyResult.annoMethod;
}
if (object instanceof PsiClass) {
return MyResult.classNameOrGlobalStatic;
}
if (object instanceof PsiField && myNonInitializedFields.contains(object)) {
return MyResult.nonInitialized;
}
}
return MyResult.normal;
}
private static boolean isLastStatement(PsiStatement statement) {
if (statement == null || !(statement.getParent() instanceof PsiCodeBlock)) {
return true;
}
PsiStatement[] siblings = ((PsiCodeBlock)statement.getParent()).getStatements();
return statement == siblings[siblings.length - 1];
}
}
/*
* 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.completion.scope.JavaCompletionProcessor;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementWeigher;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.filters.getters.MembersGetter;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
import static com.intellij.patterns.StandardPatterns.or;
/**
* @author peter
*/
public class PreferByKindWeigher extends LookupElementWeigher {
static final ElementPattern<PsiElement> IN_CATCH_TYPE =
psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).
withParent(psiElement(PsiTypeElement.class).
withParent(or(psiElement(PsiCatchSection.class),
psiElement(PsiVariable.class).withParent(PsiCatchSection.class)))));
static final ElementPattern<PsiElement> IN_MULTI_CATCH_TYPE =
or(psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiCatchSection.class)),
psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiParameter.class).withSuperParent(3, PsiCatchSection.class)));
static final ElementPattern<PsiElement> INSIDE_METHOD_THROWS_CLAUSE =
psiElement().afterLeaf(PsiKeyword.THROWS, ",").inside(psiElement(JavaElementType.THROWS_LIST));
static final ElementPattern<PsiElement> IN_RESOURCE_TYPE =
psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).
withParent(psiElement(PsiTypeElement.class).
withParent(or(psiElement(PsiResourceVariable.class), psiElement(PsiResourceList.class)))));
private final CompletionType myCompletionType;
private final PsiElement myPosition;
private final Set<PsiField> myNonInitializedFields;
@Nullable private final String myRequiredSuper;
public PreferByKindWeigher(CompletionType completionType, PsiElement position) {
super("local");
myCompletionType = completionType;
myPosition = position;
myNonInitializedFields = JavaCompletionProcessor.getNonInitializedFields(position);
if (IN_CATCH_TYPE.accepts(position) ||
IN_MULTI_CATCH_TYPE.accepts(position) ||
JavaSmartCompletionContributor.AFTER_THROW_NEW.accepts(position) ||
INSIDE_METHOD_THROWS_CLAUSE.accepts(position)) {
myRequiredSuper = CommonClassNames.JAVA_LANG_THROWABLE;
}
else if (IN_RESOURCE_TYPE.accepts(position)) {
myRequiredSuper = CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE;
}
else {
myRequiredSuper = null;
}
}
enum MyResult {
annoMethod,
probableKeyword,
localOrParameter,
qualifiedWithField,
qualifiedWithGetter,
superMethodParameters,
normal,
collectionFactory,
expectedTypeMember,
suitableClass,
nonInitialized,
classLiteral,
classNameOrGlobalStatic,
}
@NotNull
@Override
public MyResult weigh(@NotNull LookupElement item) {
final Object object = item.getObject();
if (object instanceof PsiKeyword) {
String keyword = ((PsiKeyword)object).getText();
if (PsiKeyword.RETURN.equals(keyword) && isLastStatement(PsiTreeUtil.getParentOfType(myPosition, PsiStatement.class))) {
return MyResult.probableKeyword;
}
if (PsiKeyword.ELSE.equals(keyword) || PsiKeyword.FINALLY.equals(keyword)) {
return MyResult.probableKeyword;
}
}
if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) {
return MyResult.localOrParameter;
}
if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) {
return MyResult.superMethodParameters;
}
if (myCompletionType == CompletionType.SMART) {
if (item.getUserData(CollectionsUtilityMethodsProvider.COLLECTION_FACTORY) != null) {
return MyResult.collectionFactory;
}
if (Boolean.TRUE.equals(item.getUserData(MembersGetter.EXPECTED_TYPE_INHERITOR_MEMBER))) {
return MyResult.expectedTypeMember;
}
final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY);
if (chain != null) {
Object qualifier = chain.getQualifier().getObject();
if (qualifier instanceof PsiLocalVariable || qualifier instanceof PsiParameter) {
return MyResult.localOrParameter;
}
if (qualifier instanceof PsiField) {
return MyResult.qualifiedWithField;
}
if (qualifier instanceof PsiMethod && PropertyUtil.isSimplePropertyGetter((PsiMethod)qualifier)) {
return MyResult.qualifiedWithGetter;
}
}
return MyResult.normal;
}
if (myCompletionType == CompletionType.BASIC) {
StaticallyImportable callElement = item.as(StaticallyImportable.CLASS_CONDITION_KEY);
if (callElement != null && callElement.canBeImported() && !callElement.willBeImported()) {
return MyResult.classNameOrGlobalStatic;
}
if (object instanceof PsiKeyword && PsiKeyword.CLASS.equals(item.getLookupString())) {
return MyResult.classLiteral;
}
if (object instanceof PsiAnnotationMethod && ((PsiAnnotationMethod)object).getContainingClass().isAnnotationType()) {
return MyResult.annoMethod;
}
if (object instanceof PsiClass) {
if (myRequiredSuper != null && InheritanceUtil.isInheritor((PsiClass)object, myRequiredSuper)) {
return MyResult.suitableClass;
}
return MyResult.classNameOrGlobalStatic;
}
if (object instanceof PsiField && myNonInitializedFields.contains(object)) {
return MyResult.nonInitialized;
}
}
return MyResult.normal;
}
private static boolean isLastStatement(PsiStatement statement) {
if (statement == null || !(statement.getParent() instanceof PsiCodeBlock)) {
return true;
}
PsiStatement[] siblings = ((PsiCodeBlock)statement.getParent()).getStatements();
return statement == siblings[siblings.length - 1];
}
}