Revision: 4452
Author:   mikesamuel
Date:     Mon Apr 25 23:22:07 2011
Log:      Fix issue 1348
http://codereview.appspot.com/4432067

Fix problem with optimizing dot operators in the minifier.

[email protected]

http://code.google.com/p/google-caja/source/detail?r=4452

Modified:
 /trunk/src/com/google/caja/ancillary/opt/StatementSimplifier.java
 /trunk/src/com/google/caja/demos/playground/server/AppEngineJobCache.java
/trunk/src/com/google/caja/demos/playground/server/AppEngineJobCacheKey.java
 /trunk/src/com/google/caja/lang/css/JSRE.java
 /trunk/src/com/google/caja/lang/html/HtmlDefinitions.java
 /trunk/src/com/google/caja/parser/AbstractParseTreeNode.java
 /trunk/src/com/google/caja/parser/js/Operation.java
 /trunk/src/com/google/caja/plugin/CssRuleRewriter.java
 /trunk/src/com/google/caja/plugin/stages/StubJobCache.java
 /trunk/tests/com/google/caja/ancillary/opt/JsOptimizerTest.java
 /trunk/tests/com/google/caja/parser/html/NodesTest.java
 /trunk/tests/com/google/caja/plugin/PipelineCacheTest.java

=======================================
--- /trunk/src/com/google/caja/ancillary/opt/StatementSimplifier.java Thu Nov 18 11:05:16 2010 +++ /trunk/src/com/google/caja/ancillary/opt/StatementSimplifier.java Mon Apr 25 23:22:07 2011
@@ -42,6 +42,7 @@
 import com.google.caja.parser.js.Reference;
 import com.google.caja.parser.js.ReturnStmt;
 import com.google.caja.parser.js.Statement;
+import com.google.caja.parser.js.StringLiteral;
 import com.google.caja.parser.js.SwitchCase;
 import com.google.caja.parser.js.SwitchStmt;
 import com.google.caja.parser.js.ThrowStmt;
@@ -645,11 +646,26 @@
&& ParseTreeNodes.deepEquals(xoperands.get(0), yoperands.get(0))
               ) {
             // c ? (x + 1 : x + 2)  ->  x + (c ? 1 : 2)
-            return Operation.create(
-                pos, xoper, xoperands.get(0),
-                optimizeExpressionFlow(
-                    Operation.createTernary(
-                        c, xoperands.get(1), yoperands.get(1))));
+            if (xoper != Operator.MEMBER_ACCESS) {
+              return Operation.create(
+                  pos, xoper, xoperands.get(0),
+                  optimizeExpressionFlow(
+                      Operation.createTernary(
+                          c, xoperands.get(1), yoperands.get(1))));
+            } else {
+              Reference xref = (Reference) xoperands.get(1);
+              Reference yref = (Reference) yoperands.get(1);
+              StringLiteral xname = StringLiteral.valueOf(
+                  xref.getFilePosition(), xref.getIdentifierName());
+              StringLiteral yname = StringLiteral.valueOf(
+                  yref.getFilePosition(), yref.getIdentifierName());
+              return Operation.create(
+                  pos, Operator.SQUARE_BRACKET,
+                  xoperands.get(0),
+                  optimizeExpressionFlow(
+                       Operation.createTernary(
+                         c, xname, yname)));
+            }
           }
         }
       }
=======================================
--- /trunk/src/com/google/caja/demos/playground/server/AppEngineJobCache.java Fri Apr 8 23:31:20 2011 +++ /trunk/src/com/google/caja/demos/playground/server/AppEngineJobCache.java Mon Apr 25 23:22:07 2011
@@ -18,7 +18,6 @@
 import java.util.Collections;

 import net.sf.jsr107cache.Cache;
-import net.sf.jsr107cache.CacheException;
 import net.sf.jsr107cache.CacheManager;

 import com.google.caja.parser.ParseTreeNode;
@@ -34,7 +33,7 @@
  */
 final class AppEngineJobCache extends JobCache {
   private Cache l1cache;
-
+
   AppEngineJobCache() {
     try {
       this.l1cache = CacheManager.getInstance().getCacheFactory()
@@ -44,10 +43,13 @@
     }
   }

+  @Override
public AppEngineJobCacheKey forJob(ContentType type, ParseTreeNode node) {
     return new AppEngineJobCacheKey(type, node);
   }

+  @SuppressWarnings("unchecked")
+  @Override
   public List<? extends Job> fetch(JobCache.Key k) {
     if (null == l1cache) { return null; }
     if (!(k instanceof AppEngineJobCacheKey)) { return null; }
@@ -59,6 +61,7 @@
     return cloneJobs(cachedJobs);
   }

+  @Override
   public void store(Key k, List<? extends Job> derivatives) {
     if (!(k instanceof AppEngineJobCacheKey)) {
       throw new IllegalArgumentException(k.getClass().getName());
=======================================
--- /trunk/src/com/google/caja/demos/playground/server/AppEngineJobCacheKey.java Fri Apr 8 23:31:20 2011 +++ /trunk/src/com/google/caja/demos/playground/server/AppEngineJobCacheKey.java Mon Apr 25 23:22:07 2011
@@ -111,8 +111,9 @@
     }

     private void hash(Node node) {
-      hash((short) node.getNodeType());
-      switch (node.getNodeType()) {
+      short nodeType = node.getNodeType();
+      hash(nodeType);
+      switch (nodeType) {
         case Node.ATTRIBUTE_NODE:
         case Node.ELEMENT_NODE:
           hash(node.getNodeName());
@@ -125,7 +126,7 @@

       hash((short) node.getChildNodes().getLength());

-      if (node.getNodeType() == Node.ELEMENT_NODE) {
+      if (nodeType == Node.ELEMENT_NODE) {
         NamedNodeMap attrs = node.getAttributes();
         int nAttrs = attrs.getLength();
         hash((short) nAttrs);
=======================================
--- /trunk/src/com/google/caja/lang/css/JSRE.java       Fri Apr  8 23:31:20 2011
+++ /trunk/src/com/google/caja/lang/css/JSRE.java       Mon Apr 25 23:22:07 2011
@@ -18,7 +18,6 @@
 import com.google.caja.util.Lists;
 import com.google.caja.util.Sets;

-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -390,7 +389,7 @@
     int i = 0;
     while (i < n && a.get(i).equals(b.get(i))) { ++i; }
// Wrapping in a new array list because List.subList is not serializable
-    return new ArrayList(a.subList(0, i));
+    return Lists.<T>newArrayList(a.subList(0, i));
   }

   private static <T> List<T> commonSuffix(List<T> a, List<T> b) {
@@ -400,7 +399,7 @@
       // work done in condition
     }
// Wrapping in a new array list because List.subList is not serializable
-    return new ArrayList(a.subList(i + 1, m));
+    return Lists.<T>newArrayList(a.subList(i + 1, m));
   }

   static final class Concatenation extends JSRE {
=======================================
--- /trunk/src/com/google/caja/lang/html/HtmlDefinitions.java Fri Feb 18 13:40:38 2011 +++ /trunk/src/com/google/caja/lang/html/HtmlDefinitions.java Mon Apr 25 23:22:07 2011
@@ -97,7 +97,7 @@

   private static final AttribKey SCRIPT_SRC = AttribKey.forHtmlAttrib(
       ElKey.forHtmlElement("script"), "src");
-
+
   private static <U> ExpressionStmt mapFromEnum(
       Iterable<U> entries, String key,
       Function<U, String> keyMaker, Function<U, Integer> valueMaker) {
@@ -115,7 +115,7 @@
             "k", new ParseTreeNodeContainer(keys),
             "v", new ParseTreeNodeContainer(values)));
   }
-
+
   public static Block generateJavascriptDefinitions(HtmlSchema schema) {
     final FilePosition unk = FilePosition.UNKNOWN;
     Map<AttribKey, HTML.Attribute.Type> atypes = attributeTypes(schema);
@@ -140,7 +140,7 @@
           }
         })
     );
-
+
     {
       List<StringLiteral> keys = new ArrayList<StringLiteral>();
       List<IntegerLiteral> values = new ArrayList<IntegerLiteral>();
@@ -160,7 +160,7 @@
               "k", new ParseTreeNodeContainer(keys),
               "v", new ParseTreeNodeContainer(values))));
     }
-
+
     definitions.appendChild(mapFromEnum(
         EnumSet.allOf(EFlag.class),
         "eflags",
@@ -343,9 +343,9 @@
     }
     return attributeFlags;
   }
-
+
private interface SchemaExtractor<Result> { Result extract(HTML.Attribute attr); }
-
+
   private static <A> Map<AttribKey, A> deriveMapFromSchema(
       HtmlSchema schema, SchemaExtractor<A> extractor) {
     Map<AttribKey, A> result = Maps.newTreeMap();
@@ -364,7 +364,6 @@
   private static Map<AttribKey, UriEffect> uriEffects(
       HtmlSchema schema) {
     return deriveMapFromSchema(schema, new SchemaExtractor<UriEffect>() {
-      @Override
       public UriEffect extract(Attribute attr) {
         return attr.getUriEffect();
       }
@@ -374,7 +373,6 @@
   private static Map<AttribKey, LoaderType> loaderTypes(
       HtmlSchema schema) {
     return deriveMapFromSchema(schema, new SchemaExtractor<LoaderType>() {
-      @Override
       public LoaderType extract(Attribute attr) {
         return attr.getLoaderType();
       }
=======================================
--- /trunk/src/com/google/caja/parser/AbstractParseTreeNode.java Fri Apr 8 23:31:20 2011 +++ /trunk/src/com/google/caja/parser/AbstractParseTreeNode.java Mon Apr 25 23:22:07 2011
@@ -20,6 +20,7 @@
 import com.google.caja.reporting.MessageContext;
 import com.google.caja.reporting.MessagePart;
 import com.google.caja.util.Join;
+import com.google.caja.util.Lists;
 import com.google.caja.util.SyntheticAttributeKey;
 import com.google.caja.util.SyntheticAttributes;

@@ -79,8 +80,8 @@
   @SuppressWarnings("unchecked")
   protected <T2> List<T2> childrenPart(
       int start, int end, Class<T2> cl) {
-    List<ParseTreeNode> sub =
-      new ArrayList(children.getImmutableFacet().subList(start, end));
+    List<ParseTreeNode> sub = Lists.newArrayList(
+        children.getImmutableFacet().subList(start, end));
     for (ParseTreeNode el : sub) {
       if (!cl.isInstance(el)) {
         throw new ClassCastException(
=======================================
--- /trunk/src/com/google/caja/parser/js/Operation.java Fri Apr 8 23:31:20 2011 +++ /trunk/src/com/google/caja/parser/js/Operation.java Mon Apr 25 23:22:07 2011
@@ -64,7 +64,8 @@
   @Override
   protected void childrenChanged() {
     super.childrenChanged();
-    int nChildren = children().size();
+    List<? extends Expression> children = children();
+    int nChildren = children.size();
     if (nChildren < minArity(op)) {
       throw new IllegalArgumentException(
           "Too few of children " + nChildren + " for operator " + op);
@@ -72,6 +73,19 @@
       throw new IllegalArgumentException(
           "Too many children " + nChildren + " for operator " + op);
     }
+    if (Operator.MEMBER_ACCESS == op) {
+      if (!(children.get(1) instanceof Reference)) {
+        throw new IllegalArgumentException(
+            "Bad child of . operator : " + children().get(1));
+      }
+    }
+    if (OperatorCategory.ASSIGNMENT == op.getCategory()) {
+      if (!children.get(0).isLeftHandSide()) {
+        throw new IllegalArgumentException(
+            "Invalid assignment " + op + " with left hand side "
+            + children.get(0));
+      }
+    }
   }

   public static Operation create(
=======================================
--- /trunk/src/com/google/caja/plugin/CssRuleRewriter.java Mon Apr 4 11:32:33 2011 +++ /trunk/src/com/google/caja/plugin/CssRuleRewriter.java Mon Apr 25 23:22:07 2011
@@ -193,7 +193,6 @@
     super(pos, value);
   }

-  @Override
   public void render(RenderContext r) {
     TokenConsumer tc = r.getOut();
     tc.mark(getFilePosition());
@@ -290,7 +289,6 @@
     return arrayElements;
   }

-  @Override
   public void mark(FilePosition pos) {
     cssTokenConsumer.mark(pos);
     if (inJsString && positionAtStartOfStringLiteral == null) {
@@ -299,7 +297,6 @@
     last = pos;
   }

-  @Override
   public void consume(String text) {
     if (!inJsString) {
       startPartialJsStringLiteral();
@@ -313,7 +310,6 @@
     inJsString = true;
   }

-  @Override
   public void noMoreTokens() {
     cssTokenConsumer.noMoreTokens();
     endArrayElement(false);
=======================================
--- /trunk/src/com/google/caja/plugin/stages/StubJobCache.java Sat Feb 5 15:36:47 2011 +++ /trunk/src/com/google/caja/plugin/stages/StubJobCache.java Mon Apr 25 23:22:07 2011
@@ -42,7 +42,6 @@

     public TrivialJobCacheKey(String pos) { this.pos = pos; }

-    @Override
     public JobCache.Keys asSingleton() {
       return new TrivialJobCacheKeys(
           Collections.<JobCache.Key>singletonList(this));
@@ -56,7 +55,6 @@

     TrivialJobCacheKeys(List<JobCache.Key> keys) { this.keys = keys; }

-    @Override
     public JobCache.Keys union(JobCache.Keys other) {
       if (!other.iterator().hasNext()) { return this; }
       List<JobCache.Key> keys = Lists.newArrayList();
@@ -65,7 +63,7 @@
       return new TrivialJobCacheKeys(Collections.unmodifiableList(keys));
     }

-    @Override public Iterator<JobCache.Key> iterator() {
+    public Iterator<JobCache.Key> iterator() {
       return keys.iterator();
     }

=======================================
--- /trunk/tests/com/google/caja/ancillary/opt/JsOptimizerTest.java Tue May 25 12:11:32 2010 +++ /trunk/tests/com/google/caja/ancillary/opt/JsOptimizerTest.java Mon Apr 25 23:22:07 2011
@@ -22,6 +22,7 @@
 import com.google.caja.render.JsMinimalPrinter;
 import com.google.caja.reporting.RenderContext;
 import com.google.caja.util.CajaTestCase;
+import com.google.caja.util.Join;

 import java.util.Collections;

@@ -83,6 +84,28 @@
js(fromString("alert(function(){ if (a) { foo(); bar(); return baz(); }"
                       + "else return boo(); }());")));
   }
+
+  public final void testIssue1348() throws Exception {
+    String input = Join.join(
+        "\n",
+ "if (XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()) {",
+        "  // FF 3.5+ and Safari 4",
+        "  request = requestFunctions['w3cxhr'];",
+        "} else if (XDomainRequest) {",
+        "  // IE8",
+        "  request = requestFunctions['msxdr'];",
+        "} else {",
+        "  // Older browser; fallback",
+        "  request = requestFunctions['jsonp'];",
+        "}");
+    assertOptimized(
+        js(fromString(
+          "XMLHttpRequest && 'withCredentials' in new XMLHttpRequest"
+          + "? (request = requestFunctions.w3cxhr)"
+ + ": (request = requestFunctions[XDomainRequest ? 'msxdr' : 'jsonp'])"
+          )),
+        js(fromString(input)));
+  }

   private void assertOptimized(Statement golden, Block... inputs) {
     for (Block input : inputs) { opt.addInput(input); }
=======================================
--- /trunk/tests/com/google/caja/parser/html/NodesTest.java Fri Apr 22 15:35:40 2011 +++ /trunk/tests/com/google/caja/parser/html/NodesTest.java Mon Apr 25 23:22:07 2011
@@ -25,7 +25,6 @@
 import com.google.caja.util.MoreAsserts;

 import java.util.Arrays;
-import java.io.IOException;
 import java.io.StringReader;

 import org.w3c.dom.Attr;
@@ -154,7 +153,7 @@
     assertRendersUnsafe(RENDER_WITH_COMMENTS, el, MarkupRenderMode.HTML);
     assertRendersUnsafe(RENDER_WITH_COMMENTS, el, MarkupRenderMode.XML);
   }
-
+
   public final void testIllegalCharactersInComment() throws Exception {
     assertFailsToRenderUnsafe("<!-- -- -->", MarkupRenderMode.HTML,
         "XML/HTML comment", "contains '--'");
@@ -171,7 +170,8 @@
         FilePosition.startOfFile(is), new StringReader(xml), true, true);
     return new DomParser(tq, true, mq).parseFragment();
   }
-
+
+  @SuppressWarnings("deprecation")
   private void assertRendersUnsafe(String expected, Node el,
       MarkupRenderMode mode) throws Exception {
     try {
@@ -181,8 +181,9 @@
     }
   }

+  @SuppressWarnings("deprecation")
   private void assertFailsToRenderUnsafe(
-      String xml, MarkupRenderMode mode, String... messages)
+      String xml, MarkupRenderMode mode, String... messages)
       throws Exception {
     try {
       TokenQueue<HtmlTokenType> tq = DomParser.makeTokenQueue(
=======================================
--- /trunk/tests/com/google/caja/plugin/PipelineCacheTest.java Sat Feb 5 15:36:47 2011 +++ /trunk/tests/com/google/caja/plugin/PipelineCacheTest.java Mon Apr 25 23:22:07 2011
@@ -507,7 +507,6 @@
     plm.populate(pl.getStages());
     pl.getStages().add(new PipelineStoreStage(cache));
     pl.getStages().add(new Pipeline.Stage<Jobs>() {
-      @Override
       public boolean apply(Jobs jobs) {
         for (ListIterator<JobEnvelope> it = jobs.getJobs().listIterator();
              it.hasNext();) {

Reply via email to