do not replace anonymous inheritance with delegation
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / inheritanceToDelegation / InheritanceToDelegationProcessor.java
blob1a82f3a0688ef468267a2954a181af546c5bf863
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;
44 import java.util.*;
46 /**
47 * @author dsl
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,
76 PsiClass aClass,
77 PsiClass targetBaseClass,
78 String fieldName,
79 String innerClassName,
80 PsiClass[] delegatedInterfaces,
81 PsiMethod[] delegatedMethods,
82 boolean delegateOtherMembers,
83 boolean generateGetter) {
84 super(project);
86 myClass = aClass;
87 myInnerClassName = innerClassName;
88 myIsDelegateOtherMembers = delegateOtherMembers;
89 myManager = myClass.getManager();
90 myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
92 myBaseClass = targetBaseClass;
93 LOG.assertTrue(
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);
132 return result;
135 protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
136 return new InheritanceToDelegationViewDescriptor(myClass);
139 @NotNull
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();
194 return false;
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()]));
205 prepareSuccessful();
206 return true;
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);
229 } else*/
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)) {
289 continue;
291 if (usageInfo instanceof ObjectUpcastedUsageInfo) {
292 continue;
295 if (!myIsDelegateOtherMembers) {
296 final FieldAccessibility delegateFieldAccessible = ((InheritanceToDelegationUsageInfo)usageInfo).getDelegateFieldAccessible();
297 if (!delegateFieldAccessible.isAccessible()) continue;
300 result.add(usageInfo);
302 return result;
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,
310 instanceVisitor)
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));
324 else {
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));
331 break;
340 protected void refreshElements(PsiElement[] elements) {
343 protected void performRefactoring(UsageInfo[] usages) {
344 try {
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());
353 else {
354 upcastToDelegation(usage.getElement(), usage.getDelegateFieldAccessible());
358 myAbstractDelegatedMethods = new HashSet<PsiMethod>();
359 addInnerClass();
360 addField(usages);
361 delegateMethods();
362 addImplementingInterfaces();
363 } catch (IncorrectOperationException e) {
364 LOG.error(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);
375 } else {
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);
393 } else {
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 + "()";
402 else {
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);
419 } else {
420 final String qualifier;
421 if (!fieldAccessibility.isAccessible() && myGenerateGetter) {
422 qualifier = myGetterName + "()";
424 else {
425 qualifier = myFieldName;
427 newExpr.replace(myFactory.createExpressionFromText(qualifier + "." + newExpr.getText(), parent));
430 else {
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);
436 } else {
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);
446 return false;
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.";
457 } else {
458 PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myProject).getResolveHelper();
459 final PsiVariable psiVariable = resolveHelper.resolveReferencedVariable(myFieldName, element);
460 if (psiVariable == null) {
461 delegateQualifier = "";
462 } else {
463 delegateQualifier = "a.";
466 if (!fieldAccessibility.isAccessible() && myGenerateGetter) {
467 newExpr = myFactory.createExpressionFromText(delegateQualifier + myGetterName + "()", expression);
468 ref = (PsiReferenceExpression) ((PsiMethodCallExpression) newExpr).getMethodExpression().getQualifierExpression();
469 } else {
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);
475 if (ref != null) {
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,
498 PsiMethod method,
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);
519 else {
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);
526 return 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);
538 buffer.append(".");
539 buffer.append(methodToAdd.getName());
540 buffer.append("(");
541 PsiParameter[] params = methodToAdd.getParameterList().getParameters();
542 for (int i = 0; i < params.length; i++) {
543 PsiParameter param = params[i];
544 if (i > 0) {
545 buffer.append(",");
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();
566 } else {
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();
572 break;
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);
595 myClass.add(field);
596 if (!fieldInitializerNeeded) {
597 fixConstructors();
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);
612 myClass.add(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 + "()");
643 buffer.append(";");
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.";
660 break;
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(
667 assignmentText, body
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]);
683 else {
684 body.addAfter(assignmentStatement, statements[0]);
687 else {
688 body.add(assignmentStatement);
691 else {
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;
720 return true;
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) {
746 super(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) {
755 action.run();
757 innerClass.add(myMethod);
758 myMethod.delete();
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) {
774 super(method);
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) {
796 docComment.delete();
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));
820 return result;
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);
832 manager.showUsages(
833 new UsageTarget[]{new PsiElement2UsageTargetAdapter(myClass)},
834 UsageInfoToUsageConverter.convert(new UsageInfoToUsageConverter.TargetElementsDescriptor(myClass), usages),
835 presentation
838 WindowManager.getInstance().getStatusBar(myProject).setInfo(RefactoringBundle.message("instances.upcasted.to.java.lang.object.found"));
843 * @param methodSignature
844 * @return Visibility
846 @Modifier
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);
858 return visibility;
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);
868 return result;
871 @Nullable
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)) {
879 return superMethod;
883 return null;
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())) {
901 iterator.remove();
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) {
915 for (T obj : objs) {
916 collection.add(obj);
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))) {
927 return true;
930 return false;
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) {
939 super(aClass);
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) {
955 return;
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);
965 } else {
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 {
1012 super(myClass);
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) {
1040 myRef = ref;
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) {
1142 myClass = aClass;
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();
1162 return result;
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) {
1173 return;
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)));
1201 } else {
1202 if (myBaseClassBases.contains(aClass)
1203 && !myImplementedInterfaces.contains(aClass) && !myDelegatedInterfaces.contains(aClass)) {
1204 myUsageInfoStorage.add(new UpcastedUsageInfo(instanceRef, aClass, getFieldAccessibility(instanceRef)));