@Override public boolean isMemberEnabled(MemberInfo member) { final PsiClass currentSuperClass = getSuperClass(); if (currentSuperClass == null) return true; if (myMemberInfoStorage.getDuplicatedMemberInfos(currentSuperClass).contains(member)) return false; if (myMemberInfoStorage.getExtending(currentSuperClass).contains(member.getMember())) return false; final boolean isInterface = currentSuperClass.isInterface(); if (!isInterface) return true; PsiElement element = member.getMember(); if (element instanceof PsiClass && ((PsiClass) element).isInterface()) return true; if (element instanceof PsiField) { return ((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC); } if (element instanceof PsiMethod) { final PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor( currentSuperClass, myClass, PsiSubstitutor.EMPTY); final MethodSignature signature = ((PsiMethod) element).getSignature(superSubstitutor); final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(currentSuperClass, signature, false); if (superClassMethod != null && !PsiUtil.isLanguageLevel8OrHigher(currentSuperClass)) return false; return !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC) || PsiUtil.isLanguageLevel8OrHigher(currentSuperClass); } return true; }
public void moveMembersToBase() throws IncorrectOperationException { myMovedMembers = ContainerUtil.newHashSet(); myMembersAfterMove = ContainerUtil.newHashSet(); // build aux sets for (MemberInfo info : myMembersToMove) { myMovedMembers.add(info.getMember()); } final PsiSubstitutor substitutor = upDownSuperClassSubstitutor(); for (MemberInfo info : myMembersToMove) { PullUpHelper<MemberInfo> processor = getProcessor(info); LOG.assertTrue(processor != null, info.getMember()); if (!(info.getMember() instanceof PsiClass) || info.getOverrides() == null) { processor.setCorrectVisibility(info); processor.encodeContextInfo(info); } processor.move(info, substitutor); } for (PsiMember member : myMembersAfterMove) { PullUpHelper<MemberInfo> processor = getProcessor(member); LOG.assertTrue(processor != null, member); processor.postProcessMember(member); final JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance(myProject); ((JavaRefactoringListenerManagerImpl) listenerManager).fireMemberMoved(mySourceClass, member); } }
@Override public void move(MemberInfo info, PsiSubstitutor substitutor) { if (info.getMember() instanceof PsiMethod) { doMoveMethod(substitutor, info); } else if (info.getMember() instanceof PsiField) { doMoveField(substitutor, info); } else if (info.getMember() instanceof PsiClass) { doMoveClass(substitutor, info); } }
private void doMoveClass(PsiSubstitutor substitutor, MemberInfo info) { PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); PsiClass aClass = (PsiClass) info.getMember(); if (Boolean.FALSE.equals(info.getOverrides())) { final PsiReferenceList sourceReferenceList = info.getSourceReferenceList(); LOG.assertTrue(sourceReferenceList != null); PsiJavaCodeReferenceElement ref = mySourceClass.equals(sourceReferenceList.getParent()) ? RefactoringUtil.removeFromReferenceList(sourceReferenceList, aClass) : RefactoringUtil.findReferenceToClass(sourceReferenceList, aClass); if (ref != null && !myTargetSuperClass.isInheritor(aClass, false)) { RefactoringUtil.replaceMovedMemberTypeParameters( ref, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); final PsiReferenceList referenceList = myIsTargetInterface ? myTargetSuperClass.getExtendsList() : myTargetSuperClass.getImplementsList(); assert referenceList != null; referenceList.add(ref); } } else { RefactoringUtil.replaceMovedMemberTypeParameters( aClass, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); fixReferencesToStatic(aClass); final PsiMember movedElement = (PsiMember) myTargetSuperClass.add( convertClassToLanguage(aClass, myTargetSuperClass.getLanguage())); myMembersAfterMove.add(movedElement); aClass.delete(); } }
@Nullable private PullUpHelper<MemberInfo> getProcessor(@NotNull MemberInfo info) { PsiReferenceList refList = info.getSourceReferenceList(); if (refList != null) { return getProcessor(refList.getLanguage()); } return getProcessor(info.getMember()); }
public PushDownConflicts(PsiClass aClass, MemberInfo[] memberInfos) { myClass = aClass; myMovedMembers = new HashSet<PsiMember>(); myAbstractMembers = new HashSet<PsiMethod>(); for (MemberInfo memberInfo : memberInfos) { final PsiMember member = memberInfo.getMember(); if (memberInfo.isChecked() && (!(memberInfo.getMember() instanceof PsiClass) || memberInfo.getOverrides() == null)) { myMovedMembers.add(member); if (memberInfo.isToAbstract()) { myAbstractMembers.add((PsiMethod) member); } } } myConflicts = new MultiMap<PsiElement, String>(); }
public ExtractClassProcessor( PsiClass sourceClass, List<PsiField> fields, List<PsiMethod> methods, List<PsiClass> classes, String packageName, MoveDestination moveDestination, String newClassName, String newVisibility, boolean generateAccessors, List<MemberInfo> enumConstants) { super(sourceClass.getProject()); this.sourceClass = sourceClass; this.newPackageName = packageName; myMoveDestination = moveDestination; myNewVisibility = newVisibility; myGenerateAccessors = generateAccessors; this.enumConstants = new ArrayList<PsiField>(); for (MemberInfo constant : enumConstants) { if (constant.isChecked()) { this.enumConstants.add((PsiField) constant.getMember()); } } this.fields = new ArrayList<PsiField>(fields); this.methods = new ArrayList<PsiMethod>(methods); this.innerClasses = new ArrayList<PsiClass>(classes); this.newClassName = newClassName; delegateFieldName = calculateDelegateFieldName(); requiresBackpointer = new BackpointerUsageVisitor(fields, innerClasses, methods, sourceClass) .backpointerRequired(); if (requiresBackpointer) { ContainerUtil.addAll(typeParams, sourceClass.getTypeParameters()); } else { final Set<PsiTypeParameter> typeParamSet = new HashSet<PsiTypeParameter>(); final TypeParametersVisitor visitor = new TypeParametersVisitor(typeParamSet); for (PsiField field : fields) { field.accept(visitor); } for (PsiMethod method : methods) { method.accept(visitor); // do not include method's type parameters in class signature typeParamSet.removeAll(Arrays.asList(method.getTypeParameters())); } typeParams.addAll(typeParamSet); } myClass = new WriteCommandAction<PsiClass>(myProject, getCommandName()) { @Override protected void run(@NotNull Result<PsiClass> result) throws Throwable { result.setResult(buildClass()); } }.execute().getResultObject(); myExtractEnumProcessor = new ExtractEnumProcessor(myProject, this.enumConstants, myClass); }
@Override public boolean isAbstractWhenDisabled(MemberInfo member) { PsiClass currentSuperClass = getSuperClass(); if (currentSuperClass == null) return false; if (currentSuperClass.isInterface()) { final PsiMember psiMember = member.getMember(); if (psiMember instanceof PsiMethod) { return !psiMember.hasModifierProperty(PsiModifier.STATIC); } } return false; }
public void findUsages(@NotNull List<FixableUsageInfo> usages) { for (final MemberInfo memberInfo : myDelegateMethodInfos) { if (!memberInfo.isChecked()) continue; final PsiMethod method = (PsiMethod) memberInfo.getMember(); final String getterName = GenerateMembersUtil.suggestGetterName(field); final int[] paramPermutation = DelegationUtils.getParameterPermutation(method); final PsiMethod delegatedMethod = DelegationUtils.getDelegatedMethod(method); LOG.assertTrue(!DelegationUtils.isAbstract(method)); processUsagesForMethod( memberInfo.isToAbstract(), method, paramPermutation, getterName, delegatedMethod, usages); } }
@Override @NotNull protected UsageInfo[] findUsages() { final List<UsageInfo> result = new ArrayList<>(); for (MemberInfo memberInfo : myMembersToMove) { final PsiMember member = memberInfo.getMember(); if (member.hasModifierProperty(PsiModifier.STATIC)) { for (PsiReference reference : ReferencesSearch.search(member)) { result.add(new UsageInfo(reference)); } } } return result.isEmpty() ? UsageInfo.EMPTY_ARRAY : result.toArray(new UsageInfo[result.size()]); }
@Override public int checkForProblems(@NotNull MemberInfo member) { if (member.isChecked()) return OK; PsiClass currentSuperClass = getSuperClass(); if (currentSuperClass != null && currentSuperClass.isInterface()) { PsiMember element = member.getMember(); if (element.hasModifierProperty(PsiModifier.STATIC)) { return super.checkForProblems(member); } return OK; } else { return super.checkForProblems(member); } }
@Override protected boolean preprocessUsages(@NotNull final Ref<UsageInfo[]> refUsages) { final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>(); for (MemberInfo memberInfo : myDelegateMethodInfos) { if (memberInfo.isChecked() && memberInfo.isToAbstract()) { final PsiMember psiMember = memberInfo.getMember(); if (psiMember instanceof PsiMethod && ((PsiMethod) psiMember).findDeepestSuperMethods().length > 0) { conflicts.putValue( psiMember, SymbolPresentationUtil.getSymbolPresentableText(psiMember) + " will be deleted. Hierarchy will be broken"); } } } return showConflicts(conflicts, refUsages.get()); }
@Override protected void addCustomElementsToCentralPanel(JPanel panel) { myJavaDocPanel = new DocCommentPanel(RefactoringBundle.message("javadoc.for.abstracts")); myJavaDocPanel.setPolicy(JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC); boolean hasJavadoc = false; for (MemberInfo info : myMemberInfos) { final PsiMember member = info.getMember(); if (myMemberInfoModel.isAbstractEnabled(info) && member instanceof PsiDocCommentOwner) { info.setToAbstract(myMemberInfoModel.isAbstractWhenDisabled(info)); if (((PsiDocCommentOwner) member).getDocComment() != null) { hasJavadoc = true; break; } } } UIUtil.setEnabled(myJavaDocPanel, hasJavadoc, true); panel.add(myJavaDocPanel, BorderLayout.EAST); }
@Override protected boolean preprocessUsages(final Ref<UsageInfo[]> refUsages) { final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>(); final PushDownConflicts pushDownConflicts = new PushDownConflicts(mySuperClass, myMemberInfos); for (PsiClass targetClass : myTargetClasses) { for (MemberInfo info : myMemberInfos) { final PsiMember member = info.getMember(); pushDownConflicts.checkMemberPlacementInTargetClassConflict(targetClass, member); } // todo check accessibility conflicts } final MultiMap<PsiElement, String> conflictsMap = pushDownConflicts.getConflicts(); for (PsiElement element : conflictsMap.keySet()) { conflicts.put(element, conflictsMap.get(element)); } checkConflicts(refUsages, conflicts); return showConflicts(conflicts, refUsages.get()); }
@Override public void setCorrectVisibility(MemberInfo info) { PsiModifierListOwner modifierListOwner = info.getMember(); if (myIsTargetInterface) { PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PUBLIC, true); } else if (modifierListOwner.hasModifierProperty(PsiModifier.PRIVATE)) { if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, myTargetSuperClass, mySourceClass)) { PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true); } if (modifierListOwner instanceof PsiClass) { modifierListOwner.accept( new JavaRecursiveElementWalkingVisitor() { @Override public void visitMethod(PsiMethod method) { check(method); } @Override public void visitField(PsiField field) { check(field); } @Override public void visitClass(PsiClass aClass) { check(aClass); super.visitClass(aClass); } private void check(PsiMember member) { if (member.hasModifierProperty(PsiModifier.PRIVATE)) { if (willBeUsedInSubclass(member, myTargetSuperClass, mySourceClass)) { PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true); } } } }); } } }
private void doMoveField(PsiSubstitutor substitutor, MemberInfo info) { PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); PsiField field = (PsiField) info.getMember(); if (field instanceof HaxeVarDeclarationPart) { field = (HaxeVarDeclaration) field.getParent(); } field.normalizeDeclaration(); RefactoringUtil.replaceMovedMemberTypeParameters( field, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); fixReferencesToStatic(field); if (myIsTargetInterface) { PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true); } final PsiMember movedElement = (PsiMember) myTargetSuperClass.addBefore( convertFieldToLanguage(field, myTargetSuperClass.getLanguage()), myTargetSuperClass.getRBrace()); myMembersAfterMove.add(movedElement); field.delete(); }
private static void addTestMethods( Editor editor, PsiClass targetClass, TestFramework descriptor, Collection<MemberInfo> methods, boolean generateBefore, boolean generateAfter) throws IncorrectOperationException { if (generateBefore) { generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, null); } if (generateAfter) { generateMethod( TestIntegrationUtils.MethodKind.TEAR_DOWN, descriptor, targetClass, editor, null); } for (MemberInfo m : methods) { generateMethod( TestIntegrationUtils.MethodKind.TEST, descriptor, targetClass, editor, m.getMember().getName()); } }
@Override public void encodeContextInfo(MemberInfo info) { ChangeContextUtil.encodeContextInfo(info.getMember(), true); }
private void doMoveMethod(PsiSubstitutor substitutor, MemberInfo info) { PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); PsiMethod method = (PsiMethod) info.getMember(); PsiMethod sibling = method; PsiMethod anchor = null; while (sibling != null) { sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class); if (sibling != null) { anchor = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived( method.getContainingClass(), myTargetSuperClass, sibling.getSignature(PsiSubstitutor.EMPTY), false); if (anchor != null) { break; } } } PsiMethod methodCopy = (PsiMethod) method.copy(); Language language = myTargetSuperClass.getLanguage(); final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false); if (superClassMethod != null && superClassMethod.findDeepestSuperMethods().length == 0 || method.findSuperMethods(myTargetSuperClass).length == 0) { deleteOverrideAnnotationIfFound(methodCopy); } boolean isOriginalMethodAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.DEFAULT); boolean isOriginalMethodPrototype = method instanceof HaxeFunctionPrototypeDeclarationWithAttributes; if (myIsTargetInterface || info.isToAbstract()) { ChangeContextUtil.clearContextInfo(method); if (!info.isToAbstract() && !method.hasModifierProperty(PsiModifier.ABSTRACT) && PsiUtil.isLanguageLevel8OrHigher(myTargetSuperClass)) { // pull as default RefactoringUtil.makeMethodDefault(methodCopy); isOriginalMethodAbstract = true; } else { RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy); } RefactoringUtil.replaceMovedMemberTypeParameters( methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); myJavaDocPolicy.processCopiedJavaDoc( methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract); final PsiMember movedElement; if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { movedElement = (PsiMember) superClassMethod.replace(convertMethodToLanguage(methodCopy, language)); } else { methodCopy = HaxeElementGenerator.createFunctionPrototypeDeclarationWithAttributes( myProject, methodCopy.getText().trim() + ";"); movedElement = anchor != null ? (PsiMember) myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember) myTargetSuperClass.addBefore(methodCopy, myTargetSuperClass.getRBrace()); reformat(movedElement); } CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject()); if (styleSettings.INSERT_OVERRIDE_ANNOTATION) { if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myIsTargetInterface || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) { new AddAnnotationFix(Override.class.getName(), method) .invoke(method.getProject(), null, mySourceClass.getContainingFile()); } } if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myIsTargetInterface) { if (isOriginalMethodAbstract) { for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) { deleteOverrideAnnotationIfFound(oMethod); } } deleteOverrideAnnotationIfFound(method); } myMembersAfterMove.add(movedElement); // if (isOriginalMethodAbstract) { method.delete(); // } } else { if (isOriginalMethodAbstract) { PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true); } RefactoringUtil.replaceMovedMemberTypeParameters( methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); fixReferencesToStatic(methodCopy); if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { superClassMethod.replace(convertMethodToLanguage(methodCopy, language)); } else { final PsiMember movedElement = anchor != null ? (PsiMember) myTargetSuperClass.addBefore( convertMethodToLanguage(methodCopy, language), anchor) : (PsiMember) myTargetSuperClass.addBefore( convertMethodToLanguage(methodCopy, language), myTargetSuperClass.getRBrace()); reformat(movedElement); myMembersAfterMove.add(movedElement); } method.delete(); } }
protected void findUsages(@NotNull final List<FixableUsageInfo> usages) { final JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject); final PsiElementFactory elementFactory = facade.getElementFactory(); final PsiResolveHelper resolveHelper = facade.getResolveHelper(); ReferencesSearch.search(mySuperClass) .forEach( new Processor<PsiReference>() { public boolean process(final PsiReference reference) { final PsiElement element = reference.getElement(); if (element instanceof PsiJavaCodeReferenceElement) { final PsiImportStaticStatement staticImportStatement = PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class); if (staticImportStatement != null) { usages.add( new ReplaceStaticImportUsageInfo(staticImportStatement, myTargetClasses)); } else { final PsiImportStatement importStatement = PsiTreeUtil.getParentOfType(element, PsiImportStatement.class); if (importStatement != null) { usages.add(new RemoveImportUsageInfo(importStatement)); } else { final PsiElement parent = element.getParent(); if (parent instanceof PsiReferenceList) { final PsiElement pparent = parent.getParent(); if (pparent instanceof PsiClass) { final PsiClass inheritor = (PsiClass) pparent; if (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList())) { usages.add( new ReplaceExtendsListUsageInfo( (PsiJavaCodeReferenceElement) element, mySuperClass, inheritor)); } } } else { final PsiClass targetClass = myTargetClasses[0]; final PsiClassType targetClassType = elementFactory.createType( targetClass, TypeConversionUtil.getSuperClassSubstitutor( mySuperClass, targetClass, PsiSubstitutor.EMPTY)); if (parent instanceof PsiTypeElement) { final PsiType superClassType = ((PsiTypeElement) parent).getType(); PsiSubstitutor subst = getSuperClassSubstitutor( superClassType, targetClassType, resolveHelper, targetClass); usages.add( new ReplaceWithSubtypeUsageInfo( ((PsiTypeElement) parent), elementFactory.createType(targetClass, subst), myTargetClasses)); } else if (parent instanceof PsiNewExpression) { final PsiClassType newType = elementFactory.createType( targetClass, getSuperClassSubstitutor( ((PsiNewExpression) parent).getType(), targetClassType, resolveHelper, targetClass)); usages.add( new ReplaceConstructorUsageInfo( ((PsiNewExpression) parent), newType, myTargetClasses)); } else if (parent instanceof PsiJavaCodeReferenceElement) { usages.add( new ReplaceReferenceUsageInfo( ((PsiJavaCodeReferenceElement) parent).getQualifier(), myTargetClasses)); } } } } } return true; } }); for (PsiClass targetClass : myTargetClasses) { for (MemberInfo memberInfo : myMemberInfos) { final PsiMember member = memberInfo.getMember(); for (PsiReference reference : ReferencesSearch.search(member, member.getUseScope(), true)) { final PsiElement element = reference.getElement(); if (element instanceof PsiReferenceExpression && ((PsiReferenceExpression) element).getQualifierExpression() instanceof PsiSuperExpression && PsiTreeUtil.isAncestor(targetClass, element, false)) { usages.add(new RemoveQualifierUsageInfo((PsiReferenceExpression) element)); } } } final PsiMethod[] superConstructors = mySuperClass.getConstructors(); for (PsiMethod constructor : targetClass.getConstructors()) { final PsiCodeBlock constrBody = constructor.getBody(); LOG.assertTrue(constrBody != null); final PsiStatement[] statements = constrBody.getStatements(); if (statements.length > 0) { final PsiStatement firstConstrStatement = statements[0]; if (firstConstrStatement instanceof PsiExpressionStatement) { final PsiExpression expression = ((PsiExpressionStatement) firstConstrStatement).getExpression(); if (expression instanceof PsiMethodCallExpression) { final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) expression).getMethodExpression(); if (methodExpression.getText().equals(PsiKeyword.SUPER)) { final PsiMethod superConstructor = ((PsiMethodCallExpression) expression).resolveMethod(); if (superConstructor != null && superConstructor.getBody() != null) { usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression) expression)); continue; } } } } } // insert implicit call to super for (PsiMethod superConstructor : superConstructors) { if (superConstructor.getParameterList().getParametersCount() == 0) { final PsiExpression expression = JavaPsiFacade.getElementFactory(myProject) .createExpressionFromText("super()", constructor); usages.add( new InlineSuperCallUsageInfo((PsiMethodCallExpression) expression, constrBody)); } } } if (targetClass.getConstructors().length == 0) { // copy default constructor for (PsiMethod superConstructor : superConstructors) { if (superConstructor.getParameterList().getParametersCount() == 0) { usages.add(new CopyDefaultConstructorUsageInfo(targetClass, superConstructor)); break; } } } } }