Skip to content

Commit 0494620

Browse files
authored
Merge pull request #25 from readdle/feature/kotlin-support
Kotlin support
2 parents e1650c4 + beccdd0 commit 0494620

File tree

82 files changed

+5913
-664
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+5913
-664
lines changed

.github/workflows/android.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ jobs:
2828
- name: Download Android Emulator
2929
run: $ANDROID_HOME/tools/bin/sdkmanager "system-images;android-29;google_apis;x86_64"
3030
- name: Create Android Emulator
31-
run: $ANDROID_HOME/tools/bin/avdmanager create avd -n ci-test -k "system-images;android-29;google_apis;x86_64" -d "pixel"
31+
run: $ANDROID_HOME/tools/bin/avdmanager create avd -n ci-test -k "system-images;android-29;google_apis;x86_64" -d "pixel" --force
3232
- name: Start Android Emulator
33-
run: $ANDROID_HOME/emulator/emulator-headless -avd ci-test -noaudio > /dev/null &
33+
run: $ANDROID_HOME/emulator/emulator -no-window -avd ci-test -noaudio > /dev/null &
3434
- name: Run connected android tests
3535
run: export TOOLCHAINS=org.swift.50320190830a;
3636
export ANDROID_NDK_HOME=$(pwd)/android-ndk-r17c;

build.gradle

+2-2
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,7 +9,7 @@ buildscript {
99
}
1010

1111
dependencies {
12-
classpath "com.android.tools.build:gradle:3.6.0"
12+
classpath 'com.android.tools.build:gradle:3.6.0'
1313
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"

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

+64-24
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;
@@ -57,31 +58,31 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
5758
filer = processingEnv.getFiler();
5859
messager = processingEnv.getMessager();
5960

60-
messager.printMessage(Diagnostic.Kind.WARNING, "JavaSwiftProcessor init started");
61+
note("JavaSwiftProcessor init started");
6162

6263
String packageJson = processingEnv.getOptions().get(PACKAGE_OPTION);
6364

6465
moduleDescriptor = new Gson().fromJson(packageJson, SwiftModuleDescriptor.class);
6566
if (moduleDescriptor == null) {
66-
messager.printMessage(Diagnostic.Kind.ERROR, "No package description with option: com.readdle.codegen.package", null);
67+
error(null, "No package description with option: com.readdle.codegen.package");
6768
return;
6869
}
6970

70-
messager.printMessage(Diagnostic.Kind.WARNING, "Package moduleName: " + moduleDescriptor.moduleName);
71+
note("Package moduleName: " + moduleDescriptor.moduleName);
7172

7273
if (moduleDescriptor.importPackages != null) {
7374
for (String anImport : moduleDescriptor.importPackages) {
74-
messager.printMessage(Diagnostic.Kind.WARNING, "Package import: " + anImport);
75+
note("Package import: " + anImport);
7576
}
7677
}
7778

7879
if (moduleDescriptor.customTypeMappings != null) {
7980
for (String key : moduleDescriptor.customTypeMappings.keySet()) {
80-
messager.printMessage(Diagnostic.Kind.WARNING, "Package custom mapping: " + key + " -> " + moduleDescriptor.customTypeMappings.get(key));
81+
note("Package custom mapping: " + key + " -> " + moduleDescriptor.customTypeMappings.get(key));
8182
}
8283
}
8384

84-
messager.printMessage(Diagnostic.Kind.WARNING, "JavaSwiftProcessor init finished successfully");
85+
note("JavaSwiftProcessor init finished successfully");
8586
}
8687

8788
@Override
@@ -120,7 +121,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
120121

121122
private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
122123
Filer filer = processingEnv.getFiler();
123-
messager.printMessage(Diagnostic.Kind.WARNING, "JavaSwiftProcessor start code generation");
124+
note("JavaSwiftProcessor start code generation");
124125

125126
try {
126127
generateJavaSwift(filer);
@@ -129,13 +130,13 @@ private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnviron
129130
error(null, "Can't write to file: " + e.getMessage());
130131
}
131132

132-
messager.printMessage(Diagnostic.Kind.WARNING, "SwiftValue to process: "
133+
note("SwiftValue to process: "
133134
+ roundEnv.getElementsAnnotatedWith(SwiftValue.class).size());
134-
messager.printMessage(Diagnostic.Kind.WARNING, "SwiftReference to process: "
135+
note("SwiftReference to process: "
135136
+ roundEnv.getElementsAnnotatedWith(SwiftReference.class).size());
136-
messager.printMessage(Diagnostic.Kind.WARNING, "SwiftDelegate to process: "
137+
note("SwiftDelegate to process: "
137138
+ roundEnv.getElementsAnnotatedWith(SwiftDelegate.class).size());
138-
messager.printMessage(Diagnostic.Kind.WARNING, "SwiftBlock to process: "
139+
note("SwiftBlock to process: "
139140
+ roundEnv.getElementsAnnotatedWith(SwiftBlock.class).size());
140141

141142
Map<String, SwiftValueDescriptor> swiftValues = new HashMap<>();
@@ -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) {
@@ -241,9 +242,9 @@ private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnviron
241242
try {
242243
File file = valueDescriptor.generateCode();
243244
/* Logging */
244-
messager.printMessage(Diagnostic.Kind.WARNING, "Generate SwiftValue " + file.getName() + ":");
245+
note("Generate SwiftValue " + file.getName() + ":");
245246
for (WritableElement function : valueDescriptor.getFunctions()) {
246-
messager.printMessage(Diagnostic.Kind.NOTE, function.toString(valueDescriptor.getJavaFullName()));
247+
note(function.toString(valueDescriptor.getJavaFullName()));
247248
}
248249
/* Logging */
249250
} catch (IOException e) {
@@ -257,9 +258,9 @@ private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnviron
257258
try {
258259
File file = referenceDescriptor.generateCode();
259260
/* Logging */
260-
messager.printMessage(Diagnostic.Kind.WARNING, "Generate SwiftReference " + file.getName() + ":");
261+
note("Generate SwiftReference " + file.getName() + ":");
261262
for (WritableElement function : referenceDescriptor.functions) {
262-
messager.printMessage(Diagnostic.Kind.NOTE, function.toString(referenceDescriptor.getJavaFullName()));
263+
note(function.toString(referenceDescriptor.getJavaFullName()));
263264
}
264265
/* Logging */
265266
} catch (IOException e) {
@@ -273,9 +274,9 @@ private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnviron
273274
try {
274275
File file = delegateDescriptor.generateCode();
275276
/* Logging */
276-
messager.printMessage(Diagnostic.Kind.WARNING, "Generate SwiftDelegate" + file.getName() + ":");
277+
note("Generate SwiftDelegate" + file.getName() + ":");
277278
for (WritableElement function : delegateDescriptor.functions) {
278-
messager.printMessage(Diagnostic.Kind.NOTE, function.toString(delegateDescriptor.getJavaFullName()));
279+
note(function.toString(delegateDescriptor.getJavaFullName()));
279280
}
280281
/* Logging */
281282
} catch (IOException e) {
@@ -289,7 +290,7 @@ private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnviron
289290
try {
290291
File file = blockDescriptor.generateCode();
291292
/* Logging */
292-
messager.printMessage(Diagnostic.Kind.WARNING, "Generate SwiftBlock" + file.getName());
293+
note("Generate SwiftBlock" + file.getName());
293294
/* Logging */
294295
} catch (IOException e) {
295296
e.printStackTrace();
@@ -298,7 +299,7 @@ private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnviron
298299
}
299300
}
300301

301-
messager.printMessage(Diagnostic.Kind.WARNING, "JavaSwiftProcessor finished successfully!");
302+
note("JavaSwiftProcessor finished successfully!");
302303

303304
return false;
304305
}
@@ -307,7 +308,7 @@ private void generateJavaSwift(Filer filer) throws IOException {
307308
String swiftFilePath = filer.getResource(StandardLocation.SOURCE_OUTPUT, FOLDER, "SwiftJava.swift").toUri().getPath();
308309
File swiftExtensionFile = new File(swiftFilePath);
309310
swiftExtensionFile.getParentFile().mkdir();
310-
messager.printMessage(Diagnostic.Kind.WARNING, "JavaSwiftProcessor will generate sources at: " + swiftExtensionFile.getParent());
311+
note("JavaSwiftProcessor will generate sources at: " + swiftExtensionFile.getParent());
311312
SwiftWriter swiftWriter = new SwiftWriter(swiftExtensionFile);
312313
swiftWriter.emitImports(new String[0]);
313314
swiftWriter.emitEmptyLine();
@@ -329,11 +330,25 @@ private void generateJavaSwift(Filer filer) throws IOException {
329330
swiftWriter.close();
330331
}
331332

332-
private void error(Element e, String msg, Object... args) {
333+
void note(String msg) {
334+
messager.printMessage(Diagnostic.Kind.WARNING, msg);
335+
}
336+
337+
void error(Element e, String msg, Object... args) {
333338
messager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args), e);
334339
}
335340

336-
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+
}
337352
List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
338353
for (AnnotationMirror mirror : mirrors) {
339354
Name simpleName = mirror.getAnnotationType().asElement().getSimpleName();
@@ -347,6 +362,17 @@ static boolean isNullable(Element element) {
347362
return true;
348363
}
349364

365+
boolean isUnsigned(Element element) {
366+
List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
367+
for (AnnotationMirror mirror : mirrors) {
368+
Name simpleName = mirror.getAnnotationType().asElement().getSimpleName();
369+
if (simpleName.contentEquals("Unsigned")) {
370+
return true;
371+
}
372+
}
373+
return false;
374+
}
375+
350376
static String replaceLast(String text, char replace, char replacement) {
351377
int index = text.lastIndexOf(replace);
352378
if (index >= 0) {
@@ -356,12 +382,26 @@ static String replaceLast(String text, char replace, char replacement) {
356382
}
357383

358384
public SwiftEnvironment.Type parseJavaType(String javaType) {
359-
if (moduleDescriptor.customTypeMappings.containsKey(javaType)) {
385+
if (moduleDescriptor.customTypeMappings != null && moduleDescriptor.customTypeMappings.containsKey(javaType)) {
360386
return new SwiftEnvironment.Type(moduleDescriptor.customTypeMappings.get(javaType), javaType);
361387
}
362388
switch (javaType) {
363389
case "void":
364390
return null;
391+
case "byte":
392+
return new SwiftEnvironment.Type("Int8", javaType);
393+
case "short":
394+
return new SwiftEnvironment.Type("Int16", javaType);
395+
case "int":
396+
return new SwiftEnvironment.Type("Int", javaType);
397+
case "long":
398+
return new SwiftEnvironment.Type("Int64", javaType);
399+
case "float":
400+
return new SwiftEnvironment.Type("Float", javaType);
401+
case "double":
402+
return new SwiftEnvironment.Type("Double", javaType);
403+
case "boolean":
404+
return new SwiftEnvironment.Type("Bool", javaType);
365405
case "java.lang.Integer":
366406
return new SwiftEnvironment.Type("Int", javaType);
367407
case "java.lang.Byte":

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

+42-17
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,14 @@ class SwiftBlockDescriptor {
8080
// Except init. We generate it's manually
8181
this.funcName = executableElement.getSimpleName().toString();
8282
this.isThrown = executableElement.getThrownTypes() != null && executableElement.getThrownTypes().size() > 0;
83-
this.returnSwiftType = processor.parseJavaType(executableElement.getReturnType().toString());
84-
this.isReturnTypeOptional = JavaSwiftProcessor.isNullable(executableElement);
83+
this.isReturnTypeOptional = processor.isNullable(executableElement);
84+
boolean isReturnTypeUnsigned = processor.isUnsigned(executableElement);
85+
if (isReturnTypeUnsigned) {
86+
this.returnSwiftType = processor.parseJavaType(executableElement.getReturnType().toString()).makeUnsigned();
87+
}
88+
else {
89+
this.returnSwiftType = processor.parseJavaType(executableElement.getReturnType().toString());
90+
}
8591

8692
this.sig = "(";
8793

@@ -160,7 +166,9 @@ File generateCode() throws IOException {
160166
}
161167

162168
if (params.size() > 0) {
169+
163170
swiftWriter.emitStatement("do {");
171+
164172
for (int i = 0; i < params.size(); i++) {
165173
SwiftParamDescriptor param = params.get(i);
166174
if (param.isOptional) {
@@ -171,7 +179,12 @@ File generateCode() throws IOException {
171179
swiftWriter.emitStatement(String.format("java_%s = jnull()", param.name));
172180
swiftWriter.emitStatement("}");
173181
} else {
174-
swiftWriter.emitStatement(String.format("java_%s = try $%s.javaObject()", param.name, i + ""));
182+
if (param.isPrimitive()) {
183+
swiftWriter.emitStatement(String.format("java_%s = try $%s.javaPrimitive()", param.name, i + ""));
184+
}
185+
else {
186+
swiftWriter.emitStatement(String.format("java_%s = try $%s.javaObject()", param.name, i + ""));
187+
}
175188
}
176189
}
177190

@@ -185,11 +198,13 @@ File generateCode() throws IOException {
185198
swiftWriter.emitStatement("fatalError(errorString)");
186199
}
187200
swiftWriter.emitStatement("}");
201+
188202
}
189203

190204
String jniMethodTemplate;
191205
if (returnSwiftType != null) {
192-
jniMethodTemplate = "let optionalResult = JNI.CallObjectMethod(self.jniObject, %s.javaMethod%s";
206+
String methodCallMethod = returnSwiftType.returnTypeFunc(isReturnTypeOptional);
207+
jniMethodTemplate = "let optionalResult = JNI." + methodCallMethod + "(self.jniObject, %s.javaMethod%s";
193208
}
194209
else {
195210
jniMethodTemplate = "JNI.CallVoidMethod(self.jniObject, %s.javaMethod%s";
@@ -217,19 +232,29 @@ File generateCode() throws IOException {
217232
swiftWriter.emitStatement("}");
218233

219234
if (returnSwiftType != null) {
220-
swiftWriter.emitStatement("guard let result = optionalResult else {");
221-
swiftWriter.emitStatement(isReturnTypeOptional ? "return nil" : "fatalError(\"Don't support nil here!\")");
222-
swiftWriter.emitStatement("}");
223-
swiftWriter.emitStatement("defer {");
224-
swiftWriter.emitStatement("JNI.DeleteLocalRef(result)");
225-
swiftWriter.emitStatement("}");
226-
swiftWriter.emitStatement("do {");
227-
swiftWriter.emitStatement(String.format("return try %s.from(javaObject: result)", returnSwiftType.swiftConstructorType));
228-
swiftWriter.emitStatement("}");
229-
swiftWriter.emitStatement("catch {");
230-
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
231-
swiftWriter.emitStatement("fatalError(errorString)");
232-
swiftWriter.emitStatement("}");
235+
if (!isReturnTypeOptional && returnSwiftType.isPrimitiveType()) {
236+
swiftWriter.emitStatement("return " + returnSwiftType.swiftType + "(fromJavaPrimitive: optionalResult)");
237+
}
238+
else {
239+
swiftWriter.emitStatement("guard let result = optionalResult else {");
240+
if (isReturnTypeOptional) {
241+
swiftWriter.emitStatement("return nil");
242+
} else {
243+
swiftWriter.emitStatement("fatalError(\"Don't support nil here!\")");
244+
}
245+
swiftWriter.emitStatement("}");
246+
247+
swiftWriter.emitStatement("defer {");
248+
swiftWriter.emitStatement("JNI.DeleteLocalRef(result)");
249+
swiftWriter.emitStatement("}");
250+
swiftWriter.emitStatement("do {");
251+
swiftWriter.emitStatement(String.format("return try %s.from(javaObject: result)", returnSwiftType.swiftConstructorType));
252+
swiftWriter.emitStatement("}");
253+
swiftWriter.emitStatement("catch {");
254+
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
255+
swiftWriter.emitStatement("fatalError(errorString)");
256+
swiftWriter.emitStatement("}");
257+
}
233258
}
234259

235260
swiftWriter.emitStatement("}");

0 commit comments

Comments
 (0)