From f7de41c770be1bc6c45e825ff0fbdd6bfb799fae Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Wed, 9 Mar 2016 14:38:57 +0000
Subject: Explicitly convert between nullable and non-nullable on OS X

Clang was complaining about implicit conversions between
nullable and non-nullable NSString pointers. Adjusted our
std::string -> NSString* conversion utilities to check for
nil and return an empty std::string in that case.

Replaced uses of [NSString stringWithUTF8String] with our
STD2NSSTRING macro.

Turned std::string <-> NSString* conversion macros into
functions.

Test-Information:

Builds without the warning on OS X 10.11.3 and Swift runs
without issues.

Change-Id: I949f2f3332018391aead58ef362764f4b7955b01

diff --git a/Slimber/Cocoa/CocoaMenulet.mm b/Slimber/Cocoa/CocoaMenulet.mm
index 6013b05..f62da80 100644
--- a/Slimber/Cocoa/CocoaMenulet.mm
+++ b/Slimber/Cocoa/CocoaMenulet.mm
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2012-2013 Isode Limited.
+ * Copyright (c) 2012-2016 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
 
-#include "Slimber/Cocoa/CocoaMenulet.h"
-
-#pragma GCC diagnostic ignored "-Wold-style-cast"
+#include <Slimber/Cocoa/CocoaMenulet.h>
 
 #include <boost/function.hpp>
 
+#include <SwifTools/Cocoa/CocoaUtil.h>
+
 CocoaMenulet::CocoaMenulet() {
 	restartAction = [[CocoaAction alloc] initWithFunction: 
 			new boost::function<void()>(boost::ref(onRestartClicked))];
@@ -19,7 +19,7 @@ CocoaMenulet::CocoaMenulet() {
 			statusItemWithLength: NSVariableStatusItemLength] retain];
 	[statusItem setHighlightMode: YES];
 	[statusItem setEnabled: YES];
-	[statusItem setToolTip: @"Slimber"];	
+	[statusItem setToolTip: @"Slimber"];
 	[statusItem setMenu: menu];
 }
 
@@ -30,8 +30,7 @@ CocoaMenulet::~CocoaMenulet() {
 }
 
 void CocoaMenulet::setIcon(const std::string& icon) {
-	NSString* path = [[NSBundle mainBundle] pathForResource: 
-			[NSString stringWithUTF8String: icon.c_str()] ofType:@"png"];
+	NSString* path = [[NSBundle mainBundle] pathForResource: std2NSString(icon) ofType:@"png"];
 	NSImage* image = [[NSImage alloc] initWithContentsOfFile: path];
 	[statusItem setImage: image];
 	[image release];
@@ -44,12 +43,10 @@ void CocoaMenulet::clear() {
 }
 
 void CocoaMenulet::addItem(const std::string& name, const std::string& icon) {
-	NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: 
-		[NSString stringWithUTF8String: name.c_str()]
+	NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: std2NSString(name)
 		action: NULL keyEquivalent: @""];
 	if (!icon.empty()) {
-		NSString* path = [[NSBundle mainBundle] pathForResource: 
-				[NSString stringWithUTF8String: icon.c_str()] ofType:@"png"];
+		NSString* path = [[NSBundle mainBundle] pathForResource: std2NSString(icon) ofType:@"png"];
 		NSImage* image = [[NSImage alloc] initWithContentsOfFile: path];
 		[item setImage: image];
 		[image release];
diff --git a/Sluift/ITunesInterface.mm b/Sluift/ITunesInterface.mm
index 0843aad..a11be20 100644
--- a/Sluift/ITunesInterface.mm
+++ b/Sluift/ITunesInterface.mm
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Isode Limited.
+ * Copyright (c) 2014-2016 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -40,9 +40,9 @@ boost::optional<ITunesInterface::Track> ITunesInterface::getCurrentTrack() const
 		return boost::optional<ITunesInterface::Track>();
 	}
 	ITunesInterface::Track result;
-	result.name = NS2STDSTRING(currentTrack.name);
-	result.artist = NS2STDSTRING(currentTrack.artist);
-	result.album = NS2STDSTRING(currentTrack.album);
+	result.name = ns2StdString(currentTrack.name);
+	result.artist = ns2StdString(currentTrack.artist);
+	result.album = ns2StdString(currentTrack.album);
 	result.trackNumber = currentTrack.trackNumber;
 	result.duration = currentTrack.duration;
 	result.rating = currentTrack.rating;
diff --git a/SwifTools/Cocoa/CocoaUtil.h b/SwifTools/Cocoa/CocoaUtil.h
index 49ed682..83d95b6 100644
--- a/SwifTools/Cocoa/CocoaUtil.h
+++ b/SwifTools/Cocoa/CocoaUtil.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Isode Limited.
+ * Copyright (c) 2011-2016 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -7,16 +7,36 @@
 #pragma once
 
 // Conversion utilities
-#define NS2STDSTRING(a) (a == nil ? std::string() : std::string([a cStringUsingEncoding:NSUTF8StringEncoding]))
-#define STD2NSSTRING(a) [NSString stringWithCString:a.c_str() encoding:NSUTF8StringEncoding]
+namespace {
+
+inline std::string ns2StdString(NSString* _Nullable nsString);
+inline std::string ns2StdString(NSString* _Nullable nsString) {
+	std::string stdString;
+	if (nsString != nil) {
+		stdString = std::string([nsString cStringUsingEncoding:NSUTF8StringEncoding]);
+	}
+	return stdString;
+}
+
+inline NSString* _Nonnull std2NSString(const std::string& stdString);
+inline NSString* _Nonnull std2NSString(const std::string& stdString) {
+	NSString* _Nullable nsString = [NSString stringWithUTF8String:stdString.c_str()];
+	if (nsString == nil) {
+		nsString = @"";
+	}
+	// At this point nsString is guaranteed to be not null/nil.
+	return static_cast<NSString* _Nonnull>(nsString);
+}
+
+}
 
 // Intrusive pointer for NSObjects
 namespace boost {	
-	inline void intrusive_ptr_add_ref(NSObject* object) {
+	inline void intrusive_ptr_add_ref(NSObject* _Nonnull object) {
 		[object retain];
 	}
 	
-	inline void intrusive_ptr_release(NSObject* object) {
+	inline void intrusive_ptr_release(NSObject* _Nonnull object) {
 		[object release];
 	}
 }
diff --git a/SwifTools/Notifier/GrowlNotifier.mm b/SwifTools/Notifier/GrowlNotifier.mm
index acaf45c..d5bdf6f 100644
--- a/SwifTools/Notifier/GrowlNotifier.mm
+++ b/SwifTools/Notifier/GrowlNotifier.mm
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -36,16 +36,16 @@ GrowlNotifier::GrowlNotifier(const std::string& name) {
 	p = boost::make_shared<Private>();
 	p->delegate = boost::intrusive_ptr<GrowlNotifierDelegate>([[GrowlNotifierDelegate alloc] init], false);
 	p->delegate.get().notifier = this;
-	p->delegate.get().name = STD2NSSTRING(name);
+	p->delegate.get().name = std2NSString(name);
 	
 	NSMutableArray* allNotifications = [[NSMutableArray alloc] init];
 	foreach(Type type, getAllTypes()) {
-		[allNotifications addObject: STD2NSSTRING(typeToString(type))];
+		[allNotifications addObject: std2NSString(typeToString(type))];
 	}
 
 	NSMutableArray* defaultNotifications = [[NSMutableArray alloc] init];
 	foreach(Type type, getDefaultTypes()) {
-		[defaultNotifications addObject: STD2NSSTRING(typeToString(type))];
+		[defaultNotifications addObject: std2NSString(typeToString(type))];
 	}
 
 	p->delegate.get().registrationDictionary = [[[NSDictionary alloc] 
@@ -73,9 +73,9 @@ void GrowlNotifier::showMessage(Type type, const std::string& subject, const std
 	p->pendingNotifications.insert(context);
 	
 	[GrowlApplicationBridge 
-		notifyWithTitle: STD2NSSTRING(subject)
-		description: STD2NSSTRING(description)
-		notificationName: STD2NSSTRING(typeToString(type))
+		notifyWithTitle: std2NSString(subject)
+		description: std2NSString(description)
+		notificationName: std2NSString(typeToString(type))
 		iconData: [NSData dataWithBytes: vecptr(picture) length: picture.size()]
 		priority: 0
 		isSticky: NO
diff --git a/SwifTools/Notifier/NotificationCenterNotifier.mm b/SwifTools/Notifier/NotificationCenterNotifier.mm
index 10319c8..01e6368 100644
--- a/SwifTools/Notifier/NotificationCenterNotifier.mm
+++ b/SwifTools/Notifier/NotificationCenterNotifier.mm
@@ -57,11 +57,11 @@ void NotificationCenterNotifier::showMessage(Type type, const std::string& subje
 	if (std::find(defaultTypes.begin(), defaultTypes.end(), type) == defaultTypes.end()) {
 		return;
 	}
-	NSImage* image = [[NSImage alloc] initWithContentsOfFile: STD2NSSTRING(picture.string())];
+	NSImage* image = [[NSImage alloc] initWithContentsOfFile: std2NSString(picture.string())];
 	NSUserNotification* notification = [[NSUserNotification alloc] init];
-	[notification setTitle:STD2NSSTRING(typeToString(type))];
-	[notification setSubtitle:STD2NSSTRING(subject)];
-	[notification setInformativeText:STD2NSSTRING(description)];
+	[notification setTitle:std2NSString(typeToString(type))];
+	[notification setSubtitle:std2NSString(subject)];
+	[notification setInformativeText:std2NSString(description)];
 	[notification setContentImage: image];
 	[image release];
 
@@ -73,7 +73,7 @@ void NotificationCenterNotifier::showMessage(Type type, const std::string& subje
 	/// \todo Currently the elements are only removed on application exit. Ideally the notifications not required anymore
 	///       are removed from the map; e.g. when visiting a chat view, all notifications from that view can be removed from
 	///       the map and the NSUserNotificationCenter.
-	p->callbacksForNotifications[NS2STDSTRING(notification.identifier)] = boost::make_shared<Context>(callback);
+	p->callbacksForNotifications[ns2StdString(notification.identifier)] = boost::make_shared<Context>(callback);
 	[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
 	[notification release];
 }
diff --git a/SwifTools/Notifier/NotificationCenterNotifierDelegate.mm b/SwifTools/Notifier/NotificationCenterNotifierDelegate.mm
index 617619c..2b1c2a4 100644
--- a/SwifTools/Notifier/NotificationCenterNotifierDelegate.mm
+++ b/SwifTools/Notifier/NotificationCenterNotifierDelegate.mm
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Isode Limited.
+ * Copyright (c) 2015-2016 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -19,7 +19,7 @@ using namespace Swift;
 
 - (void)userNotificationCenter:(NSUserNotificationCenter *) center didActivateNotification:(NSUserNotification *)notification {
 	(void)center;
-	std::string identifier = NS2STDSTRING(notification.identifier);
+	std::string identifier = ns2StdString(notification.identifier);
 	notifier->handleUserNotificationActivated(identifier);
 }
 
diff --git a/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm b/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm
index ed409bd..6f8e158 100644
--- a/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm
+++ b/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm
@@ -25,6 +25,19 @@ T bridge_cast(S source) {
 
 }
 
+namespace {
+
+inline std::string ns2StdString(NSString* _Nullable nsString);
+inline std::string ns2StdString(NSString* _Nullable nsString) {
+	std::string stdString;
+	if (nsString != nil) {
+		stdString = std::string([nsString cStringUsingEncoding:NSUTF8StringEncoding]);
+	}
+	return stdString;
+}
+
+}
+
 namespace Swift {
 
 SecureTransportCertificate::SecureTransportCertificate(SecCertificateRef certificate) {
@@ -49,9 +62,6 @@ SecureTransportCertificate::~SecureTransportCertificate() {
 
 }
 
-#define NS2STDSTRING(a) (a == nil ? std::string() : std::string([a cStringUsingEncoding:NSUTF8StringEncoding]))
-
-
 void SecureTransportCertificate::parse() {
 	assert(certificateHandle_);
 	CFErrorRef error = NULL;
@@ -63,7 +73,7 @@ void SecureTransportCertificate::parse() {
 		CFStringRef subject = SecCertificateCopySubjectSummary(certificateHandle_.get());
 		if (subject) {
 			NSString* subjectStr = bridge_cast<NSString*>(subject);
-			subjectName_ = NS2STDSTRING(subjectStr);
+			subjectName_ = ns2StdString(subjectStr);
 			CFRelease(subject);
 		}
 
@@ -72,7 +82,7 @@ void SecureTransportCertificate::parse() {
 		OSStatus error = SecCertificateCopyCommonName(certificateHandle_.get(), &commonName);
 		if (!error && commonName) {
 			NSString* commonNameStr = bridge_cast<NSString*>(commonName);
-			commonNames_.push_back(NS2STDSTRING(commonNameStr));
+			commonNames_.push_back(ns2StdString(commonNameStr));
 		}
 		if (commonName) {
 			CFRelease(commonName);
@@ -83,14 +93,14 @@ void SecureTransportCertificate::parse() {
 		NSDictionary* subjectAltNamesDict = certDict[@"2.5.29.17"][@"value"];
 
 		for (NSDictionary* entry in subjectAltNamesDict) {
-			if ([entry[@"label"] isEqualToString:[NSString stringWithUTF8String:ID_ON_XMPPADDR_OID]]) {
-				xmppAddresses_.push_back(NS2STDSTRING(entry[@"value"]));
+			if ([entry[@"label"] isEqualToString:static_cast<NSString * _Nonnull>([NSString stringWithUTF8String:ID_ON_XMPPADDR_OID])]) {
+				xmppAddresses_.push_back(ns2StdString(entry[@"value"]));
 			}
-			else if ([entry[@"label"] isEqualToString:[NSString stringWithUTF8String:ID_ON_DNSSRV_OID]]) {
-				srvNames_.push_back(NS2STDSTRING(entry[@"value"]));
+			else if ([entry[@"label"] isEqualToString:static_cast<NSString * _Nonnull>([NSString stringWithUTF8String:ID_ON_DNSSRV_OID])]) {
+				srvNames_.push_back(ns2StdString(entry[@"value"]));
 			}
 			else if ([entry[@"label"] isEqualToString:@"DNS Name"]) {
-				dnsNames_.push_back(NS2STDSTRING(entry[@"value"]));
+				dnsNames_.push_back(ns2StdString(entry[@"value"]));
 			}
 		}
 		CFRelease(valueDict);
-- 
cgit v0.10.2-6-g49f6