2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.refactoring
.extractclass
;
18 import com
.intellij
.ide
.util
.PackageUtil
;
19 import com
.intellij
.openapi
.application
.ApplicationManager
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.module
.Module
;
22 import com
.intellij
.openapi
.module
.ModuleUtil
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.util
.Condition
;
25 import com
.intellij
.openapi
.util
.Ref
;
26 import com
.intellij
.openapi
.util
.text
.StringUtil
;
27 import com
.intellij
.psi
.*;
28 import com
.intellij
.psi
.codeStyle
.CodeStyleManager
;
29 import com
.intellij
.psi
.codeStyle
.CodeStyleSettings
;
30 import com
.intellij
.psi
.codeStyle
.CodeStyleSettingsManager
;
31 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
32 import com
.intellij
.psi
.javadoc
.PsiDocTagValue
;
33 import com
.intellij
.psi
.search
.GlobalSearchScope
;
34 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
35 import com
.intellij
.psi
.tree
.IElementType
;
36 import com
.intellij
.psi
.util
.InheritanceUtil
;
37 import com
.intellij
.psi
.util
.PropertyUtil
;
38 import com
.intellij
.psi
.util
.PsiTreeUtil
;
39 import com
.intellij
.psi
.util
.PsiUtil
;
40 import com
.intellij
.refactoring
.RefactorJBundle
;
41 import com
.intellij
.refactoring
.extractclass
.usageInfo
.*;
42 import com
.intellij
.refactoring
.psi
.MethodInheritanceUtils
;
43 import com
.intellij
.refactoring
.psi
.TypeParametersVisitor
;
44 import com
.intellij
.refactoring
.util
.FixableUsageInfo
;
45 import com
.intellij
.refactoring
.util
.FixableUsagesRefactoringProcessor
;
46 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
47 import com
.intellij
.usageView
.UsageInfo
;
48 import com
.intellij
.usageView
.UsageViewDescriptor
;
49 import com
.intellij
.util
.IncorrectOperationException
;
50 import com
.intellij
.util
.containers
.MultiMap
;
51 import org
.jetbrains
.annotations
.NonNls
;
52 import org
.jetbrains
.annotations
.NotNull
;
56 public class ExtractClassProcessor
extends FixableUsagesRefactoringProcessor
{
57 private static final Logger logger
= Logger
.getInstance("com.siyeh.rpp.extractclass.ExtractClassProcessor");
59 private final PsiClass sourceClass
;
60 private final List
<PsiField
> fields
;
61 private final List
<PsiMethod
> methods
;
62 private final List
<PsiClass
> innerClasses
;
63 private final Set
<PsiClass
> innerClassesToMakePublic
= new HashSet
<PsiClass
>();
64 private final List
<PsiTypeParameter
> typeParams
= new ArrayList
<PsiTypeParameter
>();
65 private final String newPackageName
;
66 private final boolean myGenerateAccessors
;
67 private final String newClassName
;
68 private final String delegateFieldName
;
69 private final boolean requiresBackpointer
;
70 private boolean delegationRequired
= false;
72 public ExtractClassProcessor(PsiClass sourceClass
,
73 List
<PsiField
> fields
,
74 List
<PsiMethod
> methods
,
75 List
<PsiClass
> innerClasses
,
76 String newPackageName
,
77 String newClassName
) {
78 this(sourceClass
, fields
, methods
, innerClasses
, newPackageName
, newClassName
, false);
81 public ExtractClassProcessor(PsiClass sourceClass
,
82 List
<PsiField
> fields
,
83 List
<PsiMethod
> methods
,
84 List
<PsiClass
> classes
,
87 boolean generateAccessors
) {
88 super(sourceClass
.getProject());
89 this.sourceClass
= sourceClass
;
90 this.newPackageName
= packageName
;
91 myGenerateAccessors
= generateAccessors
;
92 this.fields
= new ArrayList
<PsiField
>(fields
);
93 this.methods
= new ArrayList
<PsiMethod
>(methods
);
94 this.innerClasses
= new ArrayList
<PsiClass
>(classes
);
95 this.newClassName
= newClassName
;
96 delegateFieldName
= calculateDelegateFieldName();
97 requiresBackpointer
= new BackpointerUsageVisitor(fields
, innerClasses
, methods
, sourceClass
).backpointerRequired();
98 if (requiresBackpointer
) {
99 typeParams
.addAll(Arrays
.asList(sourceClass
.getTypeParameters()));
102 final Set
<PsiTypeParameter
> typeParamSet
= new HashSet
<PsiTypeParameter
>();
103 final TypeParametersVisitor visitor
= new TypeParametersVisitor(typeParamSet
);
104 for (PsiField field
: fields
) {
105 field
.accept(visitor
);
107 for (PsiMethod method
: methods
) {
108 method
.accept(visitor
);
110 typeParams
.addAll(typeParamSet
);
115 protected boolean preprocessUsages(final Ref
<UsageInfo
[]> refUsages
) {
116 final MultiMap
<PsiElement
, String
> conflicts
= new MultiMap
<PsiElement
, String
>();
117 final Project project
= sourceClass
.getProject();
118 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
119 final PsiClass existingClass
=
120 JavaPsiFacade
.getInstance(project
).findClass(StringUtil
.getQualifiedName(newPackageName
, newClassName
), scope
);
121 if (existingClass
!= null) {
122 conflicts
.putValue(existingClass
, RefactorJBundle
.message("cannot.perform.the.refactoring") +
123 RefactorJBundle
.message("there.already.exists.a.class.with.the.chosen.name"));
126 if (!myGenerateAccessors
) {
127 calculateInitializersConflicts(conflicts
);
128 final NecessaryAccessorsVisitor visitor
= new NecessaryAccessorsVisitor();
129 for (PsiField field
: fields
) {
130 field
.accept(visitor
);
132 for (PsiMethod method
: methods
) {
133 method
.accept(visitor
);
135 for (PsiClass innerClass
: innerClasses
) {
136 innerClass
.accept(visitor
);
139 final Set
<PsiField
> fieldsNeedingGetter
= visitor
.getFieldsNeedingGetter();
140 for (PsiField field
: fieldsNeedingGetter
) {
141 conflicts
.putValue(field
, "Field \'" + field
.getName() + "\' needs getter");
143 final Set
<PsiField
> fieldsNeedingSetter
= visitor
.getFieldsNeedingSetter();
144 for (PsiField field
: fieldsNeedingSetter
) {
145 conflicts
.putValue(field
, "Field \'" + field
.getName() + "\' needs getter");
148 return showConflicts(conflicts
);
152 protected boolean showConflicts(final MultiMap
<PsiElement
, String
> conflicts
) {
153 if (!conflicts
.isEmpty() && ApplicationManager
.getApplication().isUnitTestMode()) {
154 throw new RuntimeException(StringUtil
.join(conflicts
.values(), "\n"));
156 return super.showConflicts(conflicts
);
159 private void calculateInitializersConflicts(MultiMap
<PsiElement
, String
> conflicts
) {
160 final PsiClassInitializer
[] initializers
= sourceClass
.getInitializers();
161 for (PsiClassInitializer initializer
: initializers
) {
162 if (initializerDependsOnMoved(initializer
)) {
163 conflicts
.putValue(initializer
, "Class initializer requires moved members");
166 for (PsiMethod constructor
: sourceClass
.getConstructors()) {
167 if (initializerDependsOnMoved(constructor
.getBody())) {
168 conflicts
.putValue(constructor
, "Constructor requires moved members");
173 private boolean initializerDependsOnMoved(PsiElement initializer
) {
174 final boolean [] dependsOnMoved
= new boolean[]{false};
175 initializer
.accept(new JavaRecursiveElementWalkingVisitor(){
176 public void visitReferenceExpression(final PsiReferenceExpression expression
) {
177 super.visitReferenceExpression(expression
);
178 final PsiElement resolved
= expression
.resolve();
179 if (resolved
!= null) {
180 dependsOnMoved
[0] |= isInMovedElement(resolved
);
184 return dependsOnMoved
[0];
187 private String
calculateDelegateFieldName() {
188 final Project project
= sourceClass
.getProject();
189 final CodeStyleSettingsManager settingsManager
= CodeStyleSettingsManager
.getInstance(project
);
190 final CodeStyleSettings settings
= settingsManager
.getCurrentSettings();
192 final String baseName
= settings
.FIELD_NAME_PREFIX
.length() == 0 ? StringUtil
.decapitalize(newClassName
) : newClassName
;
193 String name
= settings
.FIELD_NAME_PREFIX
+ baseName
+ settings
.FIELD_NAME_SUFFIX
;
194 if (!existsFieldWithName(name
) && !JavaPsiFacade
.getInstance(project
).getNameHelper().isKeyword(name
)) {
199 name
= settings
.FIELD_NAME_PREFIX
+ baseName
+ counter
+ settings
.FIELD_NAME_SUFFIX
;
200 if (!existsFieldWithName(name
) && !JavaPsiFacade
.getInstance(project
).getNameHelper().isKeyword(name
)) {
208 private boolean existsFieldWithName(String name
) {
209 final PsiField
[] allFields
= sourceClass
.getAllFields();
210 for (PsiField field
: allFields
) {
211 if (name
.equals(field
.getName()) && !fields
.contains(field
)) {
218 protected String
getCommandName() {
219 return RefactorJBundle
.message("extracted.class.command.name", newClassName
);
222 protected UsageViewDescriptor
createUsageViewDescriptor(UsageInfo
[] usageInfos
) {
223 return new ExtractClassUsageViewDescriptor(sourceClass
);
226 protected void performRefactoring(UsageInfo
[] usageInfos
) {
227 if (!buildClass()) return;
228 if (delegationRequired
) {
231 super.performRefactoring(usageInfos
);
235 private void buildDelegate() {
236 final PsiManager manager
= sourceClass
.getManager();
237 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory();
238 final CodeStyleManager codeStyleManager
= manager
.getCodeStyleManager();
239 @NonNls final StringBuilder fieldBuffer
= new StringBuilder();
240 final String delegateVisibility
= calculateDelegateVisibility();
241 fieldBuffer
.append(delegateVisibility
).append(' ');
242 fieldBuffer
.append("final ");
243 final String fullyQualifiedName
= StringUtil
.getQualifiedName(newPackageName
, newClassName
);
244 fieldBuffer
.append(fullyQualifiedName
);
245 if (!typeParams
.isEmpty()) {
246 fieldBuffer
.append('<');
247 for (PsiTypeParameter typeParameter
: typeParams
) {
248 fieldBuffer
.append(typeParameter
.getName());
250 fieldBuffer
.append('>');
252 fieldBuffer
.append(' ');
253 fieldBuffer
.append(delegateFieldName
);
254 fieldBuffer
.append('=');
255 fieldBuffer
.append("new ").append(fullyQualifiedName
);
256 if (!typeParams
.isEmpty()) {
257 fieldBuffer
.append('<');
258 for (PsiTypeParameter typeParameter
: typeParams
) {
259 fieldBuffer
.append(typeParameter
.getName());
261 fieldBuffer
.append('>');
263 fieldBuffer
.append('(');
264 boolean isFirst
= true;
265 if (requiresBackpointer
) {
266 fieldBuffer
.append("this");
269 for (PsiField field
: fields
) {
270 if (field
.hasModifierProperty(PsiModifier
.STATIC
)) {
273 if (!field
.hasInitializer()) {
276 final PsiExpression initializer
= field
.getInitializer();
277 if (PsiUtil
.isConstantExpression(initializer
)) {
281 fieldBuffer
.append(", ");
284 assert initializer
!= null;
285 fieldBuffer
.append(initializer
.getText());
288 fieldBuffer
.append(");");
290 final String fieldString
= fieldBuffer
.toString();
291 final PsiField field
= factory
.createFieldFromText(fieldString
, sourceClass
);
292 final PsiElement newField
= sourceClass
.add(field
);
293 codeStyleManager
.reformat(JavaCodeStyleManager
.getInstance(myProject
).shortenClassReferences(newField
));
295 catch (IncorrectOperationException e
) {
301 private String
calculateDelegateVisibility() {
302 for (PsiField field
: fields
) {
303 if (field
.hasModifierProperty(PsiModifier
.PUBLIC
) && !field
.hasModifierProperty(PsiModifier
.STATIC
)) {
307 for (PsiField field
: fields
) {
308 if (field
.hasModifierProperty(PsiModifier
.PROTECTED
) && !field
.hasModifierProperty(PsiModifier
.STATIC
)) {
312 for (PsiField field
: fields
) {
313 if (field
.hasModifierProperty(PsiModifier
.PACKAGE_LOCAL
) && !field
.hasModifierProperty(PsiModifier
.STATIC
)) {
320 public void findUsages(@NotNull List
<FixableUsageInfo
> usages
) {
321 for (PsiField field
: fields
) {
322 findUsagesForField(field
, usages
);
323 usages
.add(new RemoveField(field
));
325 for (PsiClass innerClass
: innerClasses
) {
326 findUsagesForInnerClass(innerClass
, usages
);
327 usages
.add(new RemoveInnerClass(innerClass
));
329 for (PsiMethod method
: methods
) {
330 if (method
.hasModifierProperty(PsiModifier
.STATIC
)) {
331 findUsagesForStaticMethod(method
, usages
);
334 findUsagesForMethod(method
, usages
);
339 private void findUsagesForInnerClass(PsiClass innerClass
, List
<FixableUsageInfo
> usages
) {
340 final PsiManager psiManager
= innerClass
.getManager();
341 final Project project
= psiManager
.getProject();
342 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
343 final Iterable
<PsiReference
> calls
= ReferencesSearch
.search(innerClass
, scope
);
344 final String innerName
= innerClass
.getQualifiedName();
345 assert innerName
!= null;
346 final String sourceClassQualifiedName
= sourceClass
.getQualifiedName();
347 assert sourceClassQualifiedName
!= null;
348 final String newInnerClassName
= StringUtil
.getQualifiedName(newPackageName
, newClassName
) + innerName
.substring(sourceClassQualifiedName
.length());
349 boolean hasExternalReference
= false;
350 for (PsiReference reference
: calls
) {
351 final PsiElement referenceElement
= reference
.getElement();
352 if (referenceElement
instanceof PsiJavaCodeReferenceElement
) {
353 if (!isInMovedElement(referenceElement
)) {
355 usages
.add(new ReplaceClassReference((PsiJavaCodeReferenceElement
)referenceElement
, newInnerClassName
));
356 hasExternalReference
= true;
360 if (hasExternalReference
) {
361 innerClassesToMakePublic
.add(innerClass
);
365 private void findUsagesForMethod(PsiMethod method
, List
<FixableUsageInfo
> usages
) {
366 final PsiManager psiManager
= method
.getManager();
367 final Project project
= psiManager
.getProject();
368 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
369 final Iterable
<PsiReference
> calls
= ReferencesSearch
.search(method
, scope
);
370 for (PsiReference reference
: calls
) {
371 final PsiElement referenceElement
= reference
.getElement();
372 final PsiElement parent
= referenceElement
.getParent();
373 if (parent
instanceof PsiMethodCallExpression
) {
374 final PsiMethodCallExpression call
= (PsiMethodCallExpression
)parent
;
375 if (isInMovedElement(call
)) {
378 final PsiReferenceExpression methodExpression
= call
.getMethodExpression();
379 final PsiExpression qualifier
= methodExpression
.getQualifierExpression();
380 if (qualifier
== null || qualifier
instanceof PsiThisExpression
) {
381 usages
.add(new ReplaceThisCallWithDelegateCall(call
, delegateFieldName
));
383 delegationRequired
= true;
387 if (!delegationRequired
&& MethodInheritanceUtils
.hasSiblingMethods(method
)) {
388 delegationRequired
= true;
391 if (delegationRequired
) {
392 usages
.add(new MakeMethodDelegate(method
, delegateFieldName
));
395 usages
.add(new RemoveMethod(method
));
399 private void findUsagesForStaticMethod(PsiMethod method
, List
<FixableUsageInfo
> usages
) {
400 final PsiManager psiManager
= method
.getManager();
401 final Project project
= psiManager
.getProject();
402 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
403 final Iterable
<PsiReference
> calls
= ReferencesSearch
.search(method
, scope
);
404 for (PsiReference reference
: calls
) {
405 final PsiElement referenceElement
= reference
.getElement();
407 final PsiElement parent
= referenceElement
.getParent();
408 if (parent
instanceof PsiMethodCallExpression
) {
409 final PsiMethodCallExpression call
= (PsiMethodCallExpression
)parent
;
410 if (!isInMovedElement(call
)) {
411 final String fullyQualifiedName
= StringUtil
.getQualifiedName(newPackageName
, newClassName
);
412 usages
.add(new RetargetStaticMethodCall(call
, fullyQualifiedName
));
416 usages
.add(new RemoveMethod(method
));
419 private boolean isInMovedElement(PsiElement exp
) {
420 for (PsiField field
: fields
) {
421 if (PsiTreeUtil
.isAncestor(field
, exp
, false)) {
425 for (PsiMethod method
: methods
) {
426 if (PsiTreeUtil
.isAncestor(method
, exp
, false)) {
433 private void findUsagesForField(PsiField field
, List
<FixableUsageInfo
> usages
) {
434 final PsiManager psiManager
= field
.getManager();
435 final Project project
= psiManager
.getProject();
436 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
438 final String qualifiedName
= StringUtil
.getQualifiedName(newPackageName
, newClassName
);
439 @NonNls final String getter
= PropertyUtil
.suggestGetterName(myProject
, field
);
440 @NonNls final String setter
= PropertyUtil
.suggestSetterName(myProject
, field
);
441 final boolean isStatic
= field
.hasModifierProperty(PsiModifier
.STATIC
);
443 for (PsiReference reference
: ReferencesSearch
.search(field
, scope
)) {
444 final PsiElement element
= reference
.getElement();
445 if (isInMovedElement(element
)) {
449 if (element
instanceof PsiReferenceExpression
) {
450 final PsiReferenceExpression exp
= (PsiReferenceExpression
)element
;
451 if (RefactoringUtil
.isPlusPlusOrMinusMinus(exp
)) {
453 ?
new ReplaceStaticVariableIncrementDecrement(exp
, qualifiedName
)
454 : new ReplaceInstanceVariableIncrementDecrement(exp
, delegateFieldName
, setter
, getter
));
456 else if (RefactoringUtil
.isAssignmentLHS(exp
)) {
458 ?
new ReplaceStaticVariableAssignment(exp
, qualifiedName
)
459 : new ReplaceInstanceVariableAssignment(PsiTreeUtil
.getParentOfType(exp
, PsiAssignmentExpression
.class),
460 delegateFieldName
, setter
, getter
));
465 ?
new ReplaceStaticVariableAccess(exp
, qualifiedName
)
466 : new ReplaceInstanceVariableAccess(exp
, delegateFieldName
, getter
));
470 delegationRequired
= true;
472 } else if (element
instanceof PsiDocTagValue
) {
473 usages
.add(new BindJavadocReference(element
, qualifiedName
, field
.getName()));
478 private boolean hasGetter(final PsiField field
) {
479 return hasGetterOrSetter(sourceClass
.findMethodsBySignature(PropertyUtil
.generateGetterPrototype(field
), false));
482 private boolean hasSetter(final PsiField field
) {
483 return hasGetterOrSetter(sourceClass
.findMethodsBySignature(PropertyUtil
.generateSetterPrototype(field
), false));
486 private boolean hasGetterOrSetter(final PsiMethod
[] getters
) {
487 for (PsiMethod getter
: getters
) {
488 if (!isInMovedElement(getter
)) return true;
494 private boolean buildClass() {
495 final PsiManager manager
= sourceClass
.getManager();
496 final Project project
= sourceClass
.getProject();
497 final ExtractedClassBuilder extractedClassBuilder
= new ExtractedClassBuilder();
498 extractedClassBuilder
.setProject(myProject
);
499 extractedClassBuilder
.setClassName(newClassName
);
500 extractedClassBuilder
.setPackageName(newPackageName
);
501 extractedClassBuilder
.setOriginalClassName(sourceClass
.getQualifiedName());
502 extractedClassBuilder
.setRequiresBackPointer(requiresBackpointer
);
503 for (PsiField field
: fields
) {
504 extractedClassBuilder
.addField(field
);
506 for (PsiMethod method
: methods
) {
507 extractedClassBuilder
.addMethod(method
);
509 for (PsiClass innerClass
: innerClasses
) {
510 extractedClassBuilder
.addInnerClass(innerClass
, innerClassesToMakePublic
.contains(innerClass
));
512 extractedClassBuilder
.setTypeArguments(typeParams
);
513 final List
<PsiClass
> interfaces
= calculateInterfacesSupported();
514 extractedClassBuilder
.setInterfaces(interfaces
);
516 if (myGenerateAccessors
) {
517 final NecessaryAccessorsVisitor visitor
= new NecessaryAccessorsVisitor() {
519 protected boolean isProhibitedReference(PsiField field
) {
520 if (fields
.contains(field
)) {
523 if (innerClasses
.contains(field
.getContainingClass())) {
529 sourceClass
.accept(visitor
);
530 extractedClassBuilder
.setFieldsNeedingGetters(visitor
.getFieldsNeedingGetter());
531 extractedClassBuilder
.setFieldsNeedingSetters(visitor
.getFieldsNeedingSetter());
534 final String classString
= extractedClassBuilder
.buildBeanClass();
537 final PsiFile containingFile
= sourceClass
.getContainingFile();
539 final PsiDirectory containingDirectory
= containingFile
.getContainingDirectory();
540 final Module module
= ModuleUtil
.findModuleForPsiElement(containingFile
);
541 assert module
!= null;
542 final PsiDirectory directory
= PackageUtil
.findOrCreateDirectoryForPackage(module
, newPackageName
, containingDirectory
, false);
543 if (directory
!= null) {
544 final PsiFile newFile
= PsiFileFactory
.getInstance(project
).createFileFromText(newClassName
+ ".java", classString
);
545 final PsiElement addedFile
= directory
.add(newFile
);
546 final CodeStyleManager codeStyleManager
= manager
.getCodeStyleManager();
547 final PsiElement shortenedFile
= JavaCodeStyleManager
.getInstance(project
).shortenClassReferences(addedFile
);
548 codeStyleManager
.reformat(shortenedFile
);
553 catch (IncorrectOperationException e
) {
559 private List
<PsiClass
> calculateInterfacesSupported() {
560 final List
<PsiClass
> out
= new ArrayList
<PsiClass
>();
561 final PsiClass
[] supers
= sourceClass
.getSupers();
562 for (PsiClass superClass
: supers
) {
563 if (!superClass
.isInterface()) {
566 final PsiMethod
[] superclassMethods
= superClass
.getMethods();
567 if (superclassMethods
.length
== 0) {
570 boolean allMethodsCovered
= true;
572 for (PsiMethod method
: superclassMethods
) {
573 boolean isCovered
= false;
574 for (PsiMethod movedMethod
: methods
) {
575 if (isSuperMethod(method
, movedMethod
)) {
581 allMethodsCovered
= false;
585 if (allMethodsCovered
) {
589 final Project project
= sourceClass
.getProject();
590 final PsiManager manager
= sourceClass
.getManager();
591 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
592 if (usesDefaultSerialization(sourceClass
)) {
593 final PsiClass serializable
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.io.Serializable", scope
);
594 out
.add(serializable
);
596 if (usesDefaultClone(sourceClass
)) {
597 final PsiClass cloneable
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.lang.Cloneable", scope
);
603 private static boolean isSuperMethod(PsiMethod method
, PsiMethod movedMethod
) {
604 final PsiMethod
[] superMethods
= movedMethod
.findSuperMethods();
605 for (PsiMethod testMethod
: superMethods
) {
606 if (testMethod
.equals(method
)) {
613 private static boolean usesDefaultClone(PsiClass aClass
) {
614 final Project project
= aClass
.getProject();
615 final PsiManager manager
= aClass
.getManager();
616 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
617 final PsiClass cloneable
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.lang.Cloneable", scope
);
618 if (!InheritanceUtil
.isCorrectDescendant(aClass
, cloneable
, true)) {
621 final PsiMethod
[] methods
= aClass
.findMethodsByName("clone", false);
622 for (PsiMethod method
: methods
) {
623 final PsiParameterList parameterList
= method
.getParameterList();
624 final PsiParameter
[] parameters
= parameterList
.getParameters();
625 if (parameters
.length
== 0) {
632 private static boolean usesDefaultSerialization(PsiClass aClass
) {
633 final Project project
= aClass
.getProject();
634 final PsiManager manager
= aClass
.getManager();
635 final GlobalSearchScope scope
= GlobalSearchScope
.allScope(project
);
636 final PsiClass serializable
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.io.Serializable", scope
);
637 if (!InheritanceUtil
.isCorrectDescendant(aClass
, serializable
, true)) {
640 final PsiMethod
[] methods
= aClass
.findMethodsByName("writeObject", false);
641 for (PsiMethod method
: methods
) {
642 final PsiParameterList parameterList
= method
.getParameterList();
643 final PsiParameter
[] parameters
= parameterList
.getParameters();
644 if (parameters
.length
== 1) {
645 final PsiType type
= parameters
[0].getType();
646 final String text
= type
.getCanonicalText();
647 if ("java.io.DataOutputStream".equals(text
)) {
655 private class NecessaryAccessorsVisitor
extends JavaRecursiveElementWalkingVisitor
{
656 private final Set
<PsiField
> fieldsNeedingGetter
= new HashSet
<PsiField
>();
657 private final Set
<PsiField
> fieldsNeedingSetter
= new HashSet
<PsiField
>();
659 public void visitReferenceExpression(PsiReferenceExpression expression
) {
660 super.visitReferenceExpression(expression
);
661 if (isProhibitedReference(expression
)) {
662 final PsiField field
= getReferencedField(expression
);
663 if (!hasGetter(field
)) {
664 fieldsNeedingGetter
.add(field
);
669 public void visitAssignmentExpression(PsiAssignmentExpression expression
) {
670 super.visitAssignmentExpression(expression
);
672 final PsiExpression lhs
= expression
.getLExpression();
673 if (isProhibitedReference(lhs
)) {
674 final PsiField field
= getReferencedField(lhs
);
675 if (!hasGetter(field
)) {
676 fieldsNeedingSetter
.add(field
);
681 public void visitPostfixExpression(PsiPostfixExpression expression
) {
682 super.visitPostfixExpression(expression
);
683 checkSetterNeeded(expression
.getOperand(), expression
.getOperationSign());
686 public void visitPrefixExpression(PsiPrefixExpression expression
) {
687 super.visitPrefixExpression(expression
);
688 checkSetterNeeded(expression
.getOperand(), expression
.getOperationSign());
691 private void checkSetterNeeded(final PsiExpression operand
, final PsiJavaToken sign
) {
692 final IElementType tokenType
= sign
.getTokenType();
693 if (!tokenType
.equals(JavaTokenType
.PLUSPLUS
) && !tokenType
.equals(JavaTokenType
.MINUSMINUS
)) {
696 if (isProhibitedReference(operand
)) {
697 final PsiField field
= getReferencedField(operand
);
698 if (!hasSetter(field
)) {
699 fieldsNeedingSetter
.add(field
);
704 public Set
<PsiField
> getFieldsNeedingGetter() {
705 return fieldsNeedingGetter
;
708 public Set
<PsiField
> getFieldsNeedingSetter() {
709 return fieldsNeedingSetter
;
713 protected boolean isProhibitedReference(PsiExpression expression
) {
714 return BackpointerUtil
.isBackpointerReference(expression
, new Condition
<PsiField
>() {
715 public boolean value(final PsiField field
) {
716 return NecessaryAccessorsVisitor
.this.isProhibitedReference(field
);
721 protected boolean isProhibitedReference(PsiField field
) {
722 if (fields
.contains(field
)) {
725 if (innerClasses
.contains(field
.getContainingClass())) {
731 private PsiField
getReferencedField(PsiExpression expression
) {
732 if (expression
instanceof PsiParenthesizedExpression
) {
733 final PsiExpression contents
= ((PsiParenthesizedExpression
)expression
).getExpression();
734 return getReferencedField(contents
);
736 final PsiReferenceExpression reference
= (PsiReferenceExpression
)expression
;
737 return (PsiField
)reference
.resolve();