1 package com
.intellij
.refactoring
.inheritanceToDelegation
;
3 import com
.intellij
.codeInsight
.AnnotationUtil
;
4 import com
.intellij
.codeInsight
.generation
.GenerateMembersUtil
;
5 import com
.intellij
.find
.findUsages
.PsiElement2UsageTargetAdapter
;
6 import com
.intellij
.openapi
.diagnostic
.Logger
;
7 import com
.intellij
.openapi
.project
.Project
;
8 import com
.intellij
.openapi
.util
.Ref
;
9 import com
.intellij
.openapi
.wm
.WindowManager
;
10 import com
.intellij
.psi
.*;
11 import com
.intellij
.psi
.codeStyle
.CodeStyleManager
;
12 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
13 import com
.intellij
.psi
.codeStyle
.VariableKind
;
14 import com
.intellij
.psi
.javadoc
.PsiDocComment
;
15 import com
.intellij
.psi
.search
.searches
.ClassInheritorsSearch
;
16 import com
.intellij
.psi
.util
.*;
17 import com
.intellij
.refactoring
.BaseRefactoringProcessor
;
18 import com
.intellij
.refactoring
.RefactoringBundle
;
19 import com
.intellij
.refactoring
.inheritanceToDelegation
.usageInfo
.*;
20 import com
.intellij
.refactoring
.ui
.ConflictsDialog
;
21 import com
.intellij
.refactoring
.util
.CommonRefactoringUtil
;
22 import com
.intellij
.refactoring
.util
.ConflictsUtil
;
23 import com
.intellij
.refactoring
.util
.RefactoringUIUtil
;
24 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
25 import com
.intellij
.refactoring
.util
.classMembers
.ClassMemberReferencesVisitor
;
26 import com
.intellij
.refactoring
.util
.classRefs
.ClassInstanceScanner
;
27 import com
.intellij
.refactoring
.util
.classRefs
.ClassReferenceScanner
;
28 import com
.intellij
.refactoring
.util
.classRefs
.ClassReferenceSearchingScanner
;
29 import com
.intellij
.usageView
.UsageInfo
;
30 import com
.intellij
.usageView
.UsageViewDescriptor
;
31 import com
.intellij
.usageView
.UsageViewUtil
;
32 import com
.intellij
.usages
.UsageInfoToUsageConverter
;
33 import com
.intellij
.usages
.UsageTarget
;
34 import com
.intellij
.usages
.UsageViewManager
;
35 import com
.intellij
.usages
.UsageViewPresentation
;
36 import com
.intellij
.util
.IncorrectOperationException
;
37 import com
.intellij
.util
.VisibilityUtil
;
38 import com
.intellij
.util
.containers
.HashMap
;
39 import com
.intellij
.util
.containers
.MultiMap
;
40 import org
.jetbrains
.annotations
.NonNls
;
41 import org
.jetbrains
.annotations
.NotNull
;
42 import org
.jetbrains
.annotations
.Nullable
;
49 public class InheritanceToDelegationProcessor
extends BaseRefactoringProcessor
{
50 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.inheritanceToDelegation.InheritanceToDelegationProcessor");
51 private final PsiClass myClass
;
52 private final String myInnerClassName
;
53 private final boolean myIsDelegateOtherMembers
;
54 private final Set
<PsiClass
> myDelegatedInterfaces
;
55 private final Set
<PsiMethod
> myDelegatedMethods
;
56 private final HashMap
<PsiMethod
,String
> myDelegatedMethodsVisibility
;
57 private final Set
<PsiMethod
> myOverriddenMethods
;
59 private final PsiClass myBaseClass
;
60 private final Set
<PsiMember
> myBaseClassMembers
;
61 private final String myFieldName
;
62 private final String myGetterName
;
63 private final boolean myGenerateGetter
;
64 private final Set
<PsiClass
> myBaseClassBases
;
65 private Set
<PsiClass
> myClassImplementedInterfaces
;
66 private final PsiElementFactory myFactory
;
67 private final PsiClassType myBaseClassType
;
68 private final PsiManager myManager
;
69 private final boolean myIsInnerClassNeeded
;
70 private Set
<PsiClass
> myClassInheritors
;
71 private HashSet
<PsiMethod
> myAbstractDelegatedMethods
;
72 private final Map
<PsiClass
, PsiSubstitutor
> mySuperClassesToSubstitutors
= new HashMap
<PsiClass
, PsiSubstitutor
>();
75 public InheritanceToDelegationProcessor(Project project
,
77 PsiClass targetBaseClass
,
79 String innerClassName
,
80 PsiClass
[] delegatedInterfaces
,
81 PsiMethod
[] delegatedMethods
,
82 boolean delegateOtherMembers
,
83 boolean generateGetter
) {
87 myInnerClassName
= innerClassName
;
88 myIsDelegateOtherMembers
= delegateOtherMembers
;
89 myManager
= myClass
.getManager();
90 myFactory
= JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory();
92 myBaseClass
= targetBaseClass
;
94 myBaseClass
!= null // && !myBaseClass.isInterface()
95 && (myBaseClass
.getQualifiedName() == null || !myBaseClass
.getQualifiedName().equals("java.lang.Object"))
97 myBaseClassMembers
= getAllBaseClassMembers();
98 myBaseClassBases
= getAllBases();
99 myBaseClassType
= myFactory
.createType(myBaseClass
, getSuperSubstitutor (myBaseClass
));
101 myIsInnerClassNeeded
= InheritanceToDelegationUtil
.isInnerClassNeeded(myClass
, myBaseClass
);
104 myFieldName
= fieldName
;
105 final String propertyName
= JavaCodeStyleManager
.getInstance(myProject
).variableNameToPropertyName(myFieldName
, VariableKind
.FIELD
);
106 myGetterName
= PropertyUtil
.suggestGetterName(propertyName
, myBaseClassType
);
107 myGenerateGetter
= generateGetter
;
109 myDelegatedInterfaces
= new LinkedHashSet
<PsiClass
>();
110 addAll(myDelegatedInterfaces
, delegatedInterfaces
);
111 myDelegatedMethods
= new LinkedHashSet
<PsiMethod
>();
112 addAll(myDelegatedMethods
, delegatedMethods
);
113 myDelegatedMethodsVisibility
= new HashMap
<PsiMethod
, String
>();
114 for (PsiMethod method
: myDelegatedMethods
) {
115 MethodSignature signature
= method
.getSignature(getSuperSubstitutor(method
.getContainingClass()));
116 PsiMethod overridingMethod
= MethodSignatureUtil
.findMethodBySignature(myClass
, signature
, false);
117 if (overridingMethod
!= null) {
118 myDelegatedMethodsVisibility
.put(method
,
119 VisibilityUtil
.getVisibilityModifier(overridingMethod
.getModifierList()));
123 myOverriddenMethods
= getOverriddenMethods();
126 private PsiSubstitutor
getSuperSubstitutor(final PsiClass superClass
) {
127 PsiSubstitutor result
= mySuperClassesToSubstitutors
.get(superClass
);
128 if (result
== null) {
129 result
= TypeConversionUtil
.getSuperClassSubstitutor(superClass
, myClass
, PsiSubstitutor
.EMPTY
);
130 mySuperClassesToSubstitutors
.put(superClass
, result
);
135 protected UsageViewDescriptor
createUsageViewDescriptor(UsageInfo
[] usages
) {
136 return new InheritanceToDelegationViewDescriptor(myClass
);
140 protected UsageInfo
[] findUsages() {
141 ArrayList
<UsageInfo
> usages
= new ArrayList
<UsageInfo
>();
142 final PsiClass
[] inheritors
= ClassInheritorsSearch
.search(myClass
, myClass
.getUseScope(), true).toArray(PsiClass
.EMPTY_ARRAY
);
143 myClassInheritors
= new HashSet
<PsiClass
>();
144 myClassInheritors
.add(myClass
);
145 addAll(myClassInheritors
, inheritors
);
148 ClassReferenceScanner scanner
= new ClassReferenceSearchingScanner(myClass
);
149 final MyClassInstanceReferenceVisitor instanceReferenceVisitor
= new MyClassInstanceReferenceVisitor(myClass
, usages
);
150 scanner
.processReferences(new ClassInstanceScanner(myClass
, instanceReferenceVisitor
));
152 MyClassMemberReferencesVisitor visitor
= new MyClassMemberReferencesVisitor(usages
, instanceReferenceVisitor
);
153 myClass
.accept(visitor
);
155 myClassImplementedInterfaces
= instanceReferenceVisitor
.getImplementedInterfaces();
157 for (PsiClass inheritor
: inheritors
) {
158 processClass(inheritor
, usages
);
161 return usages
.toArray(new UsageInfo
[usages
.size()]);
164 private FieldAccessibility
getFieldAccessibility(PsiElement element
) {
165 for (PsiClass aClass
: myClassInheritors
) {
166 if (PsiTreeUtil
.isAncestor(aClass
, element
, false)) {
167 return new FieldAccessibility(true, aClass
);
170 return FieldAccessibility
.INVISIBLE
;
173 protected boolean preprocessUsages(Ref
<UsageInfo
[]> refUsages
) {
174 UsageInfo
[] usagesIn
= refUsages
.get();
175 ArrayList
<UsageInfo
> oldUsages
= new ArrayList
<UsageInfo
>();
176 addAll(oldUsages
, usagesIn
);
177 final ObjectUpcastedUsageInfo
[] objectUpcastedUsageInfos
= objectUpcastedUsages(usagesIn
);
178 if (myPrepareSuccessfulSwingThreadCallback
!= null) {
179 MultiMap
<PsiElement
, String
> conflicts
= new MultiMap
<PsiElement
, String
>();
180 if (objectUpcastedUsageInfos
.length
> 0) {
181 final String message
= RefactoringBundle
.message("instances.of.0.upcasted.to.1.were.found",
182 RefactoringUIUtil
.getDescription(myClass
, true), CommonRefactoringUtil
.htmlEmphasize("java.lang.Object"));
184 conflicts
.putValue(myClass
, message
);
187 analyzeConflicts(usagesIn
, conflicts
);
188 if (!conflicts
.isEmpty()) {
189 ConflictsDialog conflictsDialog
=
190 new ConflictsDialog(myProject
, conflicts
);
191 conflictsDialog
.show();
192 if (!conflictsDialog
.isOK()){
193 if (conflictsDialog
.isShowConflicts()) prepareSuccessful();
198 if (objectUpcastedUsageInfos
.length
> 0) {
199 showObjectUpcastedUsageView(objectUpcastedUsageInfos
);
200 setPreviewUsages(true);
203 ArrayList
<UsageInfo
> filteredUsages
= filterUsages(oldUsages
);
204 refUsages
.set(filteredUsages
.toArray(new UsageInfo
[filteredUsages
.size()]));
209 private void analyzeConflicts(UsageInfo
[] usage
, MultiMap
<PsiElement
, String
> conflicts
) {
210 HashMap
<PsiElement
,HashSet
<PsiElement
>> reportedNonDelegatedUsages
= new HashMap
<PsiElement
, HashSet
<PsiElement
>>();
211 HashMap
<PsiClass
,HashSet
<PsiElement
>> reportedUpcasts
= new HashMap
<PsiClass
, HashSet
<PsiElement
>>();
212 // HashSet reportedObjectUpcasts = new HashSet();
214 // final String nameJavaLangObject = ConflictsUtil.htmlEmphasize("java.lang.Object");
215 final String classDescription
= RefactoringUIUtil
.getDescription(myClass
, false);
217 for (UsageInfo aUsage
: usage
) {
218 final PsiElement element
= aUsage
.getElement();
219 if (aUsage
instanceof InheritanceToDelegationUsageInfo
) {
220 InheritanceToDelegationUsageInfo usageInfo
= (InheritanceToDelegationUsageInfo
)aUsage
;
221 /*if (usageInfo instanceof ObjectUpcastedUsageInfo) {
222 PsiElement container = ConflictsUtil.getContainer(usageInfo.element);
223 if (!reportedObjectUpcasts.contains(container)) {
224 String message = "An instance of " + classDescription + " is upcasted to "
225 + nameJavaLangObject + " in " + ConflictsUtil.getDescription(container, true) + ".";
226 conflicts.add(message);
227 reportedObjectUpcasts.add(container);
230 if (!myIsDelegateOtherMembers
&& !usageInfo
.getDelegateFieldAccessible().isAccessible()) {
231 if (usageInfo
instanceof NonDelegatedMemberUsageInfo
) {
232 final PsiElement nonDelegatedMember
= ((NonDelegatedMemberUsageInfo
)usageInfo
).nonDelegatedMember
;
233 HashSet
<PsiElement
> reportedContainers
= reportedNonDelegatedUsages
.get(nonDelegatedMember
);
234 if (reportedContainers
== null) {
235 reportedContainers
= new HashSet
<PsiElement
>();
236 reportedNonDelegatedUsages
.put(nonDelegatedMember
, reportedContainers
);
238 final PsiElement container
= ConflictsUtil
.getContainer(element
);
239 if (container
!= null && !reportedContainers
.contains(container
)) {
240 String message
= RefactoringBundle
.message("0.uses.1.of.an.instance.of.a.2", RefactoringUIUtil
.getDescription(container
, true),
241 RefactoringUIUtil
.getDescription(nonDelegatedMember
, true), classDescription
);
242 conflicts
.putValue(container
, CommonRefactoringUtil
.capitalize(message
));
243 reportedContainers
.add(container
);
246 else if (usageInfo
instanceof UpcastedUsageInfo
) {
247 final PsiClass upcastedTo
= ((UpcastedUsageInfo
)usageInfo
).upcastedTo
;
248 HashSet
<PsiElement
> reportedContainers
= reportedUpcasts
.get(upcastedTo
);
249 if (reportedContainers
== null) {
250 reportedContainers
= new HashSet
<PsiElement
>();
251 reportedUpcasts
.put(upcastedTo
, reportedContainers
);
253 final PsiElement container
= ConflictsUtil
.getContainer(element
);
254 if (container
!= null && !reportedContainers
.contains(container
)) {
255 String message
= RefactoringBundle
.message("0.upcasts.an.instance.of.1.to.2",
256 RefactoringUIUtil
.getDescription(container
, true), classDescription
,
257 RefactoringUIUtil
.getDescription(upcastedTo
, false));
258 conflicts
.putValue(container
, CommonRefactoringUtil
.capitalize(message
));
259 reportedContainers
.add(container
);
264 else if (aUsage
instanceof NoLongerOverridingSubClassMethodUsageInfo
) {
265 NoLongerOverridingSubClassMethodUsageInfo info
= (NoLongerOverridingSubClassMethodUsageInfo
)aUsage
;
266 String message
= RefactoringBundle
.message("0.will.no.longer.override.1",
267 RefactoringUIUtil
.getDescription(info
.getSubClassMethod(), true),
268 RefactoringUIUtil
.getDescription(info
.getOverridenMethod(), true));
269 conflicts
.putValue(info
.getSubClassMethod(), message
);
274 private static ObjectUpcastedUsageInfo
[] objectUpcastedUsages(UsageInfo
[] usages
) {
275 ArrayList
<ObjectUpcastedUsageInfo
> result
= new ArrayList
<ObjectUpcastedUsageInfo
>();
276 for (UsageInfo usage
: usages
) {
277 if (usage
instanceof ObjectUpcastedUsageInfo
) {
278 result
.add(((ObjectUpcastedUsageInfo
)usage
));
281 return result
.toArray(new ObjectUpcastedUsageInfo
[result
.size()]);
284 private ArrayList
<UsageInfo
> filterUsages(ArrayList
<UsageInfo
> usages
) {
285 ArrayList
<UsageInfo
> result
= new ArrayList
<UsageInfo
>();
287 for (UsageInfo usageInfo
: usages
) {
288 if (!(usageInfo
instanceof InheritanceToDelegationUsageInfo
)) {
291 if (usageInfo
instanceof ObjectUpcastedUsageInfo
) {
295 if (!myIsDelegateOtherMembers
) {
296 final FieldAccessibility delegateFieldAccessible
= ((InheritanceToDelegationUsageInfo
)usageInfo
).getDelegateFieldAccessible();
297 if (!delegateFieldAccessible
.isAccessible()) continue;
300 result
.add(usageInfo
);
305 private void processClass(PsiClass inheritor
, ArrayList
<UsageInfo
> usages
) {
306 ClassReferenceScanner scanner
= new ClassReferenceSearchingScanner(inheritor
);
307 final MyClassInstanceReferenceVisitor instanceVisitor
= new MyClassInstanceReferenceVisitor(inheritor
, usages
);
308 scanner
.processReferences(
309 new ClassInstanceScanner(inheritor
,
312 MyClassInheritorMemberReferencesVisitor classMemberVisitor
= new MyClassInheritorMemberReferencesVisitor(inheritor
, usages
, instanceVisitor
);
313 inheritor
.accept(classMemberVisitor
);
314 PsiSubstitutor inheritorSubstitutor
= TypeConversionUtil
.getSuperClassSubstitutor(myClass
, inheritor
, PsiSubstitutor
.EMPTY
);
316 PsiMethod
[] methods
= inheritor
.getMethods();
317 for (PsiMethod method
: methods
) {
318 final PsiMethod baseMethod
= findSuperMethodInBaseClass(method
);
320 if (baseMethod
!= null) {
321 if (!baseMethod
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
322 usages
.add(new NoLongerOverridingSubClassMethodUsageInfo(method
, baseMethod
));
325 final PsiMethod
[] methodsByName
= myClass
.findMethodsByName(method
.getName(), false);
326 for (final PsiMethod classMethod
: methodsByName
) {
327 final MethodSignature signature
= classMethod
.getSignature(inheritorSubstitutor
);
328 if (signature
.equals(method
.getSignature(PsiSubstitutor
.EMPTY
))) {
329 if (!classMethod
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
330 usages
.add(new NoLongerOverridingSubClassMethodUsageInfo(method
, baseMethod
));
340 protected void refreshElements(PsiElement
[] elements
) {
343 protected void performRefactoring(UsageInfo
[] usages
) {
345 for (UsageInfo aUsage
: usages
) {
346 InheritanceToDelegationUsageInfo usage
= (InheritanceToDelegationUsageInfo
)aUsage
;
349 if (usage
instanceof UnqualifiedNonDelegatedMemberUsageInfo
) {
350 delegateUsageFromClass(usage
.getElement(), ((NonDelegatedMemberUsageInfo
)usage
).nonDelegatedMember
,
351 usage
.getDelegateFieldAccessible());
354 upcastToDelegation(usage
.getElement(), usage
.getDelegateFieldAccessible());
358 myAbstractDelegatedMethods
= new HashSet
<PsiMethod
>();
362 addImplementingInterfaces();
363 } catch (IncorrectOperationException e
) {
368 private void addInnerClass() throws IncorrectOperationException
{
369 if (!myIsInnerClassNeeded
) return;
371 PsiClass innerClass
= myFactory
.createClass(myInnerClassName
);
372 final PsiJavaCodeReferenceElement baseClassReferenceElement
= myFactory
.createClassReferenceElement(myBaseClass
);
373 if (!myBaseClass
.isInterface()) {
374 innerClass
.getExtendsList().add(baseClassReferenceElement
);
376 innerClass
.getImplementsList().add(baseClassReferenceElement
);
378 PsiUtil
.setModifierProperty(innerClass
, PsiModifier
.PRIVATE
, true);
379 innerClass
= (PsiClass
) myClass
.add(innerClass
);
381 List
<InnerClassMethod
> innerClassMethods
= getInnerClassMethods();
382 for (InnerClassMethod innerClassMethod
: innerClassMethods
) {
383 innerClassMethod
.createMethod(innerClass
);
387 private void delegateUsageFromClass(PsiElement element
, PsiElement nonDelegatedMember
,
388 FieldAccessibility fieldAccessibility
) throws IncorrectOperationException
{
389 if (element
instanceof PsiReferenceExpression
) {
390 PsiReferenceExpression referenceExpression
= (PsiReferenceExpression
) element
;
391 if (referenceExpression
.getQualifierExpression() != null) {
392 upcastToDelegation(referenceExpression
.getQualifierExpression(), fieldAccessibility
);
394 final String name
= ((PsiNamedElement
) nonDelegatedMember
).getName();
395 final String qualifier
;
396 if (isStatic (nonDelegatedMember
)) {
397 qualifier
= myBaseClass
.getName();
399 else if (!fieldAccessibility
.isAccessible() && myGenerateGetter
) {
400 qualifier
= myGetterName
+ "()";
403 qualifier
= myFieldName
;
406 PsiExpression newExpr
= myFactory
.createExpressionFromText(qualifier
+ "." + name
, element
);
407 newExpr
= (PsiExpression
) CodeStyleManager
.getInstance(myProject
).reformat(newExpr
);
408 element
.replace(newExpr
);
411 else if (element
instanceof PsiJavaCodeReferenceElement
) {
412 final String name
= ((PsiNamedElement
) nonDelegatedMember
).getName();
414 PsiElement parent
= element
.getParent ();
415 if (!isStatic (nonDelegatedMember
) && parent
instanceof PsiNewExpression
) {
416 final PsiNewExpression newExpr
= (PsiNewExpression
) parent
;
417 if (newExpr
.getQualifier() != null) {
418 upcastToDelegation(newExpr
.getQualifier(), fieldAccessibility
);
420 final String qualifier
;
421 if (!fieldAccessibility
.isAccessible() && myGenerateGetter
) {
422 qualifier
= myGetterName
+ "()";
425 qualifier
= myFieldName
;
427 newExpr
.replace(myFactory
.createExpressionFromText(qualifier
+ "." + newExpr
.getText(), parent
));
431 final String qualifier
= myBaseClass
.getName();
432 PsiJavaCodeReferenceElement newRef
= myFactory
.createFQClassNameReferenceElement(qualifier
+ "." + name
, element
.getResolveScope ());
433 //newRef = (PsiJavaCodeReferenceElement) CodeStyleManager.getInstance(myProject).reformat(newRef);
434 element
.replace(newRef
);
437 LOG
.assertTrue(false);
441 private static boolean isStatic(PsiElement member
) {
442 if (member
instanceof PsiModifierListOwner
) {
443 final PsiModifierListOwner method
= (PsiModifierListOwner
) member
;
444 return method
.hasModifierProperty (PsiModifier
.STATIC
);
449 private void upcastToDelegation(PsiElement element
, FieldAccessibility fieldAccessibility
) throws IncorrectOperationException
{
450 final PsiExpression expression
= (PsiExpression
) element
;
452 final PsiExpression newExpr
;
453 final PsiReferenceExpression ref
;
454 @NonNls final String delegateQualifier
;
455 if (!(expression
instanceof PsiThisExpression
|| expression
instanceof PsiSuperExpression
)) {
456 delegateQualifier
= "a.";
458 PsiResolveHelper resolveHelper
= JavaPsiFacade
.getInstance(myProject
).getResolveHelper();
459 final PsiVariable psiVariable
= resolveHelper
.resolveReferencedVariable(myFieldName
, element
);
460 if (psiVariable
== null) {
461 delegateQualifier
= "";
463 delegateQualifier
= "a.";
466 if (!fieldAccessibility
.isAccessible() && myGenerateGetter
) {
467 newExpr
= myFactory
.createExpressionFromText(delegateQualifier
+ myGetterName
+ "()", expression
);
468 ref
= (PsiReferenceExpression
) ((PsiMethodCallExpression
) newExpr
).getMethodExpression().getQualifierExpression();
470 newExpr
= myFactory
.createExpressionFromText(delegateQualifier
+ myFieldName
, expression
);
471 ref
= (PsiReferenceExpression
) ((PsiReferenceExpression
) newExpr
).getQualifierExpression();
473 // LOG.debug("upcastToDelegation:" + element + ":newExpr = " + newExpr);
474 // LOG.debug("upcastToDelegation:" + element + ":ref = " + ref);
476 ref
.replace(expression
);
478 expression
.replace(newExpr
);
479 // LOG.debug("upcastToDelegation:" + element + ":replaced = " + replaced);
482 private void delegateMethods() throws IncorrectOperationException
{
483 for (PsiMethod method
: myDelegatedMethods
) {
484 if (!myAbstractDelegatedMethods
.contains(method
)) {
485 PsiMethod methodToAdd
= delegateMethod(myFieldName
, method
, getSuperSubstitutor(method
.getContainingClass()));
487 String visibility
= myDelegatedMethodsVisibility
.get(method
);
488 if (visibility
!= null) {
489 PsiUtil
.setModifierProperty(methodToAdd
, visibility
, true);
492 myClass
.add(methodToAdd
);
497 private PsiMethod
delegateMethod(@NonNls String delegationTarget
,
499 PsiSubstitutor substitutor
) throws IncorrectOperationException
{
500 substitutor
= GenerateMembersUtil
.correctSubstitutor(method
, substitutor
);
501 PsiMethod methodToAdd
= GenerateMembersUtil
.substituteGenericMethod(method
, substitutor
);
503 final PsiModifierList modifierList
= methodToAdd
.getModifierList();
504 modifierList
.setModifierProperty(PsiModifier
.ABSTRACT
, false);
505 if (AnnotationUtil
.isAnnotated(method
, AnnotationUtil
.NULLABLE
, false)) {
506 modifierList
.addAfter(myFactory
.createAnnotationFromText("@" + AnnotationUtil
.NULLABLE
, methodToAdd
), null);
508 else if (AnnotationUtil
.isAnnotated(method
, AnnotationUtil
.NOT_NULL
, false)) {
509 modifierList
.addAfter(myFactory
.createAnnotationFromText("@" + AnnotationUtil
.NOT_NULL
, methodToAdd
), null);
512 final String delegationBody
= getDelegationBody(methodToAdd
, delegationTarget
);
513 PsiCodeBlock newBody
= myFactory
.createCodeBlockFromText(delegationBody
, method
);
515 PsiCodeBlock oldBody
= methodToAdd
.getBody();
516 if (oldBody
!= null) {
517 oldBody
.replace(newBody
);
520 methodToAdd
.addBefore(newBody
, null);
523 if (methodToAdd
.getDocComment() != null) methodToAdd
.getDocComment().delete();
524 methodToAdd
= (PsiMethod
)CodeStyleManager
.getInstance(myProject
).reformat(methodToAdd
);
525 methodToAdd
= (PsiMethod
)JavaCodeStyleManager
.getInstance(myProject
).shortenClassReferences(methodToAdd
);
529 private static String
getDelegationBody(PsiMethod methodToAdd
, String delegationTarget
) {
530 @NonNls final StringBuffer buffer
= new StringBuffer();
531 buffer
.append("{\n");
533 if (methodToAdd
.getReturnType() != PsiType
.VOID
) {
534 buffer
.append("return ");
537 buffer
.append(delegationTarget
);
539 buffer
.append(methodToAdd
.getName());
541 PsiParameter
[] params
= methodToAdd
.getParameterList().getParameters();
542 for (int i
= 0; i
< params
.length
; i
++) {
543 PsiParameter param
= params
[i
];
547 buffer
.append(param
.getName());
549 buffer
.append(");\n}");
550 return buffer
.toString();
553 private void addImplementingInterfaces() throws IncorrectOperationException
{
554 final PsiReferenceList implementsList
= myClass
.getImplementsList();
555 LOG
.assertTrue(implementsList
!= null);
556 for (PsiClass delegatedInterface
: myDelegatedInterfaces
) {
557 if (!myClassImplementedInterfaces
.contains(delegatedInterface
)) {
558 implementsList
.add(myFactory
.createClassReferenceElement(delegatedInterface
));
562 if (!myBaseClass
.isInterface()) {
563 final PsiReferenceList extendsList
= myClass
.getExtendsList();
564 LOG
.assertTrue(extendsList
!= null);
565 extendsList
.getReferenceElements()[0].delete();
567 final PsiJavaCodeReferenceElement
[] interfaceRefs
= implementsList
.getReferenceElements();
568 for (PsiJavaCodeReferenceElement interfaceRef
: interfaceRefs
) {
569 final PsiElement resolved
= interfaceRef
.resolve();
570 if (myManager
.areElementsEquivalent(myBaseClass
, resolved
)) {
571 interfaceRef
.delete();
578 private void addField(UsageInfo
[] usages
) throws IncorrectOperationException
{
579 final String fieldVisibility
= getFieldVisibility(usages
);
581 final boolean fieldInitializerNeeded
= isFieldInitializerNeeded();
583 PsiField field
= createField(fieldVisibility
, fieldInitializerNeeded
, defaultClassFieldType());
585 if (!myIsInnerClassNeeded
) {
586 field
.getTypeElement().replace(myFactory
.createTypeElement(myBaseClassType
));
587 if (fieldInitializerNeeded
) {
588 final PsiJavaCodeReferenceElement classReferenceElement
= myFactory
.createReferenceElementByType(myBaseClassType
);
589 PsiNewExpression newExpression
= (PsiNewExpression
) field
.getInitializer();
590 newExpression
.getClassReference().replace(classReferenceElement
);
594 field
= (PsiField
) CodeStyleManager
.getInstance(myProject
).reformat(field
);
596 if (!fieldInitializerNeeded
) {
600 if (myGenerateGetter
) {
601 final String getterVisibility
= PsiModifier
.PUBLIC
;
602 @NonNls StringBuffer getterBuffer
= new StringBuffer();
603 getterBuffer
.append(getterVisibility
);
604 getterBuffer
.append(" Object ");
605 getterBuffer
.append(myGetterName
);
606 getterBuffer
.append("() {\n return ");
607 getterBuffer
.append(myFieldName
);
608 getterBuffer
.append(";\n}");
609 PsiMethod getter
= myFactory
.createMethodFromText(getterBuffer
.toString(), myClass
);
610 getter
.getReturnTypeElement().replace(myFactory
.createTypeElement(myBaseClassType
));
611 getter
= (PsiMethod
) CodeStyleManager
.getInstance(myProject
).reformat(getter
);
616 private String
getFieldVisibility(UsageInfo
[] usages
) {
617 if (myIsDelegateOtherMembers
&& !myGenerateGetter
) {
618 return PsiModifier
.PUBLIC
;
621 for (UsageInfo aUsage
: usages
) {
622 InheritanceToDelegationUsageInfo usage
= (InheritanceToDelegationUsageInfo
)aUsage
;
623 final FieldAccessibility delegateFieldAccessible
= usage
.getDelegateFieldAccessible();
624 if (delegateFieldAccessible
.isAccessible() && delegateFieldAccessible
.getContainingClass() != myClass
) {
625 return PsiModifier
.PROTECTED
;
628 return PsiModifier
.PRIVATE
;
631 private @NonNls String
defaultClassFieldType() {
632 return (myIsInnerClassNeeded ? myInnerClassName
: "Object");
635 private PsiField
createField(final String fieldVisibility
, final boolean fieldInitializerNeeded
, String defaultTypeName
) throws IncorrectOperationException
{
636 @NonNls StringBuffer buffer
= new StringBuffer();
637 buffer
.append(fieldVisibility
);
638 buffer
.append(" final " + defaultTypeName
+ " ");
639 buffer
.append(myFieldName
);
640 if (fieldInitializerNeeded
) {
641 buffer
.append(" = new " + defaultTypeName
+ "()");
644 return myFactory
.createFieldFromText(buffer
.toString(), myClass
);
647 private void fixConstructors() throws IncorrectOperationException
{
648 if (myBaseClass
.isInterface()) return;
649 final PsiJavaCodeReferenceElement baseClassReference
= myFactory
.createClassReferenceElement(myBaseClass
);
651 PsiMethod
[] constructors
= myClass
.getConstructors();
652 for (PsiMethod constructor
: constructors
) {
653 PsiCodeBlock body
= constructor
.getBody();
654 final PsiStatement
[] statements
= body
.getStatements();
655 @NonNls String fieldQualifier
= "";
656 PsiParameter
[] constructorParams
= constructor
.getParameterList().getParameters();
657 for (PsiParameter constructorParam
: constructorParams
) {
658 if (myFieldName
.equals(constructorParam
.getName())) {
659 fieldQualifier
= "this.";
663 final @NonNls String assignmentText
= fieldQualifier
+ myFieldName
+ "= new " + defaultClassFieldType() + "()";
664 if (statements
.length
< 1 || !RefactoringUtil
.isSuperOrThisCall(statements
[0], true, true) || myBaseClass
.isInterface()) {
665 PsiExpressionStatement assignmentStatement
=
666 (PsiExpressionStatement
)myFactory
.createStatementFromText(
669 if (!myIsInnerClassNeeded
) {
670 final PsiAssignmentExpression assignmentExpr
= (PsiAssignmentExpression
)assignmentStatement
.getExpression();
671 final PsiNewExpression newExpression
= (PsiNewExpression
)assignmentExpr
.getRExpression();
672 assert newExpression
!= null;
673 final PsiJavaCodeReferenceElement classRef
= newExpression
.getClassReference();
674 assert classRef
!= null;
675 classRef
.replace(baseClassReference
);
678 assignmentStatement
= (PsiExpressionStatement
)CodeStyleManager
.getInstance(myProject
).reformat(assignmentStatement
);
679 if (statements
.length
> 0) {
680 if (!RefactoringUtil
.isSuperOrThisCall(statements
[0], true, false)) {
681 body
.addBefore(assignmentStatement
, statements
[0]);
684 body
.addAfter(assignmentStatement
, statements
[0]);
688 body
.add(assignmentStatement
);
692 final PsiExpressionStatement callStatement
= ((PsiExpressionStatement
)statements
[0]);
693 if (!RefactoringUtil
.isSuperOrThisCall(callStatement
, false, true)) {
694 final PsiMethodCallExpression superConstructorCall
=
695 (PsiMethodCallExpression
)callStatement
.getExpression();
696 PsiAssignmentExpression assignmentExpression
=
697 (PsiAssignmentExpression
)myFactory
.createExpressionFromText(
698 assignmentText
, superConstructorCall
700 PsiNewExpression newExpression
=
701 (PsiNewExpression
)assignmentExpression
.getRExpression();
702 if (!myIsInnerClassNeeded
) {
703 newExpression
.getClassReference().replace(baseClassReference
);
705 assignmentExpression
= (PsiAssignmentExpression
)CodeStyleManager
.getInstance(myProject
).reformat(assignmentExpression
);
706 newExpression
.getArgumentList().replace(superConstructorCall
.getArgumentList());
707 superConstructorCall
.replace(assignmentExpression
);
713 private boolean isFieldInitializerNeeded() {
714 if (myBaseClass
.isInterface()) return true;
715 PsiMethod
[] constructors
= myClass
.getConstructors();
716 for (PsiMethod constructor
: constructors
) {
717 final PsiStatement
[] statements
= constructor
.getBody().getStatements();
718 if (statements
.length
> 0 && RefactoringUtil
.isSuperOrThisCall(statements
[0], true, false)) return false;
723 private List
<InnerClassMethod
> getInnerClassMethods() {
724 ArrayList
<InnerClassMethod
> result
= new ArrayList
<InnerClassMethod
>();
726 // find all neccessary constructors
727 if (!myBaseClass
.isInterface()) {
728 PsiMethod
[] constructors
= myClass
.getConstructors();
729 for (PsiMethod constructor
: constructors
) {
730 final PsiStatement
[] statements
= constructor
.getBody().getStatements();
731 if (statements
.length
> 0 && RefactoringUtil
.isSuperOrThisCall(statements
[0], true, false)) {
732 final PsiMethodCallExpression superConstructorCall
=
733 (PsiMethodCallExpression
)((PsiExpressionStatement
)statements
[0]).getExpression();
734 PsiElement superConstructor
= superConstructorCall
.getMethodExpression().resolve();
735 if (superConstructor
instanceof PsiMethod
&& ((PsiMethod
)superConstructor
).isConstructor()) {
736 result
.add(new InnerClassConstructor((PsiMethod
)superConstructor
));
742 // find overriding/implementing method
744 class InnerClassOverridingMethod
extends InnerClassMethod
{
745 public InnerClassOverridingMethod(PsiMethod method
) {
749 public void createMethod(PsiClass innerClass
)
750 throws IncorrectOperationException
{
751 OverriddenMethodClassMemberReferencesVisitor visitor
= new OverriddenMethodClassMemberReferencesVisitor();
752 myClass
.accept(visitor
);
753 final List
<PsiAction
> actions
= visitor
.getPsiActions();
754 for (PsiAction action
: actions
) {
757 innerClass
.add(myMethod
);
759 // myMethod.replace(delegateMethod(myMethod));
763 for (PsiMethod method
: myOverriddenMethods
) {
764 result
.add(new InnerClassOverridingMethod(method
));
768 // fix abstract methods
770 class InnerClassAbstractMethod
extends InnerClassMethod
{
771 private final boolean myImplicitImplementation
;
773 public InnerClassAbstractMethod(PsiMethod method
, final boolean implicitImplementation
) {
775 myImplicitImplementation
= implicitImplementation
;
778 public void createMethod(PsiClass innerClass
)
779 throws IncorrectOperationException
{
780 PsiSubstitutor substitutor
= getSuperSubstitutor(myMethod
.getContainingClass());
781 PsiMethod method
= delegateMethod(myClass
.getName() + ".this", myMethod
, substitutor
);
782 final PsiClass containingClass
= myMethod
.getContainingClass();
783 if (myBaseClass
.isInterface() || containingClass
.isInterface()) {
784 PsiUtil
.setModifierProperty(method
, PsiModifier
.PUBLIC
, true);
786 innerClass
.add(method
);
787 if (!myImplicitImplementation
) {
788 final MethodSignature signature
= myMethod
.getSignature(substitutor
);
789 PsiMethod outerMethod
= MethodSignatureUtil
.findMethodBySignature(myClass
, signature
, false);
790 if (outerMethod
== null) {
791 @Modifier String visibility
= checkOuterClassAbstractMethod(signature
);
792 PsiMethod newOuterMethod
= (PsiMethod
)myClass
.add(myMethod
);
793 PsiUtil
.setModifierProperty(newOuterMethod
, visibility
, true);
794 final PsiDocComment docComment
= newOuterMethod
.getDocComment();
795 if (docComment
!= null) {
803 PsiMethod
[] methods
= myBaseClass
.getAllMethods();
805 for (PsiMethod method
: methods
) {
806 if (method
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
807 final MethodSignature signature
= method
.getSignature(getSuperSubstitutor(method
.getContainingClass()));
808 PsiMethod classMethod
= MethodSignatureUtil
.findMethodBySignature(myClass
, signature
, true);
809 if (classMethod
== null || classMethod
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
810 result
.add(new InnerClassAbstractMethod(method
, false));
812 else if ((myBaseClass
.isInterface() && classMethod
.getContainingClass() != myClass
)) { // IDEADEV-19675
813 result
.add(new InnerClassAbstractMethod(method
, true));
823 private void showObjectUpcastedUsageView(final ObjectUpcastedUsageInfo
[] usages
) {
824 UsageViewPresentation presentation
= new UsageViewPresentation();
825 presentation
.setTargetsNodeText(RefactoringBundle
.message("replacing.inheritance.with.delegation"));
826 presentation
.setCodeUsagesString(RefactoringBundle
.message("instances.casted.to.java.lang.object"));
827 final String upcastedString
= RefactoringBundle
.message("instances.upcasted.to.object");
828 presentation
.setUsagesString(upcastedString
);
829 presentation
.setTabText(upcastedString
);
831 UsageViewManager manager
= UsageViewManager
.getInstance(myProject
);
833 new UsageTarget
[]{new PsiElement2UsageTargetAdapter(myClass
)},
834 UsageInfoToUsageConverter
.convert(new UsageInfoToUsageConverter
.TargetElementsDescriptor(myClass
), usages
),
838 WindowManager
.getInstance().getStatusBar(myProject
).setInfo(RefactoringBundle
.message("instances.upcasted.to.java.lang.object.found"));
843 * @param methodSignature
847 private String
checkOuterClassAbstractMethod(MethodSignature methodSignature
) {
848 @Modifier String visibility
= PsiModifier
.PROTECTED
;
849 for (PsiMethod method
: myDelegatedMethods
) {
850 MethodSignature otherSignature
= method
.getSignature(getSuperSubstitutor(method
.getContainingClass()));
852 if (MethodSignatureUtil
.areSignaturesEqual(otherSignature
, methodSignature
)) {
853 visibility
= VisibilityUtil
.getHighestVisibility(visibility
,
854 VisibilityUtil
.getVisibilityModifier(method
.getModifierList()));
855 myAbstractDelegatedMethods
.add(method
);
861 private Set
<PsiMethod
> getOverriddenMethods() {
862 LinkedHashSet
<PsiMethod
> result
= new LinkedHashSet
<PsiMethod
>();
864 PsiMethod
[] methods
= myClass
.getMethods();
865 for (PsiMethod method
: methods
) {
866 if (findSuperMethodInBaseClass(method
) != null) result
.add(method
);
872 private PsiMethod
findSuperMethodInBaseClass (PsiMethod method
) {
873 final PsiMethod
[] superMethods
= method
.findSuperMethods();
874 for (PsiMethod superMethod
: superMethods
) {
875 PsiClass containingClass
= superMethod
.getContainingClass();
876 if (InheritanceUtil
.isInheritorOrSelf(myBaseClass
, containingClass
, true)) {
877 String qName
= containingClass
.getQualifiedName();
878 if (qName
== null || !"java.lang.Object".equals(qName
)) {
887 protected String
getCommandName() {
888 return RefactoringBundle
.message("replace.inheritance.with.delegation.command", UsageViewUtil
.getDescriptiveName(myClass
));
891 private Set
<PsiMember
> getAllBaseClassMembers() {
892 HashSet
<PsiMember
> result
= new HashSet
<PsiMember
>();
893 addAll(result
, myBaseClass
.getAllFields());
894 addAll(result
, myBaseClass
.getAllInnerClasses());
895 addAll(result
, myBaseClass
.getAllMethods());
897 //remove java.lang.Object members
898 for (Iterator
<PsiMember
> iterator
= result
.iterator(); iterator
.hasNext();) {
899 PsiMember member
= iterator
.next();
900 if ("java.lang.Object".equals(member
.getContainingClass().getQualifiedName())) {
904 return Collections
.unmodifiableSet(result
);
907 private Set
<PsiClass
> getAllBases() {
908 HashSet
<PsiClass
> temp
= new HashSet
<PsiClass
>();
909 InheritanceUtil
.getSuperClasses(myBaseClass
, temp
, true);
910 temp
.add(myBaseClass
);
911 return Collections
.unmodifiableSet(temp
);
914 private static <T
> void addAll(Collection
<T
> collection
, T
[] objs
) {
920 private boolean isDelegated(PsiMember classMember
) {
921 if(!(classMember
instanceof PsiMethod
)) return false;
922 final PsiMethod method
= (PsiMethod
) classMember
;
923 for (PsiMethod delegatedMethod
: myDelegatedMethods
) {
924 //methods reside in base class, so no substitutor needed
925 if (MethodSignatureUtil
.areSignaturesEqual(method
.getSignature(PsiSubstitutor
.EMPTY
),
926 delegatedMethod
.getSignature(PsiSubstitutor
.EMPTY
))) {
933 private class MyClassInheritorMemberReferencesVisitor
extends ClassMemberReferencesVisitor
{
934 private final List
<UsageInfo
> myUsageInfoStorage
;
935 private final ClassInstanceScanner
.ClassInstanceReferenceVisitor myInstanceVisitor
;
937 MyClassInheritorMemberReferencesVisitor(PsiClass aClass
, List
<UsageInfo
> usageInfoStorage
,
938 ClassInstanceScanner
.ClassInstanceReferenceVisitor instanceScanner
) {
941 myUsageInfoStorage
= usageInfoStorage
;
942 myInstanceVisitor
= instanceScanner
;
945 @Override public void visitTypeElement(PsiTypeElement type
) {
946 super.visitTypeElement (type
);
949 @Override public void visitReferenceElement(PsiJavaCodeReferenceElement element
) {
950 super.visitReferenceElement (element
);
953 protected void visitClassMemberReferenceElement(PsiMember classMember
, PsiJavaCodeReferenceElement classMemberReference
) {
954 if ("super".equals(classMemberReference
.getText()) && classMemberReference
.getParent() instanceof PsiMethodCallExpression
) {
958 if (classMember
!= null && myBaseClassMembers
.contains(classMember
) && !isDelegated(classMember
)) {
959 final FieldAccessibility delegateFieldVisibility
= new FieldAccessibility(true, getPsiClass());
960 final InheritanceToDelegationUsageInfo usageInfo
;
961 if (classMemberReference
instanceof PsiReferenceExpression
) {
962 if (((PsiReferenceExpression
) classMemberReference
).getQualifierExpression() == null) {
963 usageInfo
= new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference
, classMember
,
964 delegateFieldVisibility
);
966 usageInfo
= new NonDelegatedMemberUsageInfo(
967 ((PsiReferenceExpression
) classMemberReference
).getQualifierExpression(),
968 classMember
, delegateFieldVisibility
971 myUsageInfoStorage
.add(usageInfo
);
973 else /*if (classMemberReference instanceof PsiJavaCodeReferenceElement)*/ {
974 usageInfo
= new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference
, classMember
,
975 delegateFieldVisibility
);
976 myUsageInfoStorage
.add(usageInfo
);
982 @Override public void visitThisExpression(PsiThisExpression expression
) {
983 ClassInstanceScanner
.processNonArrayExpression(myInstanceVisitor
, expression
, null);
987 private class MyClassMemberReferencesVisitor
extends MyClassInheritorMemberReferencesVisitor
{
988 MyClassMemberReferencesVisitor(List
<UsageInfo
> usageInfoStorage
,
989 ClassInstanceScanner
.ClassInstanceReferenceVisitor instanceScanner
) {
990 super(InheritanceToDelegationProcessor
.this.myClass
, usageInfoStorage
, instanceScanner
);
993 @Override public void visitMethod(PsiMethod method
) {
994 if (!myOverriddenMethods
.contains(method
)) {
995 super.visitMethod(method
);
1000 interface PsiAction
{
1001 void run() throws IncorrectOperationException
;
1005 * This visitor should be called for overriden methods before they are moved to an inner class
1007 private class OverriddenMethodClassMemberReferencesVisitor
extends ClassMemberReferencesVisitor
{
1008 private final ArrayList
<PsiAction
> myPsiActions
;
1009 private final PsiThisExpression myQualifiedThis
;
1011 OverriddenMethodClassMemberReferencesVisitor() throws IncorrectOperationException
{
1013 myPsiActions
= new ArrayList
<PsiAction
>();
1014 final PsiJavaCodeReferenceElement classReferenceElement
= myFactory
.createClassReferenceElement(myClass
);
1015 myQualifiedThis
= (PsiThisExpression
) myFactory
.createExpressionFromText("A.this", null);
1016 myQualifiedThis
.getQualifier().replace(classReferenceElement
);
1019 public List
<PsiAction
> getPsiActions() {
1020 return myPsiActions
;
1023 class QualifyThis
implements PsiAction
{
1024 private final PsiThisExpression myThisExpression
;
1026 QualifyThis(PsiThisExpression thisExpression
) {
1027 myThisExpression
= thisExpression
;
1030 public void run() throws IncorrectOperationException
{
1031 myThisExpression
.replace(myQualifiedThis
);
1035 class QualifyName
implements PsiAction
{
1036 private final PsiReferenceExpression myRef
;
1037 private final String myReferencedName
;
1039 QualifyName(PsiReferenceExpression ref
, String name
) {
1041 myReferencedName
= name
;
1044 public void run() throws IncorrectOperationException
{
1045 PsiReferenceExpression newRef
=
1046 (PsiReferenceExpression
) myFactory
.createExpressionFromText("a." + myReferencedName
, null);
1047 newRef
.getQualifierExpression().replace(myQualifiedThis
);
1048 myRef
.replace(newRef
);
1052 class QualifyWithField
implements PsiAction
{
1053 private final PsiReferenceExpression myReference
;
1054 private final String myReferencedName
;
1056 public QualifyWithField(final PsiReferenceExpression reference
, final String name
) {
1057 myReference
= reference
;
1058 myReferencedName
= name
;
1061 public void run() throws IncorrectOperationException
{
1062 PsiReferenceExpression newRef
=
1063 (PsiReferenceExpression
) myFactory
.createExpressionFromText(myFieldName
+ "." + myReferencedName
, null);
1064 myReference
.replace(newRef
);
1068 protected void visitClassMemberReferenceExpression(PsiMember classMember
,
1069 PsiReferenceExpression classMemberReference
) {
1070 if (classMember
instanceof PsiField
) {
1071 final PsiField field
= (PsiField
) classMember
;
1073 if (field
.getContainingClass().equals(myClass
)) {
1074 final String name
= field
.getName();
1075 final PsiField baseField
= myBaseClass
.findFieldByName(name
, true);
1076 if (baseField
!= null) {
1077 myPsiActions
.add(new QualifyName(classMemberReference
, name
));
1078 } else if (classMemberReference
.getQualifierExpression() instanceof PsiThisExpression
) {
1079 myPsiActions
.add(new QualifyThis((PsiThisExpression
) classMemberReference
.getQualifierExpression()));
1082 } else if (classMember
instanceof PsiMethod
) {
1083 final PsiMethod method
= (PsiMethod
) classMember
;
1085 if (method
.getContainingClass().equals(myClass
)) {
1086 if (!myOverriddenMethods
.contains(method
)) {
1087 final PsiMethod baseMethod
= findSuperMethodInBaseClass(method
);
1088 if (baseMethod
!= null) {
1089 myPsiActions
.add(new QualifyName(classMemberReference
, baseMethod
.getName()));
1090 } else if (classMemberReference
.getQualifierExpression() instanceof PsiThisExpression
) {
1091 myPsiActions
.add(new QualifyThis((PsiThisExpression
) classMemberReference
.getQualifierExpression()));
1094 else if (!myDelegatedMethods
.contains(method
)) {
1095 myPsiActions
.add(new QualifyWithField(classMemberReference
, method
.getName()));
1101 @Override public void visitThisExpression(final PsiThisExpression expression
) {
1102 class Visitor
implements ClassInstanceScanner
.ClassInstanceReferenceVisitor
{
1103 public void visitQualifier(PsiReferenceExpression qualified
, PsiExpression instanceRef
, PsiElement referencedInstance
) {
1104 LOG
.assertTrue(false);
1107 public void visitTypeCast(PsiTypeCastExpression typeCastExpression
, PsiExpression instanceRef
, PsiElement referencedInstance
) {
1108 processType(typeCastExpression
.getCastType().getType());
1111 public void visitReadUsage(PsiExpression instanceRef
, PsiType expectedType
, PsiElement referencedInstance
) {
1112 processType(expectedType
);
1115 public void visitWriteUsage(PsiExpression instanceRef
, PsiType assignedType
, PsiElement referencedInstance
) {
1116 LOG
.assertTrue(false);
1119 private void processType(PsiType type
) {
1120 final PsiClass resolved
= PsiUtil
.resolveClassInType(type
);
1121 if (resolved
!= null && !myBaseClassBases
.contains(resolved
)) {
1122 myPsiActions
.add(new QualifyThis(expression
));
1126 Visitor visitor
= new Visitor();
1127 ClassInstanceScanner
.processNonArrayExpression(visitor
, expression
, null);
1130 protected void visitClassMemberReferenceElement(PsiMember classMember
, PsiJavaCodeReferenceElement classMemberReference
) {
1136 private final class MyClassInstanceReferenceVisitor
implements ClassInstanceScanner
.ClassInstanceReferenceVisitor
{
1137 private final PsiClass myClass
;
1138 private final List
<UsageInfo
> myUsageInfoStorage
;
1139 private final Set
<PsiClass
> myImplementedInterfaces
;
1141 public MyClassInstanceReferenceVisitor(PsiClass aClass
, List
<UsageInfo
> usageInfoStorage
) {
1143 myUsageInfoStorage
= usageInfoStorage
;
1144 myImplementedInterfaces
= getImplementedInterfaces();
1147 public Set
<PsiClass
> getImplementedInterfaces() {
1148 PsiClass aClass
= myClass
;
1149 HashSet
<PsiClass
> result
= new HashSet
<PsiClass
>();
1150 while (aClass
!= null && !myManager
.areElementsEquivalent(aClass
, myBaseClass
)) {
1151 final PsiClassType
[] implementsTypes
= aClass
.getImplementsListTypes();
1152 for (PsiClassType implementsType
: implementsTypes
) {
1153 PsiClass resolved
= implementsType
.resolve();
1154 if (resolved
!= null && !myManager
.areElementsEquivalent(resolved
, myBaseClass
)) {
1155 result
.add(resolved
);
1156 InheritanceUtil
.getSuperClasses(resolved
, result
, true);
1160 aClass
= aClass
.getSuperClass();
1166 public void visitQualifier(PsiReferenceExpression qualified
, PsiExpression instanceRef
, PsiElement referencedInstance
) {
1167 final PsiExpression qualifierExpression
= qualified
.getQualifierExpression();
1169 // do not add usages inside a class
1170 if (qualifierExpression
== null
1171 || qualifierExpression
instanceof PsiThisExpression
1172 || qualifierExpression
instanceof PsiSuperExpression
) {
1176 PsiElement resolved
= qualified
.resolve();
1177 if (resolved
!= null && (myBaseClassMembers
.contains(resolved
) || myOverriddenMethods
.contains(resolved
))
1178 && !isDelegated((PsiMember
)resolved
)) {
1179 myUsageInfoStorage
.add(new NonDelegatedMemberUsageInfo(instanceRef
, resolved
, getFieldAccessibility(instanceRef
)));
1183 public void visitTypeCast(PsiTypeCastExpression typeCastExpression
, PsiExpression instanceRef
, PsiElement referencedInstance
) {
1184 processTypedUsage(typeCastExpression
.getCastType().getType(), instanceRef
);
1188 public void visitReadUsage(PsiExpression instanceRef
, PsiType expectedType
, PsiElement referencedInstance
) {
1189 processTypedUsage(expectedType
, instanceRef
);
1192 public void visitWriteUsage(PsiExpression instanceRef
, PsiType assignedType
, PsiElement referencedInstance
) {
1195 private void processTypedUsage(PsiType type
, PsiExpression instanceRef
) {
1196 final PsiClass aClass
= PsiUtil
.resolveClassInType(type
);
1197 if (aClass
== null) return;
1198 String qName
= aClass
.getQualifiedName();
1199 if (qName
!= null && "java.lang.Object".equals(qName
)) {
1200 myUsageInfoStorage
.add(new ObjectUpcastedUsageInfo(instanceRef
, aClass
, getFieldAccessibility(instanceRef
)));
1202 if (myBaseClassBases
.contains(aClass
)
1203 && !myImplementedInterfaces
.contains(aClass
) && !myDelegatedInterfaces
.contains(aClass
)) {
1204 myUsageInfoStorage
.add(new UpcastedUsageInfo(instanceRef
, aClass
, getFieldAccessibility(instanceRef
)));