/** * Removes overloaded methods from the contents list and adds them to the overloadedMethods list * of the first overloaded method encountered. * * @param contents * @param doExtractedMethods */ private static void cullOverloadedMethods( List<ClassContentsEntry> contents, boolean doExtractedMethods) { List<ClassContentsEntry> copy = new ArrayList<ClassContentsEntry>(contents); for (ClassContentsEntry o : copy) { if (o instanceof RelatableEntry) { MethodEntry me = (MethodEntry) o; if ((me.isRelatedMethod() == doExtractedMethods) && !me.isOverloadedMethod) { String meName = me.myEnd.toString(); // search contents list for methods with identical name, and attach them as overloaded // methods. ListIterator<ClassContentsEntry> contentIterator = contents.listIterator(); while (contentIterator.hasNext()) { Object o1 = contentIterator.next(); if (o1 instanceof RelatableEntry) { MethodEntry me2 = (MethodEntry) o1; if (me2 == me) { continue; } String me2Name = me2.myEnd.toString(); if (meName.equals(me2Name)) { contentIterator.remove(); me.myOverloadedMethods.add(me2); me2.isOverloadedMethod = true; // set flag so array copy will skip this entry. } } } } } } }
/** * Getters/Setters are supposed to be kept with their associated property. Search the list of * entries to find the property and attach the setter. * * @param entries list of all items (methods, fields) in the class. */ private void hookGetterToProperty(List<ClassContentsEntry> entries) { ListIterator<ClassContentsEntry> li = entries.listIterator(); String property = MethodUtil.getPropertyName((PsiMethod) myEnd); while (li.hasNext()) { Object o = li.next(); if (o instanceof FieldEntry) { FieldEntry fe = (FieldEntry) o; StringBuffer sb = new StringBuffer(fe.getName()); sb.setCharAt(0, Character.toUpperCase(sb.charAt(0))); if (fe.getGetterMethod() == null && property.equals(sb.toString())) { fe.setGetterMethod(this); myKeptWithProperty = true; break; } } } }
void insertInList(final List<MethodEntry> list, Comparator<MethodEntry> comparator) { boolean inserted = false; ListIterator li = list.listIterator(); while (li.hasNext() && !inserted) { MethodEntry entry = ((MethodEntry) li.next()); if (comparator.compare(this, entry) < 0) { LOG.debug( "insertInList dependent method: add " + myEnd.toString() + " at index " + (li.nextIndex() - 1)); list.add(li.nextIndex() - 1, this); inserted = true; } } if (!inserted) { list.add(this); } }
/** * Decide if a method is an extracted method. It is an extracted method if: - it is called by at * least one other method, and - it is private, or passes the "never / 1 / >1" caller test. * * <p>(It is not considered an extracted method if it is a setter, there is a corresponding * getter, and the option to keep getters and setters together is set. This is a special case.) */ public void determineExtractedMethod(RelatedMethodsSettings settings) { myRelatedMethod = false; if (!isGetter() && !isSetter()) { if (myCalledByMethods.size() > 0) { PsiMethod m = (PsiMethod) myEnd; if (!m.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) { switch (settings.getNonPrivateTreatment()) { case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_NEVER: break; case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ONE_CALLER: if (myCalledByMethods.size() == 1) { myRelatedMethod = true; } break; case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ANY_CALLERS: myRelatedMethod = true; break; } } else { myRelatedMethod = true; } } } else { if (isSetter() && myCalledByMethods.size() > 0 && myCorrespondingGetterSetters.size() == 0) { myRelatedMethod = true; LOG.debug(myEnd.toString() + " is setter but has no getter, treated as extracted method"); } else { LOG.debug(myEnd.toString() + " is getter/setter, not treated as extracted method"); } } LOG.debug("determined " + myEnd.toString() + " is extracted method? " + myRelatedMethod); /** If this is not an extracted method, remove it from any callers so that it won't be moved. */ if (!myRelatedMethod) { ListIterator<MethodEntry> li = myCalledByMethods.listIterator(); while (li.hasNext()) { MethodEntry entry = (li.next()); entry.myCalledMethods.remove(this); li.remove(); } } /** * Remaining entries are only extracted methods at this point. Using first/last rule, keep only * the call by the calling method that this child method will be grouped with, and discard the * rest. */ if (myCalledByMethods.size() > 1) { ListIterator<MethodEntry> li; if (settings.isBelowFirstCaller()) { li = myCalledByMethods.listIterator(1); while (li.hasNext()) { MethodEntry entry = (li.next()); entry.myCalledMethods.remove(this); li.remove(); } } else { li = myCalledByMethods.listIterator(myCalledByMethods.size() - 1); while (li.hasPrevious()) { MethodEntry entry = (li.previous()); entry.myCalledMethods.remove(this); li.remove(); } } } if (myRelatedMethod) { LOG.debug( "extracted method " + toString() + " will be arranged under " + myCalledByMethods.get(0).toString()); } }
/** * Move methods related to this one underneath it (beginning at the index specified.) Do so in * depth-first or breadth-first order, as configured. At each level, do alphabetical, original * order, or call order sorting. * * @param entries list of global (all rule) unmatched items including dependent methods * @param parents contains a list of items to be handled; order is depth or breadth-first. */ private static void moveRelatedItems( List<ClassContentsEntry> entries, List<MethodEntry> parents, RelatedMethodsSettings rms, String topLevelMethodName, String allMethodNames, int level) { allMethodNames = buildAllMethodNamesString(allMethodNames, parents); /** First, identify all dependent methods. Move them to parents in the specified order. */ List<MethodEntry> children = ((MethodEntry) parents.get(parents.size() - 1)).sortedMethods; // if (rms.isDepthFirstOrdering()) // { switch (rms.getOrdering()) { case RelatedMethodsSettings.RETAIN_ORIGINAL_ORDER: { /** * iterate through entries looking for those that are called by method(s) in the set of * parent methods. Add these to the list of children in order seen in entries. */ ListIterator li = entries.listIterator(); while (li.hasNext()) { Object o = li.next(); if (o instanceof RelatableEntry) { MethodEntry me = (MethodEntry) o; for (MethodEntry entry : parents) { if (me.myCalledByMethods.contains(entry)) { children.add(me); li.remove(); break; } } } } } break; case RelatedMethodsSettings.ALPHABETICAL_ORDER: { /** * iterate through entries looking for those that are called by method(s) in the set of * parent methods. Add these to the list of children alphabetically. */ ListIterator li = entries.listIterator(); while (li.hasNext()) { Object o = li.next(); if (o instanceof RelatableEntry) { MethodEntry me = (MethodEntry) o; for (MethodEntry entry : parents) { if (me.myCalledByMethods.contains(entry)) { me.insertAlphabetically(children); li.remove(); break; } } } } } break; case RelatedMethodsSettings.INVOCATION_ORDER: /** * iterate through calling methods, looking for remaining unmatched methods (in 'entries' * list). Add these to the list of children in order of invocation. */ for (MethodEntry me : parents) { for (MethodEntry child : me.myCalledMethods) { if (entries.contains(child)) { children.add(child); entries.remove(child); } } } break; } /** * now children contains all the children of the parents for this level, and all these children * have been removed from "entries". Move these to the rearranged list. Then: If depth-first, * recurse setting the parent list to each of the children in turn. If breadth first, recurse * setting the parent list to all of the children. */ if (children.size() > 0) { if (rms.isDepthFirstOrdering()) { for (MethodEntry entry : children) { if (entry.myCalledMethods.size() == 0) { continue; } List<MethodEntry> parent = new LinkedList<MethodEntry>(); parent.add(entry); moveRelatedItems( entries, parent, rms, topLevelMethodName, allMethodNames + "." + ((PsiMethod) entry.myEnd).getName() + "()", level + 1); } } else { moveRelatedItems( entries, children, rms, topLevelMethodName, allMethodNames + ".Depth " + level, level + 1); } } }