diff options
Diffstat (limited to 'js/src/jscntxt.cpp')
-rw-r--r-- | js/src/jscntxt.cpp | 227 |
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 } , |