session-ios/SignalServiceKit/src/Util/OWSAsserts.h

198 lines
11 KiB
Objective-C
Executable File

//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "AppContext.h"
NS_ASSUME_NONNULL_BEGIN
#ifndef OWSAssert
#ifdef DEBUG
#define USE_ASSERTS
#define CONVERT_TO_STRING(X) #X
#define CONVERT_EXPR_TO_STRING(X) CONVERT_TO_STRING(X)
// OWSAssert() and OWSFail() should be used in Obj-C methods.
// OWSCAssert() and OWSCFail() should be used in free functions.
#define OWSAssert(X) \
if (!(X)) { \
DDLogError(@"%s Assertion failed: %s", __PRETTY_FUNCTION__, CONVERT_EXPR_TO_STRING(X)); \
[DDLog flushLog]; \
NSAssert(0, @"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
}
#define OWSCAssert(X) \
if (!(X)) { \
DDLogError(@"%s Assertion failed: %s", __PRETTY_FUNCTION__, CONVERT_EXPR_TO_STRING(X)); \
[DDLog flushLog]; \
NSCAssert(0, @"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
}
#define OWSFail(message, ...) \
{ \
NSString *formattedMessage = [NSString stringWithFormat:message, ##__VA_ARGS__]; \
DDLogError(@"%s %@", __PRETTY_FUNCTION__, formattedMessage); \
[DDLog flushLog]; \
NSAssert(0, formattedMessage); \
}
#define OWSCFail(message, ...) \
{ \
NSString *formattedMessage = [NSString stringWithFormat:message, ##__VA_ARGS__]; \
DDLogError(@"%s %@", __PRETTY_FUNCTION__, formattedMessage); \
[DDLog flushLog]; \
NSCAssert(0, formattedMessage); \
}
#define OWSFailNoFormat(message) \
{ \
DDLogError(@"%s %@", __PRETTY_FUNCTION__, message); \
[DDLog flushLog]; \
NSAssert(0, message); \
}
#define OWSCFailNoFormat(message) \
{ \
DDLogError(@"%s %@", __PRETTY_FUNCTION__, message); \
[DDLog flushLog]; \
NSCAssert(0, message); \
}
#else
#define OWSAssert(X)
#define OWSCAssert(X)
#define OWSFail(message, ...)
#define OWSCFail(message, ...)
#define OWSFailNoFormat(X)
#define OWSCFailNoFormat(X)
#endif
#endif
#define OWS_ABSTRACT_METHOD() OWSFail(@"%@ Method needs to be implemented by subclasses.", self.logTag)
#pragma mark - Singleton Asserts
// The "singleton asserts" can be used to ensure
// that we only create a singleton once.
//
// The simplest way to use them is the OWSSingletonAssert() macro.
// It is intended to be used inside the singleton's initializer.
//
// If, however, a singleton has multiple possible initializers,
// you need to:
//
// 1. Use OWSSingletonAssertFlag() outside the class definition.
// 2. Use OWSSingletonAssertInit() in each initializer.
#ifdef DEBUG
#define ENFORCE_SINGLETONS
#endif
#ifdef ENFORCE_SINGLETONS
#define OWSSingletonAssertFlag() static BOOL _isSingletonCreated = NO;
#define OWSSingletonAssertInit() \
@synchronized([self class]) \
{ \
if (!CurrentAppContext().isRunningTests) { \
OWSAssert(!_isSingletonCreated); \
_isSingletonCreated = YES; \
} \
}
#define OWSSingletonAssert() OWSSingletonAssertFlag() OWSSingletonAssertInit()
#else
#define OWSSingletonAssertFlag()
#define OWSSingletonAssertInit()
#define OWSSingletonAssert()
#endif
// This macro is intended for use in Objective-C.
#define OWSAssertIsOnMainThread() OWSCAssert([NSThread isMainThread])
#define OWSProdLogAndFail(_messageFormat, ...) \
{ \
DDLogError(_messageFormat, ##__VA_ARGS__); \
[DDLog flushLog]; \
OWSFail(_messageFormat, ##__VA_ARGS__); \
}
#define OWSProdLogAndCFail(_messageFormat, ...) \
{ \
DDLogError(_messageFormat, ##__VA_ARGS__); \
[DDLog flushLog]; \
OWSCFail(_messageFormat, ##__VA_ARGS__); \
}
// Avoids Clang analyzer warning:
// Value stored to 'x' during it's initialization is never read
#define SUPPRESS_DEADSTORE_WARNING(x) \
do { \
(void)x; \
} while (0)
__attribute__((annotate("returns_localized_nsstring"))) static inline NSString *LocalizationNotNeeded(NSString *s)
{
return s;
}
// This function is intended for use in Swift.
void SwiftAssertIsOnMainThread(NSString *functionName);
#define OWSRaiseException(name, formatParam, ...) \
{ \
DDLogError(@"Exception: %@ %@", name, [NSString stringWithFormat:formatParam, ##__VA_ARGS__]); \
[DDLog flushLog]; \
@throw [NSException exceptionWithName:name \
reason:[NSString stringWithFormat:formatParam, ##__VA_ARGS__] \
userInfo:nil]; \
}
#define OWSRaiseExceptionWithUserInfo(name, userInfoParam, formatParam, ...) \
{ \
DDLogError( \
@"Exception: %@ %@ %@", name, userInfoParam, [NSString stringWithFormat:formatParam, ##__VA_ARGS__]); \
[DDLog flushLog]; \
@throw [NSException exceptionWithName:name \
reason:[NSString stringWithFormat:formatParam, ##__VA_ARGS__] \
userInfo:userInfoParam]; \
}
// UI JANK
//
// In pursuit of smooth UI, we want to continue moving blocking operations off the main thread.
// Add `OWSJanksUI` in code paths that shouldn't be called on the main thread.
// Because we have pervasively broken this tenant, enabling it by default would be too disruptive
// but it's helpful while unjanking and maybe someday we can have it enabled by default.
//#define DEBUG_UI_JANK 1
#ifdef DEBUG
#ifdef DEBUG_UI_JANK
#define OWSJanksUI() \
do { \
OWSAssert(![NSThread isMainThread]) \
} while (NO)
#endif
#endif
#ifndef OWSJanksUI
#define OWSJanksUI()
#endif
NS_ASSUME_NONNULL_END