| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * Created by IntelliJ IDEA. |
| * User: dsl |
| * Date: 17.04.2002 |
| * Time: 14:39:57 |
| * To change template for new class use |
| * Code Style | Class Templates options (Tools | IDE Options). |
| */ |
| package com.intellij.refactoring.makeStatic; |
| |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.codeStyle.VariableKind; |
| import com.intellij.psi.util.InheritanceUtil; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import com.intellij.refactoring.util.RefactoringUtil; |
| import com.intellij.refactoring.util.VariableData; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashSet; |
| |
| public class MakeStaticUtil { |
| public static InternalUsageInfo[] findClassRefsInMember(PsiTypeParameterListOwner member, boolean includeSelf) { |
| PsiClass containingClass = member.getContainingClass(); |
| ArrayList<InternalUsageInfo> classRefs = new ArrayList<InternalUsageInfo>(); |
| addClassRefs(member, classRefs, containingClass, member, includeSelf); |
| return classRefs.toArray(new InternalUsageInfo[classRefs.size()]); |
| } |
| |
| public static boolean isParameterNeeded(PsiTypeParameterListOwner member) { |
| return findClassRefsInMember(member, false).length > 0; |
| } |
| |
| private static void addClassRefs(PsiTypeParameterListOwner originalMember, ArrayList<InternalUsageInfo> classRefs, |
| PsiClass containingClass, PsiElement element, boolean includeSelf) { |
| if (element instanceof PsiReferenceExpression) { |
| PsiReferenceExpression ref = (PsiReferenceExpression)element; |
| |
| if (!ref.isQualified()) { // resolving only "naked" fields and methods |
| PsiElement resolved = ref.resolve(); |
| |
| if (resolved instanceof PsiMember && !((PsiMember)resolved).hasModifierProperty(PsiModifier.STATIC)) { |
| PsiMember member = (PsiMember)resolved; |
| if (originalMember.getManager().areElementsEquivalent(member, originalMember)) { |
| if (includeSelf) { |
| classRefs.add(new SelfUsageInfo(element, originalMember)); |
| } |
| } |
| else { |
| final PsiClass memberContainingClass = member.getContainingClass(); |
| if (!(originalMember instanceof PsiClass) || !isPartOf(memberContainingClass, (PsiClass)originalMember)) { |
| if (isPartOf(memberContainingClass, containingClass)) { |
| classRefs.add(new InternalUsageInfo(element, member)); |
| } |
| } |
| } |
| } |
| } |
| } |
| else if (element instanceof PsiThisExpression) { |
| PsiJavaCodeReferenceElement qualifier = ((PsiThisExpression) element).getQualifier(); |
| PsiElement refElement = qualifier != null ? |
| qualifier.resolve() : PsiTreeUtil.getParentOfType(element, PsiClass.class); |
| if (refElement instanceof PsiClass && !refElement.equals(originalMember) && isPartOf((PsiClass)refElement, containingClass)) { |
| final PsiElement parent = element.getParent(); |
| if (parent instanceof PsiReferenceExpression && ((PsiReferenceExpression)parent).isReferenceTo(originalMember)) { |
| if (includeSelf) { |
| classRefs.add(new SelfUsageInfo(parent, originalMember)); |
| } |
| } else { |
| classRefs.add(new InternalUsageInfo(element, refElement)); |
| } |
| } |
| } |
| else if (element instanceof PsiSuperExpression) { |
| PsiJavaCodeReferenceElement qualifier = ((PsiSuperExpression) element).getQualifier(); |
| PsiElement refElement = qualifier != null ? |
| qualifier.resolve() : PsiTreeUtil.getParentOfType(element, PsiClass.class); |
| if (refElement instanceof PsiClass) { |
| if (isPartOf((PsiClass) refElement, containingClass)) { |
| if (!(originalMember instanceof PsiClass && isPartOf((PsiClass)refElement, (PsiClass)originalMember))) { |
| classRefs.add(new InternalUsageInfo(element, refElement)); |
| } |
| } |
| } |
| } |
| else if (element instanceof PsiNewExpression) { |
| PsiJavaCodeReferenceElement classReference = ((PsiNewExpression) element).getClassReference(); |
| if (classReference != null) { |
| PsiElement refElement = classReference.resolve(); |
| if (refElement instanceof PsiClass) { |
| PsiClass hisClass = ((PsiClass) refElement).getContainingClass(); |
| if (hisClass != originalMember && isPartOf(hisClass, containingClass) && !((PsiClass)refElement).hasModifierProperty(PsiModifier.STATIC)) { |
| classRefs.add(new InternalUsageInfo(element, refElement)); |
| } |
| } |
| } |
| } |
| |
| PsiElement[] children = element.getChildren(); |
| for (PsiElement child : children) { |
| addClassRefs(originalMember, classRefs, containingClass, child, includeSelf); |
| } |
| } |
| |
| |
| private static boolean isPartOf(PsiClass elementClass, PsiClass containingClass) { |
| while(elementClass != null) { |
| if (InheritanceUtil.isInheritorOrSelf(containingClass, elementClass, true)) return true; |
| if (elementClass.hasModifierProperty(PsiModifier.STATIC)) return false; |
| elementClass = elementClass.getContainingClass(); |
| } |
| |
| return false; |
| } |
| |
| public static boolean buildVariableData(PsiTypeParameterListOwner member, ArrayList<VariableData> result) { |
| final InternalUsageInfo[] classRefsInMethod = findClassRefsInMember(member, false); |
| return collectVariableData(member, classRefsInMethod, result); |
| } |
| |
| public static boolean collectVariableData(PsiMember member, InternalUsageInfo[] internalUsages, |
| ArrayList<VariableData> variableDatum) { |
| HashSet<PsiField> reported = new HashSet<PsiField>(); |
| HashSet<PsiField> accessedForWriting = new HashSet<PsiField>(); |
| boolean needClassParameter = false; |
| for (InternalUsageInfo usage : internalUsages) { |
| final PsiElement referencedElement = usage.getReferencedElement(); |
| if (usage.isWriting()) { |
| accessedForWriting.add((PsiField)referencedElement); |
| needClassParameter = true; |
| } |
| else if (referencedElement instanceof PsiField) { |
| PsiField field = (PsiField)referencedElement; |
| reported.add(field); |
| } |
| else { |
| needClassParameter = true; |
| } |
| } |
| |
| final ArrayList<PsiField> psiFields = new ArrayList<PsiField>(reported); |
| Collections.sort(psiFields, new Comparator<PsiField>() { |
| public int compare(PsiField psiField, PsiField psiField1) { |
| return psiField.getName().compareTo(psiField1.getName()); |
| } |
| }); |
| for (final PsiField field : psiFields) { |
| if (accessedForWriting.contains(field)) continue; |
| VariableData data = new VariableData(field); |
| JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(member.getProject()); |
| String name = field.getName(); |
| name = codeStyleManager.variableNameToPropertyName(name, VariableKind.FIELD); |
| name = codeStyleManager.propertyNameToVariableName(name, VariableKind.PARAMETER); |
| name = RefactoringUtil.suggestUniqueVariableName(name, member, field); |
| data.name = name; |
| data.passAsParameter = true; |
| variableDatum.add(data); |
| } |
| return needClassParameter; |
| } |
| } |