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 c2ce0ef0da3e..15ec279dcd43 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -20,16 +20,13 @@ import com.intellij.codeInsight.ExpectedTypeInfoImpl; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementWeigher; import com.intellij.codeInsight.lookup.PsiTypeLookupItem; -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.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -85,15 +82,12 @@ public class JavaCompletionSorting { @Nullable private static LookupElementWeigher recursion(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 null; - return new RecursionWeigher(filter, position, reference, expression, positionMethod, expectedInfos); + return new RecursionWeigher(position, reference, expression, expectedInfos); } @Nullable @@ -315,96 +309,6 @@ public class JavaCompletionSorting { } - private static class RecursionWeigher extends LookupElementWeigher { - private final ElementFilter myFilter; - private final PsiElement myPosition; - private final PsiReferenceExpression myReference; - private final PsiMethodCallExpression myExpression; - private final PsiMethod myPositionMethod; - private final ExpectedTypeInfo[] myExpectedInfos; - private final PsiExpression myQualifier; - private final boolean myDelegate; - - public RecursionWeigher(ElementFilter filter, - PsiElement position, - @NotNull PsiReferenceExpression reference, - PsiMethodCallExpression expression, - PsiMethod positionMethod, ExpectedTypeInfo[] expectedInfos) { - super("recursion"); - myFilter = filter; - myPosition = position; - myReference = reference; - myExpression = expression; - myPositionMethod = positionMethod; - myExpectedInfos = expectedInfos; - myQualifier = myReference.getQualifierExpression(); - myDelegate = myQualifier != null && !(myQualifier instanceof PsiThisExpression); - } - - private enum Result { - delegation, - normal, - passingObjectToItself, - recursive, - } - - @NotNull - @Override - public Result weigh(@NotNull LookupElement element) { - final Object object = element.getObject(); - if (!(object instanceof PsiMethod || object instanceof PsiVariable || object instanceof PsiExpression)) return Result.normal; - - if (myFilter != null && !myFilter.isAcceptable(object, myPosition)) { - return Result.recursive; - } - - if (isPassingObjectToItself(object)) { - return Result.passingObjectToItself; - } - - if (myExpression != null && myPositionMethod != null) { - if (myExpectedInfos != null) { - final PsiType itemType = JavaCompletionUtil.getLookupElementType(element); - if (itemType != null) { - for (final ExpectedTypeInfo expectedInfo : myExpectedInfos) { - if (myPositionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) { - return myDelegate ? Result.delegation : Result.recursive; - } - } - } - } - return Result.normal; - } - - if (object instanceof PsiMethod && myPositionMethod != null) { - final PsiMethod method = (PsiMethod)object; - if (PsiTreeUtil.isAncestor(myReference, myPosition, false) && - Comparing.equal(method.getName(), myPositionMethod.getName())) { - if (!myDelegate && findDeepestSuper(method).equals(findDeepestSuper(myPositionMethod))) { - return Result.recursive; - } - return Result.delegation; - } - } - - return Result.normal; - } - - private boolean isPassingObjectToItself(Object object) { - if (object instanceof PsiThisExpression) { - return !myDelegate || myQualifier instanceof PsiSuperExpression; - } - return myQualifier instanceof PsiReferenceExpression && - object.equals(((PsiReferenceExpression)myQualifier).advancedResolve(true).getElement()); - } - - @NotNull - private static PsiMethod findDeepestSuper(@NotNull final PsiMethod method) { - final PsiMethod first = DeepestSuperMethodsSearch.search(method).findFirst(); - return first == null ? method : first; - } - } - private enum ExpectedTypeMatching { ofDefaultType, expected, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 1cdfef84d0c7..3c5b21d43b46 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -677,23 +677,6 @@ public class JavaCompletionUtil { return containsMethodCalls(getQualifier(qualifier)); } - @Nullable - static ElementFilter recursionFilter(PsiElement element) { - if (PsiJavaPatterns.psiElement().afterLeaf(PsiKeyword.RETURN).inside(PsiReturnStatement.class).accepts(element)) { - return new ExcludeDeclaredFilter(ElementClassFilter.METHOD); - } - - if (PsiJavaPatterns.psiElement().inside( - PsiJavaPatterns.or( - PsiJavaPatterns.psiElement(PsiAssignmentExpression.class), - PsiJavaPatterns.psiElement(PsiVariable.class))). - andNot(PsiJavaPatterns.psiElement().afterLeaf(".")).accepts(element)) { - return new AndFilter(new ExcludeSillyAssignment(), - new ExcludeDeclaredFilter(new ClassFilter(PsiVariable.class))); - } - return null; - } - public static void insertClassReference(@NotNull PsiClass psiClass, @NotNull PsiFile file, int offset) { insertClassReference(psiClass, file, offset, offset); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java new file mode 100644 index 000000000000..26b97a1422d3 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java @@ -0,0 +1,142 @@ +/* + * Copyright 2000-2012 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.codeInsight.lookup.LookupElementWeigher; +import com.intellij.openapi.util.Comparing; +import com.intellij.patterns.PsiJavaPatterns; +import com.intellij.psi.*; +import com.intellij.psi.filters.AndFilter; +import com.intellij.psi.filters.ClassFilter; +import com.intellij.psi.filters.ElementFilter; +import com.intellij.psi.filters.element.ExcludeDeclaredFilter; +import com.intellij.psi.filters.element.ExcludeSillyAssignment; +import com.intellij.psi.scope.ElementClassFilter; +import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** +* @author peter +*/ +class RecursionWeigher extends LookupElementWeigher { + private final ElementFilter myFilter; + private final PsiElement myPosition; + private final PsiReferenceExpression myReference; + @Nullable private final PsiMethodCallExpression myExpression; + private final PsiMethod myPositionMethod; + private final ExpectedTypeInfo[] myExpectedInfos; + private final PsiExpression myQualifier; + private final boolean myDelegate; + + public RecursionWeigher(PsiElement position, + @NotNull PsiReferenceExpression reference, + PsiMethodCallExpression expression, + ExpectedTypeInfo[] expectedInfos) { + super("recursion"); + myFilter = recursionFilter(position); + myPosition = position; + myReference = reference; + myExpression = expression; + myPositionMethod = PsiTreeUtil.getParentOfType(position, PsiMethod.class, false); + myExpectedInfos = expectedInfos; + myQualifier = myReference.getQualifierExpression(); + myDelegate = myQualifier != null && !(myQualifier instanceof PsiThisExpression); + } + + @Nullable + static ElementFilter recursionFilter(PsiElement element) { + if (PsiJavaPatterns.psiElement().afterLeaf(PsiKeyword.RETURN).inside(PsiReturnStatement.class).accepts(element)) { + return new ExcludeDeclaredFilter(ElementClassFilter.METHOD); + } + + if (PsiJavaPatterns.psiElement().inside( + PsiJavaPatterns.or( + PsiJavaPatterns.psiElement(PsiAssignmentExpression.class), + PsiJavaPatterns.psiElement(PsiVariable.class))). + andNot(PsiJavaPatterns.psiElement().afterLeaf(".")).accepts(element)) { + return new AndFilter(new ExcludeSillyAssignment(), + new ExcludeDeclaredFilter(new ClassFilter(PsiVariable.class))); + } + return null; + } + + private enum Result { + delegation, + normal, + passingObjectToItself, + recursive, + } + + @NotNull + @Override + public Result weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + if (!(object instanceof PsiMethod || object instanceof PsiVariable || object instanceof PsiExpression)) return Result.normal; + + if (myFilter != null && !myFilter.isAcceptable(object, myPosition)) { + return Result.recursive; + } + + if (isPassingObjectToItself(object)) { + return Result.passingObjectToItself; + } + + if (myExpression != null && myPositionMethod != null) { + if (myExpectedInfos != null) { + final PsiType itemType = JavaCompletionUtil.getLookupElementType(element); + if (itemType != null) { + for (final ExpectedTypeInfo expectedInfo : myExpectedInfos) { + if (myPositionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) { + return myDelegate ? Result.delegation : Result.recursive; + } + } + } + } + return Result.normal; + } + + if (object instanceof PsiMethod && myPositionMethod != null) { + final PsiMethod method = (PsiMethod)object; + if (PsiTreeUtil.isAncestor(myReference, myPosition, false) && + Comparing.equal(method.getName(), myPositionMethod.getName())) { + if (!myDelegate && findDeepestSuper(method).equals(findDeepestSuper(myPositionMethod))) { + return Result.recursive; + } + return Result.delegation; + } + } + + return Result.normal; + } + + private boolean isPassingObjectToItself(Object object) { + if (object instanceof PsiThisExpression) { + return !myDelegate || myQualifier instanceof PsiSuperExpression; + } + return myQualifier instanceof PsiReferenceExpression && + object.equals(((PsiReferenceExpression)myQualifier).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/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index d6ef6a873f5a..52da4c0f460f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -97,7 +97,7 @@ public class ReferenceExpressionCompletionContributor { } if (!allowRecursion) { - final ElementFilter filter = JavaCompletionUtil.recursionFilter(element); + final ElementFilter filter = RecursionWeigher.recursionFilter(element); if (filter != null) { return new ElementExtractorFilter(filter); }