Files
kotlin-fork/kotlin-native/runtime/src/main/cpp/ObjCExportErrors.mm
T
Diego Gomez Olvera 9a430efbe7 [KT-52681] Remove unnecessary semicolon after Objective-C @end
Objective-c `@end` doesn't need a semicolon, however KMM exported header
file, for instance:
```
__attribute__((swift_name("KotlinIterator")))
@protocol MyProjectKotlinIterator
@required
- (BOOL)hasNext __attribute__((swift_name("hasNext()")));
- (id _Nullable)next __attribute__((swift_name("next()")));
@end;
```
This creates problems with some code checkers that will not expect it
there, so it seems best to remove it.
2022-06-10 15:46:27 +03:00

152 lines
5.4 KiB
Plaintext

/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if KONAN_OBJC_INTEROP
#import <Foundation/NSDictionary.h>
#import <Foundation/NSError.h>
#import <Foundation/NSString.h>
#import "Exceptions.h"
#import "ObjCExport.h"
#import "Porting.h"
#import "Runtime.h"
#import "Mutex.hpp"
#import "ObjCExportErrors.h"
extern "C" OBJ_GETTER(Kotlin_Throwable_getMessage, KRef throwable);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_getWrappedError, KRef throwable);
static void printlnMessage(const char* message) {
konan::consolePrintf("%s\n", message);
}
extern "C" RUNTIME_NORETURN void Kotlin_ObjCExport_trapOnUndeclaredException(KRef exception) {
printlnMessage("Function doesn't have or inherit @Throws annotation and thus exception isn't propagated "
"from Kotlin to Objective-C/Swift as NSError.\n"
"It is considered unexpected and unhandled instead. Program will be terminated.");
kotlin::ProcessUnhandledException(exception);
// Cannot safely continue, must terminate.
kotlin::TerminateWithUnhandledException(exception);
}
static char kotlinExceptionOriginChar;
static bool isExceptionOfType(KRef exception, const TypeInfo** types) {
if (types) for (int i = 0; types[i] != nullptr; ++i) {
// TODO: use fast instance check when possible.
if (IsInstance(exception, types[i])) return true;
}
return false;
}
extern "C" id Kotlin_ObjCExport_ExceptionAsNSError(KRef exception, const TypeInfo** types) {
ObjHolder errorHolder;
KRef error = Kotlin_ObjCExport_getWrappedError(exception, errorHolder.slot());
if (error != nullptr) {
// Thrown originally by Swift/Objective-C.
// Not actually a Kotlin exception, so don't check if it matches [types].
return Kotlin_ObjCExport_refToObjC(error);
}
if (!isExceptionOfType(exception, types)) {
printlnMessage("Exception doesn't match @Throws-specified class list and thus isn't propagated "
"from Kotlin to Objective-C/Swift as NSError.\n"
"It is considered unexpected and unhandled instead. Program will be terminated.");
kotlin::ProcessUnhandledException(exception);
// Cannot safely continue, must terminate.
kotlin::TerminateWithUnhandledException(exception);
}
return Kotlin_ObjCExport_WrapExceptionToNSError(exception);
}
extern "C" id Kotlin_ObjCExport_WrapExceptionToNSError(KRef exception) {
ObjHolder messageHolder;
KRef message = Kotlin_Throwable_getMessage(exception, messageHolder.slot());
NSString* description = Kotlin_Interop_CreateNSStringFromKString(message);
id exceptionObjCRef = Kotlin_ObjCExport_refToLocalObjC(exception);
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
NSMutableDictionary<NSErrorUserInfoKey, id>* userInfo = [[NSMutableDictionary new] autorelease];
userInfo[@"KotlinException"] = exceptionObjCRef;
userInfo[@"KotlinExceptionOrigin"] = @(&kotlinExceptionOriginChar); // Support for different Kotlin runtimes loaded.
if (description != nullptr) {
userInfo[NSLocalizedDescriptionKey] = description;
}
return [NSError errorWithDomain:@"KotlinException" code:0 userInfo:userInfo];
}
extern "C" void Kotlin_ObjCExport_RethrowExceptionAsNSError(KRef exception, id* outError, const TypeInfo** types) {
id error = Kotlin_ObjCExport_ExceptionAsNSError(exception, types); // Also traps on unexpected exception.
if (outError != nullptr) *outError = error;
}
extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsExceptionImpl, KRef message, KRef error);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsException, id error) {
NSString* description;
id wrappedKotlinException = nullptr;
NSError* e = (NSError*) error;
if (e != nullptr) {
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
auto userInfo = e.userInfo;
if (userInfo != nullptr) {
id kotlinException = userInfo[@"KotlinException"];
id kotlinExceptionOrigin = userInfo[@"KotlinExceptionOrigin"];
if (kotlinException != nullptr &&
kotlinExceptionOrigin != nullptr && [kotlinExceptionOrigin isEqual:@(&kotlinExceptionOriginChar)]
) {
wrappedKotlinException = kotlinException;
}
}
description = e.localizedDescription;
} else {
description = nullptr;
}
if (wrappedKotlinException != nullptr) {
RETURN_RESULT_OF(Kotlin_ObjCExport_refFromObjC, wrappedKotlinException);
}
ObjHolder messageHolder, errorHolder;
KRef message = Kotlin_Interop_CreateKStringFromNSString(description, messageHolder.slot());
KRef kotlinError = Kotlin_ObjCExport_refFromObjC(error, errorHolder.slot()); // TODO: a simple opaque wrapper would be enough.
RETURN_RESULT_OF(Kotlin_ObjCExport_NSErrorAsExceptionImpl, message, kotlinError);
}
@interface NSError (NSErrorKotlinException)
@end
@implementation NSError (NSErrorKotlinException)
-(id)kotlinException {
auto userInfo = self.userInfo;
return userInfo == nullptr ? nullptr : userInfo[@"KotlinException"];
}
@end
#endif