Update ExtractClassNamesVisitor to be able to ignore selectors with certain prefixes.

Patch by: bobv
Review by: rjrjr

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6346 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/resources/css/ExtractClassNamesVisitor.java b/user/src/com/google/gwt/resources/css/ExtractClassNamesVisitor.java
index ca85293..eb4617f 100644
--- a/user/src/com/google/gwt/resources/css/ExtractClassNamesVisitor.java
+++ b/user/src/com/google/gwt/resources/css/ExtractClassNamesVisitor.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2009 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
@@ -15,14 +15,18 @@
  */
 package com.google.gwt.resources.css;
 
+import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.resources.css.ast.Context;
 import com.google.gwt.resources.css.ast.CssExternalSelectors;
 import com.google.gwt.resources.css.ast.CssSelector;
 import com.google.gwt.resources.css.ast.CssStylesheet;
 import com.google.gwt.resources.css.ast.CssVisitor;
+import com.google.gwt.resources.rg.CssResourceGenerator;
 
 import java.util.HashSet;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 
 /**
@@ -33,38 +37,66 @@
    * Extract all CSS class names in the provided stylesheet.
    */
   public static Set<String> exec(CssStylesheet sheet) {
-    ExtractClassNamesVisitor v = new ExtractClassNamesVisitor();
+    return exec(sheet, new JClassType[0]);
+  }
+
+  /**
+   * Extract all CSS class names in the provided stylesheet, modulo those
+   * imported from another context.
+   */
+  public static Set<String> exec(CssStylesheet sheet, JClassType... imports) {
+    SortedSet<String> ignoredPrefixes = new TreeSet<String>();
+
+    for (JClassType clazz : imports) {
+      String prefix = CssResourceGenerator.getImportPrefix(clazz);
+      ignoredPrefixes.add(prefix);
+    }
+
+    ExtractClassNamesVisitor v = new ExtractClassNamesVisitor(ignoredPrefixes);
     v.accept(sheet);
     return v.found;
   }
 
   private final Set<String> found = new HashSet<String>();
+  private final SortedSet<String> ignoredPrefixes;
 
   /**
    * Package-protected for testing.
    */
-  ExtractClassNamesVisitor() {
+  ExtractClassNamesVisitor(SortedSet<String> ignoredPrefixes) {
+    this.ignoredPrefixes = ignoredPrefixes;
   }
 
   @Override
   public void endVisit(CssExternalSelectors x, Context ctx) {
-    found.addAll(x.getClasses());
+    addAll(x.getClasses());
   }
 
   @Override
   public void endVisit(CssSelector x, Context ctx) {
     Matcher m = CssSelector.CLASS_SELECTOR_PATTERN.matcher(x.getSelector());
     while (m.find()) {
-      found.add(m.group(1));
+      add(m.group(1));
     }
   }
 
   /**
    * Package-protected for testing.
-   *
-   * @return
    */
   Set<String> getFoundClasses() {
     return found;
   }
+
+  private void add(String selector) {
+    SortedSet<String> headSet = ignoredPrefixes.headSet(selector);
+    if (headSet.isEmpty() || !selector.startsWith(headSet.last())) {
+      found.add(selector);
+    }
+  }
+
+  private void addAll(Iterable<String> selectors) {
+    for (String selector : selectors) {
+      add(selector);
+    }
+  }
 }
diff --git a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
index 3922349..0027209 100644
--- a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
@@ -125,6 +125,19 @@
   private static final String KEY_CLASS_PREFIX = "prefix";
   private static final String KEY_CLASS_COUNTER = "counter";
 
+  /**
+   * Returns the import prefix for a type, including the trailing hyphen.
+   */
+  public static String getImportPrefix(JClassType importType) {
+    String prefix = importType.getSimpleSourceName();
+    ImportedWithPrefix exp = importType.getAnnotation(ImportedWithPrefix.class);
+    if (exp != null) {
+      prefix = exp.value();
+    }
+
+    return prefix + "-";
+  }
+
   public static boolean haveCommonProperties(CssRule a, CssRule b) {
     if (a.getProperties().size() == 0 || b.getProperties().size() == 0) {
       return false;
@@ -369,6 +382,7 @@
   public String createAssignment(TreeLogger logger, ResourceContext context,
       JMethod method) throws UnableToCompleteException {
 
+    TypeOracle typeOracle = context.getGeneratorContext().getTypeOracle();
     SourceWriter sw = new StringSourceWriter();
     // Write the expression to create the subtype.
     sw.println("new " + method.getReturnType().getQualifiedSourceName()
@@ -385,16 +399,14 @@
     if (imp != null) {
       boolean fail = false;
       for (Class<? extends CssResource> clazz : imp.value()) {
-        JClassType importType = context.getGeneratorContext().getTypeOracle().findType(
-            clazz.getName().replace('$', '.'));
-        assert importType != null;
-        String prefix = importType.getSimpleSourceName();
-        ImportedWithPrefix exp = importType.getAnnotation(ImportedWithPrefix.class);
-        if (exp != null) {
-          prefix = exp.value();
-        }
+        JClassType importType = typeOracle.findType(clazz.getName().replace(
+            '$', '.'));
+        assert importType != null : "TypeOracle does not have type "
+            + clazz.getName();
 
-        if (replacementsWithPrefix.put(prefix + "-",
+        String prefix = getImportPrefix(importType);
+
+        if (replacementsWithPrefix.put(prefix,
             computeReplacementsForType(importType)) != null) {
           logger.log(TreeLogger.ERROR,
               "Multiple imports that would use the prefix " + prefix);
diff --git a/user/test/com/google/gwt/resources/css/ExtractClassNamesVisitorTest.java b/user/test/com/google/gwt/resources/css/ExtractClassNamesVisitorTest.java
index 532a9d4..0ebaaf6 100644
--- a/user/test/com/google/gwt/resources/css/ExtractClassNamesVisitorTest.java
+++ b/user/test/com/google/gwt/resources/css/ExtractClassNamesVisitorTest.java
@@ -29,7 +29,23 @@
 public class ExtractClassNamesVisitorTest extends CssTestCase {
 
   public void test() throws UnableToCompleteException {
-    ExtractClassNamesVisitor v = new ExtractClassNamesVisitor();
+    ExtractClassNamesVisitor v = new ExtractClassNamesVisitor(
+        new TreeSet<String>());
+
+    test(TreeLogger.NULL, "extractClassNames", false, v);
+
+    Set<String> expected = new TreeSet<String>(Arrays.asList("selector1",
+        "selector2", "selector3", "external1", "external2", "external3",
+        "prefixed-selector"));
+    Set<String> actual = new TreeSet<String>(v.getFoundClasses());
+
+    assertEquals(expected, actual);
+  }
+
+  public void testImportedClasses() throws UnableToCompleteException {
+    ExtractClassNamesVisitor v = new ExtractClassNamesVisitor(
+        new TreeSet<String>(Arrays.asList("blah-selector-", "prefixed-",
+            "postfixed-")));
 
     test(TreeLogger.NULL, "extractClassNames", false, v);
 
diff --git a/user/test/com/google/gwt/resources/css/extractClassNames_expected.css b/user/test/com/google/gwt/resources/css/extractClassNames_expected.css
index 1459ed4..3a023ff 100644
--- a/user/test/com/google/gwt/resources/css/extractClassNames_expected.css
+++ b/user/test/com/google/gwt/resources/css/extractClassNames_expected.css
@@ -21,6 +21,10 @@
 .selector2 .selector3 {
 }
 
+.prefixed-selector {
+}
+
+/* This is not a class selector */
 fail {
 }
 
diff --git a/user/test/com/google/gwt/resources/css/extractClassNames_test.css b/user/test/com/google/gwt/resources/css/extractClassNames_test.css
index 1459ed4..3a023ff 100644
--- a/user/test/com/google/gwt/resources/css/extractClassNames_test.css
+++ b/user/test/com/google/gwt/resources/css/extractClassNames_test.css
@@ -21,6 +21,10 @@
 .selector2 .selector3 {
 }
 
+.prefixed-selector {
+}
+
+/* This is not a class selector */
 fail {
 }