/**
  * 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.
             }
           }
         }
       }
     }
   }
 }
 /**
  * Called after top level methods (and other items) have been moved from entries to
  * ruleInstanceList. Task now is to scan ruleInstanceList looking for MethodEntry objects with
  * dependent (related, extracted) methods. Move these from the entries list to the correct place
  * in the ruleInstanceList list.
  *
  * @param entries Remaining (unarranged) items, including all dependent (extracted) methods.
  * @param ruleInstance Rule containing parents (callers) of potentially related methods
  */
 public static void rearrangeRelatedItems(
     List<ClassContentsEntry> entries, RuleInstance ruleInstance, RelatedMethodsSettings rms) {
   List<RangeEntry> parentEntries = new ArrayList<RangeEntry>(ruleInstance.getMatches());
   for (RangeEntry o : parentEntries) {
     if (o instanceof RelatableEntry) {
       MethodEntry me = (MethodEntry) o;
       if (me.isGetter()) {
         if (me.myKeptWithProperty) {
           if (me.getMatchedRule() != null && me.getMatchedRule().getMatches() != null) {
             // prevent the getter from appearing under a rule it matches; it will be placed under
             // the property
             me.getMatchedRule().getMatches().remove(me);
           }
         }
         for (MethodEntry theSetter : me.myCorrespondingGetterSetters) {
           final RuleInstance theRule = theSetter.getMatchedRule();
           LOG.debug(
               "rearrangeRelatedItems: for getter method "
                   + me
                   + ", corresponding setter is "
                   + theSetter);
           if (theRule != null && theRule.getMatches() != null) {
             LOG.debug(
                 "remove entry "
                             + theSetter.myEnd
                             + " from matched rule"
                             + theRule
                             + "; matches = "
                             + ((java.util.List) theRule.getMatches())
                         == null
                     ? "null"
                     : "");
             theRule.getMatches().remove(theSetter);
           }
         }
       }
       if (me.myCalledMethods.size() > 0) {
         List<MethodEntry> parents = new LinkedList<MethodEntry>();
         parents.add(me);
         moveRelatedItems(
             entries,
             parents,
             rms,
             ((PsiMethod) me.myEnd).getName(),
             ((PsiMethod) me.myEnd).getName() + "()",
             1);
         if (LOG.isDebugEnabled()) {
           // dump sorted children recursively
           me.dumpChild(0);
         }
         me.assignComments(rms);
       }
     }
   }
 }
 private static void test(MethodEntry current, List<MethodEntry> set) {
   Iterator<MethodEntry> it = current.myCalledMethods.iterator();
   while (it.hasNext()) {
     MethodEntry callee = it.next();
     if (set.contains(callee)) {
       callee.myCalledByMethods.remove(current);
       if (callee.myCalledByMethods.size() == 0) {
         callee.myRelatedMethod = false;
       }
       it.remove();
     } else {
       set.add(callee);
       test(callee, set);
     }
   }
 }
 public void emit(Emitter emitter) {
   StringBuilder sb = emitter.getTextBuffer();
   if (getCustomizedPrecedingComment().length() > 0) {
     sb.append("\n");
     sb.append(getCustomizedPrecedingComment());
   }
   emitAllElements(sb, emitter.getDocument());
   if (getCustomizedTrailingComment().length() > 0) {
     sb.append("\n");
     sb.append(getCustomizedTrailingComment());
   }
   /** emit corresponding setter, overloaded methods, and related methods, if any. */
   ListIterator li;
   if (isGetter()) {
     for (MethodEntry entry : myCorrespondingGetterSetters) {
       entry.emit(emitter);
     }
   }
   for (MethodEntry me : myOverloadedMethods) {
     me.emit(emitter);
   }
   for (MethodEntry me : sortedMethods) {
     me.emit(emitter);
   }
 }
 /**
  * Called when getters and setters are to be kept together in pairs. Searches the list of entries
  * for any getter/setter methods that matches this getter method. Normally there is only one
  * setter per getter, but one could have a "getXXX", "isXXX" and "setXXX" trio which need to be
  * related. In this case, the first getter encountered finds the other getter and setter and the
  * three will be emitted in that order.
  *
  * @param possibleMethods entry list, possibly containing the corresponding setter for this
  *     getter.
  * @param settings
  */
 public void determineSetter(
     final List<ClassContentsEntry> possibleMethods, RearrangerSettings settings) {
   if (!isGetter()) // wasted assertion, already checked before calling
   {
     return;
   }
   final PsiMethod thisMethod = (PsiMethod) myEnd;
   String thisProperty = MethodUtil.getPropertyName(thisMethod);
   if (isGetter() && !myKeptWithProperty) {
     if (settings.isKeepGettersSettersWithProperty()) {
       hookGetterToProperty(possibleMethods);
     }
   }
   for (ClassContentsEntry o : possibleMethods) {
     if (o instanceof RelatableEntry) {
       MethodEntry me = (MethodEntry) o;
       // don't use a setter twice (could be two methods which both look like getters; assign the
       // setter
       // to only one of them.)  Also, associate all getter/setter methods for the same property
       // with the
       // first one encountered.
       if ((me.isSetter() || me.isGetter())
           && me.myCorrespondingGetterSetters.size() == 0
           && me != this) {
         PsiMethod m = (PsiMethod) me.myEnd;
         String otherProperty = MethodUtil.getPropertyName(m);
         if (thisProperty.equals(otherProperty)) {
           LOG.debug(
               "method " + thisMethod.toString() + " is getter; its setter is " + m.toString());
           // place getters ahead of setters
           if (me.isGetter()) {
             myCorrespondingGetterSetters.add(0, me);
             // clear the getter flag and set the setter flag; this causes the method to be emitted
             // under the first getter encountered.
             me.setGetter(false);
             me.setSetter(true);
           } else {
             myCorrespondingGetterSetters.add(me);
           }
           me.myCorrespondingGetterSetters.add(this);
         }
       }
     }
   }
 }
 public DefaultMutableTreeNode addToPopupTree(
     DefaultMutableTreeNode parent, RearrangerSettings settings) {
   DefaultMutableTreeNode node = new RearrangerTreeNode(this, myName);
   parent.add(node);
   ListIterator li;
   for (MethodEntry methodEntry : sortedMethods) {
     if (methodEntry.isSetter() && methodEntry.myCalledByMethods.size() > 0) {
       // setters are arranged with getters when "keep getters/setters together" option is checked.
       // but setters are not really called by getters.  So attach them to the upper level.
       methodEntry.addToPopupTree(parent, settings);
     } else {
       methodEntry.addToPopupTree(node, settings);
     }
   }
   for (MethodEntry methodEntry : myOverloadedMethods) {
     methodEntry.addToPopupTree(node, settings);
   }
   return node;
 }
 /**
  * Set preceding and/or trailing comments on the appropriate methods, based on the comment type.
  *
  * @param rms
  * @param allMethodNames contains a list of methods invoked to reach this point. Top level is
  *     empty string.
  * @param level current nesting level; top level is 1.
  */
 private void assignComments(
     RelatedMethodsSettings rms,
     List<MethodEntry> allCallingMethods,
     String allMethodNames,
     int level) {
   final String currentMethodName = ((PsiMethod) myEnd).getName();
   String[] callingNames = new String[allCallingMethods.size()];
   for (int i = 0; i < allCallingMethods.size(); i++) {
     MethodEntry me = allCallingMethods.get(i);
     callingNames[i] = ((PsiMethod) me.myEnd).getName();
   }
   MethodEntry topLevel = this;
   while (topLevel.myCalledByMethods.size() > 0) {
     topLevel = (topLevel.myCalledByMethods.get(0));
   }
   switch (rms.getCommentType()) {
     case RelatedMethodsSettings.COMMENT_TYPE_TOP_LEVEL:
       customizedPrecedingComment =
           expandComment(
               rms.getPrecedingComment(),
               currentMethodName,
               allMethodNames,
               currentMethodName,
               level);
       MethodEntry last = this;
       while (last.sortedMethods.size() > 0) {
         last = (last.sortedMethods.get(last.sortedMethods.size() - 1));
       }
       last.customizedTrailingComment =
           expandComment(
               rms.getTrailingComment(),
               currentMethodName,
               allMethodNames,
               currentMethodName,
               level);
       break;
     case RelatedMethodsSettings.COMMENT_TYPE_EACH_METHOD:
       customizedPrecedingComment =
           expandComment(
               rms.getPrecedingComment(),
               currentMethodName,
               allMethodNames,
               ((PsiMethod) topLevel.myEnd).getName(),
               level);
       customizedTrailingComment =
           expandComment(
               rms.getTrailingComment(),
               currentMethodName,
               allMethodNames,
               ((PsiMethod) topLevel.myEnd).getName(),
               level);
       // recursively assign comments.
       for (MethodEntry methodEntry : sortedMethods) {
         String newAllMethodNames =
             appendMN(allMethodNames, callingNames, allCallingMethods, this, rms);
         methodEntry.assignComments(rms, sortedMethods, newAllMethodNames, level + 1);
       }
       break;
     case RelatedMethodsSettings.COMMENT_TYPE_NEW_FAMILY:
       {
         /**
          * Specialized routine to assign comments to "families" of methods. Insert a preceding
          * comment before every sibling except: when it is the first, and when the prior sibling
          * had no children and this sibling has no children.
          */
         MethodEntry firstEntry = null;
         MethodEntry previousEntry = null;
         for (MethodEntry methodEntry : allCallingMethods) {
           if (firstEntry == null) {
             firstEntry = methodEntry;
           } else if (methodEntry.sortedMethods.size() != 0
               || previousEntry.sortedMethods.size() != 0) {
             methodEntry.customizedPrecedingComment =
                 expandComment(
                     rms.getPrecedingComment(),
                     currentMethodName,
                     allMethodNames,
                     ((PsiMethod) topLevel.myEnd).getName(),
                     level);
           }
           previousEntry = methodEntry;
           if (methodEntry.sortedMethods.size() != 0) {
             String newAllMethodNames =
                 appendMN(allMethodNames, callingNames, allCallingMethods, methodEntry, rms);
             methodEntry.assignComments(
                 rms, methodEntry.sortedMethods, newAllMethodNames, level + 1);
           }
         }
       }
       break;
     case RelatedMethodsSettings.COMMENT_TYPE_EACH_LEVEL:
       {
         MethodEntry beginLevel = allCallingMethods.get(0);
         MethodEntry endLevel = allCallingMethods.get(allCallingMethods.size() - 1);
         beginLevel.customizedPrecedingComment =
             expandComment(
                 rms.getPrecedingComment(),
                 currentMethodName,
                 allMethodNames,
                 ((PsiMethod) topLevel.myEnd).getName(),
                 level);
         // recursively assign comments for each level.
         for (MethodEntry methodEntry : allCallingMethods) {
           if (methodEntry.sortedMethods.size() > 0) {
             String newAllMethodNames =
                 appendMN(allMethodNames, callingNames, allCallingMethods, methodEntry, rms);
             methodEntry.assignComments(
                 rms, methodEntry.sortedMethods, newAllMethodNames, level + 1);
           }
         }
         while (endLevel.sortedMethods.size() > 0) {
           endLevel = endLevel.sortedMethods.get(endLevel.sortedMethods.size() - 1);
         }
         if (endLevel.customizedTrailingComment.length() > 0) {
           endLevel.customizedTrailingComment += "\n";
         }
         endLevel.customizedTrailingComment +=
             expandComment(
                 rms.getTrailingComment(),
                 currentMethodName,
                 allMethodNames,
                 ((PsiMethod) topLevel.myEnd).getName(),
                 level);
       }
       break;
   }
 }
 /**
  * If setting indicates, move all overloaded methods (of the same name) adjacent with the first
  * encountered. Sort in the configured order (original order, or by number of parameters).
  */
 public static void handleOverloadedMethods(
     List<ClassContentsEntry> contents, RearrangerSettings settings) {
   if (!settings.isKeepOverloadedMethodsTogether()) return;
   /**
    * first, detect overloaded methods and move them to the first method's list of overloaded
    * methods. Make two passes, first for extracted methods, then for non-extracted methods. This
    * will organize any overloaded methods for extracted methods with them (as opposed to whichever
    * was seen first.)
    */
   cullOverloadedMethods(contents, true);
   LOG.debug("entered handleOverloadedMethods(): move overloaded methods together");
   cullOverloadedMethods(contents, false);
   List<ClassContentsEntry> copy = new ArrayList<ClassContentsEntry>(contents);
   for (ClassContentsEntry rangeEntry : copy) {
     if (rangeEntry instanceof RelatableEntry) {
       MethodEntry current = (MethodEntry) rangeEntry;
       if (current.myOverloadedMethods.size() > 0) {
         List<MethodEntry> newList =
             new ArrayList<MethodEntry>(current.myOverloadedMethods.size() + 1);
         newList.add(current);
         /**
          * we are looking at the head of a list of overloaded methods. We need to sort the list if
          * necessary and, if the head of the list has changed, replace it in the contents array.
          */
         switch (settings.getOverloadedOrder()) {
           case RearrangerSettings.OVERLOADED_ORDER_RETAIN_ORIGINAL:
             // list is already in original order, except perhaps that the top-most extracted
             // method
             // comes first (if there is one).
             newList.addAll(current.myOverloadedMethods);
             break;
           case RearrangerSettings.OVERLOADED_ORDER_ASCENDING_PARAMETERS:
           case RearrangerSettings.OVERLOADED_ORDER_DESCENDING_PARAMETERS:
             for (MethodEntry entry : current.myOverloadedMethods) {
               boolean inserted = false;
               for (int index = 0; index < newList.size(); index++) {
                 MethodEntry me = newList.get(index);
                 if (settings.getOverloadedOrder()
                         == RearrangerSettings.OVERLOADED_ORDER_ASCENDING_PARAMETERS
                     ? me.getnParameters() > entry.getnParameters()
                     : me.getnParameters() < entry.getnParameters()) {
                   newList.add(index, entry);
                   inserted = true;
                   break;
                 }
               }
               if (!inserted) {
                 newList.add(entry);
               }
             }
             break;
         }
         current.myOverloadedMethods.clear();
         /**
          * if the head of the arraylist is not the same as "current", then the sort operation
          * moved another method to the head of the list. Replace that in the contents array. Then
          * assign a new ordered list.
          */
         int index = contents.indexOf(current);
         if (newList.get(0) != current) {
           contents.set(index, ((MethodEntry) newList.get(0)));
         }
         /** insert the remaining overloaded methods after the current entry. */
         newList.remove(0);
         for (int j = 0; j < newList.size(); j++) {
           contents.add(index + j + 1, ((MethodEntry) newList.get(j)));
         }
       }
     }
   }
 }
 void dumpChild(int level) {
   LOG.debug(level + ": " + ((PsiMethod) myEnd).getName());
   for (MethodEntry methodEntry : sortedMethods) {
     methodEntry.dumpChild(level + 1);
   }
 }
Esempio n. 10
0
 /**
  * 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);
     }
   }
 }