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
.usages
.impl
.rules
;
18 import com
.intellij
.psi
.*;
19 import com
.intellij
.psi
.util
.PsiTreeUtil
;
20 import com
.intellij
.psi
.util
.PsiUtil
;
21 import com
.intellij
.util
.containers
.HashSet
;
22 import org
.jetbrains
.annotations
.NotNull
;
23 import org
.jetbrains
.annotations
.Nullable
;
25 import java
.util
.Arrays
;
30 public class JavaUsageTypeProvider
implements UsageTypeProvider
{
31 public UsageType
getUsageType(final PsiElement element
) {
32 UsageType classUsageType
= getClassUsageType(element
);
33 if (classUsageType
!= null) return classUsageType
;
35 UsageType methodUsageType
= getMethodUsageType(element
);
36 if (methodUsageType
!= null) return methodUsageType
;
38 if (element
instanceof PsiLiteralExpression
) {return UsageType
.LITERAL_USAGE
; }
44 private static UsageType
getMethodUsageType(PsiElement element
) {
45 if (element
instanceof PsiReferenceExpression
) {
46 final PsiMethod containerMethod
= PsiTreeUtil
.getParentOfType(element
, PsiMethod
.class);
47 if (containerMethod
!= null) {
48 final PsiReferenceExpression referenceExpression
= (PsiReferenceExpression
)element
;
49 final PsiExpression qualifier
= referenceExpression
.getQualifierExpression();
50 final PsiElement p
= referenceExpression
.getParent();
51 if (p
instanceof PsiMethodCallExpression
) {
52 final PsiMethodCallExpression callExpression
= (PsiMethodCallExpression
)p
;
53 final PsiMethod calledMethod
= callExpression
.resolveMethod();
54 if (qualifier
!= null && !(qualifier
instanceof PsiThisExpression
) && calledMethod
!= null) {
55 if (haveCommonSuperMethod(containerMethod
, calledMethod
)) {
56 boolean parametersDelegated
= parametersDelegated(containerMethod
, callExpression
);
58 if (qualifier
instanceof PsiSuperExpression
) {
59 return parametersDelegated ? UsageType
.DELEGATE_TO_SUPER
: UsageType
.DELEGATE_TO_SUPER_PARAMETERS_CHANGED
;
62 return parametersDelegated ? UsageType
.DELEGATE_TO_ANOTHER_INSTANCE
: UsageType
.DELEGATE_TO_ANOTHER_INSTANCE_PARAMETERS_CHANGED
;
66 else if (calledMethod
== containerMethod
) {
67 return UsageType
.RECURSION
;
76 private static boolean parametersDelegated(final PsiMethod method
, final PsiMethodCallExpression call
) {
77 final PsiParameter
[] parameters
= method
.getParameterList().getParameters();
78 final PsiExpression
[] arguments
= call
.getArgumentList().getExpressions();
79 if (parameters
.length
!= arguments
.length
) return false;
81 for (int i
= 0; i
< parameters
.length
; i
++) {
82 PsiParameter parameter
= parameters
[i
];
83 PsiExpression argument
= arguments
[i
];
85 if (!(argument
instanceof PsiReferenceExpression
)) return false;
86 if (!((PsiReferenceExpression
)argument
).isReferenceTo(parameter
)) return false;
89 for (PsiParameter parameter
: parameters
) {
90 if (PsiUtil
.isAssigned(parameter
)) return false;
96 private static boolean haveCommonSuperMethod(@NotNull PsiMethod m1
, @NotNull PsiMethod m2
) {
97 HashSet
<PsiMethod
> s1
= new HashSet
<PsiMethod
>(Arrays
.asList(m1
.findDeepestSuperMethods()));
100 HashSet
<PsiMethod
> s2
= new HashSet
<PsiMethod
>(Arrays
.asList(m2
.findDeepestSuperMethods()));
104 return !s1
.isEmpty();
108 private static UsageType
getClassUsageType(PsiElement element
) {
110 if (element
.getParent() instanceof PsiAnnotation
&&
111 element
== ((PsiAnnotation
)element
.getParent()).getNameReferenceElement()) return UsageType
.ANNOTATION
;
113 if (PsiTreeUtil
.getParentOfType(element
, PsiImportStatement
.class, false) != null) return UsageType
.CLASS_IMPORT
;
114 PsiReferenceList referenceList
= PsiTreeUtil
.getParentOfType(element
, PsiReferenceList
.class);
115 if (referenceList
!= null) {
116 if (referenceList
.getParent() instanceof PsiClass
) return UsageType
.CLASS_EXTENDS_IMPLEMENTS_LIST
;
117 if (referenceList
.getParent() instanceof PsiMethod
) return UsageType
.CLASS_METHOD_THROWS_LIST
;
120 PsiTypeCastExpression castExpression
= PsiTreeUtil
.getParentOfType(element
, PsiTypeCastExpression
.class);
121 if (castExpression
!= null) {
122 if (PsiTreeUtil
.isAncestor(castExpression
.getCastType(), element
, true)) return UsageType
.CLASS_CAST_TO
;
125 PsiInstanceOfExpression instanceOfExpression
= PsiTreeUtil
.getParentOfType(element
, PsiInstanceOfExpression
.class);
126 if (instanceOfExpression
!= null) {
127 if (PsiTreeUtil
.isAncestor(instanceOfExpression
.getCheckType(), element
, true)) return UsageType
.CLASS_INSTANCE_OF
;
130 if (PsiTreeUtil
.getParentOfType(element
, PsiClassObjectAccessExpression
.class) != null) return UsageType
.CLASS_CLASS_OBJECT_ACCESS
;
132 if (element
instanceof PsiReferenceExpression
) {
133 PsiReferenceExpression expression
= (PsiReferenceExpression
)element
;
134 if (expression
.resolve() instanceof PsiClass
) {
135 return UsageType
.CLASS_STATIC_MEMBER_ACCESS
;
139 final PsiParameter psiParameter
= PsiTreeUtil
.getParentOfType(element
, PsiParameter
.class);
140 if (psiParameter
!= null) {
141 final PsiElement scope
= psiParameter
.getDeclarationScope();
142 if (scope
instanceof PsiMethod
) return UsageType
.CLASS_METHOD_PARAMETER_DECLARATION
;
143 if (scope
instanceof PsiCatchSection
) return UsageType
.CLASS_CATCH_CLAUSE_PARAMETER_DECLARATION
;
144 if (scope
instanceof PsiForeachStatement
) return UsageType
.CLASS_LOCAL_VAR_DECLARATION
;
148 PsiField psiField
= PsiTreeUtil
.getParentOfType(element
, PsiField
.class);
149 if (psiField
!= null) {
150 if (PsiTreeUtil
.isAncestor(psiField
.getTypeElement(), element
, true)) return UsageType
.CLASS_FIELD_DECLARATION
;
153 PsiLocalVariable psiLocalVar
= PsiTreeUtil
.getParentOfType(element
, PsiLocalVariable
.class);
154 if (psiLocalVar
!= null) {
155 if (PsiTreeUtil
.isAncestor(psiLocalVar
.getTypeElement(), element
, true)) return UsageType
.CLASS_LOCAL_VAR_DECLARATION
;
158 PsiMethod psiMethod
= PsiTreeUtil
.getParentOfType(element
, PsiMethod
.class);
159 if (psiMethod
!= null) {
160 final PsiTypeElement retType
= psiMethod
.getReturnTypeElement();
161 if (retType
!= null && PsiTreeUtil
.isAncestor(retType
, element
, true)) return UsageType
.CLASS_METHOD_RETURN_TYPE
;
164 final PsiNewExpression psiNewExpression
= PsiTreeUtil
.getParentOfType(element
, PsiNewExpression
.class);
165 if (psiNewExpression
!= null) {
166 final PsiJavaCodeReferenceElement classReference
= psiNewExpression
.getClassReference();
167 if (classReference
!= null && PsiTreeUtil
.isAncestor(classReference
, element
, false)) return UsageType
.CLASS_NEW_OPERATOR
;