Add a stack trace collector for Chrome.
This is mapped into the webkit user.agent, but will fall back to the standard collector when running on Safari.
Patch by: schuck
Review by: bobv
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5979 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
index cd34b6b..723063a 100644
--- a/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
+++ b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
@@ -15,7 +15,17 @@
<!-- Deferred binding rules for core classes based on user agent. -->
<module>
<inherits name="com.google.gwt.core.Core"/>
-
+
+ <replace-with class="com.google.gwt.core.client.impl.StackTraceCreator.CollectorChrome">
+ <when-type-is class="com.google.gwt.core.client.impl.StackTraceCreator.Collector" />
+ <when-property-is name="compiler.emulatedStack" value="false" />
+ <any>
+ <!-- For now, only Chrome provides Error.stack support, so we hijack the
+ entire WebKit permutation -->
+ <when-property-is name="user.agent" value="safari" />
+ </any>
+ </replace-with>
+
<replace-with class="com.google.gwt.core.client.impl.StackTraceCreator.CollectorMoz">
<when-type-is class="com.google.gwt.core.client.impl.StackTraceCreator.Collector" />
<when-property-is name="compiler.emulatedStack" value="false" />
@@ -32,4 +42,4 @@
<when-property-is name="user.agent" value="opera" />
</any>
</replace-with>
-</module>
\ No newline at end of file
+</module>
diff --git a/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java b/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
index 3dc8a5e..1847972 100644
--- a/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
+++ b/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
@@ -209,6 +209,88 @@
}
/**
+ * Chrome uses a slightly different format to Mozilla.
+ *
+ * See http://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/
+ * messages.js?r=2340#712 for formatting code.
+ *
+ * Function calls can be of the four following forms:
+ *
+ * <pre>
+ * at file.js:1:2
+ * at functionName (file.js:1:2)
+ * at Type.functionName (file.js:1:2)
+ * at Type.functionName [as methodName] (file.js:1:2)
+ * </pre>
+ */
+ static class CollectorChrome extends CollectorMoz {
+ @Override
+ public JsArrayString collect() {
+ JsArrayString res = super.collect();
+ if (res.length() == 0) {
+ /*
+ * Ensure Safari falls back to default Collector implementation.
+ * Remember to remove this method call from the stack:
+ */
+ res = splice(new Collector().collect(), 1);
+ }
+ return res;
+ }
+
+ @Override
+ public JsArrayString inferFrom(JavaScriptObject e) {
+ JsArrayString stack = super.inferFrom(e);
+ if (stack.length() == 0) {
+ // Safari should fall back to default Collector:
+ return new Collector().inferFrom(e);
+ } else {
+ // Chrome contains the error itself as the first line of the stack:
+ return splice(stack, 1);
+ }
+ }
+
+ @Override
+ protected String extractName(String fnToString) {
+ if (fnToString.length() == 0) {
+ return "anonymous";
+ }
+
+ String toReturn = fnToString.trim();
+
+ // Strip the "at " prefix:
+ if (toReturn.startsWith("at ")) {
+ toReturn = toReturn.substring(3);
+ }
+
+ // Strip bracketed items from the end:
+ int index = toReturn.indexOf("[");
+ if (index == -1) {
+ index = toReturn.indexOf("(");
+ }
+ if (index == -1) {
+ // No bracketed items found, hence no function name available:
+ return "anonymous";
+ } else {
+ // Bracketed items found: strip them off.
+ toReturn = toReturn.substring(0, index).trim();
+ }
+
+ // Strip the Type off to leave just the functionName:
+ index = toReturn.indexOf('.');
+ if (index != -1) {
+ toReturn = toReturn.substring(index + 1);
+ }
+
+ return toReturn.length() > 0 ? toReturn : "anonymous";
+ }
+
+ @Override
+ protected int toSplice() {
+ return 3;
+ }
+ }
+
+ /**
* Opera encodes stack trace information in the error's message.
*/
static class CollectorOpera extends CollectorMoz {
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java
index 9083605..b3f9dde 100644
--- a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java
@@ -19,6 +19,7 @@
import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.core.client.impl.StackTraceCreator.CollectorChrome;
import com.google.gwt.junit.DoNotRunWith;
import com.google.gwt.junit.Platform;
import com.google.gwt.junit.client.GWTTestCase;
@@ -64,7 +65,7 @@
/**
* Just make sure that reentrant behavior doesn't fail.
*/
- @DoNotRunWith({Platform.Htmlunit})
+ @DoNotRunWith(value = {Platform.Htmlunit})
public static void testReentrantCalls() {
if (!GWT.isScript()) {
// sample is useless in hosted mode
@@ -81,7 +82,7 @@
assertEquals(start, end);
}
- @DoNotRunWith({Platform.Htmlunit})
+ @DoNotRunWith(value = {Platform.Htmlunit})
public static void testStackTraces() {
JsArrayString start = sample();
@@ -193,4 +194,16 @@
assertEquals("foo",
StackTraceCreator.extractNameFromToString(" function foo (){}"));
}
+
+ public void testChromeExtractName() {
+ CollectorChrome c = new CollectorChrome();
+
+ assertEquals("anonymous", c.extractName(" at file.js:1:2"));
+ assertEquals("functionName",
+ c.extractName(" at functionName (file.js:1:2)"));
+ assertEquals("functionName",
+ c.extractName(" at Type.functionName (file.js:1:2)"));
+ assertEquals("functionName",
+ c.extractName(" at Type.functionName [as methodName] (file.js:1:2)"));
+ }
}