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.
21 package com
.intellij
.codeInspection
.reference
;
23 import com
.intellij
.codeInspection
.InspectionsBundle
;
24 import com
.intellij
.psi
.*;
25 import com
.intellij
.psi
.search
.GlobalSearchScope
;
26 import com
.intellij
.psi
.util
.MethodSignatureUtil
;
27 import com
.intellij
.psi
.util
.PsiTreeUtil
;
28 import com
.intellij
.psi
.util
.PsiUtil
;
29 import com
.intellij
.util
.VisibilityUtil
;
30 import org
.jetbrains
.annotations
.Nullable
;
32 public class RefJavaUtilImpl
extends RefJavaUtil
{
34 public void addReferences(final PsiModifierListOwner psiFrom
, final RefJavaElement ref
, @Nullable PsiElement findIn
) {
35 final RefJavaElementImpl refFrom
= (RefJavaElementImpl
)ref
;
38 new JavaRecursiveElementWalkingVisitor() {
39 @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference
) {
42 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
43 visitElement(expression
);
45 PsiElement psiResolved
= expression
.resolve();
47 if (psiResolved
instanceof PsiModifierListOwner
) {
48 if (isDeprecated(psiResolved
)) refFrom
.setUsesDeprecatedApi(true);
51 RefElement refResolved
= refFrom
.getRefManager().getReference(psiResolved
);
53 refResolved
, psiResolved
, psiFrom
, PsiUtil
.isAccessedForWriting(expression
),
54 PsiUtil
.isAccessedForReading(expression
), expression
57 if (refResolved
instanceof RefMethod
) {
58 updateRefMethod(psiResolved
, refResolved
, expression
, psiFrom
, refFrom
);
63 @Override public void visitEnumConstant(PsiEnumConstant enumConstant
) {
64 super.visitEnumConstant(enumConstant
);
65 processNewLikeConstruct(enumConstant
.resolveConstructor(), enumConstant
.getArgumentList());
68 @Override public void visitNewExpression(PsiNewExpression newExpr
) {
69 super.visitNewExpression(newExpr
);
70 PsiMethod psiConstructor
= newExpr
.resolveConstructor();
71 final PsiExpressionList argumentList
= newExpr
.getArgumentList();
73 RefMethod refConstructor
= processNewLikeConstruct(psiConstructor
, argumentList
);
75 if (refConstructor
== null) { // No explicit constructor referenced. Should use default one.
76 PsiType newType
= newExpr
.getType();
77 if (newType
instanceof PsiClassType
) {
78 processClassReference(PsiUtil
.resolveClassInType(newType
), refFrom
, psiFrom
);
84 private RefMethod
processNewLikeConstruct(final PsiMethod psiConstructor
, final PsiExpressionList argumentList
) {
85 if (psiConstructor
!= null) {
86 if (isDeprecated(psiConstructor
)) refFrom
.setUsesDeprecatedApi(true);
89 RefMethodImpl refConstructor
= (RefMethodImpl
)refFrom
.getRefManager().getReference(
92 refFrom
.addReference(refConstructor
, psiConstructor
, psiFrom
, false, true, null);
94 if (argumentList
!= null) {
95 PsiExpression
[] psiParams
= argumentList
.getExpressions();
96 for (PsiExpression param
: psiParams
) {
100 if (refConstructor
!= null) {
101 refConstructor
.updateParameterValues(psiParams
);
104 return refConstructor
;
107 @Override public void visitAnonymousClass(PsiAnonymousClass psiClass
) {
108 RefClassImpl refClass
= (RefClassImpl
)refFrom
.getRefManager().getReference(psiClass
);
109 refFrom
.addReference(refClass
, psiClass
, psiFrom
, false, true, null);
112 @Override public void visitReturnStatement(PsiReturnStatement statement
) {
113 super.visitReturnStatement(statement
);
115 if (refFrom
instanceof RefMethodImpl
) {
116 RefMethodImpl refMethod
= (RefMethodImpl
)refFrom
;
117 refMethod
.updateReturnValueTemplate(statement
.getReturnValue());
121 @Override public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression
) {
122 super.visitClassObjectAccessExpression(expression
);
123 final PsiTypeElement operand
= expression
.getOperand();
124 final PsiType type
= operand
.getType();
125 if (type
instanceof PsiClassType
) {
126 processClassReference(((PsiClassType
)type
).resolve(), refFrom
, psiFrom
);
130 private void processClassReference(final PsiClass psiClass
, final RefJavaElementImpl refFrom
, final PsiModifierListOwner psiFrom
) {
131 if (psiClass
!= null) {
132 RefClassImpl refClass
= (RefClassImpl
)refFrom
.getRefManager().getReference(psiClass
);
134 if (refClass
!= null) {
135 RefMethodImpl refDefaultConstructor
= (RefMethodImpl
)refClass
.getDefaultConstructor();
137 if (refDefaultConstructor
!= null && !(refDefaultConstructor
instanceof RefImplicitConstructor
)) {
138 refDefaultConstructor
.addInReference(refFrom
);
139 refFrom
.addOutReference(refDefaultConstructor
);
142 refFrom
.addReference(refClass
, psiClass
, psiFrom
, false, true, null);
152 private void updateRefMethod(PsiElement psiResolved
,
153 RefElement refResolved
,
154 PsiElement refExpression
,
155 final PsiElement psiFrom
,
156 final RefElement refFrom
) {
157 PsiMethod psiMethod
= (PsiMethod
)psiResolved
;
158 RefMethodImpl refMethod
= (RefMethodImpl
)refResolved
;
160 PsiMethodCallExpression call
= PsiTreeUtil
.getParentOfType(
162 PsiMethodCallExpression
.class
165 PsiType returnType
= psiMethod
.getReturnType();
166 if (!psiMethod
.isConstructor() && returnType
!= PsiType
.VOID
) {
167 if (!(call
.getParent() instanceof PsiExpressionStatement
)) {
168 refMethod
.setReturnValueUsed(true);
171 addTypeReference(psiFrom
, returnType
, refFrom
.getRefManager());
174 PsiExpressionList argumentList
= call
.getArgumentList();
175 if (argumentList
.getExpressions().length
> 0) {
176 refMethod
.updateParameterValues(argumentList
.getExpressions());
179 final PsiExpression psiExpression
= call
.getMethodExpression().getQualifierExpression();
180 if (psiExpression
!= null) {
181 final PsiType usedType
= psiExpression
.getType();
182 if (usedType
!= null) {
183 final String fqName
= psiMethod
.getContainingClass().getQualifiedName();
184 if (fqName
!= null) {
185 final PsiClassType methodOwnerType
= JavaPsiFacade
.getInstance(call
.getProject()).getElementFactory()
186 .createTypeByFQClassName(fqName
, GlobalSearchScope
.allScope(psiMethod
.getProject()));
187 if (!usedType
.equals(methodOwnerType
)) {
188 refMethod
.setCalledOnSubClass(true);
199 public RefClass
getTopLevelClass(RefElement refElement
) {
200 RefEntity refParent
= refElement
.getOwner();
202 while (refParent
!= null && refParent
instanceof RefElement
&& !(refParent
instanceof RefFile
)) {
203 refElement
= (RefElementImpl
)refParent
;
204 refParent
= refParent
.getOwner();
207 return (RefClass
)refElement
;
210 public boolean isInheritor(RefClass subClass
, RefClass superClass
) {
211 if (subClass
== superClass
) return true;
213 for (RefClass baseClass
: subClass
.getBaseClasses()) {
214 if (isInheritor(baseClass
, superClass
)) return true;
221 public String
getPackageName(RefEntity refEntity
) {
222 if (refEntity
instanceof RefProject
) {
225 RefPackage refPackage
= getPackage(refEntity
);
227 return refPackage
== null ? InspectionsBundle
.message("inspection.reference.default.package") : refPackage
.getQualifiedName();
230 public String
getAccessModifier(PsiModifierListOwner psiElement
) {
231 if (psiElement
instanceof PsiParameter
) return PsiModifier
.PACKAGE_LOCAL
;
233 PsiModifierList list
= psiElement
.getModifierList();
234 String result
= PsiModifier
.PACKAGE_LOCAL
;
237 if (list
.hasModifierProperty(PsiModifier
.PRIVATE
)) {
238 result
= PsiModifier
.PRIVATE
;
240 else if (list
.hasModifierProperty(PsiModifier
.PROTECTED
)) {
241 result
= PsiModifier
.PROTECTED
;
243 else if (list
.hasModifierProperty(PsiModifier
.PUBLIC
)) {
244 result
= PsiModifier
.PUBLIC
;
246 else if (psiElement
.getParent() instanceof PsiClass
) {
247 PsiClass ownerClass
= (PsiClass
)psiElement
.getParent();
248 if (ownerClass
.isInterface()) {
249 result
= PsiModifier
.PUBLIC
;
257 @Nullable public RefClass
getOwnerClass(RefManager refManager
, PsiElement psiElement
) {
258 while (psiElement
!= null && !(psiElement
instanceof PsiClass
)) {
259 psiElement
= psiElement
.getParent();
262 return psiElement
!= null ?
(RefClass
)refManager
.getReference(psiElement
) : null;
265 @Nullable public RefClass
getOwnerClass(RefElement refElement
) {
266 RefEntity parent
= refElement
.getOwner();
268 while (!(parent
instanceof RefClass
) && parent
instanceof RefElement
) {
269 parent
= parent
.getOwner();
272 if (parent
instanceof RefClass
) return (RefClass
)parent
;
279 public boolean isMethodOnlyCallsSuper(PsiMethod method
) {
280 boolean hasStatements
= false;
281 PsiCodeBlock body
= method
.getBody();
283 PsiStatement
[] statements
= body
.getStatements();
284 for (PsiStatement statement
: statements
) {
285 boolean isCallToSameSuper
= false;
286 if (statement
instanceof PsiExpressionStatement
) {
287 isCallToSameSuper
= isCallToSuperMethod(((PsiExpressionStatement
)statement
).getExpression(), method
);
289 else if (statement
instanceof PsiReturnStatement
) {
290 PsiExpression expression
= ((PsiReturnStatement
)statement
).getReturnValue();
291 isCallToSameSuper
= expression
== null || isCallToSuperMethod(expression
, method
);
294 hasStatements
= true;
295 if (isCallToSameSuper
) continue;
302 final PsiMethod
[] superMethods
= method
.findSuperMethods();
303 for (PsiMethod superMethod
: superMethods
) {
304 if (VisibilityUtil
.compare(VisibilityUtil
.getVisibilityModifier(superMethod
.getModifierList()),
305 VisibilityUtil
.getVisibilityModifier(method
.getModifierList())) > 0) return false;
308 return hasStatements
;
311 public boolean isCallToSuperMethod(PsiExpression expression
, PsiMethod method
) {
312 if (expression
instanceof PsiMethodCallExpression
) {
313 PsiMethodCallExpression methodCall
= (PsiMethodCallExpression
)expression
;
314 if (methodCall
.getMethodExpression().getQualifierExpression() instanceof PsiSuperExpression
) {
315 PsiMethod superMethod
= (PsiMethod
)methodCall
.getMethodExpression().resolve();
316 if (superMethod
== null || !MethodSignatureUtil
.areSignaturesEqual(method
, superMethod
)) return false;
317 PsiExpression
[] args
= methodCall
.getArgumentList().getExpressions();
318 PsiParameter
[] parms
= method
.getParameterList().getParameters();
320 for (int i
= 0; i
< args
.length
; i
++) {
321 PsiExpression arg
= args
[i
];
322 if (!(arg
instanceof PsiReferenceExpression
)) return false;
323 if (!parms
[i
].equals(((PsiReferenceExpression
)arg
).resolve())) return false;
333 public int compareAccess(String a1
, String a2
) {
334 int i1
= getAccessNumber(a1
);
335 int i2
= getAccessNumber(a2
);
337 if (i1
== i2
) return 0;
338 if (i1
< i2
) return -1;
342 @SuppressWarnings("StringEquality")
343 private static int getAccessNumber(String a
) {
344 if (a
== PsiModifier
.PRIVATE
) {
347 else if (a
== PsiModifier
.PACKAGE_LOCAL
) {
350 else if (a
== PsiModifier
.PROTECTED
) {
353 else if (a
== PsiModifier
.PUBLIC
) return 3;
358 public void setAccessModifier(RefJavaElement refElement
, String newAccess
) {
359 ((RefJavaElementImpl
)refElement
).setAccessModifier(newAccess
);
362 public void setIsStatic(RefJavaElement refElement
, boolean isStatic
) {
363 ((RefJavaElementImpl
)refElement
).setIsStatic(isStatic
);
366 public void setIsFinal(RefJavaElement refElement
, boolean isFinal
) {
367 ((RefJavaElementImpl
)refElement
).setIsFinal(isFinal
);
370 public void addTypeReference(PsiElement psiElement
, PsiType psiType
, RefManager refManager
) {
371 RefClass ownerClass
= getOwnerClass(refManager
, psiElement
);
373 if (ownerClass
!= null) {
374 psiType
= psiType
.getDeepComponentType();
376 if (psiType
instanceof PsiClassType
) {
377 PsiClass psiClass
= PsiUtil
.resolveClassInType(psiType
);
378 if (psiClass
!= null && refManager
.belongsToScope(psiClass
)) {
379 RefClassImpl refClass
= (RefClassImpl
)refManager
.getReference(psiClass
);
380 if (refClass
!= null) {
381 refClass
.addTypeReference(ownerClass
);