Order the contents of cssmap to stablize the compiler's output

Review by: cromwellian@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10828 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
index e63b6d8..0fe7c04 100644
--- a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * 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
@@ -91,18 +91,20 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedSet;
+import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.zip.Adler32;
 
 /**
  * Provides implementations of CSSResources.
  */
-public class CssResourceGenerator extends AbstractResourceGenerator 
+public class CssResourceGenerator extends AbstractResourceGenerator
     implements SupportsGeneratorResultCaching {
 
   @SuppressWarnings("serial")
   static class JClassOrderComparator implements Comparator<JClassType>,
       Serializable {
+    @Override
     public int compare(JClassType o1, JClassType o2) {
       return o1.getQualifiedSourceName().compareTo(o2.getQualifiedSourceName());
     }
@@ -232,7 +234,7 @@
       /*
        * Compute a new prefix for the identifier to mask the prefix and add the
        * reserved identifier character to prevent conflicts with makeIdent().
-       * 
+       *
        * Assuming "gwt-" is a reserved prefix: gwt-A -> ab32ZA
        */
       String newPrefix = makeIdent(hash.getValue()).substring(0,
@@ -267,7 +269,7 @@
      * Very large concatenation expressions using '+' cause the GWT compiler to
      * overflow the stack due to deep AST nesting. The workaround for now is to
      * force it to be more balanced using intermediate concatenation groupings.
-     * 
+     *
      * This variable is used to track the number of subexpressions within the
      * current parenthetical expression.
      */
@@ -339,7 +341,7 @@
   /**
    * Check if number of concat expressions currently exceeds limit and either
    * append '+' if the limit isn't reached or ') + (' if it is.
-   * 
+   *
    * @return numExpressions + 1 or 0 if limit was exceeded.
    */
   private static int concatOp(int numExpressions, StringBuilder b) {
@@ -442,7 +444,7 @@
     JClassType cssResourceSubtype = method.getReturnType().isInterface();
     assert cssResourceSubtype != null;
     CssStylesheet stylesheet = stylesheetMap.get(method);
-    
+
     // Optimize the stylesheet, recording the class selector obfuscations
     Map<JMethod, String> actualReplacements = optimize(logger, context, method);
 
@@ -450,7 +452,7 @@
 
     outputAdditionalArtifacts(logger, context, method, actualReplacements,
         cssResourceSubtype, stylesheet);
-    
+
     return getResourceImplAsString(logger, context, method, actualReplacements,
         cssResourceSubtype, stylesheet);
   }
@@ -460,22 +462,22 @@
       throws UnableToCompleteException {
     String classPrefix;
     try {
-      PropertyOracle propertyOracle = 
+      PropertyOracle propertyOracle =
         context.getGeneratorContext().getPropertyOracle();
-      ConfigurationProperty styleProp = 
+      ConfigurationProperty styleProp =
         propertyOracle.getConfigurationProperty(KEY_STYLE);
       obfuscationStyle = CssObfuscationStyle.getObfuscationStyle(
           styleProp.getValues().get(0));
-      
-      ConfigurationProperty mergeProp = 
+
+      ConfigurationProperty mergeProp =
         propertyOracle.getConfigurationProperty(KEY_MERGE_ENABLED);
       String merge = mergeProp.getValues().get(0);
       enableMerge = merge.equals("true");
 
-      ConfigurationProperty classPrefixProp = 
+      ConfigurationProperty classPrefixProp =
         propertyOracle.getConfigurationProperty(KEY_OBFUSCATION_PREFIX);
       classPrefix = classPrefixProp.getValues().get(0);
-      
+
       // add these configuration properties to our requirements
       ClientBundleRequirements requirements = context.getRequirements();
       requirements.addConfigurationProperty(KEY_STYLE);
@@ -495,7 +497,7 @@
     }
 
     stylesheetMap = new IdentityHashMap<JMethod, CssStylesheet>();
-    
+
     SortedSet<JClassType> cssResourceSubtypes =
       computeOperableTypes(logger, baseInterface);
     initReplacements(logger, context, classPrefix, cssResourceSubtypes);
@@ -521,14 +523,14 @@
     CssStylesheet sheet = GenerateCssAst.exec(logger, resources);
     checkSheet(logger, sheet);
     stylesheetMap.put(method, sheet);
-    (new RequirementsCollector(logger, context.getRequirements())).accept(sheet);    
+    (new RequirementsCollector(logger, context.getRequirements())).accept(sheet);
   }
-  
+
   protected void checkSheet(TreeLogger logger, CssStylesheet stylesheet)
   throws UnableToCompleteException {
     // Do nothing
   }
- 
+
   /**
    * Return the name of the class which is at the base of the CssResource
    * generation tree.  Since obfuscation is done globally, this should be the
@@ -552,18 +554,18 @@
     // Methods defined by CssResource interface
     writeEnsureInjected(sw);
     writeGetName(method, sw);
-  
+
     // Create the Java expression that generates the CSS
     writeGetText(logger, context, method, sw);
-   
+
     // getOverridableMethods is used to handle CssResources extending
     // non-CssResource types. See the discussion in computeReplacementsForType.
     writeUserMethods(logger, sw, stylesheet,
         cssResourceSubtype.getOverridableMethods(), actualReplacements);
-   
+
     sw.outdent();
     sw.println("}");
-   
+
     return sw.toString();
   }
 
@@ -579,7 +581,7 @@
   protected String getSuperclassInterfaceName() {
     return CssResource.class.getCanonicalName();
   }
-  
+
   /**
    * Output additional artifacts. Does nothing in this baseclass, but is a hook
    * for subclasses to do so.
@@ -764,7 +766,7 @@
          */
         String obfuscatedClassName = computeObfuscatedClassName(classPrefix,
             classCounter, reservedPrefixes);
-        
+
         // Modify the name based on the obfuscation style requested
         obfuscatedClassName = obfuscationStyle.getPrettyName(name, type,
               obfuscatedClassName);
@@ -852,7 +854,7 @@
 
     return toReturn;
   }
-  
+
   /**
    * Determine if a type is derived from CssResource.
    */
@@ -891,13 +893,13 @@
      * result regardless of the order in which the generators fired. (It no
      * longer behaves that way, as that scheme prevented the generation of new
      * CssResource interfaces, but the complexity lives on.)
-     * 
+     *
      * TODO(rjrjr,bobv) These days scottb tells us we're guaranteed that the
      * recompiling the same code will fire the generators in a consistent order,
      * so the old gymnastics aren't really justified anyway. It would probably
      * be be worth the effort to simplify this.
      */
-    
+
     if (context.getCachedData(KEY_HAS_CACHED_DATA, Boolean.class) != Boolean.TRUE) {
 
       ConfigurationProperty prop;
@@ -990,7 +992,7 @@
   /**
    * Create a Java expression that evaluates to the string representation of the
    * stylesheet resource.
-   * 
+   *
    * @param actualReplacements An out parameter that will be populated by the
    *          obfuscated class names that should be used for the particular
    *          instance of the CssResource, based on any substitution
@@ -1003,7 +1005,7 @@
       String standard = makeExpression(logger, context, sheet, obfuscationStyle.isPretty());
       (new RtlVisitor()).accept(sheet);
       String reversed = makeExpression(logger, context, sheet, obfuscationStyle.isPretty());
-      
+
       if (standard.equals(reversed)) {
         return standard;
       } else {
@@ -1021,7 +1023,7 @@
 
   private Map<JMethod, String> optimize(TreeLogger logger,
       ResourceContext context, JMethod method) throws UnableToCompleteException {
-    
+
     TypeOracle typeOracle = context.getGeneratorContext().getTypeOracle();
     JClassType cssResourceSubtype = method.getReturnType().isInterface();
     assert cssResourceSubtype != null;
@@ -1034,7 +1036,7 @@
 
     boolean strict = isStrict(logger, method);
     CssStylesheet sheet = stylesheetMap.get(method);
-    
+
     // Create CSS sprites
     (new Spriter(logger, context)).accept(sheet);
 
@@ -1056,7 +1058,22 @@
     ClassRenamer renamer = new ClassRenamer(logger,
         classReplacementsWithPrefix, strict, externalClasses.getClasses());
     renamer.accept(sheet);
-    Map<JMethod, String> actualReplacements = new HashMap<JMethod, String>();
+    Map<JMethod, String> actualReplacements = new TreeMap<JMethod, String>(
+        new Comparator<JMethod>() {
+          @Override
+          public int compare(JMethod o1, JMethod o2) {
+            String qualifiedName = source(o1);
+            int result = source(o1).compareTo(source(o2));
+            if (result == 0) {
+              result = o1.getName().compareTo(o2.getName());
+            }
+            return result;
+          }
+
+          private String source(JMethod o) {
+            return o.getEnclosingType().getQualifiedSourceName();
+          }
+        });
     actualReplacements.putAll(renamer.getReplacements());
 
     // Combine rules with identical selectors
@@ -1064,8 +1081,8 @@
       (new SplitRulesVisitor()).accept(sheet);
       (new MergeIdenticalSelectorsVisitor()).accept(sheet);
       (new MergeRulesByContentVisitor()).accept(sheet);
-    } 
-    
+    }
+
     return actualReplacements;
   }
 
@@ -1093,7 +1110,7 @@
 
         // add this import type as a requirement for this generator
         context.getRequirements().addTypeHierarchy(importType);
-        
+
         String prefix = getImportPrefix(importType);
 
         if (replacementsWithPrefix.put(prefix,
@@ -1105,7 +1122,7 @@
       }
       if (fail) {
         throw new UnableToCompleteException();
-      }  
+      }
     }
     return replacementsWithPrefix;
   }