private void createCanonicalMethods() {
   if (!hasAnnotation(annotatedClass, EQUALS_HASHCODE_ANNOT)) {
     createHashCode(annotatedClass, false, false, true, null, null);
     createEquals(annotatedClass, false, true, true, null, null);
   }
   if (!hasAnnotation(annotatedClass, TOSTRING_ANNOT)) {
     if (ownerField == null) createToString(annotatedClass, false, false, null, null, false);
     else
       createToString(
           annotatedClass,
           false,
           false,
           Collections.singletonList(ownerField.getName()),
           null,
           false);
   }
 }
  private static void doAddGlobalTransforms(
      ASTTransformationsContext context, boolean isFirstScan) {
    final CompilationUnit compilationUnit = context.getCompilationUnit();
    GroovyClassLoader transformLoader = compilationUnit.getTransformLoader();
    Map<String, URL> transformNames = new LinkedHashMap<String, URL>();
    try {
      Enumeration<URL> globalServices =
          transformLoader.getResources(
              "META-INF/services/org.codehaus.groovy.transform.ASTTransformation");
      while (globalServices.hasMoreElements()) {
        URL service = globalServices.nextElement();
        String className;
        BufferedReader svcIn = null;
        try {
          svcIn = new BufferedReader(new InputStreamReader(service.openStream()));
          try {
            className = svcIn.readLine();
          } catch (IOException ioe) {
            compilationUnit
                .getErrorCollector()
                .addError(
                    new SimpleMessage(
                        "IOException reading the service definition at "
                            + service.toExternalForm()
                            + " because of exception "
                            + ioe.toString(),
                        null));
            continue;
          }
          Set<String> disabledGlobalTransforms =
              compilationUnit.getConfiguration().getDisabledGlobalASTTransformations();
          if (disabledGlobalTransforms == null) disabledGlobalTransforms = Collections.emptySet();
          while (className != null) {
            if (!className.startsWith("#") && className.length() > 0) {
              if (!disabledGlobalTransforms.contains(className)) {
                if (transformNames.containsKey(className)) {
                  if (!service.equals(transformNames.get(className))) {
                    compilationUnit
                        .getErrorCollector()
                        .addWarning(
                            WarningMessage.POSSIBLE_ERRORS,
                            "The global transform for class "
                                + className
                                + " is defined in both "
                                + transformNames.get(className).toExternalForm()
                                + " and "
                                + service.toExternalForm()
                                + " - the former definition will be used and the latter ignored.",
                            null,
                            null);
                  }

                } else {
                  transformNames.put(className, service);
                }
              }
            }
            try {
              className = svcIn.readLine();
            } catch (IOException ioe) {
              compilationUnit
                  .getErrorCollector()
                  .addError(
                      new SimpleMessage(
                          "IOException reading the service definition at "
                              + service.toExternalForm()
                              + " because of exception "
                              + ioe.toString(),
                          null));
              //noinspection UnnecessaryContinue
              continue;
            }
          }
        } finally {
          if (svcIn != null) svcIn.close();
        }
      }
    } catch (IOException e) {
      // FIXME the warning message will NPE with what I have :(
      compilationUnit
          .getErrorCollector()
          .addError(
              new SimpleMessage(
                  "IO Exception attempting to load global transforms:" + e.getMessage(), null));
    }
    try {
      Class.forName("java.lang.annotation.Annotation"); // test for 1.5 JVM
    } catch (Exception e) {
      // we failed, notify the user
      StringBuffer sb = new StringBuffer();
      sb.append("Global ASTTransformations are not enabled in retro builds of groovy.\n");
      sb.append("The following transformations will be ignored:");
      for (Map.Entry<String, URL> entry : transformNames.entrySet()) {
        sb.append('\t');
        sb.append(entry.getKey());
        sb.append('\n');
      }
      compilationUnit
          .getErrorCollector()
          .addWarning(
              new WarningMessage(WarningMessage.POSSIBLE_ERRORS, sb.toString(), null, null));
      return;
    }

    // record the transforms found in the first scan, so that in the 2nd scan, phase operations
    // can be added for only for new transforms that have come in
    if (isFirstScan) {
      for (Map.Entry<String, URL> entry : transformNames.entrySet()) {
        context.getGlobalTransformNames().add(entry.getKey());
      }
      addPhaseOperationsForGlobalTransforms(
          context.getCompilationUnit(), transformNames, isFirstScan);
    } else {
      Iterator<Map.Entry<String, URL>> it = transformNames.entrySet().iterator();
      while (it.hasNext()) {
        Map.Entry<String, URL> entry = it.next();
        if (!context.getGlobalTransformNames().add(entry.getKey())) {
          // phase operations for this transform class have already been added before, so remove
          // from current scan cycle
          it.remove();
        }
      }
      addPhaseOperationsForGlobalTransforms(
          context.getCompilationUnit(), transformNames, isFirstScan);
    }
  }
  private List getPrimaryClassNodes(boolean sort) {
    if (sort == true) {
      List<ModuleNode> sortedModules = this.ast.getSortedModules();
      if (sortedModules != null) {
        return sortedModules;
      }
    }
    // FIXASC (groovychange) rewritten
    /*old{
    List unsorted = new ArrayList();
    Iterator modules = this.ast.getModules().iterator();
    while (modules.hasNext()) {
        ModuleNode module = (ModuleNode) modules.next();

        Iterator classNodes = module.getClasses().iterator();
        while (classNodes.hasNext()) {
            ClassNode classNode = (ClassNode) classNodes.next();
            unsorted.add(classNode);
        }
    }
    */
    // new
    List<ClassNode> unsorted = new ArrayList<ClassNode>();
    for (ModuleNode module : this.ast.getModules()) {
      unsorted.addAll(module.getClasses());
    }
    // FIXASC (groovychange) end

    if (!sort) return unsorted;

    // GRECLIPSE: start: rewritten sort algorithm
    /*old{
            int[] indexClass = new int[unsorted.size()];
            int[] indexInterface = new int[unsorted.size()];
            {
                int i = 0;
                for (Iterator<ClassNode> iter = unsorted.iterator(); iter.hasNext(); i++) {
                    ClassNode element = iter.next();
                    if (element.isInterface()) {
                        indexInterface[i] = getSuperInterfaceCount(element);
                        indexClass[i] = -1;
                    } else {
                        indexClass[i] = getSuperClassCount(element);
                        indexInterface[i] = -1;
                    }
                }
            }

            List<ClassNode> sorted = getSorted(indexInterface, unsorted);
            sorted.addAll(getSorted(indexClass, unsorted));
    */
    // newcode:
    // Sort them by how many types are in their hierarchy, but all interfaces first.
    // Algorithm:
    // Create a list of integers.  Each integer captures the index into the unsorted
    // list (bottom 16bits) and the count of how many types are in that types
    // hierarchy (top 16bits).  For classes the count is augmented by 2000 so that
    // when sorting the classes will come out after the interfaces.
    // This list of integers is sorted.  We then just go through it and for the
    // lower 16bits of each entry (0xffff) that is the index of the next value to
    // pull from the unsorted list and put into the sorted list.
    // Will break down if more than 2000 interfaces in the type hierarchy for an
    // individual type, or a project contains > 65535 files... but if you've got
    // that kind of setup, you have other problems...
    List<Integer> countIndexPairs = new ArrayList<Integer>();
    {
      int i = 0;
      for (Iterator iter = unsorted.iterator(); iter.hasNext(); i++) {
        ClassNode node = (ClassNode) iter.next();
        if (node.isInterface()) {
          countIndexPairs.add((getSuperInterfaceCount(node) << 16) + i);
        } else {
          countIndexPairs.add(((getSuperClassCount(node) + 2000) << 16) + i);
        }
      }
    }
    Collections.sort(countIndexPairs);
    List sorted = new ArrayList();
    for (int i : countIndexPairs) {
      sorted.add(unsorted.get(i & 0xffff));
    }
    this.ast.setSortedModules(sorted);
    // end
    return sorted;
  }