diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index acb62b5a201a..82740b64a4b1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -18,10 +18,13 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementWeigher; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; +import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -50,17 +53,96 @@ public class JavaCompletionSorting { } }); } + sorter = sorter.weighAfter("negativeStats", new PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(type)); if (!smart) { sorter = preferStatics(sorter, position); } if (smart) { sorter = sorter.weighAfter("negativeStats", new PreferDefaultTypeWeigher(expectedTypes, parameters)); } - + sorter = recursion(sorter, parameters, expectedTypes); return result.withRelevanceSorter(sorter); } + enum Result { + delegation, + normal, + passingObjectToItself, + recursive, + } + static CompletionSorter recursion(CompletionSorter sorter, CompletionParameters parameters, final ExpectedTypeInfo[] expectedInfos) { + + final PsiElement position = parameters.getPosition(); + final PsiMethod positionMethod = PsiTreeUtil.getParentOfType(position, PsiMethod.class, false); + final ElementFilter filter = JavaCompletionUtil.recursionFilter(position); + final PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(position, PsiMethodCallExpression.class, true, PsiClass.class); + final PsiReferenceExpression reference = expression != null ? expression.getMethodExpression() : PsiTreeUtil.getParentOfType(position, PsiReferenceExpression.class); + //if (reference == null) return sorter; + + return sorter.weighAfter("local", new LookupElementWeigher("recursion") { + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + if (!(object instanceof PsiMethod || object instanceof PsiVariable || object instanceof PsiExpression)) return Result.normal; + + if (filter != null && !filter.isAcceptable(object, position)) { + return Result.recursive; + } + + if (reference == null) return Result.normal; + + final PsiExpression qualifier = reference.getQualifierExpression(); + boolean isDelegate = qualifier != null && !(qualifier instanceof PsiThisExpression); + + if (isPassingObjectToItself(object, qualifier, isDelegate)) { + return Result.passingObjectToItself; + } + + if (expression != null && positionMethod != null) { + if (expectedInfos != null) { + final PsiType itemType = JavaCompletionUtil.getLookupElementType(element); + if (itemType != null) { + for (final ExpectedTypeInfo expectedInfo : expectedInfos) { + if (positionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) { + return isDelegate ? Result.delegation : Result.recursive; + } + } + } + } + return Result.normal; + } + + if (object instanceof PsiMethod && positionMethod != null) { + final PsiMethod method = (PsiMethod)object; + if (PsiTreeUtil.isAncestor(reference, position, false) && + Comparing.equal(method.getName(), positionMethod.getName())) { + if (!isDelegate && findDeepestSuper(method).equals(findDeepestSuper(positionMethod))) { + return Result.recursive; + } + return Result.delegation; + } + } + + return Result.normal; + } + + private boolean isPassingObjectToItself(Object object, PsiExpression qualifier, boolean delegate) { + if (object instanceof PsiThisExpression) { + return !delegate || qualifier instanceof PsiSuperExpression; + } + return qualifier instanceof PsiReferenceExpression && + object.equals(((PsiReferenceExpression)qualifier).advancedResolve(true).getElement()); + } + + @NotNull + private PsiMethod findDeepestSuper(@NotNull final PsiMethod method) { + final PsiMethod first = DeepestSuperMethodsSearch.search(method).findFirst(); + return first == null ? method : first; + } + }); + } static CompletionSorter preferStatics(CompletionSorter sorter, PsiElement position) { if (PsiTreeUtil.getParentOfType(position, PsiDocComment.class) != null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java index c8a837d1177a..7529eb848e53 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java @@ -16,38 +16,47 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementWeigher; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; /** * @author peter */ -public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends CompletionWeigher { +public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupElementWeigher { + private final CompletionType myCompletionType; - enum MyResult { - className, - classLiteral, - normal, - superMethodParameters, - localOrParameter, - annoMethod, + public PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(CompletionType completionType) { + super("local"); + myCompletionType = completionType; } - public MyResult weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { + enum MyResult { + annoMethod, + localOrParameter, + superMethodParameters, + normal, + classLiteral, + className, + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement item) { final Object object = item.getObject(); if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) { return MyResult.localOrParameter; } - if (location.getCompletionType() == CompletionType.SMART) { + if (myCompletionType == CompletionType.SMART) { if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) { return MyResult.superMethodParameters; } return MyResult.normal; } - if (location.getCompletionType() == CompletionType.BASIC) { + if (myCompletionType == CompletionType.BASIC) { if (object instanceof PsiKeyword && PsiKeyword.CLASS.equals(item.getLookupString())) { return MyResult.classLiteral; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java deleted file mode 100644 index c481bd86145b..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.lookup.LookupElement; -import com.intellij.openapi.util.Comparing; -import com.intellij.psi.*; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter - */ -public class RecursionWeigher extends CompletionWeigher { - - private enum Result { - recursive, - passingObjectToItself, - normal, - delegation, - } - - public Result weigh(@NotNull final LookupElement element, @NotNull final CompletionLocation location) { - if (location.getCompletionType() != CompletionType.BASIC && location.getCompletionType() != CompletionType.SMART) return Result.normal; - - final Object object = element.getObject(); - if (!(object instanceof PsiMethod || object instanceof PsiVariable || object instanceof PsiExpression)) return Result.normal; - - final PsiMethod positionMethod = JavaCompletionUtil.POSITION_METHOD.getValue(location); - - final PsiElement position = location.getCompletionParameters().getPosition(); - final ElementFilter filter = JavaCompletionUtil.recursionFilter(position); - if (filter != null && !filter.isAcceptable(object, position)) { - return Result.recursive; - } - - final PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(position, PsiMethodCallExpression.class, true, PsiClass.class); - final PsiReferenceExpression reference = expression != null ? expression.getMethodExpression() : PsiTreeUtil.getParentOfType(position, PsiReferenceExpression.class); - if (reference == null) return Result.normal; - - final PsiExpression qualifier = reference.getQualifierExpression(); - boolean isDelegate = qualifier != null && !(qualifier instanceof PsiThisExpression); - - if (isPassingObjectToItself(object, qualifier, isDelegate)) { - return Result.passingObjectToItself; - } - - if (expression != null && positionMethod != null) { - final ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location); - if (expectedInfos != null) { - final PsiType itemType = JavaCompletionUtil.getLookupElementType(element); - if (itemType != null) { - for (final ExpectedTypeInfo expectedInfo : expectedInfos) { - if (positionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) { - return isDelegate ? Result.delegation : Result.recursive; - } - } - } - } - return Result.normal; - } - - if (object instanceof PsiMethod && positionMethod != null) { - final PsiMethod method = (PsiMethod)object; - if (PsiTreeUtil.isAncestor(reference, position, false) && - Comparing.equal(method.getName(), positionMethod.getName())) { - if (!isDelegate && findDeepestSuper(method).equals(findDeepestSuper(positionMethod))) { - return Result.recursive; - } - return RecursionWeigher.Result.delegation; - } - } - - return Result.normal; - } - - private static boolean isPassingObjectToItself(Object object, PsiExpression qualifier, boolean delegate) { - if (object instanceof PsiThisExpression) { - return !delegate || qualifier instanceof PsiSuperExpression; - } - return qualifier instanceof PsiReferenceExpression && - object.equals(((PsiReferenceExpression)qualifier).advancedResolve(true).getElement()); - } - - @NotNull - private static PsiMethod findDeepestSuper(@NotNull final PsiMethod method) { - final PsiMethod first = DeepestSuperMethodsSearch.search(method).findFirst(); - return first == null ? method : first; - } -} diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index a4a86907e1ff..b232f1ff6e19 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -803,12 +803,8 @@ - - + order="after negativeStats"/>