Skip to content

Commit d3a47b1

Browse files
committed
Dev: add Kotlin support SwiftCallbackFunc and SwiftBlock
1 parent 9704d3c commit d3a47b1

14 files changed

Lines changed: 353 additions & 163 deletions

File tree

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
buildscript {
2-
ext.kotlin_version = '1.3.50'
2+
ext.kotlin_version = '1.3.61'
33

44
repositories {
55
google()
@@ -9,8 +9,8 @@ buildscript {
99
}
1010

1111
dependencies {
12-
classpath "com.android.tools.build:gradle:3.5.0"
13-
classpath "com.readdle.android.swift:gradle:1.3.1"
12+
classpath "com.android.tools.build:gradle:3.5.1"
13+
classpath "com.readdle.android.swift:gradle:1.3.2"
1414
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1515
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
1616
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4"

compiler/src/main/java/com/readdle/codegen/JavaSwiftProcessor.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import javax.lang.model.element.AnnotationMirror;
2626
import javax.lang.model.element.Element;
2727
import javax.lang.model.element.ElementKind;
28+
import javax.lang.model.element.ExecutableElement;
2829
import javax.lang.model.element.Name;
2930
import javax.lang.model.element.TypeElement;
3031
import javax.lang.model.util.Elements;
@@ -201,7 +202,7 @@ private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnviron
201202
TypeElement typeElement = (TypeElement) annotatedElement;
202203

203204
try {
204-
SwiftDelegateDescriptor delegateDescriptor = new SwiftDelegateDescriptor(typeElement, filer, this);
205+
SwiftDelegateDescriptor delegateDescriptor = new SwiftDelegateDescriptor(typeElement, filer, messager, this);
205206
swiftDelegates.put(delegateDescriptor.simpleTypeName, delegateDescriptor);
206207
}
207208
catch (IllegalArgumentException e) {
@@ -337,7 +338,17 @@ private void error(Element e, String msg, Object... args) {
337338
messager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args), e);
338339
}
339340

340-
static boolean isNullable(Element element) {
341+
boolean isNullable(Element element) {
342+
note("Check nullability " + element.asType().toString());
343+
if (element.asType().getKind().isPrimitive()) {
344+
return false;
345+
}
346+
if (element.getKind() == ElementKind.METHOD) {
347+
ExecutableElement executableElement = (ExecutableElement) element;
348+
if (executableElement.getReturnType().getKind().isPrimitive()) {
349+
return false;
350+
}
351+
}
341352
List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
342353
for (AnnotationMirror mirror : mirrors) {
343354
Name simpleName = mirror.getAnnotationType().asElement().getSimpleName();
@@ -366,6 +377,20 @@ public SwiftEnvironment.Type parseJavaType(String javaType) {
366377
switch (javaType) {
367378
case "void":
368379
return null;
380+
case "byte":
381+
return new SwiftEnvironment.Type("Int8", javaType);
382+
case "short":
383+
return new SwiftEnvironment.Type("Int16", javaType);
384+
case "int":
385+
return new SwiftEnvironment.Type("Int", javaType);
386+
case "long":
387+
return new SwiftEnvironment.Type("Int64", javaType);
388+
case "float":
389+
return new SwiftEnvironment.Type("Float", javaType);
390+
case "double":
391+
return new SwiftEnvironment.Type("Double", javaType);
392+
case "boolean":
393+
return new SwiftEnvironment.Type("Bool", javaType);
369394
case "java.lang.Integer":
370395
return new SwiftEnvironment.Type("Int", javaType);
371396
case "java.lang.Byte":

compiler/src/main/java/com/readdle/codegen/SwiftBlockDescriptor.java

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class SwiftBlockDescriptor {
8181
this.funcName = executableElement.getSimpleName().toString();
8282
this.isThrown = executableElement.getThrownTypes() != null && executableElement.getThrownTypes().size() > 0;
8383
this.returnSwiftType = processor.parseJavaType(executableElement.getReturnType().toString());
84-
this.isReturnTypeOptional = JavaSwiftProcessor.isNullable(executableElement);
84+
this.isReturnTypeOptional = processor.isNullable(executableElement);
8585

8686
this.sig = "(";
8787

@@ -160,7 +160,19 @@ File generateCode() throws IOException {
160160
}
161161

162162
if (params.size() > 0) {
163-
swiftWriter.emitStatement("do {");
163+
boolean hasNonPrimitiveParam = false;
164+
for (int i = 0; i < params.size(); i++) {
165+
SwiftParamDescriptor param = params.get(i);
166+
if (param.isOptional || !param.isPrimitive()) {
167+
hasNonPrimitiveParam = true;
168+
break;
169+
}
170+
}
171+
172+
if (hasNonPrimitiveParam) {
173+
swiftWriter.emitStatement("do {");
174+
}
175+
164176
for (int i = 0; i < params.size(); i++) {
165177
SwiftParamDescriptor param = params.get(i);
166178
if (param.isOptional) {
@@ -171,20 +183,27 @@ File generateCode() throws IOException {
171183
swiftWriter.emitStatement(String.format("java_%s = jnull()", param.name));
172184
swiftWriter.emitStatement("}");
173185
} else {
174-
swiftWriter.emitStatement(String.format("java_%s = try $%s.javaObject()", param.name, i + ""));
186+
if (param.isPrimitive()) {
187+
swiftWriter.emitStatement(String.format("java_%s = $%s.javaPrimitive()", param.name, i + ""));
188+
}
189+
else {
190+
swiftWriter.emitStatement(String.format("java_%s = try $%s.javaObject()", param.name, i + ""));
191+
}
175192
}
176193
}
177194

178-
swiftWriter.emitStatement("}");
179-
swiftWriter.emitStatement("catch {");
180-
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
181-
if (returnSwiftType == null) {
182-
swiftWriter.emitStatement("assert(false, errorString)");
183-
swiftWriter.emitStatement("return");
184-
} else {
185-
swiftWriter.emitStatement("fatalError(errorString)");
195+
if (hasNonPrimitiveParam) {
196+
swiftWriter.emitStatement("}");
197+
swiftWriter.emitStatement("catch {");
198+
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
199+
if (returnSwiftType == null) {
200+
swiftWriter.emitStatement("assert(false, errorString)");
201+
swiftWriter.emitStatement("return");
202+
} else {
203+
swiftWriter.emitStatement("fatalError(errorString)");
204+
}
205+
swiftWriter.emitStatement("}");
186206
}
187-
swiftWriter.emitStatement("}");
188207
}
189208

190209
String jniMethodTemplate;

compiler/src/main/java/com/readdle/codegen/SwiftCallbackFuncDescriptor.java

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import java.io.IOException;
66
import java.util.Arrays;
7-
import java.util.HashMap;
87
import java.util.LinkedList;
98
import java.util.List;
109

@@ -36,7 +35,7 @@ public class SwiftCallbackFuncDescriptor {
3635
this.isStatic = executableElement.getModifiers().contains(Modifier.STATIC);
3736
this.isThrown = executableElement.getThrownTypes() != null && executableElement.getThrownTypes().size() > 0;
3837
this.returnSwiftType = processor.parseJavaType(executableElement.getReturnType().toString());
39-
this.isReturnTypeOptional = JavaSwiftProcessor.isNullable(executableElement);
38+
this.isReturnTypeOptional = processor.isNullable(executableElement);
4039

4140
StringBuilder signatureBuilder = new StringBuilder("(");
4241

@@ -142,39 +141,60 @@ void generateCode(SwiftWriter swiftWriter, String javaFullName, String swiftType
142141
swiftWriter.emitStatement("}");
143142

144143
if (params.size() > 0) {
145-
swiftWriter.emitStatement("do {");
144+
boolean hasNonPrimitiveParam = false;
145+
for (int i = 0; i < params.size(); i++) {
146+
SwiftParamDescriptor param = params.get(i);
147+
if (param.isOptional || !param.isPrimitive()) {
148+
hasNonPrimitiveParam = true;
149+
break;
150+
}
151+
}
152+
153+
if (hasNonPrimitiveParam) {
154+
swiftWriter.emitStatement("do {");
155+
}
156+
146157
for (SwiftParamDescriptor param : params) {
147158
if (param.isOptional) {
148159
swiftWriter.emitStatement(String.format("if let %1$s = %1$s {", param.name));
149160
swiftWriter.emitStatement(String.format("java%1$s = try %1$s.javaObject()", param.name));
150161
swiftWriter.emitStatement("}");
151162
} else {
152-
swiftWriter.emitStatement(String.format("java%s = try %s.javaObject()", param.name, param.name));
163+
if (param.isPrimitive()) {
164+
swiftWriter.emitStatement(String.format("java%s = %s.javaPrimitive()", param.name, param.name));
165+
}
166+
else {
167+
swiftWriter.emitStatement(String.format("java%s = try %s.javaObject()", param.name, param.name));
168+
}
153169
}
154170
}
155171

156-
swiftWriter.emitStatement("}");
157-
swiftWriter.emitStatement("catch {");
158-
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
159-
if (returnSwiftType == null) {
160-
swiftWriter.emitStatement("assert(false, errorString)");
161-
swiftWriter.emitStatement("return");
162-
} else if (isReturnTypeOptional) {
163-
swiftWriter.emitStatement("assert(false, errorString)");
164-
swiftWriter.emitStatement("return nil");
165-
} else {
166-
swiftWriter.emitStatement("fatalError(errorString)");
172+
if (hasNonPrimitiveParam) {
173+
swiftWriter.emitStatement("}");
174+
swiftWriter.emitStatement("catch {");
175+
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
176+
if (returnSwiftType == null) {
177+
swiftWriter.emitStatement("assert(false, errorString)");
178+
swiftWriter.emitStatement("return");
179+
} else if (isReturnTypeOptional) {
180+
swiftWriter.emitStatement("assert(false, errorString)");
181+
swiftWriter.emitStatement("return nil");
182+
} else {
183+
swiftWriter.emitStatement("fatalError(errorString)");
184+
}
185+
swiftWriter.emitStatement("}");
167186
}
168-
swiftWriter.emitStatement("}");
169187
}
170188

171189
String jniMethodTemplate;
172190
if (returnSwiftType != null) {
173191
if (!isStatic) {
174-
jniMethodTemplate = "let optionalResult = JNI.CallObjectMethod(jniObject, %s.javaMethod%s";
192+
String methodCallMethod = returnSwiftType.returnTypeFunc(isReturnTypeOptional);
193+
jniMethodTemplate = "let optionalResult = JNI." + methodCallMethod + "(jniObject, %s.javaMethod%s";
175194
}
176195
else {
177-
jniMethodTemplate = "let optionalResult = JNI.CallStaticObjectMethod(javaClass, %s.javaMethod%s";
196+
String methodCallMethod = returnSwiftType.staticReturnTypeFunc(isReturnTypeOptional);
197+
jniMethodTemplate = "let optionalResult = JNI." + methodCallMethod + "(javaClass, %s.javaMethod%s";
178198
}
179199
}
180200
else {
@@ -208,25 +228,29 @@ void generateCode(SwiftWriter swiftWriter, String javaFullName, String swiftType
208228
swiftWriter.emitStatement("}");
209229

210230
if (returnSwiftType != null) {
211-
swiftWriter.emitStatement("guard let result = optionalResult else {");
212-
if (isReturnTypeOptional) {
213-
swiftWriter.emitStatement("return nil");
231+
if (!isReturnTypeOptional && returnSwiftType.isPrimitiveType()) {
232+
swiftWriter.emitStatement("return optionalResult");
214233
}
215234
else {
216-
swiftWriter.emitStatement("fatalError(\"Don't support nil here!\")");
235+
swiftWriter.emitStatement("guard let result = optionalResult else {");
236+
if (isReturnTypeOptional) {
237+
swiftWriter.emitStatement("return nil");
238+
} else {
239+
swiftWriter.emitStatement("fatalError(\"Don't support nil here!\")");
240+
}
241+
swiftWriter.emitStatement("}");
242+
243+
swiftWriter.emitStatement("defer {");
244+
swiftWriter.emitStatement("JNI.DeleteLocalRef(result)");
245+
swiftWriter.emitStatement("}");
246+
swiftWriter.emitStatement("do {");
247+
swiftWriter.emitStatement(String.format("return try %s.from(javaObject: result)", returnSwiftType.swiftConstructorType));
248+
swiftWriter.emitStatement("}");
249+
swiftWriter.emitStatement("catch {");
250+
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
251+
swiftWriter.emitStatement("fatalError(errorString)");
252+
swiftWriter.emitStatement("}");
217253
}
218-
swiftWriter.emitStatement("}");
219-
220-
swiftWriter.emitStatement("defer {");
221-
swiftWriter.emitStatement("JNI.DeleteLocalRef(result)");
222-
swiftWriter.emitStatement("}");
223-
swiftWriter.emitStatement("do {");
224-
swiftWriter.emitStatement(String.format("return try %s.from(javaObject: result)", returnSwiftType.swiftConstructorType));
225-
swiftWriter.emitStatement("}");
226-
swiftWriter.emitStatement("catch {");
227-
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
228-
swiftWriter.emitStatement("fatalError(errorString)");
229-
swiftWriter.emitStatement("}");
230254
}
231255

232256
swiftWriter.emitStatement("}");

compiler/src/main/java/com/readdle/codegen/SwiftDelegateDescriptor.java

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.List;
1111

1212
import javax.annotation.processing.Filer;
13+
import javax.annotation.processing.Messager;
1314
import javax.lang.model.element.Element;
1415
import javax.lang.model.element.ElementKind;
1516
import javax.lang.model.element.ExecutableElement;
@@ -18,6 +19,7 @@
1819
import javax.lang.model.element.VariableElement;
1920
import javax.lang.model.type.DeclaredType;
2021
import javax.lang.model.type.MirroredTypeException;
22+
import javax.tools.Diagnostic;
2123
import javax.tools.StandardLocation;
2224

2325
import static com.readdle.codegen.JavaSwiftProcessor.FOLDER;
@@ -39,7 +41,7 @@ class SwiftDelegateDescriptor {
3941

4042
private boolean isInterface;
4143

42-
SwiftDelegateDescriptor(TypeElement classElement, Filer filer, JavaSwiftProcessor processor) throws IllegalArgumentException {
44+
SwiftDelegateDescriptor(TypeElement classElement, Filer filer, Messager messager, JavaSwiftProcessor processor) throws IllegalArgumentException {
4345
this.annotatedClassElement = classElement;
4446
this.isInterface = classElement.getKind() == ElementKind.INTERFACE;
4547
this.importPackages = processor.moduleDescriptor.importPackages;
@@ -135,26 +137,40 @@ class SwiftDelegateDescriptor {
135137
throw new IllegalArgumentException(String.format("%s doesn't contain release native method", simpleTypeName));
136138
}
137139
}
140+
try {
141+
142+
for (Element element : classElement.getEnclosedElements()) {
143+
messager.printMessage(Diagnostic.Kind.WARNING, "Element: " + element);
138144

139-
for (Element element : classElement.getEnclosedElements()) {
140-
if (element.getKind() == ElementKind.METHOD) {
141-
ExecutableElement executableElement = (ExecutableElement) element;
142-
// Except init. We generate it's manually
143-
if (executableElement.getModifiers().contains(Modifier.NATIVE) && !executableElement.getSimpleName().contentEquals("init")) {
144-
functions.add(new SwiftFuncDescriptor(executableElement, processor));
145+
if (element.getKind() == ElementKind.METHOD) {
146+
ExecutableElement executableElement = (ExecutableElement) element;
147+
// Except init. We generate it's manually
148+
if (executableElement.getModifiers().contains(Modifier.NATIVE) && !executableElement.getSimpleName().contentEquals("init")) {
149+
functions.add(new SwiftFuncDescriptor(executableElement, processor));
150+
}
145151
}
146-
}
147152

148-
if (element.getKind() == ElementKind.METHOD && element.getAnnotation(SwiftCallbackFunc.class) != null) {
149-
ExecutableElement executableElement = (ExecutableElement) element;
150-
if (executableElement.getModifiers().contains(Modifier.NATIVE)) {
151-
String message = String.format("%s is native method. Only java methods can be annotated with @%s",
152-
executableElement.getSimpleName(), SwiftCallbackFunc.class.getSimpleName());
153-
throw new SwiftMappingException(message, executableElement);
153+
if (element.getAnnotation(SwiftCallbackFunc.class) != null) {
154+
String message = String.format("%s SwiftCallbackFunc",
155+
element.getSimpleName());
156+
messager.printMessage(Diagnostic.Kind.WARNING, message);
154157
}
155158

156-
callbackFunctions.add(new SwiftCallbackFuncDescriptor(executableElement, processor));
159+
if (element.getKind() == ElementKind.METHOD && element.getAnnotation(SwiftCallbackFunc.class) != null) {
160+
ExecutableElement executableElement = (ExecutableElement) element;
161+
if (executableElement.getModifiers().contains(Modifier.NATIVE)) {
162+
String message = String.format("%s is native method. Only java methods can be annotated with @%s",
163+
executableElement.getSimpleName(), SwiftCallbackFunc.class.getSimpleName());
164+
throw new SwiftMappingException(message, executableElement);
165+
}
166+
167+
callbackFunctions.add(new SwiftCallbackFuncDescriptor(executableElement, processor));
168+
}
157169
}
170+
171+
}
172+
catch (Throwable e) {
173+
messager.printMessage(Diagnostic.Kind.WARNING, "Error: " + e.toString());
158174
}
159175
}
160176

0 commit comments

Comments
 (0)