refactoring conflicts in usage view: strip html
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / inheritanceToDelegation / InheritanceToDelegationProcessor.java
blob1316df548f090b53f79bdd9a46e102503ddfd30b
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.*;
22 import com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor;
23 import com.intellij.refactoring.util.classRefs.ClassInstanceScanner;
24 import com.intellij.refactoring.util.classRefs.ClassReferenceScanner;
25 import com.intellij.refactoring.util.classRefs.ClassReferenceSearchingScanner;
26 import com.intellij.usageView.UsageInfo;
27 import com.intellij.usageView.UsageViewDescriptor;
28 import com.intellij.usageView.UsageViewUtil;
29 import com.intellij.usages.UsageInfoToUsageConverter;
30 import com.intellij.usages.UsageTarget;
31 import com.intellij.usages.UsageViewManager;
32 import com.intellij.usages.UsageViewPresentation;
33 import com.intellij.util.IncorrectOperationException;
34 import com.intellij.util.VisibilityUtil;
35 import com.intellij.util.containers.HashMap;
36 import org.jetbrains.annotations.NonNls;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
40 import java.util.*;
42 /**
43 * @author dsl
45 public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
46 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.inheritanceToDelegation.InheritanceToDelegationProcessor");
47 private final PsiClass myClass;
48 private final String myInnerClassName;
49 private final boolean myIsDelegateOtherMembers;
50 private final Set<PsiClass> myDelegatedInterfaces;
51 private final Set<PsiMethod> myDelegatedMethods;
52 private final HashMap<PsiMethod,String> myDelegatedMethodsVisibility;
53 private final Set<PsiMethod> myOverriddenMethods;
55 private final PsiClass myBaseClass;
56 private final Set<PsiMember> myBaseClassMembers;
57 private final String myFieldName;
58 private final String myGetterName;
59 private final boolean myGenerateGetter;
60 private final Set<PsiClass> myBaseClassBases;
61 private Set<PsiClass> myClassImplementedInterfaces;
62 private final PsiElementFactory myFactory;
63 private final PsiClassType myBaseClassType;
64 private final PsiManager myManager;
65 private final boolean myIsInnerClassNeeded;
66 private Set<PsiClass> myClassInheritors;
67 private HashSet<PsiMethod> myAbstractDelegatedMethods;
68 private final Map<PsiClass, PsiSubstitutor> mySuperClassesToSubstitutors = new HashMap<PsiClass, PsiSubstitutor>();
71 public InheritanceToDelegationProcessor(Project project,
72 PsiClass aClass,
73 PsiClass targetBaseClass,
74 String fieldName,
75 String innerClassName,
76 PsiClass[] delegatedInterfaces,
77 PsiMethod[] delegatedMethods,
78 boolean delegateOtherMembers,
79 boolean generateGetter) {
80 super(project);
82 myClass = aClass;
83 myInnerClassName = innerClassName;
84 myIsDelegateOtherMembers = delegateOtherMembers;
85 myManager = myClass.getManager();
86 myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
88 myBaseClass = targetBaseClass;
89 LOG.assertTrue(
90 myBaseClass != null // && !myBaseClass.isInterface()
91 && (myBaseClass.getQualifiedName() == null || !myBaseClass.getQualifiedName().equals("java.lang.Object"))
93 myBaseClassMembers = getAllBaseClassMembers();
94 myBaseClassBases = getAllBases();
95 myBaseClassType = myFactory.createType(myBaseClass, getSuperSubstitutor (myBaseClass));
97 myIsInnerClassNeeded = InheritanceToDelegationUtil.isInnerClassNeeded(myClass, myBaseClass);
100 myFieldName = fieldName;
101 final String propertyName = JavaCodeStyleManager.getInstance(myProject).variableNameToPropertyName(myFieldName, VariableKind.FIELD);
102 myGetterName = PropertyUtil.suggestGetterName(propertyName, myBaseClassType);
103 myGenerateGetter = generateGetter;
105 myDelegatedInterfaces = new LinkedHashSet<PsiClass>();
106 addAll(myDelegatedInterfaces, delegatedInterfaces);
107 myDelegatedMethods = new LinkedHashSet<PsiMethod>();
108 addAll(myDelegatedMethods, delegatedMethods);
109 myDelegatedMethodsVisibility = new HashMap<PsiMethod, String>();
110 for (PsiMethod method : myDelegatedMethods) {
111 MethodSignature signature = method.getSignature(getSuperSubstitutor(method.getContainingClass()));
112 PsiMethod overridingMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, false);
113 if (overridingMethod != null) {
114 myDelegatedMethodsVisibility.put(method,
115 VisibilityUtil.getVisibilityModifier(overridingMethod.getModifierList()));
119 myOverriddenMethods = getOverriddenMethods();
122 private PsiSubstitutor getSuperSubstitutor(final PsiClass superClass) {
123 PsiSubstitutor result = mySuperClassesToSubstitutors.get(superClass);
124 if (result == null) {
125 result = TypeConversionUtil.getSuperClassSubstitutor(superClass, myClass, PsiSubstitutor.EMPTY);
126 mySuperClassesToSubstitutors.put(superClass, result);
128 return result;
131 protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
132 return new InheritanceToDelegationViewDescriptor(myClass);
135 @NotNull
136 protected UsageInfo[] findUsages() {
137 ArrayList<UsageInfo> usages = new ArrayList<UsageInfo>();
138 final PsiClass[] inheritors = ClassInheritorsSearch.search(myClass, myClass.getUseScope(), true).toArray(PsiClass.EMPTY_ARRAY);
139 myClassInheritors = new HashSet<PsiClass>();
140 myClassInheritors.add(myClass);
141 addAll(myClassInheritors, inheritors);
144 ClassReferenceScanner scanner = new ClassReferenceSearchingScanner(myClass);
145 final MyClassInstanceReferenceVisitor instanceReferenceVisitor = new MyClassInstanceReferenceVisitor(myClass, usages);
146 scanner.processReferences(new ClassInstanceScanner(myClass, instanceReferenceVisitor));
148 MyClassMemberReferencesVisitor visitor = new MyClassMemberReferencesVisitor(usages, instanceReferenceVisitor);
149 myClass.accept(visitor);
151 myClassImplementedInterfaces = instanceReferenceVisitor.getImplementedInterfaces();
153 for (PsiClass inheritor : inheritors) {
154 processClass(inheritor, usages);
157 return usages.toArray(new UsageInfo[usages.size()]);
160 private FieldAccessibility getFieldAccessibility(PsiElement element) {
161 for (PsiClass aClass : myClassInheritors) {
162 if (PsiTreeUtil.isAncestor(aClass, element, false)) {
163 return new FieldAccessibility(true, aClass);
166 return FieldAccessibility.INVISIBLE;
169 protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
170 UsageInfo[] usagesIn = refUsages.get();
171 ArrayList<UsageInfo> oldUsages = new ArrayList<UsageInfo>();
172 addAll(oldUsages, usagesIn);
173 final ObjectUpcastedUsageInfo[] objectUpcastedUsageInfos = objectUpcastedUsages(usagesIn);
174 if (myPrepareSuccessfulSwingThreadCallback != null) {
175 Map<PsiElement, String> conflicts = new LinkedHashMap<PsiElement, String>();
176 if (objectUpcastedUsageInfos.length > 0) {
177 final String message = RefactoringBundle.message("instances.of.0.upcasted.to.1.were.found",
178 RefactoringUIUtil.getDescription(myClass, true), CommonRefactoringUtil.htmlEmphasize("java.lang.Object"));
180 conflicts.put(myClass, message);
183 analyzeConflicts(usagesIn, conflicts);
184 if (!conflicts.isEmpty()) {
185 ConflictsDialog conflictsDialog =
186 new ConflictsDialog(myProject, conflicts);
187 conflictsDialog.show();
188 if (!conflictsDialog.isOK()){
189 if (conflictsDialog.isShowConflicts()) prepareSuccessful();
190 return false;
194 if (objectUpcastedUsageInfos.length > 0) {
195 showObjectUpcastedUsageView(objectUpcastedUsageInfos);
196 setPreviewUsages(true);
199 ArrayList<UsageInfo> filteredUsages = filterUsages(oldUsages);
200 refUsages.set(filteredUsages.toArray(new UsageInfo[filteredUsages.size()]));
201 prepareSuccessful();
202 return true;
205 private void analyzeConflicts(UsageInfo[] usage, Map<PsiElement, String> conflicts) {
206 HashMap<PsiElement,HashSet<PsiElement>> reportedNonDelegatedUsages = new HashMap<PsiElement, HashSet<PsiElement>>();
207 HashMap<PsiClass,HashSet<PsiElement>> reportedUpcasts = new HashMap<PsiClass, HashSet<PsiElement>>();
208 // HashSet reportedObjectUpcasts = new HashSet();
210 // final String nameJavaLangObject = ConflictsUtil.htmlEmphasize("java.lang.Object");
211 final String classDescription = RefactoringUIUtil.getDescription(myClass, false);
213 for (UsageInfo aUsage : usage) {
214 final PsiElement element = aUsage.getElement();
215 if (aUsage instanceof InheritanceToDelegationUsageInfo) {
216 InheritanceToDelegationUsageInfo usageInfo = (InheritanceToDelegationUsageInfo)aUsage;
217 /*if (usageInfo instanceof ObjectUpcastedUsageInfo) {
218 PsiElement container = ConflictsUtil.getContainer(usageInfo.element);
219 if (!reportedObjectUpcasts.contains(container)) {
220 String message = "An instance of " + classDescription + " is upcasted to "
221 + nameJavaLangObject + " in " + ConflictsUtil.getDescription(container, true) + ".";
222 conflicts.add(message);
223 reportedObjectUpcasts.add(container);
225 } else*/
226 if (!myIsDelegateOtherMembers && !usageInfo.getDelegateFieldAccessible().isAccessible()) {
227 if (usageInfo instanceof NonDelegatedMemberUsageInfo) {
228 final PsiElement nonDelegatedMember = ((NonDelegatedMemberUsageInfo)usageInfo).nonDelegatedMember;
229 HashSet<PsiElement> reportedContainers = reportedNonDelegatedUsages.get(nonDelegatedMember);
230 if (reportedContainers == null) {
231 reportedContainers = new HashSet<PsiElement>();
232 reportedNonDelegatedUsages.put(nonDelegatedMember, reportedContainers);
234 final PsiElement container = ConflictsUtil.getContainer(element);
235 if (container != null && !reportedContainers.contains(container)) {
236 String message = RefactoringBundle.message("0.uses.1.of.an.instance.of.a.2", RefactoringUIUtil.getDescription(container, true),
237 RefactoringUIUtil.getDescription(nonDelegatedMember, true), classDescription);
238 conflicts.put(container, CommonRefactoringUtil.capitalize(message));
239 reportedContainers.add(container);
242 else if (usageInfo instanceof UpcastedUsageInfo) {
243 final PsiClass upcastedTo = ((UpcastedUsageInfo)usageInfo).upcastedTo;
244 HashSet<PsiElement> reportedContainers = reportedUpcasts.get(upcastedTo);
245 if (reportedContainers == null) {
246 reportedContainers = new HashSet<PsiElement>();
247 reportedUpcasts.put(upcastedTo, reportedContainers);
249 final PsiElement container = ConflictsUtil.getContainer(element);
250 if (container != null && !reportedContainers.contains(container)) {
251 String message = RefactoringBundle.message("0.upcasts.an.instance.of.1.to.2",
252 RefactoringUIUtil.getDescription(container, true), classDescription,
253 RefactoringUIUtil.getDescription(upcastedTo, false));
254 conflicts.put(container, CommonRefactoringUtil.capitalize(message));
255 reportedContainers.add(container);
260 else if (aUsage instanceof NoLongerOverridingSubClassMethodUsageInfo) {
261 NoLongerOverridingSubClassMethodUsageInfo info = (NoLongerOverridingSubClassMethodUsageInfo)aUsage;
262 String message = RefactoringBundle.message("0.will.no.longer.override.1",
263 RefactoringUIUtil.getDescription(info.getSubClassMethod(), true),
264 RefactoringUIUtil.getDescription(info.getOverridenMethod(), true));
265 conflicts.put(info.getSubClassMethod(), message);
270 private static ObjectUpcastedUsageInfo[] objectUpcastedUsages(UsageInfo[] usages) {
271 ArrayList<ObjectUpcastedUsageInfo> result = new ArrayList<ObjectUpcastedUsageInfo>();
272 for (UsageInfo usage : usages) {
273 if (usage instanceof ObjectUpcastedUsageInfo) {
274 result.add(((ObjectUpcastedUsageInfo)usage));
277 return result.toArray(new ObjectUpcastedUsageInfo[result.size()]);
280 private ArrayList<UsageInfo> filterUsages(ArrayList<UsageInfo> usages) {
281 ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
283 for (UsageInfo usageInfo : usages) {
284 if (!(usageInfo instanceof InheritanceToDelegationUsageInfo)) {
285 continue;
287 if (usageInfo instanceof ObjectUpcastedUsageInfo) {
288 continue;
291 if (!myIsDelegateOtherMembers) {
292 final FieldAccessibility delegateFieldAccessible = ((InheritanceToDelegationUsageInfo)usageInfo).getDelegateFieldAccessible();
293 if (!delegateFieldAccessible.isAccessible()) continue;
296 result.add(usageInfo);
298 return result;
301 private void processClass(PsiClass inheritor, ArrayList<UsageInfo> usages) {
302 ClassReferenceScanner scanner = new ClassReferenceSearchingScanner(inheritor);
303 final MyClassInstanceReferenceVisitor instanceVisitor = new MyClassInstanceReferenceVisitor(inheritor, usages);
304 scanner.processReferences(
305 new ClassInstanceScanner(inheritor,
306 instanceVisitor)
308 MyClassInheritorMemberReferencesVisitor classMemberVisitor = new MyClassInheritorMemberReferencesVisitor(inheritor, usages, instanceVisitor);
309 inheritor.accept(classMemberVisitor);
310 PsiSubstitutor inheritorSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(myClass, inheritor, PsiSubstitutor.EMPTY);
312 PsiMethod[] methods = inheritor.getMethods();
313 for (PsiMethod method : methods) {
314 final PsiMethod baseMethod = findSuperMethodInBaseClass(method);
316 if (baseMethod != null) {
317 if (!baseMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
318 usages.add(new NoLongerOverridingSubClassMethodUsageInfo(method, baseMethod));
320 else {
321 final PsiMethod[] methodsByName = myClass.findMethodsByName(method.getName(), false);
322 for (final PsiMethod classMethod : methodsByName) {
323 final MethodSignature signature = classMethod.getSignature(inheritorSubstitutor);
324 if (signature.equals(method.getSignature(PsiSubstitutor.EMPTY))) {
325 if (!classMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
326 usages.add(new NoLongerOverridingSubClassMethodUsageInfo(method, baseMethod));
327 break;
336 protected void refreshElements(PsiElement[] elements) {
339 protected void performRefactoring(UsageInfo[] usages) {
340 try {
341 for (UsageInfo aUsage : usages) {
342 InheritanceToDelegationUsageInfo usage = (InheritanceToDelegationUsageInfo)aUsage;
345 if (usage instanceof UnqualifiedNonDelegatedMemberUsageInfo) {
346 delegateUsageFromClass(usage.getElement(), ((NonDelegatedMemberUsageInfo)usage).nonDelegatedMember,
347 usage.getDelegateFieldAccessible());
349 else {
350 upcastToDelegation(usage.getElement(), usage.getDelegateFieldAccessible());
354 myAbstractDelegatedMethods = new HashSet<PsiMethod>();
355 addInnerClass();
356 addField(usages);
357 delegateMethods();
358 addImplementingInterfaces();
359 } catch (IncorrectOperationException e) {
360 LOG.error(e);
364 private void addInnerClass() throws IncorrectOperationException {
365 if (!myIsInnerClassNeeded) return;
367 PsiClass innerClass = myFactory.createClass(myInnerClassName);
368 final PsiJavaCodeReferenceElement baseClassReferenceElement = myFactory.createClassReferenceElement(myBaseClass);
369 if (!myBaseClass.isInterface()) {
370 innerClass.getExtendsList().add(baseClassReferenceElement);
371 } else {
372 innerClass.getImplementsList().add(baseClassReferenceElement);
374 PsiUtil.setModifierProperty(innerClass, PsiModifier.PRIVATE, true);
375 innerClass = (PsiClass) myClass.add(innerClass);
377 List<InnerClassMethod> innerClassMethods = getInnerClassMethods();
378 for (InnerClassMethod innerClassMethod : innerClassMethods) {
379 innerClassMethod.createMethod(innerClass);
383 private void delegateUsageFromClass(PsiElement element, PsiElement nonDelegatedMember,
384 FieldAccessibility fieldAccessibility) throws IncorrectOperationException {
385 if (element instanceof PsiReferenceExpression) {
386 PsiReferenceExpression referenceExpression = (PsiReferenceExpression) element;
387 if (referenceExpression.getQualifierExpression() != null) {
388 upcastToDelegation(referenceExpression.getQualifierExpression(), fieldAccessibility);
389 } else {
390 final String name = ((PsiNamedElement) nonDelegatedMember).getName();
391 final String qualifier;
392 if (isStatic (nonDelegatedMember)) {
393 qualifier = myBaseClass.getName();
395 else if (!fieldAccessibility.isAccessible() && myGenerateGetter) {
396 qualifier = myGetterName + "()";
398 else {
399 qualifier = myFieldName;
402 PsiExpression newExpr = myFactory.createExpressionFromText(qualifier + "." + name, element);
403 newExpr = (PsiExpression) CodeStyleManager.getInstance(myProject).reformat(newExpr);
404 element.replace(newExpr);
407 else if (element instanceof PsiJavaCodeReferenceElement) {
408 final String name = ((PsiNamedElement) nonDelegatedMember).getName();
410 PsiElement parent = element.getParent ();
411 if (!isStatic (nonDelegatedMember) && parent instanceof PsiNewExpression) {
412 final PsiNewExpression newExpr = (PsiNewExpression) parent;
413 if (newExpr.getQualifier() != null) {
414 upcastToDelegation(newExpr.getQualifier(), fieldAccessibility);
415 } else {
416 final String qualifier;
417 if (!fieldAccessibility.isAccessible() && myGenerateGetter) {
418 qualifier = myGetterName + "()";
420 else {
421 qualifier = myFieldName;
423 newExpr.replace(myFactory.createExpressionFromText(qualifier + "." + newExpr.getText(), parent));
426 else {
427 final String qualifier = myBaseClass.getName();
428 PsiJavaCodeReferenceElement newRef = myFactory.createFQClassNameReferenceElement(qualifier + "." + name, element.getResolveScope ());
429 //newRef = (PsiJavaCodeReferenceElement) CodeStyleManager.getInstance(myProject).reformat(newRef);
430 element.replace(newRef);
432 } else {
433 LOG.assertTrue(false);
437 private static boolean isStatic(PsiElement member) {
438 if (member instanceof PsiModifierListOwner) {
439 final PsiModifierListOwner method = (PsiModifierListOwner) member;
440 return method.hasModifierProperty (PsiModifier.STATIC);
442 return false;
445 private void upcastToDelegation(PsiElement element, FieldAccessibility fieldAccessibility) throws IncorrectOperationException {
446 final PsiExpression expression = (PsiExpression) element;
448 final PsiExpression newExpr;
449 final PsiReferenceExpression ref;
450 @NonNls final String delegateQualifier;
451 if (!(expression instanceof PsiThisExpression || expression instanceof PsiSuperExpression)) {
452 delegateQualifier = "a.";
453 } else {
454 PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myProject).getResolveHelper();
455 final PsiVariable psiVariable = resolveHelper.resolveReferencedVariable(myFieldName, element);
456 if (psiVariable == null) {
457 delegateQualifier = "";
458 } else {
459 delegateQualifier = "a.";
462 if (!fieldAccessibility.isAccessible() && myGenerateGetter) {
463 newExpr = myFactory.createExpressionFromText(delegateQualifier + myGetterName + "()", expression);
464 ref = (PsiReferenceExpression) ((PsiMethodCallExpression) newExpr).getMethodExpression().getQualifierExpression();
465 } else {
466 newExpr = myFactory.createExpressionFromText(delegateQualifier + myFieldName, expression);
467 ref = (PsiReferenceExpression) ((PsiReferenceExpression) newExpr).getQualifierExpression();
469 // LOG.debug("upcastToDelegation:" + element + ":newExpr = " + newExpr);
470 // LOG.debug("upcastToDelegation:" + element + ":ref = " + ref);
471 if (ref != null) {
472 ref.replace(expression);
474 expression.replace(newExpr);
475 // LOG.debug("upcastToDelegation:" + element + ":replaced = " + replaced);
478 private void delegateMethods() throws IncorrectOperationException {
479 for (PsiMethod method : myDelegatedMethods) {
480 if (!myAbstractDelegatedMethods.contains(method)) {
481 PsiMethod methodToAdd = delegateMethod(myFieldName, method, getSuperSubstitutor(method.getContainingClass()));
483 String visibility = myDelegatedMethodsVisibility.get(method);
484 if (visibility != null) {
485 PsiUtil.setModifierProperty(methodToAdd, visibility, true);
488 myClass.add(methodToAdd);
493 private PsiMethod delegateMethod(@NonNls String delegationTarget,
494 PsiMethod method,
495 PsiSubstitutor substitutor) throws IncorrectOperationException {
496 substitutor = GenerateMembersUtil.correctSubstitutor(method, substitutor);
497 PsiMethod methodToAdd = GenerateMembersUtil.substituteGenericMethod(method, substitutor);
499 final PsiModifierList modifierList = methodToAdd.getModifierList();
500 modifierList.setModifierProperty(PsiModifier.ABSTRACT, false);
501 if (AnnotationUtil.isAnnotated(method, AnnotationUtil.NULLABLE, false)) {
502 modifierList.addAfter(myFactory.createAnnotationFromText("@" + AnnotationUtil.NULLABLE, methodToAdd), null);
504 else if (AnnotationUtil.isAnnotated(method, AnnotationUtil.NOT_NULL, false)) {
505 modifierList.addAfter(myFactory.createAnnotationFromText("@" + AnnotationUtil.NOT_NULL, methodToAdd), null);
508 final String delegationBody = getDelegationBody(methodToAdd, delegationTarget);
509 PsiCodeBlock newBody = myFactory.createCodeBlockFromText(delegationBody, method);
511 PsiCodeBlock oldBody = methodToAdd.getBody();
512 if (oldBody != null) {
513 oldBody.replace(newBody);
515 else {
516 methodToAdd.addBefore(newBody, null);
519 if (methodToAdd.getDocComment() != null) methodToAdd.getDocComment().delete();
520 methodToAdd = (PsiMethod)CodeStyleManager.getInstance(myProject).reformat(methodToAdd);
521 methodToAdd = (PsiMethod)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(methodToAdd);
522 return methodToAdd;
525 private static String getDelegationBody(PsiMethod methodToAdd, String delegationTarget) {
526 @NonNls final StringBuffer buffer = new StringBuffer();
527 buffer.append("{\n");
529 if (methodToAdd.getReturnType() != PsiType.VOID) {
530 buffer.append("return ");
533 buffer.append(delegationTarget);
534 buffer.append(".");
535 buffer.append(methodToAdd.getName());
536 buffer.append("(");
537 PsiParameter[] params = methodToAdd.getParameterList().getParameters();
538 for (int i = 0; i < params.length; i++) {
539 PsiParameter param = params[i];
540 if (i > 0) {
541 buffer.append(",");
543 buffer.append(param.getName());
545 buffer.append(");\n}");
546 return buffer.toString();
549 private void addImplementingInterfaces() throws IncorrectOperationException {
550 final PsiReferenceList implementsList = myClass.getImplementsList();
551 for (PsiClass delegatedInterface : myDelegatedInterfaces) {
552 if (!myClassImplementedInterfaces.contains(delegatedInterface)) {
553 implementsList.add(myFactory.createClassReferenceElement(delegatedInterface));
557 if (!myBaseClass.isInterface()) {
558 final PsiReferenceList extendsList = myClass.getExtendsList();
559 extendsList.getReferenceElements()[0].delete();
560 } else {
561 final PsiJavaCodeReferenceElement[] interfaceRefs = implementsList.getReferenceElements();
562 for (PsiJavaCodeReferenceElement interfaceRef : interfaceRefs) {
563 final PsiElement resolved = interfaceRef.resolve();
564 if (myManager.areElementsEquivalent(myBaseClass, resolved)) {
565 interfaceRef.delete();
566 break;
572 private void addField(UsageInfo[] usages) throws IncorrectOperationException {
573 final String fieldVisibility = getFieldVisibility(usages);
575 final boolean fieldInitializerNeeded = isFieldInitializerNeeded();
577 PsiField field = createField(fieldVisibility, fieldInitializerNeeded, defaultClassFieldType());
579 if (!myIsInnerClassNeeded) {
580 field.getTypeElement().replace(myFactory.createTypeElement(myBaseClassType));
581 if (fieldInitializerNeeded) {
582 final PsiJavaCodeReferenceElement classReferenceElement = myFactory.createReferenceElementByType(myBaseClassType);
583 PsiNewExpression newExpression = (PsiNewExpression) field.getInitializer();
584 newExpression.getClassReference().replace(classReferenceElement);
588 field = (PsiField) CodeStyleManager.getInstance(myProject).reformat(field);
589 myClass.add(field);
590 if (!fieldInitializerNeeded) {
591 fixConstructors();
594 if (myGenerateGetter) {
595 final String getterVisibility = PsiModifier.PUBLIC;
596 @NonNls StringBuffer getterBuffer = new StringBuffer();
597 getterBuffer.append(getterVisibility);
598 getterBuffer.append(" Object ");
599 getterBuffer.append(myGetterName);
600 getterBuffer.append("() {\n return ");
601 getterBuffer.append(myFieldName);
602 getterBuffer.append(";\n}");
603 PsiMethod getter = myFactory.createMethodFromText(getterBuffer.toString(), myClass);
604 getter.getReturnTypeElement().replace(myFactory.createTypeElement(myBaseClassType));
605 getter = (PsiMethod) CodeStyleManager.getInstance(myProject).reformat(getter);
606 myClass.add(getter);
610 private String getFieldVisibility(UsageInfo[] usages) {
611 if (myIsDelegateOtherMembers && !myGenerateGetter) {
612 return PsiModifier.PUBLIC;
615 for (UsageInfo aUsage : usages) {
616 InheritanceToDelegationUsageInfo usage = (InheritanceToDelegationUsageInfo)aUsage;
617 final FieldAccessibility delegateFieldAccessible = usage.getDelegateFieldAccessible();
618 if (delegateFieldAccessible.isAccessible() && delegateFieldAccessible.getContainingClass() != myClass) {
619 return PsiModifier.PROTECTED;
622 return PsiModifier.PRIVATE;
625 private @NonNls String defaultClassFieldType() {
626 return (myIsInnerClassNeeded ? myInnerClassName : "Object");
629 private PsiField createField(final String fieldVisibility, final boolean fieldInitializerNeeded, String defaultTypeName) throws IncorrectOperationException {
630 @NonNls StringBuffer buffer = new StringBuffer();
631 buffer.append(fieldVisibility);
632 buffer.append(" final " + defaultTypeName + " ");
633 buffer.append(myFieldName);
634 if (fieldInitializerNeeded) {
635 buffer.append(" = new " + defaultTypeName + "()");
637 buffer.append(";");
638 return myFactory.createFieldFromText(buffer.toString(), myClass);
641 private void fixConstructors() throws IncorrectOperationException {
642 if (myBaseClass.isInterface()) return;
643 final PsiJavaCodeReferenceElement baseClassReference = myFactory.createClassReferenceElement(myBaseClass);
645 PsiMethod[] constructors = myClass.getConstructors();
646 for (PsiMethod constructor : constructors) {
647 PsiCodeBlock body = constructor.getBody();
648 final PsiStatement[] statements = body.getStatements();
649 @NonNls String fieldQualifier = "";
650 PsiParameter[] constructorParams = constructor.getParameterList().getParameters();
651 for (PsiParameter constructorParam : constructorParams) {
652 if (myFieldName.equals(constructorParam.getName())) {
653 fieldQualifier = "this.";
654 break;
657 final @NonNls String assignmentText = fieldQualifier + myFieldName + "= new " + defaultClassFieldType() + "()";
658 if (statements.length < 1 || !RefactoringUtil.isSuperOrThisCall(statements[0], true, true) || myBaseClass.isInterface()) {
659 PsiExpressionStatement assignmentStatement =
660 (PsiExpressionStatement)myFactory.createStatementFromText(
661 assignmentText, body
663 if (!myIsInnerClassNeeded) {
664 final PsiAssignmentExpression assignmentExpr = (PsiAssignmentExpression)assignmentStatement.getExpression();
665 final PsiNewExpression newExpression = (PsiNewExpression)assignmentExpr.getRExpression();
666 assert newExpression != null;
667 final PsiJavaCodeReferenceElement classRef = newExpression.getClassReference();
668 assert classRef != null;
669 classRef.replace(baseClassReference);
672 assignmentStatement = (PsiExpressionStatement)CodeStyleManager.getInstance(myProject).reformat(assignmentStatement);
673 if (statements.length > 0) {
674 if (!RefactoringUtil.isSuperOrThisCall(statements[0], true, false)) {
675 body.addBefore(assignmentStatement, statements[0]);
677 else {
678 body.addAfter(assignmentStatement, statements[0]);
681 else {
682 body.add(assignmentStatement);
685 else {
686 final PsiExpressionStatement callStatement = ((PsiExpressionStatement)statements[0]);
687 if (!RefactoringUtil.isSuperOrThisCall(callStatement, false, true)) {
688 final PsiMethodCallExpression superConstructorCall =
689 (PsiMethodCallExpression)callStatement.getExpression();
690 PsiAssignmentExpression assignmentExpression =
691 (PsiAssignmentExpression)myFactory.createExpressionFromText(
692 assignmentText, superConstructorCall
694 PsiNewExpression newExpression =
695 (PsiNewExpression)assignmentExpression.getRExpression();
696 if (!myIsInnerClassNeeded) {
697 newExpression.getClassReference().replace(baseClassReference);
699 assignmentExpression = (PsiAssignmentExpression)CodeStyleManager.getInstance(myProject).reformat(assignmentExpression);
700 newExpression.getArgumentList().replace(superConstructorCall.getArgumentList());
701 superConstructorCall.replace(assignmentExpression);
707 private boolean isFieldInitializerNeeded() {
708 if (myBaseClass.isInterface()) return true;
709 PsiMethod[] constructors = myClass.getConstructors();
710 for (PsiMethod constructor : constructors) {
711 final PsiStatement[] statements = constructor.getBody().getStatements();
712 if (statements.length > 0 && RefactoringUtil.isSuperOrThisCall(statements[0], true, false)) return false;
714 return true;
717 private List<InnerClassMethod> getInnerClassMethods() {
718 ArrayList<InnerClassMethod> result = new ArrayList<InnerClassMethod>();
720 // find all neccessary constructors
721 if (!myBaseClass.isInterface()) {
722 PsiMethod[] constructors = myClass.getConstructors();
723 for (PsiMethod constructor : constructors) {
724 final PsiStatement[] statements = constructor.getBody().getStatements();
725 if (statements.length > 0 && RefactoringUtil.isSuperOrThisCall(statements[0], true, false)) {
726 final PsiMethodCallExpression superConstructorCall =
727 (PsiMethodCallExpression)((PsiExpressionStatement)statements[0]).getExpression();
728 PsiElement superConstructor = superConstructorCall.getMethodExpression().resolve();
729 if (superConstructor instanceof PsiMethod && ((PsiMethod)superConstructor).isConstructor()) {
730 result.add(new InnerClassConstructor((PsiMethod)superConstructor));
736 // find overriding/implementing method
738 class InnerClassOverridingMethod extends InnerClassMethod {
739 public InnerClassOverridingMethod(PsiMethod method) {
740 super(method);
743 public void createMethod(PsiClass innerClass)
744 throws IncorrectOperationException {
745 OverriddenMethodClassMemberReferencesVisitor visitor = new OverriddenMethodClassMemberReferencesVisitor();
746 myClass.accept(visitor);
747 final List<PsiAction> actions = visitor.getPsiActions();
748 for (PsiAction action : actions) {
749 action.run();
751 innerClass.add(myMethod);
752 myMethod.delete();
753 // myMethod.replace(delegateMethod(myMethod));
757 for (PsiMethod method : myOverriddenMethods) {
758 result.add(new InnerClassOverridingMethod(method));
762 // fix abstract methods
764 class InnerClassAbstractMethod extends InnerClassMethod {
765 private final boolean myImplicitImplementation;
767 public InnerClassAbstractMethod(PsiMethod method, final boolean implicitImplementation) {
768 super(method);
769 myImplicitImplementation = implicitImplementation;
772 public void createMethod(PsiClass innerClass)
773 throws IncorrectOperationException {
774 PsiSubstitutor substitutor = getSuperSubstitutor(myMethod.getContainingClass());
775 PsiMethod method = delegateMethod(myClass.getName() + ".this", myMethod, substitutor);
776 final PsiClass containingClass = myMethod.getContainingClass();
777 if (myBaseClass.isInterface() || containingClass.isInterface()) {
778 PsiUtil.setModifierProperty(method, PsiModifier.PUBLIC, true);
780 innerClass.add(method);
781 if (!myImplicitImplementation) {
782 final MethodSignature signature = myMethod.getSignature(substitutor);
783 PsiMethod outerMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, false);
784 if (outerMethod == null) {
785 @Modifier String visibility = checkOuterClassAbstractMethod(signature);
786 PsiMethod newOuterMethod = (PsiMethod)myClass.add(myMethod);
787 PsiUtil.setModifierProperty(newOuterMethod, visibility, true);
788 final PsiDocComment docComment = newOuterMethod.getDocComment();
789 if (docComment != null) {
790 docComment.delete();
797 PsiMethod[] methods = myBaseClass.getAllMethods();
799 for (PsiMethod method : methods) {
800 if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
801 final MethodSignature signature = method.getSignature(getSuperSubstitutor(method.getContainingClass()));
802 PsiMethod classMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, true);
803 if (classMethod == null || classMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
804 result.add(new InnerClassAbstractMethod(method, false));
806 else if ((myBaseClass.isInterface() && classMethod.getContainingClass() != myClass)) { // IDEADEV-19675
807 result.add(new InnerClassAbstractMethod(method, true));
814 return result;
817 private void showObjectUpcastedUsageView(final ObjectUpcastedUsageInfo[] usages) {
818 UsageViewPresentation presentation = new UsageViewPresentation();
819 presentation.setTargetsNodeText(RefactoringBundle.message("replacing.inheritance.with.delegation"));
820 presentation.setCodeUsagesString(RefactoringBundle.message("instances.casted.to.java.lang.object"));
821 final String upcastedString = RefactoringBundle.message("instances.upcasted.to.object");
822 presentation.setUsagesString(upcastedString);
823 presentation.setTabText(upcastedString);
825 UsageViewManager manager = UsageViewManager.getInstance(myProject);
826 manager.showUsages(
827 new UsageTarget[]{new PsiElement2UsageTargetAdapter(myClass)},
828 UsageInfoToUsageConverter.convert(new UsageInfoToUsageConverter.TargetElementsDescriptor(myClass), usages),
829 presentation
832 WindowManager.getInstance().getStatusBar(myProject).setInfo(RefactoringBundle.message("instances.upcasted.to.java.lang.object.found"));
837 * @param methodSignature
838 * @return Visibility
840 @Modifier
841 private String checkOuterClassAbstractMethod(MethodSignature methodSignature) {
842 @Modifier String visibility = PsiModifier.PROTECTED;
843 for (PsiMethod method : myDelegatedMethods) {
844 MethodSignature otherSignature = method.getSignature(getSuperSubstitutor(method.getContainingClass()));
846 if (MethodSignatureUtil.areSignaturesEqual(otherSignature, methodSignature)) {
847 visibility = VisibilityUtil.getHighestVisibility(visibility,
848 VisibilityUtil.getVisibilityModifier(method.getModifierList()));
849 myAbstractDelegatedMethods.add(method);
852 return visibility;
855 private Set<PsiMethod> getOverriddenMethods() {
856 LinkedHashSet<PsiMethod> result = new LinkedHashSet<PsiMethod>();
858 PsiMethod[] methods = myClass.getMethods();
859 for (PsiMethod method : methods) {
860 if (findSuperMethodInBaseClass(method) != null) result.add(method);
862 return result;
865 @Nullable
866 private PsiMethod findSuperMethodInBaseClass (PsiMethod method) {
867 final PsiMethod[] superMethods = method.findSuperMethods();
868 for (PsiMethod superMethod : superMethods) {
869 PsiClass containingClass = superMethod.getContainingClass();
870 if (InheritanceUtil.isInheritorOrSelf(myBaseClass, containingClass, true)) {
871 String qName = containingClass.getQualifiedName();
872 if (qName == null || !"java.lang.Object".equals(qName)) {
873 return superMethod;
877 return null;
881 protected String getCommandName() {
882 return RefactoringBundle.message("replace.inheritance.with.delegation.command", UsageViewUtil.getDescriptiveName(myClass));
885 private Set<PsiMember> getAllBaseClassMembers() {
886 HashSet<PsiMember> result = new HashSet<PsiMember>();
887 addAll(result, myBaseClass.getAllFields());
888 addAll(result, myBaseClass.getAllInnerClasses());
889 addAll(result, myBaseClass.getAllMethods());
891 //remove java.lang.Object members
892 for (Iterator<PsiMember> iterator = result.iterator(); iterator.hasNext();) {
893 PsiMember member = iterator.next();
894 if ("java.lang.Object".equals(member.getContainingClass().getQualifiedName())) {
895 iterator.remove();
898 return Collections.unmodifiableSet(result);
901 private Set<PsiClass> getAllBases() {
902 HashSet<PsiClass> temp = new HashSet<PsiClass>();
903 InheritanceUtil.getSuperClasses(myBaseClass, temp, true);
904 temp.add(myBaseClass);
905 return Collections.unmodifiableSet(temp);
908 private static <T> void addAll(Collection<T> collection, T[] objs) {
909 for (T obj : objs) {
910 collection.add(obj);
914 private boolean isDelegated(PsiMember classMember) {
915 if(!(classMember instanceof PsiMethod)) return false;
916 final PsiMethod method = (PsiMethod) classMember;
917 for (PsiMethod delegatedMethod : myDelegatedMethods) {
918 //methods reside in base class, so no substitutor needed
919 if (MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY),
920 delegatedMethod.getSignature(PsiSubstitutor.EMPTY))) {
921 return true;
924 return false;
927 private class MyClassInheritorMemberReferencesVisitor extends ClassMemberReferencesVisitor {
928 private final List<UsageInfo> myUsageInfoStorage;
929 private final ClassInstanceScanner.ClassInstanceReferenceVisitor myInstanceVisitor;
931 MyClassInheritorMemberReferencesVisitor(PsiClass aClass, List<UsageInfo> usageInfoStorage,
932 ClassInstanceScanner.ClassInstanceReferenceVisitor instanceScanner) {
933 super(aClass);
935 myUsageInfoStorage = usageInfoStorage;
936 myInstanceVisitor = instanceScanner;
939 @Override public void visitTypeElement(PsiTypeElement type) {
940 super.visitTypeElement (type);
943 @Override public void visitReferenceElement(PsiJavaCodeReferenceElement element) {
944 super.visitReferenceElement (element);
947 protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
948 if ("super".equals(classMemberReference.getText()) && classMemberReference.getParent() instanceof PsiMethodCallExpression) {
949 return;
952 if (classMember != null && myBaseClassMembers.contains(classMember) && !isDelegated(classMember)) {
953 final FieldAccessibility delegateFieldVisibility = new FieldAccessibility(true, getPsiClass());
954 final InheritanceToDelegationUsageInfo usageInfo;
955 if (classMemberReference instanceof PsiReferenceExpression) {
956 if (((PsiReferenceExpression) classMemberReference).getQualifierExpression() == null) {
957 usageInfo = new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference, classMember,
958 delegateFieldVisibility);
959 } else {
960 usageInfo = new NonDelegatedMemberUsageInfo(
961 ((PsiReferenceExpression) classMemberReference).getQualifierExpression(),
962 classMember, delegateFieldVisibility
965 myUsageInfoStorage.add(usageInfo);
967 else /*if (classMemberReference instanceof PsiJavaCodeReferenceElement)*/ {
968 usageInfo = new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference, classMember,
969 delegateFieldVisibility);
970 myUsageInfoStorage.add(usageInfo);
976 @Override public void visitThisExpression(PsiThisExpression expression) {
977 ClassInstanceScanner.processNonArrayExpression(myInstanceVisitor, expression, null);
981 private class MyClassMemberReferencesVisitor extends MyClassInheritorMemberReferencesVisitor {
982 MyClassMemberReferencesVisitor(List<UsageInfo> usageInfoStorage,
983 ClassInstanceScanner.ClassInstanceReferenceVisitor instanceScanner) {
984 super(InheritanceToDelegationProcessor.this.myClass, usageInfoStorage, instanceScanner);
987 @Override public void visitMethod(PsiMethod method) {
988 if (!myOverriddenMethods.contains(method)) {
989 super.visitMethod(method);
994 interface PsiAction {
995 void run() throws IncorrectOperationException;
999 * This visitor should be called for overriden methods before they are moved to an inner class
1001 private class OverriddenMethodClassMemberReferencesVisitor extends ClassMemberReferencesVisitor {
1002 private final ArrayList<PsiAction> myPsiActions;
1003 private final PsiThisExpression myQualifiedThis;
1005 OverriddenMethodClassMemberReferencesVisitor() throws IncorrectOperationException {
1006 super(myClass);
1007 myPsiActions = new ArrayList<PsiAction>();
1008 final PsiJavaCodeReferenceElement classReferenceElement = myFactory.createClassReferenceElement(myClass);
1009 myQualifiedThis = (PsiThisExpression) myFactory.createExpressionFromText("A.this", null);
1010 myQualifiedThis.getQualifier().replace(classReferenceElement);
1013 public List<PsiAction> getPsiActions() {
1014 return myPsiActions;
1017 class QualifyThis implements PsiAction {
1018 private final PsiThisExpression myThisExpression;
1020 QualifyThis(PsiThisExpression thisExpression) {
1021 myThisExpression = thisExpression;
1024 public void run() throws IncorrectOperationException {
1025 myThisExpression.replace(myQualifiedThis);
1029 class QualifyName implements PsiAction {
1030 private final PsiReferenceExpression myRef;
1031 private final String myReferencedName;
1033 QualifyName(PsiReferenceExpression ref, String name) {
1034 myRef = ref;
1035 myReferencedName = name;
1038 public void run() throws IncorrectOperationException {
1039 PsiReferenceExpression newRef =
1040 (PsiReferenceExpression) myFactory.createExpressionFromText("a." + myReferencedName, null);
1041 newRef.getQualifierExpression().replace(myQualifiedThis);
1042 myRef.replace(newRef);
1046 class QualifyWithField implements PsiAction {
1047 private final PsiReferenceExpression myReference;
1048 private final String myReferencedName;
1050 public QualifyWithField(final PsiReferenceExpression reference, final String name) {
1051 myReference = reference;
1052 myReferencedName = name;
1055 public void run() throws IncorrectOperationException {
1056 PsiReferenceExpression newRef =
1057 (PsiReferenceExpression) myFactory.createExpressionFromText(myFieldName + "." + myReferencedName, null);
1058 myReference.replace(newRef);
1062 protected void visitClassMemberReferenceExpression(PsiMember classMember,
1063 PsiReferenceExpression classMemberReference) {
1064 if (classMember instanceof PsiField) {
1065 final PsiField field = (PsiField) classMember;
1067 if (field.getContainingClass().equals(myClass)) {
1068 final String name = field.getName();
1069 final PsiField baseField = myBaseClass.findFieldByName(name, true);
1070 if (baseField != null) {
1071 myPsiActions.add(new QualifyName(classMemberReference, name));
1072 } else if (classMemberReference.getQualifierExpression() instanceof PsiThisExpression) {
1073 myPsiActions.add(new QualifyThis((PsiThisExpression) classMemberReference.getQualifierExpression()));
1076 } else if (classMember instanceof PsiMethod) {
1077 final PsiMethod method = (PsiMethod) classMember;
1079 if (method.getContainingClass().equals(myClass)) {
1080 if (!myOverriddenMethods.contains(method)) {
1081 final PsiMethod baseMethod = findSuperMethodInBaseClass(method);
1082 if (baseMethod != null) {
1083 myPsiActions.add(new QualifyName(classMemberReference, baseMethod.getName()));
1084 } else if (classMemberReference.getQualifierExpression() instanceof PsiThisExpression) {
1085 myPsiActions.add(new QualifyThis((PsiThisExpression) classMemberReference.getQualifierExpression()));
1088 else if (!myDelegatedMethods.contains(method)) {
1089 myPsiActions.add(new QualifyWithField(classMemberReference, method.getName()));
1095 @Override public void visitThisExpression(final PsiThisExpression expression) {
1096 class Visitor implements ClassInstanceScanner.ClassInstanceReferenceVisitor {
1097 public void visitQualifier(PsiReferenceExpression qualified, PsiExpression instanceRef, PsiElement referencedInstance) {
1098 LOG.assertTrue(false);
1101 public void visitTypeCast(PsiTypeCastExpression typeCastExpression, PsiExpression instanceRef, PsiElement referencedInstance) {
1102 processType(typeCastExpression.getCastType().getType());
1105 public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) {
1106 processType(expectedType);
1109 public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType, PsiElement referencedInstance) {
1110 LOG.assertTrue(false);
1113 private void processType(PsiType type) {
1114 final PsiClass resolved = PsiUtil.resolveClassInType(type);
1115 if (resolved != null && !myBaseClassBases.contains(resolved)) {
1116 myPsiActions.add(new QualifyThis(expression));
1120 Visitor visitor = new Visitor();
1121 ClassInstanceScanner.processNonArrayExpression(visitor, expression, null);
1124 protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
1130 private final class MyClassInstanceReferenceVisitor implements ClassInstanceScanner.ClassInstanceReferenceVisitor {
1131 private final PsiClass myClass;
1132 private final List<UsageInfo> myUsageInfoStorage;
1133 private final Set<PsiClass> myImplementedInterfaces;
1135 public MyClassInstanceReferenceVisitor(PsiClass aClass, List<UsageInfo> usageInfoStorage) {
1136 myClass = aClass;
1137 myUsageInfoStorage = usageInfoStorage;
1138 myImplementedInterfaces = getImplementedInterfaces();
1141 public Set<PsiClass> getImplementedInterfaces() {
1142 PsiClass aClass = myClass;
1143 HashSet<PsiClass> result = new HashSet<PsiClass>();
1144 while (aClass != null && !myManager.areElementsEquivalent(aClass, myBaseClass)) {
1145 final PsiClassType[] implementsTypes = aClass.getImplementsListTypes();
1146 for (PsiClassType implementsType : implementsTypes) {
1147 PsiClass resolved = implementsType.resolve();
1148 if (resolved != null && !myManager.areElementsEquivalent(resolved, myBaseClass)) {
1149 result.add(resolved);
1150 InheritanceUtil.getSuperClasses(resolved, result, true);
1154 aClass = aClass.getSuperClass();
1156 return result;
1160 public void visitQualifier(PsiReferenceExpression qualified, PsiExpression instanceRef, PsiElement referencedInstance) {
1161 final PsiExpression qualifierExpression = qualified.getQualifierExpression();
1163 // do not add usages inside a class
1164 if (qualifierExpression == null
1165 || qualifierExpression instanceof PsiThisExpression
1166 || qualifierExpression instanceof PsiSuperExpression) {
1167 return;
1170 PsiElement resolved = qualified.resolve();
1171 if (resolved != null && (myBaseClassMembers.contains(resolved) || myOverriddenMethods.contains(resolved))
1172 && !isDelegated((PsiMember)resolved)) {
1173 myUsageInfoStorage.add(new NonDelegatedMemberUsageInfo(instanceRef, resolved, getFieldAccessibility(instanceRef)));
1177 public void visitTypeCast(PsiTypeCastExpression typeCastExpression, PsiExpression instanceRef, PsiElement referencedInstance) {
1178 processTypedUsage(typeCastExpression.getCastType().getType(), instanceRef);
1182 public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) {
1183 processTypedUsage(expectedType, instanceRef);
1186 public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType, PsiElement referencedInstance) {
1189 private void processTypedUsage(PsiType type, PsiExpression instanceRef) {
1190 final PsiClass aClass = PsiUtil.resolveClassInType(type);
1191 if (aClass == null) return;
1192 String qName = aClass.getQualifiedName();
1193 if (qName != null && "java.lang.Object".equals(qName)) {
1194 myUsageInfoStorage.add(new ObjectUpcastedUsageInfo(instanceRef, aClass, getFieldAccessibility(instanceRef)));
1195 } else {
1196 if (myBaseClassBases.contains(aClass)
1197 && !myImplementedInterfaces.contains(aClass) && !myDelegatedInterfaces.contains(aClass)) {
1198 myUsageInfoStorage.add(new UpcastedUsageInfo(instanceRef, aClass, getFieldAccessibility(instanceRef)));