2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.codeInsight
.completion
;
18 import com
.intellij
.codeInsight
.ExpectedTypeInfo
;
19 import com
.intellij
.codeInsight
.lookup
.LookupElement
;
20 import com
.intellij
.openapi
.util
.Comparing
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.filters
.ElementFilter
;
23 import com
.intellij
.psi
.search
.searches
.DeepestSuperMethodsSearch
;
24 import com
.intellij
.psi
.util
.PsiTreeUtil
;
25 import org
.jetbrains
.annotations
.NotNull
;
30 public class RecursionWeigher
extends CompletionWeigher
{
34 passingObjectToItself
,
39 public Result
weigh(@NotNull final LookupElement element
, final CompletionLocation location
) {
40 if (location
.getCompletionType() != CompletionType
.BASIC
&& location
.getCompletionType() != CompletionType
.SMART
) return Result
.normal
;
42 final Object object
= element
.getObject();
43 if (!(object
instanceof PsiModifierListOwner
) && !(object
instanceof PsiExpression
)) return Result
.normal
;
45 final PsiMethod positionMethod
= JavaCompletionUtil
.POSITION_METHOD
.getValue(location
);
46 if (positionMethod
== null) return Result
.normal
;
48 final PsiElement position
= location
.getCompletionParameters().getPosition();
49 final ElementFilter filter
= JavaCompletionUtil
.recursionFilter(position
);
50 if (filter
!= null && !filter
.isAcceptable(object
, position
)) {
51 return Result
.recursive
;
54 final PsiMethodCallExpression expression
= PsiTreeUtil
.getParentOfType(position
, PsiMethodCallExpression
.class, true, PsiClass
.class);
55 final PsiReferenceExpression reference
= expression
!= null ? expression
.getMethodExpression() : PsiTreeUtil
.getParentOfType(position
, PsiReferenceExpression
.class);
56 if (reference
== null) return Result
.normal
;
58 final PsiExpression qualifier
= reference
.getQualifierExpression();
59 boolean isDelegate
= qualifier
!= null && !(qualifier
instanceof PsiThisExpression
);
61 if (isPassingObjectToItself(object
, qualifier
, isDelegate
)) {
62 return Result
.passingObjectToItself
;
65 if (expression
!= null) {
66 final ExpectedTypeInfo
[] expectedInfos
= JavaCompletionUtil
.EXPECTED_TYPES
.getValue(location
);
67 if (expectedInfos
!= null) {
68 final PsiType itemType
= JavaCompletionUtil
.getLookupElementType(element
);
69 if (itemType
!= null) {
70 for (final ExpectedTypeInfo expectedInfo
: expectedInfos
) {
71 if (positionMethod
.equals(expectedInfo
.getCalledMethod()) && expectedInfo
.getType().isAssignableFrom(itemType
)) {
72 return isDelegate ? Result
.delegation
: Result
.recursive
;
80 if (object
instanceof PsiMethod
) {
81 final PsiMethod method
= (PsiMethod
)object
;
82 if (PsiTreeUtil
.isAncestor(reference
, position
, false) &&
83 Comparing
.equal(method
.getName(), positionMethod
.getName()) &&
84 method
.getParameterList().getParametersCount() == positionMethod
.getParameterList().getParametersCount()) {
85 if (findDeepestSuper(method
).equals(findDeepestSuper(positionMethod
))) {
86 return isDelegate ? Result
.delegation
: Result
.recursive
;
94 private static boolean isPassingObjectToItself(Object object
, PsiExpression qualifier
, boolean delegate
) {
95 if (object
instanceof PsiThisExpression
) {
96 return !delegate
|| qualifier
instanceof PsiSuperExpression
;
98 return qualifier
instanceof PsiReferenceExpression
&&
99 object
.equals(((PsiReferenceExpression
)qualifier
).advancedResolve(true).getElement());
103 private static PsiMethod
findDeepestSuper(@NotNull final PsiMethod method
) {
104 final PsiMethod first
= DeepestSuperMethodsSearch
.search(method
).findFirst();
105 return first
== null ? method
: first
;