summaryrefslogtreecommitdiff
path: root/Runtime/Utilities/LogAssert.h
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Utilities/LogAssert.h')
-rw-r--r--Runtime/Utilities/LogAssert.h340
1 files changed, 340 insertions, 0 deletions
diff --git a/Runtime/Utilities/LogAssert.h b/Runtime/Utilities/LogAssert.h
new file mode 100644
index 0000000..f3cb304
--- /dev/null
+++ b/Runtime/Utilities/LogAssert.h
@@ -0,0 +1,340 @@
+#ifndef LOGASSERT_H
+#define LOGASSERT_H
+
+class Object;
+#include <string>
+#include <set>
+#include <stdarg.h>
+#include <stdio.h>
+#include "Annotations.h"
+#include "Runtime/Utilities/FileStripped.h"
+#if UNITY_EXTERNAL_TOOL
+#define EXPORT_COREMODULE
+#else
+#include "Runtime/Modules/ExportModules.h"
+#endif
+
+#if UNITY_LINUX || UNITY_BB10 || UNITY_TIZEN
+ #include <signal.h>
+#endif
+
+#if UNITY_OSX || UNITY_IPHONE || UNITY_LINUX
+ extern bool IsDebuggerPresent();
+#endif
+
+enum
+{
+ kError = 1 << 0,
+ kAssert = 1 << 1,
+ kLog = 1 << 2,
+ kFatal = 1 << 4,
+ kAssetImportError = 1 << 6,
+ kAssetImportWarning = 1 << 7,
+ kScriptingError = 1 << 8,
+ kScriptingWarning = 1 << 9,
+ kScriptingLog = 1 << 10,
+ kScriptCompileError = 1 << 11,
+ kScriptCompileWarning = 1 << 12,
+ kStickyError = 1 << 13,
+ kMayIgnoreLineNumber = 1 << 14,
+ kReportBug = 1 << 15,
+ kDisplayPreviousErrorInStatusBar = 1 << 16,
+ kScriptingException = 1 << 17,
+ kDontExtractStacktrace = 1 << 18,
+ kGraphCompileError = 1 << 20,
+};
+
+/// The type of the log message in the delegate registered with Application.RegisterLogCallback.
+///
+enum LogType
+{
+ /// LogType used for Errors.
+ LogType_Error = 0,
+ /// LogType used for Asserts. (These indicate an error inside Unity itself.)
+ LogType_Assert = 1,
+ /// LogType used for Warnings.
+ LogType_Warning = 2,
+ /// LogType used for regular log messages.
+ LogType_Log = 3,
+ /// LogType used for Exceptions.
+ LogType_Exception = 4,
+ /// LogType used for Debug.
+ LogType_Debug = 5,
+ ///
+ LogType_NumLevels
+};
+
+inline const char* LogTypeToString (LogType type)
+{
+ switch (type)
+ {
+ case LogType_Assert: return "Assert";
+ case LogType_Debug: return "Debug";
+ case LogType_Exception: return "Exception";
+ case LogType_Error: return "Error";
+ case LogType_Log: return "Log";
+ case LogType_Warning: return "Warning";
+ default: return "";
+ }
+}
+
+typedef void LogToConsoleImpl (const std::string& condition, int errorNum, const char* file, int line, int type, int targetObjectInstanceID, int identifier);
+typedef void LogCallback (const std::string& condition, const std::string &stackTrace, int type);
+typedef void PreprocessCondition (const std::string& condition, std::string &strippedStacktrace, std::string &stackTrace, int errorNum, std::string& file, int* line, int type, int targetInstanceID);
+typedef void RemoveLogFunction (int identifier);
+
+/// Callback function that is invoked before a log message is written to the log output. Return true to
+/// continue logging the message as normal or false to mark the log message as handled and prevent normal
+/// processing of it.
+typedef bool (*LogEntryHandler) (LogType logType, const char* log, va_list list);
+
+void RegisterLogToConsole (LogToConsoleImpl* func);
+void RegisterLogCallback (LogCallback* callback, bool threadSafe);
+void RegisterLogPreprocessor (PreprocessCondition* func);
+void RegisterRemoveImportErrorFromConsole (RemoveLogFunction* func);
+void RegisterShowErrorWithMode (RemoveLogFunction* func);
+
+void DebugStringToFilePostprocessedStacktrace (const char* condition, const char* strippedStacktrace, const char* stacktrace, int errorNum, const char* file, int line, int mode, int targetInstanceID = 0, int identifier = 0);
+void EXPORT_COREMODULE DebugStringToFile (const char* condition, int errorNum, const char* file, int line, int mode, int targetInstanceID = 0, int identifier = 0);
+template<typename alloc>
+void EXPORT_COREMODULE DebugStringToFile (const std::basic_string<char, std::char_traits<char>, alloc>& condition, int errorNum, const char* file, int line, int mode, const int objectInstanceID = 0, int identifier = 0)
+{
+ DebugStringToFile (condition.c_str (), errorNum, file, line, mode, objectInstanceID, identifier);
+}
+
+void SetLogEntryHandler(LogEntryHandler newHandler);
+void AddCleanLogEntryHandler(LogEntryHandler newHandler);
+void ReleaseLogHandlers();
+
+void DumpCallstackConsole( const char* prefix, const char* file, int line );
+#define DUMP_CALLSTACK(message) DumpCallstackConsole(message, __FILE_STRIPPED__, __LINE__)
+
+void DebugTextLineByLine(const char* text, int maxLineLen=-1);
+
+#define ErrorIf(x) do{ if (x) DebugStringToFile (#x, 0, __FILE_STRIPPED__, __LINE__, kError); ANALYSIS_ASSUME(!(x)); }while(0)
+#define ErrorAndReturnValueIf(x, y) do{ if (x) { DebugStringToFile (#x, 0, __FILE_STRIPPED__, __LINE__, kError); return y; ANALYSIS_ASSUME(!(x)); } else { ANALYSIS_ASSUME(!(x)); } }while(0)
+#define ErrorAndReturnIf(x) ErrorAndReturnValueIf( x, /**/ )
+
+#define ErrorString(x) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kError); }while(0)
+#define ErrorStringWithoutStacktrace(x) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kDontExtractStacktrace | kError); }while(0)
+#define ErrorStringMsg(...) do{ DebugStringToFile (Format(__VA_ARGS__), 0, __FILE_STRIPPED__, __LINE__, kError); }while(0)
+#define WarningString(x) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kScriptingWarning); }while(0)
+#define WarningStringWithoutStacktrace(x) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kDontExtractStacktrace | kScriptingWarning); }while(0)
+#define WarningStringMsg(...) do{ DebugStringToFile (Format(__VA_ARGS__), 0, __FILE_STRIPPED__, __LINE__, kScriptingWarning); }while(0)
+
+
+#define ErrorOSErr(x) do{ int XERRORRESULT = x; if (XERRORRESULT) DebugStringToFile (#x, XERRORRESULT, __FILE_STRIPPED__, __LINE__, kError); }while(0)
+
+/// These errors pass an Object* as the place in which object the error occurred
+#define ErrorIfObject(x,o) do{ if (x) DebugStringToFile (#x, 0, __FILE_STRIPPED__, __LINE__, kError, (o) ? (o)->GetInstanceID() : 0); }while(0)
+#define ErrorStringObject(x,o) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kError, (o) ? (o)->GetInstanceID() : 0); }while(0)
+#define WarningStringObject(x,o) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kScriptingWarning, (o) ? (o)->GetInstanceID() : 0); }while(0)
+
+#define LogStringObject(x,o) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kLog, (o) ? (o)->GetInstanceID() : 0); }while(0)
+#define LogString(x) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kLog); }while(0)
+#define LogStringMsg(...) do{ DebugStringToFile (Format(__VA_ARGS__), 0, __FILE_STRIPPED__, __LINE__, kLog); }while(0)
+
+#define FatalErrorOSErr(x) do{ int XERRORRESULT = x; if (XERRORRESULT) DebugStringToFile (#x, XERRORRESULT, __FILE_STRIPPED__, __LINE__, kError | kFatal | kReportBug); }while(0)
+#define FatalErrorString(x) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kError | kFatal | kReportBug); }while(0)
+#define FatalErrorIf(x) do{ if (x) DebugStringToFile (#x, 0, __FILE_STRIPPED__, __LINE__, kError | kFatal | kReportBug); }while(0)
+#define FatalErrorStringDontReport(x) do{ DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kError | kFatal); }while(0)
+#define FatalErrorMsg(...) do{ DebugStringToFile (Format(__VA_ARGS__), 0, __FILE_STRIPPED__, __LINE__, kError | kFatal); }while(0)
+
+
+#define ErrorFiniteParameter(x) if (!IsFinite(x)) { ErrorString("Invalid parameter because it was infinity or nan."); return; }
+#define ErrorFiniteParameterReturnFalse(x) if (!IsFinite(x)) { ErrorString("Invalid parameter because it was infinity or nan."); return false; }
+
+
+/***** MAKE SURE THAT AssertIf's only compare code to compare, ****/
+/***** Which can safely be not called in non-debug mode ****/
+
+
+// TODO: should have ASSERT_ENABLED define, but difficult to add now
+
+#if defined(__ppc__)
+ #define DEBUG_BREAK __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" : : : "memory","r0","r3","r4" )
+#elif UNITY_OSX
+ #define DEBUG_BREAK if(IsDebuggerPresent()) __asm { int 3 }
+#elif UNITY_WIN
+ #define DEBUG_BREAK if (IsDebuggerPresent()) __debugbreak()
+#elif UNITY_XENON || UNITY_METRO
+ #define DEBUG_BREAK __debugbreak()
+#elif UNITY_PS3
+ #define DEBUG_BREAK __asm__ volatile ("tw 31,1,1 ")
+#elif (UNITY_IPHONE && !TARGET_IPHONE_SIMULATOR)
+ #define DEBUG_BREAK __asm__ __volatile__ ( "bkpt #0\n\t bx lr\n\t" : : : )
+#elif UNITY_ANDROID
+ #define DEBUG_BREAK __builtin_trap()
+#elif UNITY_LINUX
+ #define DEBUG_BREAK if (IsDebuggerPresent ()) raise(SIGTRAP)
+#else
+ #define DEBUG_BREAK
+#endif
+
+#ifndef ASSERT_SHOULD_BREAK
+// On Metro breaking without debugger attached stops the program... So don't do it !
+#define ASSERT_SHOULD_BREAK DEBUGMODE && !UNITY_RELEASE && !UNITY_METRO
+#endif
+
+#if ASSERT_SHOULD_BREAK
+ #define ASSERT_BREAK DEBUG_BREAK
+#else
+ #define ASSERT_BREAK
+#endif
+
+
+#if DEBUGMODE
+
+ #define AssertIf(x) \
+ do { \
+ if(x) \
+ { \
+ DebugStringToFile (#x, 0, __FILE_STRIPPED__, __LINE__, kAssert); \
+ ASSERT_BREAK; \
+ ANALYSIS_ASSUME(!(x)); \
+ } \
+ } while(0)
+
+ #define AssertIfObject(x,o) \
+ do { \
+ if(x) \
+ { \
+ DebugStringToFile (#x, 0, __FILE_STRIPPED__, __LINE__, kAssert, (o)?(o)->GetInstanceID():0); \
+ ASSERT_BREAK; \
+ ANALYSIS_ASSUME(!(x)); \
+ } \
+ } while(0)
+
+
+ #define Assert(x) \
+ do { \
+ if(!(x)) \
+ { \
+ DebugStringToFile (#x, 0, __FILE_STRIPPED__, __LINE__, kAssert); \
+ ASSERT_BREAK; \
+ ANALYSIS_ASSUME(x); \
+ } \
+ } while(0)
+
+ #define AssertMsg(x,...) \
+ do { \
+ if(!(x)) \
+ { \
+ DebugStringToFile (Format(__VA_ARGS__), 0, __FILE_STRIPPED__, __LINE__, kAssert); \
+ ASSERT_BREAK; \
+ ANALYSIS_ASSUME(x); \
+ } \
+ } while(0)
+
+ #define AssertMsgObject(x,o,...) \
+ do { \
+ if(!(x)) \
+ { \
+ DebugStringToFile (Format(__VA_ARGS__), 0, __FILE_STRIPPED__, __LINE__, kAssert, (o) ? (o)->GetInstanceID() : 0); \
+ ASSERT_BREAK; \
+ ANALYSIS_ASSUME(x); \
+ } \
+ } while(0)
+
+
+#else
+
+ #define AssertIf(x) do { (void)sizeof(x); } while(0)
+ #define AssertIfObject(x,o) do { (void)sizeof(x); (void)sizeof(o); } while(0)
+ #define Assert(x) do { (void)sizeof(x); } while(0)
+ #define AssertMsg(x,...) do { (void)sizeof(x); } while(0)
+ #define AssertMsgObject(x,o,...) do { (void)sizeof(x); } while(0)
+
+#endif
+
+
+#if DEBUGMODE
+
+ #define AssertString(x) { DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kAssert); }
+ #define AssertFiniteParameter(x) if (!IsFinite(x)) { AssertString("Invalid parameter because it was infinity or nan."); }
+
+ /// These errors pass an Object* as the place in which object the error occurred
+ #define AssertStringObject(x,o) { DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kAssert, (o) ? (o)->GetInstanceID() : 0); }
+ #define ScriptWarning(x,o) { DebugStringToFile (x, 0, __FILE_STRIPPED__, __LINE__, kScriptingWarning); }
+#else
+
+ #define AssertString(x) { }
+ #define AssertFiniteParameter(x) {}
+
+ #define AssertStringObject(x,o) { }
+ #define ScriptWarning(x,o) { }
+#endif
+
+
+#if UNITY_RELEASE
+ #define DebugAssertIf(x) do { (void)sizeof(x); } while(0)
+ #define DebugAssert(x) do { (void)sizeof(x); } while(0)
+ #define DebugAssertMsg(x, ...) { }
+ #define AssertBreak(x) Assert(x)
+#else
+ #define DebugAssertIf(x) AssertIf(x)
+ #define DebugAssert(x) Assert(x)
+ #define DebugAssertMsg(x, ...) AssertMsg(x, __VA_ARGS__)
+
+ #define AssertBreak(x) \
+ do { \
+ if(!(x)) \
+ { \
+ DEBUG_BREAK; \
+ Assert(x); \
+ } \
+ } while(0)
+ #endif
+
+
+#ifdef __cplusplus
+extern "C"
+ {
+#endif
+EXPORT_COREMODULE TAKES_PRINTF_ARGS(1,2) void printf_console (const char* string, ...);
+#ifdef __cplusplus
+ }
+#endif
+void printf_consolev (LogType logType, const char* log, va_list list);
+
+#if MASTER_BUILD
+#define UNITY_TRACE(...)
+#define UNITY_TRACEIF(condition, ...)
+#else
+#define UNITY_TRACE(...) printf_console(__VA_ARGS__)
+#define UNITY_TRACEIF(condition, ...) if (condition) printf_console(__VA_ARGS__)
+#endif
+
+/// When logging an error it can be passed an identifier. The identifier can be used to remove errors from the console later on.
+/// Eg. when reimporting an asset all errors generated for that asset should be removed before importing!
+void RemoveErrorWithIdentifierFromConsole (int identifier);
+void ShowErrorWithMode (int mode);
+
+#if UNITY_OSX
+void ResetStdout();
+#endif
+
+// Route input to a custom outputfile out instead of Player.log
+void LogOutputToSpecificFile (const char* path);
+void InitializeCleanedLogFile (FILE* file);
+std::string GetCleanedLogFile();
+std::string GetConsoleLogPath();
+
+#if UNITY_EDITOR
+std::string GetEditorConsoleLogPath ();
+std::string GetPlayerConsoleLogPath ();
+std::string GetMonoDevelopLogPath ();
+#endif
+
+#if UNITY_WIN
+FILE* OpenConsole ();
+std::string SetLogFilePath(std::string const& path);
+#endif
+
+#if defined(_MSC_VER)
+ #define PRINTF_SIZET_FORMAT "Iu"
+#else
+ #define PRINTF_SIZET_FORMAT "zu"
+#endif
+
+#endif