summaryrefslogtreecommitdiffstats
path: root/js/src/jscntxt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jscntxt.cpp')
-rw-r--r--js/src/jscntxt.cpp227
1 files changed, 181 insertions, 46 deletions
diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp
index 31d62332d..441b006d6 100644
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -381,49 +381,16 @@ js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg)
}
}
-bool
-js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
- JSErrorReport* report, bool reportWarnings)
-{
- MOZ_ASSERT(report);
-
- /* Conditionally ignore reported warnings. */
- if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
- return false;
-
- char* prefix = nullptr;
- if (report->filename)
- prefix = JS_smprintf("%s:", report->filename);
- if (report->lineno) {
- char* tmp = prefix;
- prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column);
- JS_free(cx, tmp);
- }
- if (JSREPORT_IS_WARNING(report->flags)) {
- char* tmp = prefix;
- prefix = JS_smprintf("%s%swarning: ",
- tmp ? tmp : "",
- JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
- JS_free(cx, tmp);
- }
-
- const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str();
-
- /* embedded newlines -- argh! */
- const char* ctmp;
- while ((ctmp = strchr(message, '\n')) != 0) {
- ctmp++;
- if (prefix)
- fputs(prefix, file);
- fwrite(message, 1, ctmp - message, file);
- message = ctmp;
- }
-
- /* If there were no filename or lineno, the prefix might be empty */
- if (prefix)
- fputs(prefix, file);
- fputs(message, file);
+enum class PrintErrorKind {
+ Error,
+ Warning,
+ StrictWarning,
+ Note
+};
+static void
+PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorReport* report)
+{
if (const char16_t* linebuf = report->linebuf()) {
size_t n = report->linebufLength();
@@ -453,9 +420,96 @@ js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
}
fputc('^', file);
}
+}
+
+static void
+PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorNotes::Note* note)
+{
+}
+
+template <typename T>
+static bool
+PrintSingleError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
+ T* report, PrintErrorKind kind)
+{
+ UniquePtr<char> prefix;
+ if (report->filename)
+ prefix.reset(JS_smprintf("%s:", report->filename));
+
+ if (report->lineno) {
+ UniquePtr<char> tmp(JS_smprintf("%s%u:%u ", prefix ? prefix.get() : "", report->lineno,
+ report->column));
+ prefix = Move(tmp);
+ }
+
+ if (kind != PrintErrorKind::Error) {
+ const char* kindPrefix = nullptr;
+ switch (kind) {
+ case PrintErrorKind::Error:
+ break;
+ case PrintErrorKind::Warning:
+ kindPrefix = "warning";
+ break;
+ case PrintErrorKind::StrictWarning:
+ kindPrefix = "strict warning";
+ break;
+ case PrintErrorKind::Note:
+ kindPrefix = "note";
+ break;
+ }
+
+ UniquePtr<char> tmp(JS_smprintf("%s%s: ", prefix ? prefix.get() : "", kindPrefix));
+ prefix = Move(tmp);
+ }
+
+ const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str();
+
+ /* embedded newlines -- argh! */
+ const char* ctmp;
+ while ((ctmp = strchr(message, '\n')) != 0) {
+ ctmp++;
+ if (prefix)
+ fputs(prefix.get(), file);
+ fwrite(message, 1, ctmp - message, file);
+ message = ctmp;
+ }
+
+ /* If there were no filename or lineno, the prefix might be empty */
+ if (prefix)
+ fputs(prefix.get(), file);
+ fputs(message, file);
+
+ PrintErrorLine(cx, file, prefix.get(), report);
fputc('\n', file);
+
fflush(file);
- JS_free(cx, prefix);
+ return true;
+}
+
+bool
+js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
+ JSErrorReport* report, bool reportWarnings)
+{
+ MOZ_ASSERT(report);
+
+ /* Conditionally ignore reported warnings. */
+ if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
+ return false;
+
+ PrintErrorKind kind = PrintErrorKind::Error;
+ if (JSREPORT_IS_WARNING(report->flags)) {
+ if (JSREPORT_IS_STRICT(report->flags))
+ kind = PrintErrorKind::StrictWarning;
+ else
+ kind = PrintErrorKind::Warning;
+ }
+ PrintSingleError(cx, file, toStringResult, report, kind);
+
+ if (report->notes) {
+ for (auto&& note : *report->notes)
+ PrintSingleError(cx, file, JS::ConstUTF8CharsZ(), note.get(), PrintErrorKind::Note);
+ }
+
return true;
}
@@ -557,6 +611,18 @@ class MOZ_RAII AutoMessageArgs
}
};
+static void
+SetExnType(JSErrorReport* reportp, int16_t exnType)
+{
+ reportp->exnType = exnType;
+}
+
+static void
+SetExnType(JSErrorNotes::Note* notep, int16_t exnType)
+{
+ // Do nothing for JSErrorNotes::Note.
+}
+
/*
* The arguments from ap need to be packaged up into an array and stored
* into the report struct.
@@ -568,12 +634,13 @@ class MOZ_RAII AutoMessageArgs
*
* Returns true if the expansion succeeds (can fail if out of memory).
*/
+template <typename T>
bool
-js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
+ExpandErrorArgumentsHelper(ExclusiveContext* cx, JSErrorCallback callback,
void* userRef, const unsigned errorNumber,
const char16_t** messageArgs,
ErrorArgumentsType argumentsType,
- JSErrorReport* reportp, va_list ap)
+ T* reportp, va_list ap)
{
const JSErrorFormatString* efs;
@@ -586,7 +653,7 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
}
if (efs) {
- reportp->exnType = efs->exnType;
+ SetExnType(reportp, efs->exnType);
MOZ_ASSERT_IF(argumentsType == ArgumentsAreASCII, JS::StringIsASCII(efs->format));
@@ -670,6 +737,28 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
}
bool
+js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
+ void* userRef, const unsigned errorNumber,
+ const char16_t** messageArgs,
+ ErrorArgumentsType argumentsType,
+ JSErrorReport* reportp, va_list ap)
+{
+ return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber,
+ messageArgs, argumentsType, reportp, ap);
+}
+
+bool
+js::ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
+ void* userRef, const unsigned errorNumber,
+ const char16_t** messageArgs,
+ ErrorArgumentsType argumentsType,
+ JSErrorNotes::Note* notep, va_list ap)
+{
+ return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber,
+ messageArgs, argumentsType, notep, ap);
+}
+
+bool
js::ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback,
void* userRef, const unsigned errorNumber,
ErrorArgumentsType argumentsType, va_list ap)
@@ -832,6 +921,52 @@ js::ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNum
return ok;
}
+JSObject*
+js::CreateErrorNotesArray(JSContext* cx, JSErrorReport* report)
+{
+ RootedArrayObject notesArray(cx, NewDenseEmptyArray(cx));
+ if (!notesArray)
+ return nullptr;
+
+ if (!report->notes)
+ return notesArray;
+
+ for (auto&& note : *report->notes) {
+ RootedPlainObject noteObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!noteObj)
+ return nullptr;
+
+ RootedString messageStr(cx, note->newMessageString(cx));
+ if (!messageStr)
+ return nullptr;
+ RootedValue messageVal(cx, StringValue(messageStr));
+ if (!DefineProperty(cx, noteObj, cx->names().message, messageVal))
+ return nullptr;
+
+ RootedValue filenameVal(cx);
+ if (note->filename) {
+ RootedString filenameStr(cx, NewStringCopyZ<CanGC>(cx, note->filename));
+ if (!filenameStr)
+ return nullptr;
+ filenameVal = StringValue(filenameStr);
+ }
+ if (!DefineProperty(cx, noteObj, cx->names().fileName, filenameVal))
+ return nullptr;
+
+ RootedValue linenoVal(cx, Int32Value(note->lineno));
+ if (!DefineProperty(cx, noteObj, cx->names().lineNumber, linenoVal))
+ return nullptr;
+ RootedValue columnVal(cx, Int32Value(note->column));
+ if (!DefineProperty(cx, noteObj, cx->names().columnNumber, columnVal))
+ return nullptr;
+
+ if (!NewbornArrayPush(cx, notesArray, ObjectValue(*noteObj)))
+ return nullptr;
+ }
+
+ return notesArray;
+}
+
const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
#define MSG_DEF(name, count, exception, format) \
{ #name, format, count, exception } ,