mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
198 lines
9.4 KiB
Java
198 lines
9.4 KiB
Java
/*
|
|
* 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.
|
|
*/
|
|
package com.intellij.refactoring.extractSuperclass;
|
|
|
|
import com.intellij.codeInsight.generation.OverrideImplementUtil;
|
|
import com.intellij.openapi.diagnostic.Logger;
|
|
import com.intellij.openapi.project.Project;
|
|
import com.intellij.openapi.util.Condition;
|
|
import com.intellij.psi.*;
|
|
import com.intellij.psi.codeStyle.CodeStyleManager;
|
|
import com.intellij.psi.util.MethodSignature;
|
|
import com.intellij.psi.util.PsiUtil;
|
|
import com.intellij.psi.util.TypeConversionUtil;
|
|
import com.intellij.refactoring.memberPullUp.PullUpHelper;
|
|
import com.intellij.refactoring.util.DocCommentPolicy;
|
|
import com.intellij.refactoring.util.RefactoringUtil;
|
|
import com.intellij.refactoring.util.classMembers.MemberInfo;
|
|
import com.intellij.util.IncorrectOperationException;
|
|
import com.intellij.util.containers.HashMap;
|
|
import org.jetbrains.annotations.NonNls;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* @author dsl
|
|
*/
|
|
public class ExtractSuperClassUtil {
|
|
private static final Logger LOG = Logger.getInstance("com.intellij.refactoring.extractSuperclass.ExtractSuperClassUtil");
|
|
private ExtractSuperClassUtil() {}
|
|
|
|
public static PsiClass extractSuperClass(final Project project,
|
|
final PsiDirectory targetDirectory,
|
|
final String superclassName,
|
|
final PsiClass subclass,
|
|
final MemberInfo[] selectedMemberInfos,
|
|
final DocCommentPolicy javaDocPolicy)
|
|
throws IncorrectOperationException {
|
|
PsiClass superclass = JavaDirectoryService.getInstance().createClass(targetDirectory, superclassName);
|
|
final PsiModifierList superClassModifierList = superclass.getModifierList();
|
|
assert superClassModifierList != null;
|
|
superClassModifierList.setModifierProperty(PsiModifier.FINAL, false);
|
|
final PsiReferenceList subClassExtends = subclass.getExtendsList();
|
|
assert subClassExtends != null: subclass;
|
|
copyPsiReferenceList(subClassExtends, superclass.getExtendsList());
|
|
|
|
// create constructors if neccesary
|
|
PsiMethod[] constructors = getCalledBaseConstructors(subclass);
|
|
if (constructors.length > 0) {
|
|
createConstructorsByPattern(project, superclass, constructors);
|
|
}
|
|
|
|
// clear original class' "extends" list
|
|
clearPsiReferenceList(subclass.getExtendsList());
|
|
|
|
// make original class extend extracted superclass
|
|
PsiJavaCodeReferenceElement ref = createExtendingReference(superclass, subclass, selectedMemberInfos);
|
|
subclass.getExtendsList().add(ref);
|
|
|
|
PullUpHelper pullUpHelper = new PullUpHelper(subclass, superclass, selectedMemberInfos,
|
|
javaDocPolicy
|
|
);
|
|
|
|
pullUpHelper.moveMembersToBase();
|
|
pullUpHelper.moveFieldInitializations();
|
|
|
|
Collection<MethodSignature> toImplement = OverrideImplementUtil.getMethodSignaturesToImplement(superclass);
|
|
if (!toImplement.isEmpty()) {
|
|
superClassModifierList.setModifierProperty(PsiModifier.ABSTRACT, true);
|
|
}
|
|
return superclass;
|
|
}
|
|
|
|
private static void createConstructorsByPattern(Project project, final PsiClass superclass, PsiMethod[] patternConstructors) throws IncorrectOperationException {
|
|
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
|
CodeStyleManager styleManager = CodeStyleManager.getInstance(project);
|
|
for (PsiMethod baseConstructor : patternConstructors) {
|
|
PsiMethod constructor = (PsiMethod)superclass.add(factory.createConstructor());
|
|
PsiParameterList paramList = constructor.getParameterList();
|
|
PsiParameter[] baseParams = baseConstructor.getParameterList().getParameters();
|
|
@NonNls StringBuilder superCallText = new StringBuilder();
|
|
superCallText.append("super(");
|
|
final PsiClass baseClass = baseConstructor.getContainingClass();
|
|
LOG.assertTrue(baseClass != null);
|
|
final PsiSubstitutor classSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, superclass, PsiSubstitutor.EMPTY);
|
|
for (int i = 0; i < baseParams.length; i++) {
|
|
final PsiParameter baseParam = baseParams[i];
|
|
final PsiParameter newParam = (PsiParameter)paramList.add(factory.createParameter(baseParam.getName(), classSubstitutor.substitute(baseParam.getType())));
|
|
if (i > 0) {
|
|
superCallText.append(",");
|
|
}
|
|
superCallText.append(newParam.getName());
|
|
}
|
|
superCallText.append(");");
|
|
PsiStatement statement = factory.createStatementFromText(superCallText.toString(), null);
|
|
statement = (PsiStatement)styleManager.reformat(statement);
|
|
final PsiCodeBlock body = constructor.getBody();
|
|
assert body != null;
|
|
body.add(statement);
|
|
constructor.getThrowsList().replace(baseConstructor.getThrowsList());
|
|
}
|
|
}
|
|
|
|
private static PsiMethod[] getCalledBaseConstructors(final PsiClass subclass) {
|
|
Set<PsiMethod> baseConstructors = new HashSet<PsiMethod>();
|
|
PsiMethod[] constructors = subclass.getConstructors();
|
|
for (PsiMethod constructor : constructors) {
|
|
PsiCodeBlock body = constructor.getBody();
|
|
if (body == null) continue;
|
|
PsiStatement[] statements = body.getStatements();
|
|
if (statements.length > 0) {
|
|
PsiStatement first = statements[0];
|
|
if (first instanceof PsiExpressionStatement) {
|
|
PsiExpression expression = ((PsiExpressionStatement)first).getExpression();
|
|
if (expression instanceof PsiMethodCallExpression) {
|
|
PsiReferenceExpression calledMethod = ((PsiMethodCallExpression)expression).getMethodExpression();
|
|
@NonNls String text = calledMethod.getText();
|
|
if ("super".equals(text)) {
|
|
PsiMethod baseConstructor = (PsiMethod)calledMethod.resolve();
|
|
if (baseConstructor != null) {
|
|
baseConstructors.add(baseConstructor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return baseConstructors.toArray(new PsiMethod[baseConstructors.size()]);
|
|
}
|
|
|
|
private static void clearPsiReferenceList(PsiReferenceList refList) throws IncorrectOperationException {
|
|
PsiJavaCodeReferenceElement[] refs = refList.getReferenceElements();
|
|
for (PsiJavaCodeReferenceElement ref : refs) {
|
|
ref.delete();
|
|
}
|
|
}
|
|
|
|
private static void copyPsiReferenceList(PsiReferenceList sourceList, PsiReferenceList destinationList) throws IncorrectOperationException {
|
|
clearPsiReferenceList(destinationList);
|
|
PsiJavaCodeReferenceElement[] refs = sourceList.getReferenceElements();
|
|
for (PsiJavaCodeReferenceElement ref : refs) {
|
|
destinationList.add(ref);
|
|
}
|
|
}
|
|
|
|
public static PsiJavaCodeReferenceElement createExtendingReference(final PsiClass superClass,
|
|
final PsiClass derivedClass,
|
|
final MemberInfo[] selectedMembers) throws IncorrectOperationException {
|
|
final PsiManager manager = derivedClass.getManager();
|
|
Set<PsiElement> movedElements = new com.intellij.util.containers.HashSet<PsiElement>();
|
|
for (final MemberInfo info : selectedMembers) {
|
|
movedElements.add(info.getMember());
|
|
}
|
|
final PsiTypeParameterList typeParameterList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(null, new Condition<PsiTypeParameter>() {
|
|
@Override
|
|
public boolean value(PsiTypeParameter parameter) {
|
|
return findTypeParameterInDerived(derivedClass, parameter.getName()) != null;
|
|
}
|
|
}, movedElements.toArray(new PsiElement[movedElements.size()]));
|
|
final PsiTypeParameterList originalTypeParameterList = superClass.getTypeParameterList();
|
|
assert originalTypeParameterList != null;
|
|
final PsiTypeParameterList newList = typeParameterList != null ? (PsiTypeParameterList)originalTypeParameterList.replace(typeParameterList) : originalTypeParameterList;
|
|
final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
|
|
Map<PsiTypeParameter, PsiType> substitutionMap = new HashMap<PsiTypeParameter, PsiType>();
|
|
for (final PsiTypeParameter parameter : newList.getTypeParameters()) {
|
|
final PsiTypeParameter parameterInDerived = findTypeParameterInDerived(derivedClass, parameter.getName());
|
|
if (parameterInDerived != null) {
|
|
substitutionMap.put(parameter, factory.createType(parameterInDerived));
|
|
}
|
|
}
|
|
|
|
final PsiClassType type = factory.createType(superClass, factory.createSubstitutor(substitutionMap));
|
|
return factory.createReferenceElementByType(type);
|
|
}
|
|
|
|
@Nullable
|
|
public static PsiTypeParameter findTypeParameterInDerived(final PsiClass aClass, final String name) {
|
|
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) {
|
|
if (name.equals(typeParameter.getName())) return typeParameter;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|