Web Inspector: Pause on exceptions should show the actual exception
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Nov 2014 00:31:37 +0000 (00:31 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Nov 2014 00:31:37 +0000 (00:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=63096

Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

* debugger/Debugger.h:
Expose accessor for the pause reason to subclasses.

* inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::type):
New "error" subtype for error objects.

* inspector/InjectedScriptSource.js:
When an object is an error object, use toString to provide a richer description.

* inspector/protocol/Runtime.json:
Expose a new "error" subtype for Error types (TypeError, ReferenceError, EvalError, etc).

* inspector/protocol/Debugger.json:
Provide type checked objects for different Debugger.pause pause reasons.
An exception provides the thrown object, but assert / CSP pauses provide
a richer typed object as the auxiliary data.

* inspector/ScriptDebugServer.cpp:
(Inspector::ScriptDebugServer::dispatchDidPause):
When paused because of an exception, pass the exception on.

* inspector/agents/InspectorDebuggerAgent.h:
* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::InspectorDebuggerAgent::handleConsoleAssert):
(Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP):
Provide richer data in pause events.

* inspector/scripts/codegen/generate_backend_commands.py:
(BackendCommandsGenerator.generate_domain.is_anonymous_enum_param):
(BackendCommandsGenerator.generate_domain):
* inspector/scripts/tests/expected/enum-values.json-result:
Generate frontend enums for anonymous enum event parameters.

Source/WebCore:

* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::addMessageToConsoleImpl):
Pass assertion message on.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Main.html:
New strings / files.

* UserInterface/Controllers/DebuggerManager.js:
(WebInspector.DebuggerManager.prototype.get pauseReason):
(WebInspector.DebuggerManager.prototype.get pauseData):
(WebInspector.DebuggerManager.prototype.reset):
(WebInspector.DebuggerManager.prototype.debuggerDidPause):
(WebInspector.DebuggerManager.prototype._pauseReasonFromPayload):
Maintain the current pause reason and auxiliary data in the manager.

* UserInterface/Protocol/DebuggerObserver.js:
(WebInspector.DebuggerObserver.prototype.paused):
Pass previously unused event parameters on to the manager.

* UserInterface/Views/ConsoleMessageImpl.js:
(WebInspector.ConsoleMessageImpl):
Style error objects in the console like Objects. The new description
string provides a richer message if you console.log(exception).

* UserInterface/Views/DebuggerSidebarPanel.js:
(WebInspector.DebuggerSidebarPanel):
(WebInspector.DebuggerSidebarPanel.prototype._debuggerDidPause):
(WebInspector.DebuggerSidebarPanel.prototype._debuggerDidResume):
(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReason):
Update the UI when we pause / resume to show / hide a pause reason section.

* UserInterface/Views/DetailsSectionRow.js:
(WebInspector.DetailsSectionRow.prototype.set emptyMessage):
Fix a latent bug that would have thrown an exception if the setter was ever used.

* UserInterface/Views/DetailsSectionTextRow.js: Added.
(WebInspector.DetailsSectionTextRow):
(WebInspector.DetailsSectionTextRow.prototype.get text):
(WebInspector.DetailsSectionTextRow.prototype.set text):
* UserInterface/Views/DetailsSection.css:
(.details-section > .content > .group > .row.simple.data > .value):
(.details-section > .content > .group > .row.text):
Simple class for a section of centered text. This is modelled after
the empty message text style in other sections.

* UserInterface/Views/LogContentView.css:
(.console-formatted-object, .console-formatted-node, .console-formatted-error):
(.console-formatted-object .section, .console-formatted-node .section, .console-formatted-error .section):
(.console-formatted-object .properties, .console-formatted-node .properties, .console-formatted-error .properties):
Style "error" objects like regular objects. We may wish to treat differently later.

* UserInterface/Protocol/Legacy/6.0/InspectorBackendCommands.js:
* UserInterface/Protocol/Legacy/7.0/InspectorBackendCommands.js:
* UserInterface/Protocol/Legacy/8.0/InspectorBackendCommands.js:
Regenerate legacy backend commands to get the new enum.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@175588 268f45cc-cd09-0410-ab3c-d52691b4dbfc

28 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/debugger/Debugger.h
Source/JavaScriptCore/inspector/InjectedScriptSource.js
Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
Source/JavaScriptCore/inspector/ScriptDebugServer.cpp
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h
Source/JavaScriptCore/inspector/protocol/Debugger.json
Source/JavaScriptCore/inspector/protocol/Runtime.json
Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_commands.py
Source/JavaScriptCore/inspector/scripts/tests/expected/enum-values.json-result
Source/WebCore/ChangeLog
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Protocol/DebuggerObserver.js
Source/WebInspectorUI/UserInterface/Protocol/Legacy/6.0/InspectorBackendCommands.js
Source/WebInspectorUI/UserInterface/Protocol/Legacy/7.0/InspectorBackendCommands.js
Source/WebInspectorUI/UserInterface/Protocol/Legacy/8.0/InspectorBackendCommands.js
Source/WebInspectorUI/UserInterface/Views/ConsoleMessageImpl.js
Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/DetailsSection.css
Source/WebInspectorUI/UserInterface/Views/DetailsSectionRow.js
Source/WebInspectorUI/UserInterface/Views/DetailsSectionTextRow.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/LogContentView.css
Source/WebInspectorUI/UserInterface/Views/ScopeChainDetailsSidebarPanel.js

index 33d1bfc..e993dfa 100644 (file)
@@ -1,3 +1,44 @@
+2014-11-04  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Pause on exceptions should show the actual exception
+        https://bugs.webkit.org/show_bug.cgi?id=63096
+
+        Reviewed by Timothy Hatcher.
+
+        * debugger/Debugger.h:
+        Expose accessor for the pause reason to subclasses.
+
+        * inspector/JSInjectedScriptHost.cpp:
+        (Inspector::JSInjectedScriptHost::type):
+        New "error" subtype for error objects.
+
+        * inspector/InjectedScriptSource.js:
+        When an object is an error object, use toString to provide a richer description.
+
+        * inspector/protocol/Runtime.json:
+        Expose a new "error" subtype for Error types (TypeError, ReferenceError, EvalError, etc).
+
+        * inspector/protocol/Debugger.json:
+        Provide type checked objects for different Debugger.pause pause reasons.
+        An exception provides the thrown object, but assert / CSP pauses provide
+        a richer typed object as the auxiliary data.
+
+        * inspector/ScriptDebugServer.cpp:
+        (Inspector::ScriptDebugServer::dispatchDidPause):
+        When paused because of an exception, pass the exception on.
+
+        * inspector/agents/InspectorDebuggerAgent.h:
+        * inspector/agents/InspectorDebuggerAgent.cpp:
+        (Inspector::InspectorDebuggerAgent::handleConsoleAssert):
+        (Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP):
+        Provide richer data in pause events.
+
+        * inspector/scripts/codegen/generate_backend_commands.py:
+        (BackendCommandsGenerator.generate_domain.is_anonymous_enum_param):
+        (BackendCommandsGenerator.generate_domain):
+        * inspector/scripts/tests/expected/enum-values.json-result:
+        Generate frontend enums for anonymous enum event parameters.
+
 2014-11-04  Michael Saboff  <msaboff@apple.com>
 
         Disable flakey float32-repeat-out-of-bounds.js and int8-repeat-out-of-bounds.js tests for ARM64
index 9820215..787b93a 100644 (file)
@@ -122,6 +122,8 @@ protected:
         PausedForBreakpoint
     };
 
+    ReasonForPause reasonForPause() const { return m_reasonForPause; }
+
     virtual void handlePause(ReasonForPause, JSGlobalObject*) { }
     virtual void notifyDoneProcessingDebuggerEvents() { }
 
index 04e9049..fc9ef7a 100644 (file)
@@ -750,6 +750,9 @@ InjectedScript.prototype = {
         if (subtype === "date")
             return this._toString(obj);
 
+        if (subtype === "error")
+            return this._toString(obj);
+
         if (subtype === "node") {
             var description = obj.nodeName.toLowerCase();
             switch (obj.nodeType) {
index b58601a..a484ce0 100644 (file)
@@ -121,6 +121,10 @@ JSValue JSInjectedScriptHost::type(ExecState* exec)
     if (value.isNumber())
         return exec->vm().smallStrings.numberString();
 
+    JSObject* object = asObject(value);
+    if (object && object->isErrorInstance())
+        return jsNontrivialString(exec, ASCIILiteral("error"));
+
     if (value.inherits(JSArray::info()))
         return jsNontrivialString(exec, ASCIILiteral("array"));
     if (value.inherits(DateInstance::info()))
index 3a61663..43d0227 100644 (file)
@@ -138,7 +138,8 @@ void ScriptDebugServer::dispatchDidPause(ScriptDebugListener* listener)
     JSC::ExecState* state = globalObject->globalExec();
     RefPtr<JavaScriptCallFrame> javaScriptCallFrame = JavaScriptCallFrame::create(debuggerCallFrame);
     JSValue jsCallFrame = toJS(state, globalObject, javaScriptCallFrame.get());
-    listener->didPause(state, Deprecated::ScriptValue(state->vm(), jsCallFrame), Deprecated::ScriptValue());
+    Deprecated::ScriptValue exception = reasonForPause() == PausedForException ? Deprecated::ScriptValue(state->vm(), currentException()) : Deprecated::ScriptValue();
+    listener->didPause(state, Deprecated::ScriptValue(state->vm(), jsCallFrame), exception);
 }
 
 void ScriptDebugServer::dispatchBreakpointActionLog(ExecState* exec, const String& message)
index 49e72b8..a06a6d3 100644 (file)
@@ -143,10 +143,14 @@ bool InspectorDebuggerAgent::isPaused()
     return scriptDebugServer().isPaused();
 }
 
-void InspectorDebuggerAgent::handleConsoleAssert()
+void InspectorDebuggerAgent::handleConsoleAssert(const String& message)
 {
-    if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions)
-        breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Assert, nullptr);
+    if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) {
+        RefPtr<Inspector::Protocol::Debugger::AssertPauseReason> reason = Inspector::Protocol::Debugger::AssertPauseReason::create();
+        if (!message.isNull())
+            reason->setMessage(message);
+        breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Assert, reason->openAccessors());
+    }
 }
 
 static PassRefPtr<InspectorObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, RefPtr<InspectorArray>& actions, bool isRegex, bool autoContinue)
@@ -548,9 +552,8 @@ void InspectorDebuggerAgent::setOverlayMessage(ErrorString&, const String*)
 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
 {
     if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) {
-        RefPtr<InspectorObject> directive = InspectorObject::create();
-        directive->setString(ASCIILiteral("directiveText"), directiveText);
-        breakProgram(InspectorDebuggerFrontendDispatcher::Reason::CSPViolation, directive.release());
+        RefPtr<Inspector::Protocol::Debugger::CSPViolationPauseReason> reason = Inspector::Protocol::Debugger::CSPViolationPauseReason::create().setDirective(directiveText);
+        breakProgram(InspectorDebuggerFrontendDispatcher::Reason::CSPViolation, reason->openAccessors());
     }
 }
 
index cb4f85b..743c729 100644 (file)
@@ -93,7 +93,7 @@ public:
 
     bool isPaused();
     
-    void handleConsoleAssert();
+    void handleConsoleAssert(const String& message);
 
     void schedulePauseOnNextStatement(InspectorDebuggerFrontendDispatcher::Reason breakReason, PassRefPtr<InspectorObject> data);
     void cancelPauseOnNextStatement();
index 247be8c..ebf73f8 100644 (file)
                 { "name": "timestamp", "type": "number", "description": "Timestamp of when the sample was taken." },
                 { "name": "payload", "$ref": "Runtime.RemoteObject", "description": "Contents of the sample." }
             ]
+        },
+        {
+            "id": "AssertPauseReason",
+            "description": "The pause reason auxiliary data when paused because of an assertion.",
+            "type": "object",
+            "properties": [
+                { "name": "message", "type": "string", "optional": true, "description": "The console.assert message string if provided." }
+            ]
+        },
+        {
+            "id": "CSPViolationPauseReason",
+            "description": "The pause reason auxiliary data when paused because of a Content Security Policy directive.",
+            "type": "object",
+            "properties": [
+                { "name": "directive", "type": "string", "description": "The CSP directive that blocked script execution." }
+            ]
         }
     ],
     "commands": [
index af63495..69762ad 100644 (file)
@@ -13,7 +13,7 @@
             "description": "Mirror object referencing original JavaScript object.",
             "properties": [
                 { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean"], "description": "Object type." },
-                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
+                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
                 { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for <code>object</code> type values only." },
                 { "name": "value", "type": "any", "optional": true, "description": "Remote object value (in case of primitive values or JSON values if it was requested)." },
                 { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." },
@@ -39,7 +39,7 @@
                 { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean"], "description": "Object type." },
                 { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." },
                 { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." },
-                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }
+                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }
             ]
         },
         {
index 08fbb47..a8cce55 100755 (executable)
@@ -88,7 +88,18 @@ class BackendCommandsGenerator(Generator):
                 }
                 lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args)
 
+        def is_anonymous_enum_param(param):
+            return isinstance(param.type, EnumType) and param.type.is_anonymous
+
         for event in domain.events:
+            for param in filter(is_anonymous_enum_param, event.event_parameters):
+                enum_args = {
+                    'domain': domain.domain_name,
+                    'enumName': '%s%s' % (ucfirst(event.event_name), ucfirst(param.parameter_name)),
+                    'enumMap': ", ".join(['%s: "%s"' % (Generator.stylized_name_for_enum_value(enum_value), enum_value) for enum_value in param.type.enum_values()])
+                }
+                lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args)
+
             event_args = {
                 'domain': domain.domain_name,
                 'eventName': event.event_name,
@@ -97,7 +108,6 @@ class BackendCommandsGenerator(Generator):
             lines.append('InspectorBackend.registerEvent("%(domain)s.%(eventName)s", [%(params)s]);' % event_args)
 
         for command in domain.commands:
-
             def generate_parameter_object(parameter):
                 optional_string = "true" if parameter.is_optional else "false"
                 pairs = []
index de7e9e8..202773c 100644 (file)
@@ -101,6 +101,7 @@ InspectorBackend.activateDomain("CommandDomain");
 
 // EventDomain.
 InspectorBackend.registerEventDomainDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "EventDomain");
+InspectorBackend.registerEnum("EventDomain.EventWithEnumParameterParameter", {Shared: "shared", Black: "black", White: "white"});
 InspectorBackend.registerEvent("EventDomain.eventWithEnumParameter", ["parameter"]);
 InspectorBackend.activateDomain("EventDomain");
 ### End File: InspectorBackendCommands.js
index cff63f9..c8d9d6f 100644 (file)
@@ -1,3 +1,14 @@
+2014-11-04  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Pause on exceptions should show the actual exception
+        https://bugs.webkit.org/show_bug.cgi?id=63096
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::addMessageToConsoleImpl):
+        Pass assertion message on.
+
 2014-11-04  Reza Abbasian  <rabbasian@apple.com>
 
         [iOS] Fix incorrect interface orientation that can be caused by fullscreen video dismissal.
index 30b5a20..7952366 100644 (file)
@@ -888,7 +888,7 @@ void InspectorInstrumentation::addMessageToConsoleImpl(InstrumentingAgents* inst
     // FIXME: This should just pass the message on to the debugger agent. JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes.
     if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent()) {
         if (isConsoleAssertMessage(source, type))
-            debuggerAgent->handleConsoleAssert();
+            debuggerAgent->handleConsoleAssert(message);
     }
 }
 
@@ -899,7 +899,7 @@ void InspectorInstrumentation::addMessageToConsoleImpl(InstrumentingAgents* inst
     // FIXME: This should just pass the message on to the debugger agent. JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes.
     if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent()) {
         if (isConsoleAssertMessage(source, type))
-            debuggerAgent->handleConsoleAssert();
+            debuggerAgent->handleConsoleAssert(message);
     }
 }
 
@@ -907,6 +907,11 @@ void InspectorInstrumentation::addMessageToConsoleImpl(InstrumentingAgents* inst
 {
     if (WebConsoleAgent* consoleAgent = instrumentingAgents->webConsoleAgent())
         consoleAgent->addMessageToConsole(source, type, level, message, scriptID, lineNumber, columnNumber, state, requestIdentifier);
+    // FIXME: This should just pass the message on to the debugger agent. JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes.
+    if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent()) {
+        if (isConsoleAssertMessage(source, type))
+            debuggerAgent->handleConsoleAssert(message);
+    }
 }
 
 void InspectorInstrumentation::consoleCountImpl(InstrumentingAgents* instrumentingAgents, JSC::ExecState* state, PassRefPtr<ScriptArguments> arguments)
index 193ccd8..b08d864 100644 (file)
@@ -1,3 +1,63 @@
+2014-11-04  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Pause on exceptions should show the actual exception
+        https://bugs.webkit.org/show_bug.cgi?id=63096
+
+        Reviewed by Timothy Hatcher.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Main.html:
+        New strings / files.
+
+        * UserInterface/Controllers/DebuggerManager.js:
+        (WebInspector.DebuggerManager.prototype.get pauseReason):
+        (WebInspector.DebuggerManager.prototype.get pauseData):
+        (WebInspector.DebuggerManager.prototype.reset):
+        (WebInspector.DebuggerManager.prototype.debuggerDidPause):
+        (WebInspector.DebuggerManager.prototype._pauseReasonFromPayload):
+        Maintain the current pause reason and auxiliary data in the manager.
+
+        * UserInterface/Protocol/DebuggerObserver.js:
+        (WebInspector.DebuggerObserver.prototype.paused):
+        Pass previously unused event parameters on to the manager.
+
+        * UserInterface/Views/ConsoleMessageImpl.js:
+        (WebInspector.ConsoleMessageImpl):
+        Style error objects in the console like Objects. The new description
+        string provides a richer message if you console.log(exception).
+
+        * UserInterface/Views/DebuggerSidebarPanel.js:
+        (WebInspector.DebuggerSidebarPanel):
+        (WebInspector.DebuggerSidebarPanel.prototype._debuggerDidPause):
+        (WebInspector.DebuggerSidebarPanel.prototype._debuggerDidResume):
+        (WebInspector.DebuggerSidebarPanel.prototype._updatePauseReason):
+        Update the UI when we pause / resume to show / hide a pause reason section.
+
+        * UserInterface/Views/DetailsSectionRow.js:
+        (WebInspector.DetailsSectionRow.prototype.set emptyMessage):
+        Fix a latent bug that would have thrown an exception if the setter was ever used.
+
+        * UserInterface/Views/DetailsSectionTextRow.js: Added.
+        (WebInspector.DetailsSectionTextRow):
+        (WebInspector.DetailsSectionTextRow.prototype.get text):
+        (WebInspector.DetailsSectionTextRow.prototype.set text):
+        * UserInterface/Views/DetailsSection.css:
+        (.details-section > .content > .group > .row.simple.data > .value):
+        (.details-section > .content > .group > .row.text):
+        Simple class for a section of centered text. This is modelled after
+        the empty message text style in other sections.
+
+        * UserInterface/Views/LogContentView.css:
+        (.console-formatted-object, .console-formatted-node, .console-formatted-error):
+        (.console-formatted-object .section, .console-formatted-node .section, .console-formatted-error .section):
+        (.console-formatted-object .properties, .console-formatted-node .properties, .console-formatted-error .properties):
+        Style "error" objects like regular objects. We may wish to treat differently later.
+
+        * UserInterface/Protocol/Legacy/6.0/InspectorBackendCommands.js:
+        * UserInterface/Protocol/Legacy/7.0/InspectorBackendCommands.js:
+        * UserInterface/Protocol/Legacy/8.0/InspectorBackendCommands.js:
+        Regenerate legacy backend commands to get the new enum.
+
 2014-11-04  Andrei Bucur  <abucur@adobe.com>
 
         Building WebInspectorUI should not run the clang static analyzer by default
index 546114f..26b00d3 100644 (file)
Binary files a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js and b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js differ
index b49a1e5..8d9f64d 100644 (file)
@@ -55,6 +55,10 @@ WebInspector.DebuggerManager = function()
 
     this._nextBreakpointActionIdentifier = 1;
 
+    this._paused = false;
+    this._pauseReason = null;
+    this._pauseData = null;
+
     this._scriptIdMap = {};
     this._scriptURLMap = {};
 
@@ -91,6 +95,13 @@ WebInspector.DebuggerManager.Event = {
     BreakpointsEnabledDidChange: "debugger-manager-breakpoints-enabled-did-change"
 };
 
+WebInspector.DebuggerManager.PauseReason = {
+    Exception: "exception",
+    Assertion: "assertion",
+    CSPViolation: "CSP-violation",
+    Other: "other",
+}
+
 WebInspector.DebuggerManager.prototype = {
     constructor: WebInspector.DebuggerManager,
 
@@ -120,6 +131,16 @@ WebInspector.DebuggerManager.prototype = {
         return this._paused;
     },
 
+    get pauseReason()
+    {
+        return this._pauseReason;
+    },
+
+    get pauseData()
+    {
+        return this._pauseData;
+    },
+
     get callFrames()
     {
         return this._callFrames;
@@ -404,6 +425,9 @@ WebInspector.DebuggerManager.prototype = {
         WebInspector.Script.resetUniqueDisplayNameNumbers();
 
         this._paused = false;
+        this._pauseReason = null;
+        this._pauseData = null;
+
         this._scriptIdMap = {};
         this._scriptURLMap = {};
 
@@ -426,7 +450,7 @@ WebInspector.DebuggerManager.prototype = {
             this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.Resumed);
     },
 
-    debuggerDidPause: function(callFramesPayload)
+    debuggerDidPause: function(callFramesPayload, reason, data)
     {
         // Called from WebInspector.DebuggerObserver.
 
@@ -440,6 +464,9 @@ WebInspector.DebuggerManager.prototype = {
         this._paused = true;
         this._callFrames = [];
 
+        this._pauseReason = this._pauseReasonFromPayload(reason);
+        this._pauseData = data || null;
+
         for (var i = 0; i < callFramesPayload.length; ++i) {
             var callFramePayload = callFramesPayload[i];
             var sourceCodeLocation = this._sourceCodeLocationFromPayload(callFramePayload.location);
@@ -583,6 +610,21 @@ WebInspector.DebuggerManager.prototype = {
         return new WebInspector.ScopeChainNode(type, object);
     },
 
+    _pauseReasonFromPayload: function(payload)
+    {
+        // FIXME: Handle other backend pause seasons.
+        switch (payload) {
+        case DebuggerAgent.PausedReason.Exception:
+            return WebInspector.DebuggerManager.PauseReason.Exception;
+        case DebuggerAgent.PausedReason.Assert:
+            return WebInspector.DebuggerManager.PauseReason.Assertion;
+        case DebuggerAgent.PausedReason.CSPViolation:
+            return WebInspector.DebuggerManager.PauseReason.CSPViolation;
+        default:
+            return WebInspector.DebuggerManager.PauseReason.Other;
+        }
+    },
+
     _debuggerBreakpointActionType: function(type)
     {
         switch (type) {
index 3077968..545b41d 100644 (file)
     <script src="Views/DetailsSectionGroup.js"></script>
     <script src="Views/DetailsSectionPropertiesRow.js"></script>
     <script src="Views/DetailsSectionSimpleRow.js"></script>
+    <script src="Views/DetailsSectionTextRow.js"></script>
     <script src="Views/DividerNavigationItem.js"></script>
     <script src="Views/EditingSupport.js"></script>
     <script src="Views/EventListenerSection.js"></script>
index 0b21a13..52aadc8 100644 (file)
@@ -55,7 +55,7 @@ WebInspector.DebuggerObserver.prototype = {
 
     paused: function(callFrames, reason, data)
     {
-        WebInspector.debuggerManager.debuggerDidPause(callFrames);
+        WebInspector.debuggerManager.debuggerDidPause(callFrames, reason, data);
     },
 
     resumed: function()
index 22bb485..25f8afd 100644 (file)
@@ -233,6 +233,7 @@ InspectorBackend.registerEvent("Debugger.globalObjectCleared", []);
 InspectorBackend.registerEvent("Debugger.scriptParsed", ["scriptId", "url", "startLine", "startColumn", "endLine", "endColumn", "isContentScript", "sourceMapURL"]);
 InspectorBackend.registerEvent("Debugger.scriptFailedToParse", ["url", "scriptSource", "startLine", "errorLine", "errorMessage"]);
 InspectorBackend.registerEvent("Debugger.breakpointResolved", ["breakpointId", "location"]);
+InspectorBackend.registerEnum("Debugger.PausedReason", {XHR: "XHR", DOM: "DOM", EventListener: "EventListener", Exception: "exception", Other: "other"});
 InspectorBackend.registerEvent("Debugger.paused", ["callFrames", "reason", "data"]);
 InspectorBackend.registerEvent("Debugger.resumed", []);
 InspectorBackend.registerCommand("Debugger.supportsNativeBreakpoints", [], ["result"]);
index d6f6524..a1415e0 100644 (file)
@@ -264,6 +264,7 @@ InspectorBackend.registerEvent("Debugger.globalObjectCleared", []);
 InspectorBackend.registerEvent("Debugger.scriptParsed", ["scriptId", "url", "startLine", "startColumn", "endLine", "endColumn", "isContentScript", "sourceMapURL", "hasSourceURL"]);
 InspectorBackend.registerEvent("Debugger.scriptFailedToParse", ["url", "scriptSource", "startLine", "errorLine", "errorMessage"]);
 InspectorBackend.registerEvent("Debugger.breakpointResolved", ["breakpointId", "location"]);
+InspectorBackend.registerEnum("Debugger.PausedReason", {XHR: "XHR", DOM: "DOM", EventListener: "EventListener", Exception: "exception", Assert: "assert", CSPViolation: "CSPViolation", Other: "other"});
 InspectorBackend.registerEvent("Debugger.paused", ["callFrames", "reason", "data"]);
 InspectorBackend.registerEvent("Debugger.resumed", []);
 InspectorBackend.registerCommand("Debugger.enable", [], []);
index f7dbad2..733b278 100644 (file)
@@ -51,6 +51,7 @@ InspectorBackend.registerEvent("Debugger.globalObjectCleared", []);
 InspectorBackend.registerEvent("Debugger.scriptParsed", ["scriptId", "url", "startLine", "startColumn", "endLine", "endColumn", "isContentScript", "sourceMapURL", "hasSourceURL"]);
 InspectorBackend.registerEvent("Debugger.scriptFailedToParse", ["url", "scriptSource", "startLine", "errorLine", "errorMessage"]);
 InspectorBackend.registerEvent("Debugger.breakpointResolved", ["breakpointId", "location"]);
+InspectorBackend.registerEnum("Debugger.PausedReason", {XHR: "XHR", DOM: "DOM", EventListener: "EventListener", Exception: "exception", Assert: "assert", CSPViolation: "CSPViolation", Other: "other"});
 InspectorBackend.registerEvent("Debugger.paused", ["callFrames", "reason", "data"]);
 InspectorBackend.registerEvent("Debugger.resumed", []);
 InspectorBackend.registerEvent("Debugger.didSampleProbe", ["sample"]);
index e185083..6fd5d3f 100644 (file)
@@ -41,6 +41,7 @@ WebInspector.ConsoleMessageImpl = function(source, level, message, linkifier, ty
 
     this._customFormatters = {
         "object": this._formatParameterAsObject,
+        "error": this._formatParameterAsObject,
         "array":  this._formatParameterAsArray,
         "node":   this._formatParameterAsNode,
         "string": this._formatParameterAsString
index 6b2a4f2..91e74a1 100644 (file)
@@ -132,6 +132,10 @@ WebInspector.DebuggerSidebarPanel = function()
     var callStackGroup = new WebInspector.DetailsSectionGroup([this._callStackRow]);
     this._callStackSection = new WebInspector.DetailsSection("call-stack", WebInspector.UIString("Call Stack"), [callStackGroup]);
 
+    this._pauseReasonRow = new WebInspector.DetailsSectionTextRow;
+    this._pauseReasonGroup = new WebInspector.DetailsSectionGroup([this._pauseReasonRow]);
+    this._pauseReasonSection = new WebInspector.DetailsSection("paused-reason", null, [this._pauseReasonGroup]);
+
     WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.DisplayLocationDidChange, this._breakpointDisplayLocationDidChange, this);
 };
 
@@ -229,6 +233,8 @@ WebInspector.DebuggerSidebarPanel.prototype = {
     _debuggerDidPause: function(event)
     {
         this.contentElement.insertBefore(this._callStackSection.element, this.contentElement.firstChild);
+        if (this._updatePauseReason())
+            this.contentElement.insertBefore(this._pauseReasonSection.element, this.contentElement.firstChild);
 
         this._debuggerPauseResumeButtonItem.enabled = true;
         this._debuggerPauseResumeButtonItem.toggled = true;
@@ -239,6 +245,7 @@ WebInspector.DebuggerSidebarPanel.prototype = {
     _debuggerDidResume: function(event)
     {
         this._callStackSection.element.remove();
+        this._pauseReasonSection.element.remove();
 
         this._debuggerPauseResumeButtonItem.enabled = true;
         this._debuggerPauseResumeButtonItem.toggled = false;
@@ -584,6 +591,50 @@ WebInspector.DebuggerSidebarPanel.prototype = {
             return comparisonResult;
 
         return aLocation.displayColumnNumber - bLocation.displayColumnNumber;
+    },
+
+    _updatePauseReason: function()
+    {
+        var pauseData = WebInspector.debuggerManager.pauseData;
+        
+        switch (WebInspector.debuggerManager.pauseReason) {
+        case WebInspector.DebuggerManager.PauseReason.Exception:
+            console.assert(pauseData, "Expected data with an exception, but found none.");
+            if (pauseData) {
+                // FIXME: We should improve the appearance of thrown objects. This works well for exception strings.
+                var data = WebInspector.RemoteObject.fromPayload(pauseData);
+                this._pauseReasonRow.text = data.description;
+                this._pauseReasonSection.title = WebInspector.UIString("Exception");
+                return true;
+            }
+            break;
+
+        case WebInspector.DebuggerManager.PauseReason.Assertion:
+            console.assert(pauseData, "Expected data with an assertion, but found none.");
+            if (pauseData && pauseData.message) {
+                // FIXME: We should include the assertion condition string.
+                this._pauseReasonRow.text = pauseData.message;
+                this._pauseReasonSection.title = WebInspector.UIString("Assertion");
+                return true;
+            }
+            break;
+
+        case WebInspector.DebuggerManager.PauseReason.CSPViolation:
+            console.assert(pauseData, "Expected data with a CSP Violation, but found none.");
+            if (pauseData) {
+                // COMPATIBILITY (iOS 8): 'directive' was 'directiveText'.
+                this._pauseReasonRow.text = pauseData.directive || pauseData.directiveText;
+                this._pauseReasonSection.title = WebInspector.UIString("Content Security Policy Violation");
+                return true;
+            }
+            break;
+
+        case WebInspector.DebuggerManager.PauseReason.Other:
+            console.error("Paused for unknown reason. We should always have a reason.");
+            break;
+        }
+
+        return false;
     }
 };
 
index a157d82..4e765d2 100644 (file)
@@ -290,12 +290,17 @@ body.mac-platform.legacy .details-section > .content > .group:last-child > .row.
     word-break: break-all;
 }
 
-.details-section > .content > .group > .row.empty {
-    padding: 6px;
+.details-section > .content > .group > .row.empty,
+.details-section > .content > .group > .row.text {
+    padding: 0 6px 7px 6px;
     text-align: center;
     color: gray;
 }
 
+.details-section > .content > .group > .row.text {
+    -webkit-user-select: text;
+}
+
 .details-section > .content > .group > .row.properties:not(.empty) {
     padding: 4px 6px;
 }
index f195847..300ee44 100644 (file)
@@ -54,7 +54,7 @@ WebInspector.DetailsSectionRow.prototype = {
     {
         this._emptyMessage = emptyMessage || "";
 
-        if (!this.childNodes.length)
+        if (!this._element.childNodes.length)
             this.showEmptyMessage();
     },
 
diff --git a/Source/WebInspectorUI/UserInterface/Views/DetailsSectionTextRow.js b/Source/WebInspectorUI/UserInterface/Views/DetailsSectionTextRow.js
new file mode 100644 (file)
index 0000000..9490ffe
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.DetailsSectionTextRow = function(text)
+{
+    WebInspector.DetailsSectionRow.call(this);
+
+    this.element.classList.add(WebInspector.DetailsSectionTextRow.StyleClassName);
+
+    this.element.textContent = text;
+};
+
+WebInspector.DetailsSectionTextRow.StyleClassName = "text";
+
+WebInspector.DetailsSectionTextRow.prototype = {
+    constructor: WebInspector.DetailsSectionTextRow,
+    __proto__: WebInspector.DetailsSectionRow.prototype,
+
+    // Public
+
+    get text()
+    {
+        return this.element.textContent;
+    },
+
+    set text(text)
+    {
+        this.element.textContent = text;
+    }
+};
index 8dd6f72..a09a0cc 100644 (file)
     display: none;
 }
 
-.console-formatted-object, .console-formatted-node {
+.console-formatted-object, .console-formatted-node, .console-formatted-error {
     position: relative;
     display: inline-block;
     vertical-align: top;
     color: black;
 }
 
-.console-formatted-object .section, .console-formatted-node .section {
+.console-formatted-object .section, .console-formatted-node .section, .console-formatted-error .section {
     position: static;
 }
 
-.console-formatted-object .properties, .console-formatted-node .properties {
+.console-formatted-object .properties, .console-formatted-node .properties, .console-formatted-error .properties {
     padding-left: 0 !important;
 }
 
index d0ffc65..fe8c6c0 100644 (file)
@@ -23,7 +23,8 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ScopeChainDetailsSidebarPanel = function() {
+WebInspector.ScopeChainDetailsSidebarPanel = function()
+{
     WebInspector.DetailsSidebarPanel.call(this, "scope-chain", WebInspector.UIString("Scope Chain"), WebInspector.UIString("Scope Chain"), "Images/NavigationItemVariable.svg", "5");
 
     this._callFrame = null;