├── .github └── workflows │ └── gradle.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── Readme.md ├── annotations ├── build.gradle └── src │ └── commonMain │ └── kotlin │ └── de │ └── ffuf │ └── kotlin │ └── multiplatform │ └── annotations │ ├── Annotations.kt │ └── SuspendResult.kt ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── kotlin │ └── de │ └── ffuf │ └── kotlin │ └── multiplatform │ └── processor │ ├── NativeSuspendFunctionsGradlePlugin.kt │ └── NativeSuspendFunctionsGradleSubplugin.kt ├── docs └── images │ ├── KonanDebug.png │ ├── kotlincompilerdebug.png │ ├── logJs.png │ ├── logJvm.png │ ├── logNative.png │ └── terminaldebugnative.png ├── example ├── build.gradle └── src │ ├── commonMain │ └── kotlin │ │ └── CommonAnnotated.kt │ ├── jsMain │ └── kotlin │ │ └── de │ │ └── jensklingenberg │ │ └── mpapt │ │ ├── Generated.kt │ │ ├── JSAnnotated.kt │ │ └── JsSecondAnnotated.kt │ └── jvmMain │ └── kotlin │ └── de │ └── jensklingenberg │ └── mpapt │ ├── Generated.kt │ └── JVMAnnotated.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── kotlin-plugin ├── build.gradle └── src │ └── main │ └── java │ └── de │ └── ffuf │ └── kotlin │ └── multiplatform │ └── processor │ └── registrar │ ├── CommonComponentRegistrar.kt │ └── NativeSuspendedFunctionProcessor.kt ├── mpapt-runtime ├── build.gradle └── src │ └── main │ └── java │ └── de │ └── jensklingenberg │ └── mpapt │ ├── Notes.txt │ ├── common │ ├── AnnotationDescriptorExt.kt │ ├── ClassDescriptorExt.kt │ ├── ClassParser.kt │ ├── Ext.kt │ ├── FunctionDescriptorExt.kt │ ├── ModuleDescriptorExt.kt │ ├── MpAptProject.kt │ └── PropertyDescriptorExt.kt │ ├── extension │ ├── ClassBuilderInterceptorExtensionImpl.kt │ ├── CompilerConfigurationExtensionExt.kt │ ├── DelegatingClassBuilderImpl.kt │ ├── ExpressionCodegenExtensionImpl.kt │ ├── MetaPreprocessedVirtualFileFactoryExtension.kt │ ├── NativeIrGenerationExtension.kt │ ├── StorageComponentContainerContributorImpl.kt │ ├── SyntheticResolveExtensionImpl.kt │ ├── js │ │ └── JsSyntheticTranslateExtensionExt.kt │ └── unused │ │ └── AnalysisHandlerExtensionImpl.kt │ ├── model │ ├── AbstractProcessor.kt │ ├── Element.kt │ ├── FunctionParameter.kt │ ├── Platform.kt │ ├── ProcessingEnvironment.kt │ ├── Processor.kt │ ├── ProcessorProject.kt │ ├── RoundEnvironment.kt │ └── SourceVersion.kt │ └── utils │ ├── KonanTargetValues.kt │ └── KotlinPlatformValues.kt └── settings.gradle /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Set up JDK 1.8 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 1.8 16 | - name: Build with Gradle 17 | run: ./gradlew :annotations:publishToMavenLocal 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /mpapt/build/ 2 | /kotlin-plugin/build/ 3 | /gradle-plugin/build/ 4 | /example/build/ 5 | /.idea/ 6 | /annotations/build/ 7 | /kotlin-compiler-native-plugin/build/ 8 | /.gradle/ 9 | /build/ 10 | /mpapt-runtime/build/* 11 | /kotlin-plugin-shared/build/ 12 | /buildSrc/build/ 13 | /buildSrc/.gradle/ 14 | /kotlin-compiler-native-plugin/out/ 15 | /mpapt-runtime/out/ 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | ## [1.0.15] - *(2019-09-09)* 4 | 5 | ### Fixed 6 | - generated annotations also include their values 7 | - fix with `.launch { }` creation for long functions 8 | 9 | ## [1.0.14] - *(2019-09-09)* 10 | 11 | ### Added 12 | Initial release 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 |

Native Suspended Functions - Generates a wrapper with a callback for suspended functions for Kotlin Native to consume

2 | 3 | [![Kotlin](https://img.shields.io/badge/Kotlin-1.3.50-green.svg)](https://github.com/Foso/MpApt/blob/master/LICENSE) 4 | [![License](https://img.shields.io/badge/Apache-2.0-green.svg)](https://github.com/Foso/MpApt/blob/master/LICENSE) 5 | [ ![Download](https://api.bintray.com/packages/jonasbark/ffuf/nativesuspendfunction-compiler/images/download.svg) ](https://bintray.com/jonasbark/ffuf/nativesuspendfunction-compiler/) 6 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) 7 | Tweet 9 | 10 | 11 | 12 | ## Introduction 13 | As suspended functions aren't visible from Kotlin Native I created this plugin that adds support for annotating existing 14 | functions with `@NativeSuspendedFunction`. The plugin will find these methods and generate a Kotlin source code file 15 | that uses callbacks that can be used from Kotlin Native. 16 | 17 | Additionally you may use `@NativeFlowFunction` to generate a wrapper around a function that returns a Flow - something that 18 | Kotlin Native also cannot handle right now. 19 | 20 | This plugin uses mpapt-runtime from Jens Klingenberg: https://github.com/Foso/MpApt 21 | 22 | ## Example 23 | Class with annotated suspended function: 24 | ```kotlin 25 | class CommonAnnotated { 26 | 27 | @NativeSuspendedFunction 28 | internal suspend fun firstFunction2(id: Datum, type: Double?): Int { 29 | return 0 30 | } 31 | 32 | @ExperimentalCoroutinesApi 33 | @NativeFlowFunction 34 | fun subscribeToMowerChanges(test: Int): Flow { 35 | return callbackFlow { 36 | offer(GlobalScope) 37 | } 38 | } 39 | 40 | } 41 | ``` 42 | Generated extension: 43 | ```kotlin 44 | internal fun CommonAnnotated.firstFunction2( 45 | id: Datum, 46 | type: Double?, 47 | callback: (SuspendResult) -> Unit 48 | ) = mainScope.launch { 49 | callback(suspendRunCatching { firstFunction2(id, type) }) 50 | } 51 | 52 | @ExperimentalCoroutinesApi 53 | fun CommonAnnotated.testFlowFunction(test: Int, callback: (CoroutineScope) -> Unit) = 54 | GlobalScope.launch { 55 | testFlowFunction(test).collect { 56 | callback(it) 57 | } 58 | } 59 | ``` 60 | The class `SuspendResult` is an implementation of https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/index.html 61 | that was made compatible with Kotlin Native (no inline functions etc.) 62 | 63 | Currently the plugin only supports: 64 | - copying over annotations 65 | - parameters + their nullability (no default values) 66 | 67 | Please check other limitations on https://github.com/Foso/MpApt 68 | 69 | Feel free to open tickets for new features. 70 | 71 | ## Usage 72 | 73 | Inside your projects build.gradle(.kts) add the following plugin: 74 | 75 | ```groovy 76 | repositories { 77 | jcenter() 78 | } 79 | 80 | plugins { 81 | id("native-suspend-function") version "1.0.18" 82 | // or as dependency: "de.ffuf.kotlin.multiplatform.processor:nativesuspendfunction:1.0.18" 83 | } 84 | 85 | // also add the annotations as dependency: 86 | dependencies { 87 | // multiplatform binaries are ready - please have a look at the example project 88 | implementation("de.ffuf.kotlin.multiplatform.annotations:annotations:1.0.18") 89 | } 90 | 91 | ``` 92 | and in your `pluginManagement`: 93 | ```kotlin 94 | pluginManagement { 95 | repositories { 96 | // .... 97 | jcenter() 98 | } 99 | // .... 100 | resolutionStrategy { 101 | eachPlugin { 102 | // .... 103 | if (requested.id.id == "native-suspend-function") { 104 | useModule("de.ffuf.kotlin.multiplatform.processor:nativesuspendfunction:${requested.version}") 105 | } 106 | } 107 | } 108 | } 109 | ``` 110 | 111 | ## Configuration 112 | The compiler plugin unfortunately won't be able to resolve all needed imports but you may add them in the configuration: 113 | ```kotlin 114 | nativeSuspendExtension { 115 | outputDirectory = "src/commonMain/kotlin" // this is the default output directory for the generated extension file (without package) 116 | scopeName = "mainScope" // in our case we use a CoroutineScope called "mainScope" - don#t forget to import that location 117 | imports = listOf("test.import.package") // additional imports for the generated file 118 | packageName = "de.ffuf.kotlin.extensions" //allows configuring the package name of the generated file 119 | } 120 | ``` 121 | 122 | ## Release notes 123 | For unknown reasons, uploading the kotlin-plugin doesn't upload the buildSrc package as well. 124 | So, publish it to mavenLocal first, then manually upload those files to: 125 | `/de/ffuf/kotlin/multiplatform/processor/nativesuspendfunction/1.0.**` 126 | 127 | ## License 128 | 129 | This project is licensed under the Apache License, Version 2.0 - see the [LICENSE.md](https://github.com/feilfeilundfeil/kotlin-native-suspend-function-callback/blob/master/LICENSE) file for details 130 | 131 | ------- 132 | 133 | Copyright 2019 FFUF 134 | 135 | Licensed under the Apache License, Version 2.0 (the "License"); 136 | you may not use this file except in compliance with the License. 137 | You may obtain a copy of the License at 138 | 139 | http://www.apache.org/licenses/LICENSE-2.0 140 | 141 | Unless required by applicable law or agreed to in writing, software 142 | distributed under the License is distributed on an "AS IS" BASIS, 143 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 144 | See the License for the specific language governing permissions and 145 | limitations under the License. 146 | 147 | 148 | -------------------------------------------------------------------------------- /annotations/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | ext.buildMaven = { p -> repositories { maven { url p } } } 4 | 5 | 6 | repositories { 7 | mavenLocal() 8 | google() 9 | jcenter() 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.+' 15 | } 16 | 17 | } 18 | 19 | plugins { 20 | id 'org.jetbrains.kotlin.multiplatform' version '1.3.50' 21 | id("maven-publish") 22 | } 23 | apply plugin: 'com.jfrog.bintray' 24 | 25 | group = "de.ffuf.kotlin.multiplatform.annotations" 26 | version = plugin_version 27 | 28 | repositories { 29 | 30 | jcenter() 31 | mavenCentral() 32 | } 33 | 34 | 35 | task emptyJar(type: Jar) { 36 | } 37 | 38 | task emptySourceJar(type: Jar) { 39 | classifier = 'sources' 40 | from sourceSets 41 | } 42 | 43 | task stubJavadoc(type: Jar) { 44 | classifier 'javadoc' 45 | } 46 | 47 | task sourcesJar(type: Jar) { 48 | classifier = 'sources' 49 | from sourceSets 50 | } 51 | 52 | 53 | def pomConfig = { 54 | licenses { 55 | license { 56 | name 'The Apache Software License, Version 2.0' 57 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 58 | distribution 'repo' 59 | } 60 | } 61 | developers { 62 | developer { 63 | id "Jonas Bark" 64 | name "Jonas Bark" 65 | organization "FFUF" 66 | organizationUrl "http://twitter.com/boni2k" 67 | } 68 | developer { 69 | id "FFUF" 70 | name "Feil Feil & Feil GmbH" 71 | organization "FFUF" 72 | organizationUrl "http://www.ffuf.de" 73 | } 74 | } 75 | scm { 76 | url "https://github.com/feilfeilundfeil/kotlin-native-suspend-function-callback" 77 | } 78 | } 79 | 80 | 81 | 82 | project.ext.configureMavenCentralMetadata = { pom -> 83 | def root = asNode() 84 | root.appendNode('name', "kotlin-native-suspend-function-callback-annotations") 85 | root.appendNode('description', 'Annotations for kotlin-native-suspend-function-callback') 86 | root.appendNode('url', 'https://ffuf.de') 87 | root.children().last() + pomConfig 88 | 89 | def dependenciesNode = asNode().getAt("dependencies")[0] 90 | if (dependenciesNode != null) { 91 | def dependencyNode = dependenciesNode.appendNode('dependency') 92 | dependencyNode.appendNode('groupId', "$group") 93 | dependencyNode.appendNode('artifactId', "$project.name") 94 | dependencyNode.appendNode('version', "$project.version") 95 | } 96 | } 97 | 98 | kotlin { 99 | jvm { 100 | mavenPublication { 101 | pom.withXml(configureMavenCentralMetadata) 102 | //artifact(sourcesJar) 103 | } 104 | } 105 | js() 106 | iosX64 { 107 | mavenPublication { 108 | pom.withXml(configureMavenCentralMetadata) 109 | artifact(emptyJar) 110 | //artifact(sourcesJar) 111 | } 112 | } 113 | iosArm64 { 114 | mavenPublication { 115 | pom.withXml(configureMavenCentralMetadata) 116 | artifact(emptyJar) 117 | } 118 | } 119 | iosArm32 { 120 | mavenPublication { 121 | pom.withXml(configureMavenCentralMetadata) 122 | artifact(emptyJar) 123 | //artifact(sourcesJar) 124 | } 125 | } 126 | 127 | sourceSets { 128 | commonMain { 129 | dependencies { 130 | implementation kotlin('stdlib-common') 131 | 132 | } 133 | } 134 | commonTest { 135 | dependencies { 136 | implementation kotlin('test-common') 137 | implementation kotlin('test-annotations-common') 138 | } 139 | } 140 | 141 | jsMain { 142 | dependencies { 143 | implementation kotlin('stdlib-js') 144 | 145 | } 146 | } 147 | jsTest { 148 | dependencies { 149 | implementation kotlin('test-js') 150 | } 151 | } 152 | 153 | jvmMain { 154 | dependencies { 155 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" 156 | } 157 | } 158 | jsTest { 159 | dependencies { 160 | implementation kotlin('test-js') 161 | } 162 | } 163 | 164 | iosX64Main { 165 | dependencies { 166 | 167 | } 168 | } 169 | 170 | iosArm64Main { 171 | dependencies { 172 | 173 | } 174 | } 175 | 176 | } 177 | } 178 | 179 | build.finalizedBy(publishToMavenLocal) 180 | publishing { 181 | publications { 182 | kotlinMultiplatform { 183 | artifactId = "annotations" 184 | artifact(emptyJar) 185 | } 186 | } 187 | repositories { 188 | maven { 189 | //url "${System.getProperty('user.home')}/.m2/repository" 190 | url 'https://api.bintray.com/maven/jonasbark/ffuf/kotlin-native-suspend-function-callback-annotations' 191 | credentials { 192 | username = bintray_user 193 | password = bintray_api_key 194 | } 195 | } 196 | } 197 | } 198 | 199 | /*def selectArtifactId(project, type, defaultName) { 200 | def name = project.name 201 | 202 | switch (type) { 203 | case 'metadata': 204 | return "$name" 205 | break 206 | case 'kotlinMultiplatform': 207 | return "$name-native" 208 | break 209 | case 'jvm': 210 | return "$name-jvm" 211 | break 212 | default: 213 | return defaultName// : "$name" 214 | break 215 | } 216 | } 217 | 218 | publishing { 219 | publications.all { 220 | pom.withXml(configureMavenCentralMetadata) 221 | 222 | def type = it.name 223 | def id = selectArtifactId(project, type, it.artifactId) 224 | it.artifactId = id 225 | if (id.endsWith('native')) { 226 | it.artifact stubJavadoc 227 | it.artifact emptySourceJar 228 | it.artifact emptyJar 229 | } 230 | } 231 | 232 | kotlin.targets.all { target -> 233 | def publication = publishing.publications.findByName(target.name) 234 | 235 | if (publication != null) { 236 | publication.artifact stubJavadoc 237 | 238 | if (target.platformType.name != 'native') { 239 | publication.moduleDescriptorGenerator = null 240 | } else { 241 | publication.artifact emptyJar 242 | } 243 | } 244 | } 245 | 246 | // Disable gradle metadata in root jvm modules 247 | def hasNative = project.ext.has("hasNative") && project.ext.hasNative 248 | if (!hasNative) { 249 | def rootPublication = publishing.publications.findByName('kotlinMultiplatform') 250 | rootPublication.moduleDescriptorGenerator = null 251 | } 252 | }*/ 253 | 254 | /*bintray { 255 | user = bintray_user 256 | key = bintray_api_key 257 | pkg { 258 | repo = "ffuf" 259 | name = "kotlin-native-suspend-function-callback-annotations" 260 | licenses = ['Apache-2.0'] 261 | websiteUrl = "https://ffuf.de" 262 | vcsUrl = 'https://github.com/feilfeilundfeil/kotlin-native-suspend-function-callback' 263 | version { 264 | name = project.version 265 | desc = 'Initial bintray release' 266 | released = new Date() 267 | } 268 | 269 | } 270 | } 271 | 272 | bintrayUpload.doFirst { 273 | publications = [] 274 | def projectPublications = project.publishing.publications 275 | for (publication in projectPublications) { 276 | if (publication.artifactId.endsWith("-test")) { 277 | continue 278 | } 279 | publications += publication.name 280 | } 281 | }*/ 282 | bintrayUpload.dependsOn(publishToMavenLocal) 283 | -------------------------------------------------------------------------------- /annotations/src/commonMain/kotlin/de/ffuf/kotlin/multiplatform/annotations/Annotations.kt: -------------------------------------------------------------------------------- 1 | package de.ffuf.kotlin.multiplatform.annotations 2 | 3 | @Target(AnnotationTarget.FUNCTION) 4 | annotation class NativeSuspendedFunction() 5 | 6 | @Target(AnnotationTarget.FUNCTION) 7 | annotation class NativeFlowFunction() 8 | -------------------------------------------------------------------------------- /annotations/src/commonMain/kotlin/de/ffuf/kotlin/multiplatform/annotations/SuspendResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. 3 | * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. 4 | */ 5 | 6 | @file:Suppress("UNCHECKED_CAST", "RedundantVisibilityModifier") 7 | 8 | package de.ffuf.kotlin.multiplatform.annotations 9 | 10 | import kotlin.jvm.JvmField 11 | 12 | /** 13 | * A discriminated union that encapsulates successful outcome with a value of type [T] 14 | * or a failure with an arbitrary [Throwable] exception. 15 | */ 16 | @Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS") 17 | @SinceKotlin("1.3") 18 | public class SuspendResult @PublishedApi internal constructor( 19 | @PublishedApi 20 | internal val value: Any? 21 | ) { 22 | // discovery 23 | 24 | /** 25 | * Returns `true` if this instance represents successful outcome. 26 | * In this case [isFailure] returns `false`. 27 | */ 28 | public val isSuccess: Boolean get() = value !is Failure 29 | 30 | /** 31 | * Returns `true` if this instance represents failed outcome. 32 | * In this case [isSuccess] returns `false`. 33 | */ 34 | public val isFailure: Boolean get() = value is Failure 35 | 36 | // value & exception retrieval 37 | 38 | /** 39 | * Returns the encapsulated value if this instance represents [success][SuspendResult.isSuccess] or `null` 40 | * if it is [failure][SuspendResult.isFailure]. 41 | * 42 | * This function is shorthand for `getOrElse { null }` (see [getOrElse]) or 43 | * `fold(onSuccess = { it }, onFailure = { null })` (see [fold]). 44 | */ 45 | public fun getOrNull(): T? = 46 | when { 47 | isFailure -> null 48 | else -> value as T 49 | } 50 | 51 | /** 52 | * Returns the encapsulated exception if this instance represents [failure][isFailure] or `null` 53 | * if it is [success][isSuccess]. 54 | * 55 | * This function is shorthand for `fold(onSuccess = { null }, onFailure = { it })` (see [fold]). 56 | */ 57 | public fun exceptionOrNull(): Throwable? = 58 | when (value) { 59 | is Failure -> value.exception 60 | else -> null 61 | } 62 | 63 | /** 64 | * Throws exception if the result is failure. This internal function minimizes 65 | * inlined bytecode for [getOrThrow] and makes sure that in the future we can 66 | * add some exception-augmenting logic here (if needed). 67 | */ 68 | @PublishedApi 69 | @SinceKotlin("1.3") 70 | internal fun SuspendResult<*>.throwOnFailure() { 71 | if (value is SuspendResult.Failure) throw value.exception 72 | } 73 | 74 | /** 75 | * Calls the specified function [block] and returns its encapsulated result if invocation was successful, 76 | * catching and encapsulating any thrown exception as a failure. 77 | */ 78 | 79 | // -- extensions --- 80 | 81 | /** 82 | * Returns the encapsulated value if this instance represents [success][SuspendResult.isSuccess] or throws the encapsulated exception 83 | * if it is [failure][SuspendResult.isFailure]. 84 | * 85 | * This function is shorthand for `getOrElse { throw it }` (see [getOrElse]). 86 | */ 87 | 88 | @SinceKotlin("1.3") 89 | public fun getOrThrow(): T { 90 | throwOnFailure() 91 | return value as T 92 | } 93 | 94 | /** 95 | * Returns the encapsulated value if this instance represents [success][SuspendResult.isSuccess] or the 96 | * result of [onFailure] function for encapsulated exception if it is [failure][SuspendResult.isFailure]. 97 | * 98 | * Note, that an exception thrown by [onFailure] function is rethrown by this function. 99 | * 100 | * This function is shorthand for `fold(onSuccess = { it }, onFailure = onFailure)` (see [fold]). 101 | */ 102 | 103 | @SinceKotlin("1.3") 104 | public fun getOrElse(onFailure: (exception: Throwable) -> T): T { 105 | return when (val exception = exceptionOrNull()) { 106 | null -> value as T 107 | else -> onFailure(exception) 108 | } 109 | } 110 | 111 | /** 112 | * Returns the encapsulated value if this instance represents [success][SuspendResult.isSuccess] or the 113 | * [defaultValue] if it is [failure][SuspendResult.isFailure]. 114 | * 115 | * This function is shorthand for `getOrElse { defaultValue }` (see [getOrElse]). 116 | */ 117 | 118 | /*@SinceKotlin("1.3") 119 | public fun getOrDefault(defaultValue: T): T { 120 | if (isFailure) return defaultValue 121 | return value as R 122 | }*/ //TODO 123 | 124 | /** 125 | * Returns the the result of [onSuccess] for encapsulated value if this instance represents [success][SuspendResult.isSuccess] 126 | * or the result of [onFailure] function for encapsulated exception if it is [failure][SuspendResult.isFailure]. 127 | * 128 | * Note, that an exception thrown by [onSuccess] or by [onFailure] function is rethrown by this function. 129 | */ 130 | 131 | @SinceKotlin("1.3") 132 | public fun fold( 133 | onSuccess: (value: T) -> T, 134 | onFailure: (exception: Throwable) -> T 135 | ): T { 136 | return when (val exception = exceptionOrNull()) { 137 | null -> onSuccess(value as T) 138 | else -> onFailure(exception) 139 | } 140 | } 141 | 142 | // transformation 143 | 144 | /** 145 | * Returns the encapsulated result of the given [transform] function applied to encapsulated value 146 | * if this instance represents [success][SuspendResult.isSuccess] or the 147 | * original encapsulated exception if it is [failure][SuspendResult.isFailure]. 148 | * 149 | * Note, that an exception thrown by [transform] function is rethrown by this function. 150 | * See [mapCatching] for an alternative that encapsulates exceptions. 151 | */ 152 | 153 | @SinceKotlin("1.3") 154 | public fun map(transform: (value: T) -> T): SuspendResult { 155 | return when { 156 | isSuccess -> SuspendResult.success(transform(value as T)) 157 | else -> SuspendResult(value) 158 | } 159 | } 160 | 161 | /** 162 | * Returns the encapsulated result of the given [transform] function applied to encapsulated value 163 | * if this instance represents [success][SuspendResult.isSuccess] or the 164 | * original encapsulated exception if it is [failure][SuspendResult.isFailure]. 165 | * 166 | * Any exception thrown by [transform] function is caught, encapsulated as a failure and returned by this function. 167 | * See [map] for an alternative that rethrows exceptions. 168 | */ 169 | 170 | @SinceKotlin("1.3") 171 | public suspend fun mapCatching(transform: (value: T) -> T): SuspendResult { 172 | return when { 173 | isSuccess -> suspendRunCatching { transform(value as T) } 174 | else -> SuspendResult(value) 175 | } 176 | } 177 | 178 | /** 179 | * Returns the encapsulated result of the given [transform] function applied to encapsulated exception 180 | * if this instance represents [failure][SuspendResult.isFailure] or the 181 | * original encapsulated value if it is [success][SuspendResult.isSuccess]. 182 | * 183 | * Note, that an exception thrown by [transform] function is rethrown by this function. 184 | * See [recoverCatching] for an alternative that encapsulates exceptions. 185 | */ 186 | 187 | @SinceKotlin("1.3") 188 | public fun recover(transform: (exception: Throwable) -> T): SuspendResult { 189 | return when (val exception = exceptionOrNull()) { 190 | null -> this 191 | else -> SuspendResult.success(transform(exception)) 192 | } 193 | } 194 | 195 | /** 196 | * Returns the encapsulated result of the given [transform] function applied to encapsulated exception 197 | * if this instance represents [failure][SuspendResult.isFailure] or the 198 | * original encapsulated value if it is [success][SuspendResult.isSuccess]. 199 | * 200 | * Any exception thrown by [transform] function is caught, encapsulated as a failure and returned by this function. 201 | * See [recover] for an alternative that rethrows exceptions. 202 | */ 203 | 204 | @SinceKotlin("1.3") 205 | public suspend fun recoverCatching(transform: (exception: Throwable) -> T): SuspendResult { 206 | val value = value // workaround for classes BE bug 207 | return when (val exception = exceptionOrNull()) { 208 | null -> this 209 | else -> suspendRunCatching { transform(exception) } 210 | } 211 | } 212 | 213 | // "peek" onto value/exception and pipe 214 | 215 | /** 216 | * Performs the given [action] on encapsulated exception if this instance represents [failure][SuspendResult.isFailure]. 217 | * Returns the original `Result` unchanged. 218 | */ 219 | 220 | @SinceKotlin("1.3") 221 | public fun onFailure(action: (exception: Throwable) -> Unit): SuspendResult { 222 | exceptionOrNull()?.let { action(it) } 223 | return this 224 | } 225 | 226 | /** 227 | * Performs the given [action] on encapsulated value if this instance represents [success][SuspendResult.isSuccess]. 228 | * Returns the original `Result` unchanged. 229 | */ 230 | 231 | @SinceKotlin("1.3") 232 | public fun onSuccess(action: (value: T) -> Unit): SuspendResult { 233 | if (isSuccess) action(value as T) 234 | return this 235 | } 236 | 237 | // ------------------- 238 | 239 | 240 | /** 241 | * Returns a string `Success(v)` if this instance represents [success][SuspendResult.isSuccess] 242 | * where `v` is a string representation of the value or a string `Failure(x)` if 243 | * it is [failure][isFailure] where `x` is a string representation of the exception. 244 | */ 245 | public override fun toString(): String = 246 | when (value) { 247 | is Failure -> value.toString() // "Failure($exception)" 248 | else -> "Success($value)" 249 | } 250 | 251 | // companion with constructors 252 | 253 | /** 254 | * Companion object for [SuspendResult] class that contains its constructor functions 255 | * [success] and [failure]. 256 | */ 257 | public companion object { 258 | /** 259 | * Returns an instance that encapsulates the given [value] as successful value. 260 | */ 261 | 262 | public fun success(value: T): SuspendResult = 263 | SuspendResult(value) 264 | 265 | /** 266 | * Returns an instance that encapsulates the given [exception] as failure. 267 | */ 268 | 269 | public fun failure(exception: Throwable): SuspendResult = 270 | SuspendResult(createFailure(exception)) 271 | } 272 | 273 | internal class Failure( 274 | @JvmField 275 | val exception: Throwable 276 | ) { 277 | override fun equals(other: Any?): Boolean = other is Failure && exception == other.exception 278 | override fun hashCode(): Int = exception.hashCode() 279 | override fun toString(): String = "Failure($exception)" 280 | } 281 | } 282 | 283 | /** 284 | * Creates an instance of internal marker [SuspendResult.Failure] class to 285 | * make sure that this class is not exposed in ABI. 286 | */ 287 | @PublishedApi 288 | @SinceKotlin("1.3") 289 | internal fun createFailure(exception: Throwable): Any = 290 | SuspendResult.Failure(exception) 291 | 292 | @SinceKotlin("1.3") 293 | public suspend inline fun suspendRunCatching(crossinline block: suspend () -> R): SuspendResult { 294 | return try { 295 | SuspendResult.success(block()) 296 | } catch (e: Throwable) { 297 | SuspendResult.failure(e) 298 | } 299 | } 300 | 301 | /** 302 | * Calls the specified function [block] with `this` value as its receiver and returns its encapsulated result 303 | * if invocation was successful, catching and encapsulating any thrown exception as a failure. 304 | */ 305 | 306 | @SinceKotlin("1.3") 307 | public inline fun T.suspendRunCatching(block: T.() -> T): SuspendResult { 308 | return try { 309 | SuspendResult.success(block()) 310 | } catch (e: Throwable) { 311 | SuspendResult.failure(e) 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | //./gradlew :example:clean :example:build --no-daemon -Dorg.gradle.debug=true -Dkotlin.compiler.execution.strategy="in-process" -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket\,address=5005\,server=y\,suspend=n" -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | 4 | 5 | repositories { 6 | mavenCentral() 7 | 8 | jcenter() 9 | } 10 | dependencies { 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | classpath 'com.github.jengelman.gradle.plugins:shadow:5.0.0' 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenCentral() 18 | mavenLocal() 19 | jcenter() 20 | } 21 | } 22 | } 23 | 24 | 25 | plugins { 26 | id 'org.jetbrains.kotlin.jvm' version '1.3.50' 27 | } 28 | apply plugin: "java-gradle-plugin" 29 | apply plugin: "kotlin-kapt" 30 | apply plugin: "maven" 31 | 32 | 33 | group = "de.ffuf.kotlin.multiplatform.processor" 34 | archivesBaseName = "nativesuspendfunction" 35 | version = "1.0.18" 36 | 37 | 38 | install { 39 | repositories.mavenInstaller { 40 | pom.artifactId = archivesBaseName 41 | } 42 | } 43 | 44 | gradlePlugin { 45 | plugins { 46 | simplePlugin { 47 | id = "native-suspend-function" // users will do `apply plugin: "de.jensklingenberg.mpapt"` 48 | implementationClass = "de.ffuf.kotlin.multiplatform.processor.NativeSuspendFunctionsGradlePlugin" // entry-point class 49 | } 50 | } 51 | } 52 | 53 | dependencies { 54 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" 55 | compile "org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.3.50" 56 | compileOnly "com.google.auto.service:auto-service:1.0-rc6" 57 | kapt "com.google.auto.service:auto-service:1.0-rc6" 58 | } 59 | 60 | 61 | build { 62 | dependsOn install 63 | } 64 | 65 | 66 | 67 | task sourcesJar(type: Jar, dependsOn: classes) { 68 | classifier = 'sources' 69 | from sourceSets.main.allSource 70 | } 71 | 72 | artifacts { 73 | archives sourcesJar 74 | } 75 | 76 | uploadArchives { 77 | repositories { 78 | mavenDeployer { 79 | //repository(url: uri("${System.getProperty('user.home')}/.m2/repository")) 80 | repository ( 81 | url: 'https://api.bintray.com/maven/jonasbark/ffuf/nativesuspendfunction-compiler' 82 | ) { 83 | authentication( 84 | userName: bintray_user, 85 | password: bintray_api_key 86 | ) 87 | } 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/de/ffuf/kotlin/multiplatform/processor/NativeSuspendFunctionsGradlePlugin.kt: -------------------------------------------------------------------------------- 1 | package de.ffuf.kotlin.multiplatform.processor 2 | 3 | import org.gradle.api.Project 4 | 5 | open class NativeSuspendFunctionsExtension { 6 | var scopeName = "mainScope" 7 | var outputDirectory = "src/commonMain/kotlin" 8 | var packageName: String = "" 9 | var imports: List = emptyList() 10 | 11 | override fun toString(): String { 12 | return "NativeSuspendFunctionsExtension(scopeName='$scopeName', outputDirectory='$outputDirectory', packageName=$packageName, imports=$imports)" 13 | } 14 | } 15 | 16 | open class NativeSuspendFunctionsGradlePlugin : org.gradle.api.Plugin { 17 | override fun apply(project: Project) { 18 | project.extensions.create("nativeSuspendExtension", NativeSuspendFunctionsExtension::class.java) 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/de/ffuf/kotlin/multiplatform/processor/NativeSuspendFunctionsGradleSubplugin.kt: -------------------------------------------------------------------------------- 1 | package de.ffuf.kotlin.multiplatform.processor 2 | 3 | import com.google.auto.service.AutoService 4 | import org.gradle.api.Project 5 | import org.gradle.api.tasks.compile.AbstractCompile 6 | import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions 7 | import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation 8 | import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin 9 | import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact 10 | import org.jetbrains.kotlin.gradle.plugin.SubpluginOption 11 | 12 | @AutoService(KotlinGradleSubplugin::class) // don't forget! 13 | class NativeSuspendFunctionsGradleSubplugin : KotlinGradleSubplugin { 14 | override fun apply( 15 | project: Project, 16 | kotlinCompile: AbstractCompile, 17 | javaCompile: AbstractCompile?, 18 | variantData: Any?, 19 | androidProjectHandler: Any?, 20 | kotlinCompilation: KotlinCompilation? 21 | ): List { 22 | 23 | val extension = project.extensions.getByType(NativeSuspendFunctionsExtension::class.java) 24 | 25 | return listOf( 26 | SubpluginOption(NativeSuspendFunctionsExtension::scopeName.name, extension.scopeName), 27 | SubpluginOption(NativeSuspendFunctionsExtension::outputDirectory.name, extension.outputDirectory), 28 | SubpluginOption(NativeSuspendFunctionsExtension::imports.name, extension.imports.joinToString("&")), 29 | SubpluginOption(NativeSuspendFunctionsExtension::packageName.name, extension.packageName) 30 | ) 31 | } 32 | 33 | override fun isApplicable(project: Project, task: AbstractCompile) = 34 | project.plugins.hasPlugin(NativeSuspendFunctionsGradlePlugin::class.java) 35 | 36 | 37 | /** 38 | * Just needs to be consistent with the key for CommandLineProcessor#pluginId 39 | */ 40 | override fun getCompilerPluginId(): String = "native-suspend-function" 41 | 42 | override fun getPluginArtifact(): SubpluginArtifact = SubpluginArtifact( 43 | groupId = "de.ffuf.kotlin.multiplatform.processor", 44 | artifactId = "nativesuspendfunction-compiler", 45 | version = "1.0.18" // remember to bump this version before any release! 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /docs/images/KonanDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilfeilundfeil/kotlin-native-suspend-function-callback/10aa7bd48f9a6d5f31bdae84bc9a68d29e3e3e97/docs/images/KonanDebug.png -------------------------------------------------------------------------------- /docs/images/kotlincompilerdebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilfeilundfeil/kotlin-native-suspend-function-callback/10aa7bd48f9a6d5f31bdae84bc9a68d29e3e3e97/docs/images/kotlincompilerdebug.png -------------------------------------------------------------------------------- /docs/images/logJs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilfeilundfeil/kotlin-native-suspend-function-callback/10aa7bd48f9a6d5f31bdae84bc9a68d29e3e3e97/docs/images/logJs.png -------------------------------------------------------------------------------- /docs/images/logJvm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilfeilundfeil/kotlin-native-suspend-function-callback/10aa7bd48f9a6d5f31bdae84bc9a68d29e3e3e97/docs/images/logJvm.png -------------------------------------------------------------------------------- /docs/images/logNative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilfeilundfeil/kotlin-native-suspend-function-callback/10aa7bd48f9a6d5f31bdae84bc9a68d29e3e3e97/docs/images/logNative.png -------------------------------------------------------------------------------- /docs/images/terminaldebugnative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilfeilundfeil/kotlin-native-suspend-function-callback/10aa7bd48f9a6d5f31bdae84bc9a68d29e3e3e97/docs/images/terminaldebugnative.png -------------------------------------------------------------------------------- /example/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | ext.buildMaven = { p -> repositories { maven { url p } } } 4 | 5 | 6 | repositories { 7 | mavenLocal() 8 | google() 9 | jcenter() 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | classpath "de.ffuf.kotlin.multiplatform.processor:nativesuspendfunction:$plugin_version" 15 | 16 | } 17 | 18 | } 19 | 20 | plugins { 21 | id 'org.jetbrains.kotlin.multiplatform' version '1.3.50' 22 | } 23 | 24 | apply plugin: 'native-suspend-function' 25 | 26 | 27 | System.setProperty("kotlin.compiler.execution.strategy", "in-process") // For debugging 28 | 29 | allprojects { 30 | repositories { 31 | mavenLocal() 32 | mavenCentral() 33 | google() 34 | 35 | maven { url "https://maven.google.com" } 36 | maven { url "https://plugins.gradle.org/m2/" } 37 | } 38 | } 39 | 40 | nativeSuspendExtension { 41 | scopeName = "GlobalScope" 42 | imports = ["kotlinx.coroutines.GlobalScope"] 43 | } 44 | 45 | allprojects { 46 | ext.buildMaven = { p -> repositories { maven { url p } } } 47 | 48 | repositories { 49 | mavenLocal() 50 | mavenCentral() 51 | maven { url "https://maven.google.com" } 52 | maven { url "https://plugins.gradle.org/m2/" } 53 | google() 54 | jcenter() 55 | 56 | 57 | } 58 | } 59 | 60 | 61 | kotlin { 62 | jvm() 63 | js() 64 | iosX64() 65 | 66 | sourceSets { 67 | commonMain { 68 | dependencies { 69 | implementation kotlin('stdlib-common') 70 | implementation "de.ffuf.kotlin.multiplatform.annotations:annotations:$plugin_version" 71 | 72 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.0" 73 | } 74 | } 75 | commonTest { 76 | dependencies { 77 | implementation kotlin('test-common') 78 | implementation kotlin('test-annotations-common') 79 | 80 | } 81 | } 82 | 83 | jsMain { 84 | dependencies { 85 | implementation kotlin('stdlib-js') 86 | } 87 | } 88 | jsTest { 89 | dependencies { 90 | implementation kotlin('test-js') 91 | } 92 | } 93 | 94 | jvmMain { 95 | dependencies { 96 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" 97 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0" 98 | } 99 | } 100 | jvmTest { 101 | dependencies { 102 | // implementation kotlin('test-junit') 103 | implementation group: 'junit', name: 'junit', version: '4.4' 104 | } 105 | } 106 | iosX64Main { 107 | dependencies { 108 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.0" 109 | } 110 | } 111 | } 112 | } 113 | 114 | 115 | 116 | // workaround for https://youtrack.jetbrains.com/issue/KT-27170 117 | configurations { 118 | compileClasspath 119 | } 120 | 121 | //./gradlew :clean :build --no-daemon -Dorg.gradle.debug=true -Dkotlin.compiler.execution.strategy="in-process" -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket\,address=5005\,server=y\,suspend=n" 122 | -------------------------------------------------------------------------------- /example/src/commonMain/kotlin/CommonAnnotated.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt 2 | 3 | import de.ffuf.kotlin.multiplatform.annotations.NativeFlowFunction 4 | import de.ffuf.kotlin.multiplatform.annotations.NativeSuspendedFunction 5 | import kotlinx.coroutines.* 6 | import kotlinx.coroutines.channels.awaitClose 7 | import kotlinx.coroutines.flow.Flow 8 | import kotlinx.coroutines.flow.callbackFlow 9 | import kotlinx.coroutines.flow.collect 10 | 11 | typealias Datum = CharProgression 12 | 13 | class CommonAnnotated { 14 | 15 | @NativeSuspendedFunction 16 | @PublishedApi 17 | @Deprecated("Test") 18 | internal suspend fun firstFunction2(id: Datum, type: Double?): Int { 19 | return 0 20 | } 21 | 22 | @NativeSuspendedFunction 23 | suspend fun goToDockingStation(commandHandler: Regex?) = 24 | Regex("") 25 | 26 | @NativeSuspendedFunction 27 | suspend fun testList(list: List) = 28 | Regex("") 29 | 30 | @ExperimentalCoroutinesApi 31 | @NativeFlowFunction 32 | fun testFlowFunction(test: Int): Flow { 33 | return callbackFlow { 34 | offer(GlobalScope) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/src/jsMain/kotlin/de/jensklingenberg/mpapt/Generated.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt 2 | 3 | class Generated { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /example/src/jsMain/kotlin/de/jensklingenberg/mpapt/JSAnnotated.kt: -------------------------------------------------------------------------------- 1 | import de.ffuf.kotlin.multiplatform.annotations.NativeSuspendedFunction 2 | 3 | class Annotated { 4 | 5 | @NativeSuspendedFunction 6 | fun firstFunction() { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/src/jsMain/kotlin/de/jensklingenberg/mpapt/JsSecondAnnotated.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt 2 | 3 | import de.ffuf.kotlin.multiplatform.annotations.NativeSuspendedFunction 4 | 5 | 6 | class JsSecondAnnotated { 7 | 8 | @NativeSuspendedFunction 9 | fun what() { 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example/src/jvmMain/kotlin/de/jensklingenberg/mpapt/Generated.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt 2 | 3 | class Generated { 4 | 5 | } -------------------------------------------------------------------------------- /example/src/jvmMain/kotlin/de/jensklingenberg/mpapt/JVMAnnotated.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt 2 | 3 | import de.ffuf.kotlin.multiplatform.annotations.NativeSuspendedFunction 4 | 5 | 6 | class Annotated constructor() { 7 | 8 | @NativeSuspendedFunction 9 | fun firstFunction() { 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.incremental=false 2 | org.gradle.daemon=false 3 | org.gradle.parallel=false 4 | org.gradle.configureondemand=false 5 | kotlin.compiler.execution.strategy=in-process 6 | kotlin.daemon.debug.log=true 7 | org.gradle.jvmargs=-Xmx6g -XX:MaxPermSize=1024m 8 | //kotlin.native.jvmArgs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5006 9 | gnsp.disableApplyOnlyOnRootProjectEnforcement 10 | 11 | plugin_version = 1.0.18 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilfeilundfeil/kotlin-native-suspend-function-callback/10aa7bd48f9a6d5f31bdae84bc9a68d29e3e3e97/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Aug 25 15:26:06 CEST 2019 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /kotlin-plugin/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | 4 | 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | classpath 'com.github.jengelman.gradle.plugins:shadow:5.0.0' 11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.+' 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | mavenLocal() 17 | jcenter() 18 | } 19 | } 20 | } 21 | 22 | apply plugin: "org.jetbrains.kotlin.jvm" 23 | apply plugin: "kotlin-kapt" 24 | apply plugin: "maven" 25 | apply plugin: "com.jfrog.bintray" 26 | apply plugin: 'com.github.johnrengelman.shadow' 27 | 28 | group = "de.ffuf.kotlin.multiplatform.processor" 29 | archivesBaseName = "nativesuspendfunction-compiler" 30 | version = plugin_version 31 | 32 | install { 33 | repositories.mavenInstaller { 34 | pom.artifactId = archivesBaseName 35 | } 36 | } 37 | 38 | repositories { 39 | mavenCentral() 40 | mavenLocal() 41 | jcenter() 42 | } 43 | 44 | subprojects { subProject -> 45 | subProject.configurations.all { configuration -> 46 | // Workaround for kapt bug with MPP dependencies 47 | // https://youtrack.jetbrains.com/issue/KT-31641 48 | // https://youtrack.jetbrains.com/issue/KT-33206 49 | if (name.contains('kapt')) { 50 | attributes.attribute(Usage.USAGE_ATTRIBUTE, subProject.objects.named(Usage.class, Usage.JAVA_RUNTIME)) 51 | } 52 | } 53 | } 54 | 55 | dependencies { 56 | compile 'de.jensklingenberg:mpapt-runtime:0.8.2' 57 | compile "de.ffuf.kotlin.multiplatform.annotations:annotations-jvm:1.0.12" 58 | compile 'com.squareup:kotlinpoet:1.3.0' 59 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" 60 | compileOnly "org.jetbrains.kotlin:kotlin-compiler-embeddable" 61 | compileOnly "com.google.auto.service:auto-service:1.0-rc6" 62 | kapt "com.google.auto.service:auto-service:1.0-rc6" 63 | } 64 | 65 | def pomConfig = { 66 | developers { 67 | developer { 68 | id "Jonas Bark" 69 | organization "FFUF" 70 | organizationUrl "http://twitter.com/boni2k" 71 | } 72 | developer { 73 | id "FFUF" 74 | organization "FFUF" 75 | organizationUrl "http://www.ffuf.de" 76 | } 77 | } 78 | scm { 79 | url "https://github.com/feilfeilundfeil/kotlin-native-suspend-function-callback" 80 | } 81 | } 82 | 83 | project.ext.configureMavenCentralMetadata = { pom -> 84 | def root = asNode() 85 | root.appendNode('name', "kotlin-native-suspend-function-callback") 86 | root.appendNode('description', 'Kotlin Multiplatform compiler plugin to generate a callback implementation for suspended functions so they are visible from Kotlin Native') 87 | root.appendNode('url', 'https://ffuf.de') 88 | root.children().last() + pomConfig 89 | 90 | root.remove(root.get("dependencies")) // remove dependencies as we have a fat jar 91 | } 92 | 93 | task sourcesJar(type: Jar, dependsOn: classes) { 94 | classifier = 'sources' 95 | from sourceSets.main.allSource 96 | } 97 | 98 | artifacts { 99 | archives sourcesJar 100 | archives shadowJar 101 | } 102 | 103 | task fatJar(type: Jar) { 104 | manifest { 105 | attributes 'Implementation-Title': 'Gradle Jar File Example', 106 | 'Implementation-Version': version, 107 | 'Main-Class': 'de.ffuf.kotlin.multiplatform.processor.registrar.CommonComponentRegistrar' 108 | } 109 | baseName = "nativesuspendfunction-compiler" 110 | version = this.version 111 | 112 | from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 113 | with jar 114 | } 115 | 116 | shadowJar { 117 | manifest { 118 | inheritFrom project.tasks.fatJar.manifest 119 | } 120 | baseName = "nativesuspendfunction-compiler" 121 | version = this.version 122 | classifier = null 123 | } 124 | 125 | build { 126 | finalizedBy(install) 127 | } 128 | 129 | kapt { 130 | includeCompileClasspath = true 131 | } 132 | 133 | uploadArchives { 134 | repositories { 135 | mavenDeployer { 136 | //repository(url: uri("${System.getProperty('user.home')}/.m2/repository")) 137 | 138 | pom.withXml(configureMavenCentralMetadata) 139 | repository ( 140 | url: 'https://api.bintray.com/maven/jonasbark/ffuf/nativesuspendfunction-compiler' 141 | ) { 142 | authentication( 143 | userName: bintray_user, 144 | password: bintray_api_key 145 | ) 146 | } 147 | } 148 | 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /kotlin-plugin/src/main/java/de/ffuf/kotlin/multiplatform/processor/registrar/CommonComponentRegistrar.kt: -------------------------------------------------------------------------------- 1 | package de.ffuf.kotlin.multiplatform.processor.registrar 2 | 3 | import com.google.auto.service.AutoService 4 | import de.jensklingenberg.mpapt.common.MpAptProject 5 | import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension 6 | import org.jetbrains.kotlin.com.intellij.mock.MockProject 7 | import org.jetbrains.kotlin.compiler.plugin.* 8 | import org.jetbrains.kotlin.config.CompilerConfiguration 9 | import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor 10 | import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension 11 | import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension 12 | 13 | /** 14 | * This is the entry class for a compiler plugin 15 | */ 16 | @AutoService(ComponentRegistrar::class) 17 | open class CommonComponentRegistrar : ComponentRegistrar { 18 | 19 | override fun registerProjectComponents( 20 | project: MockProject, 21 | configuration: CompilerConfiguration 22 | ) { 23 | val processor = NativeSuspendedFunctionProcessor() 24 | val mpapt = MpAptProject(processor, configuration) 25 | StorageComponentContainerContributor.registerExtension(project, mpapt) 26 | SyntheticResolveExtension.registerExtension(project, mpapt) 27 | ClassBuilderInterceptorExtension.registerExtension(project, mpapt) 28 | JsSyntheticTranslateExtension.registerExtension(project, mpapt) 29 | } 30 | } 31 | 32 | 33 | @AutoService(CommandLineProcessor::class) 34 | class NativeTestComponentCommandLineProcessor : CommandLineProcessor { 35 | companion object { 36 | val IMPORTS_OPTION = CliOption( 37 | "imports", "", NativeSuspendedFunctionKeys.IMPORTS.toString(), 38 | required = false, allowMultipleOccurrences = false 39 | ) 40 | 41 | val SCOPENAME_OPTION = CliOption( 42 | "scopeName", "", NativeSuspendedFunctionKeys.SCOPENAME.toString(), 43 | required = false, allowMultipleOccurrences = false 44 | ) 45 | 46 | val OUTPUTDIRECTORY_OPTION = CliOption( 47 | "outputDirectory", "", 48 | NativeSuspendedFunctionKeys.OUTPUTDIRECTORY.toString(), 49 | required = false, allowMultipleOccurrences = false 50 | ) 51 | val PACKAGENAME_OPTION = CliOption( 52 | "packageName", "", 53 | NativeSuspendedFunctionKeys.PACKAGENAME.toString(), 54 | required = false, allowMultipleOccurrences = false 55 | ) 56 | 57 | val PLUGIN_ID = "native-suspend-function" 58 | } 59 | 60 | override val pluginId = PLUGIN_ID 61 | override val pluginOptions = listOf(IMPORTS_OPTION, SCOPENAME_OPTION, OUTPUTDIRECTORY_OPTION, PACKAGENAME_OPTION) 62 | 63 | override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) { 64 | return when (option) { 65 | IMPORTS_OPTION -> configuration.put(NativeSuspendedFunctionKeys.IMPORTS, value) 66 | SCOPENAME_OPTION -> configuration.put(NativeSuspendedFunctionKeys.SCOPENAME, value) 67 | OUTPUTDIRECTORY_OPTION -> configuration.put(NativeSuspendedFunctionKeys.OUTPUTDIRECTORY, value) 68 | PACKAGENAME_OPTION -> configuration.put(NativeSuspendedFunctionKeys.PACKAGENAME, value) 69 | else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}") 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /kotlin-plugin/src/main/java/de/ffuf/kotlin/multiplatform/processor/registrar/NativeSuspendedFunctionProcessor.kt: -------------------------------------------------------------------------------- 1 | package de.ffuf.kotlin.multiplatform.processor.registrar 2 | 3 | import com.squareup.kotlinpoet.* 4 | import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy 5 | import de.ffuf.kotlin.multiplatform.annotations.NativeFlowFunction 6 | import de.ffuf.kotlin.multiplatform.annotations.NativeSuspendedFunction 7 | import de.ffuf.kotlin.multiplatform.annotations.SuspendResult 8 | import de.ffuf.kotlin.multiplatform.processor.registrar.NativeSuspendedFunctionKeys.IMPORTS 9 | import de.ffuf.kotlin.multiplatform.processor.registrar.NativeSuspendedFunctionKeys.OUTPUTDIRECTORY 10 | import de.ffuf.kotlin.multiplatform.processor.registrar.NativeSuspendedFunctionKeys.PACKAGENAME 11 | import de.ffuf.kotlin.multiplatform.processor.registrar.NativeSuspendedFunctionKeys.SCOPENAME 12 | import de.jensklingenberg.mpapt.common.* 13 | import de.jensklingenberg.mpapt.model.AbstractProcessor 14 | import de.jensklingenberg.mpapt.model.Element 15 | import de.jensklingenberg.mpapt.model.RoundEnvironment 16 | import org.jetbrains.kotlin.config.CompilerConfigurationKey 17 | import org.jetbrains.kotlin.descriptors.EffectiveVisibility 18 | import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass 19 | import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 20 | import org.jetbrains.kotlin.resolve.descriptorUtil.module 21 | import java.io.File 22 | 23 | object NativeSuspendedFunctionKeys { 24 | val IMPORTS: CompilerConfigurationKey = 25 | CompilerConfigurationKey.create("additional import statements") 26 | 27 | val SCOPENAME: CompilerConfigurationKey = CompilerConfigurationKey.create("scope name to use") 28 | 29 | val OUTPUTDIRECTORY: CompilerConfigurationKey = CompilerConfigurationKey.create( 30 | "output directory of generated extension class (excluding package name)" 31 | ) 32 | 33 | val PACKAGENAME: CompilerConfigurationKey = CompilerConfigurationKey.create( 34 | "output package name of generated extension - if empty it uses the package name of the first found annotation" 35 | ) 36 | } 37 | 38 | private const val TAG = "NativeSuspendedFunctionProcessor" 39 | 40 | 41 | class NativeSuspendedFunctionProcessor : AbstractProcessor() { 42 | 43 | private val nativeSuspendFunction = NativeSuspendedFunction::class.java.name 44 | private val nativeFlowFunction = NativeFlowFunction::class.java.name 45 | 46 | private var fileBuilder: FileSpec.Builder? = null 47 | private var outputFile: File? = null 48 | 49 | override fun process(roundEnvironment: RoundEnvironment) { 50 | roundEnvironment.getElementsAnnotatedWith(NativeSuspendedFunction::class.java.name).forEach { 51 | when (it) { 52 | is Element.FunctionElement -> { 53 | if (it.func.isSuspend) { //sanity check 54 | generateFunction(it, false) 55 | } 56 | } 57 | } 58 | } 59 | roundEnvironment.getElementsAnnotatedWith(NativeFlowFunction::class.java.name).forEach { 60 | when (it) { 61 | is Element.FunctionElement -> { 62 | generateFunction(it, true) 63 | } 64 | } 65 | } 66 | } 67 | 68 | private fun generateFunction(functionElement: Element.FunctionElement, isFlow: Boolean) { 69 | log("Found suspended Function: " + functionElement.func.name + " Module: " + functionElement.func.module.simpleName() + " platform " + activeTargetPlatform.first().platformName) 70 | 71 | val packageName = configuration.get( 72 | PACKAGENAME, "" 73 | ).let { 74 | if (it.isEmpty()) functionElement.descriptor.original.containingDeclaration.fqNameSafe.asString() else it 75 | } 76 | 77 | val className = functionElement.descriptor.defaultType.toString() 78 | val generatedClassName = "NativeCoroutineExtensions" 79 | 80 | if (fileBuilder == null) { 81 | fileBuilder = FileSpec.builder(packageName, generatedClassName) 82 | .indent(" ") 83 | .addImport("de.ffuf.kotlin.multiplatform.annotations", "suspendRunCatching") 84 | .addImport("kotlinx.coroutines", "launch") 85 | .addImport("kotlinx.coroutines.flow", "collect") 86 | 87 | val outputDirectory = configuration.get( 88 | OUTPUTDIRECTORY, "src/commonMain/kotlin" 89 | ) 90 | val possibleProjectDirectory = functionElement.descriptor.guessingProjectFolder() 91 | outputFile = File( 92 | // fix when trying to compile Android app 93 | possibleProjectDirectory.substringBefore(outputDirectory), 94 | outputDirectory 95 | ) 96 | log("Outputfile: ${outputFile?.path} Package: $packageName") 97 | 98 | val imports: String? = configuration.get(IMPORTS) 99 | imports?.let { imports -> 100 | imports.split("&").forEach { import -> 101 | fileBuilder?.addImport( 102 | import.split(".").dropLast(1).joinToString("."), 103 | import.split(".").last() 104 | ) 105 | } 106 | } 107 | } 108 | 109 | val originalPackageName = functionElement.descriptor.original.containingDeclaration.fqNameSafe.asString() 110 | fileBuilder?.addImport(originalPackageName, className) 111 | 112 | val returnType: TypeName = if (functionElement.func.returnType != null) { 113 | val value = if (isFlow) { //kotlin. 114 | functionElement.func.getReturnTypeImport().substringAfter("<").substringBefore(">").split(".") 115 | } else { 116 | functionElement.func.getReturnTypeImport().split(".") 117 | } 118 | ClassName(value.dropLast(1).joinToString("."), value.last()) 119 | } else { 120 | Unit::class.asTypeName() 121 | } 122 | 123 | fileBuilder?.addFunction( 124 | FunSpec.builder(functionElement.func.name.identifier) 125 | .receiver(ClassName(packageName, className)) 126 | .addAnnotations(functionElement.func.annotations.filterNot { it.type.toString() == NativeSuspendedFunction::class.java.simpleName || it.type.toString() == NativeFlowFunction::class.java.simpleName }.map { annotation -> 127 | AnnotationSpec.builder( 128 | ClassName( 129 | annotation.annotationClass?.original?.containingDeclaration?.fqNameSafe?.asString() 130 | ?: "", 131 | annotation.type.toString() 132 | ) 133 | ).addMember(annotation.allValueArguments.map { "${it.key} = ${it.value}" }.joinToString(", ")) 134 | .build() 135 | }) 136 | .apply { 137 | if (functionElement.func.visibility == EffectiveVisibility.Internal.toVisibility()) { 138 | addModifiers(KModifier.INTERNAL) 139 | } 140 | } 141 | .addParameters(functionElement.func.getFunctionParameters().map { param -> 142 | ParameterSpec.builder( 143 | param.parameterName, 144 | ClassName( 145 | param.packagee.packagename, 146 | param.packagee.classname 147 | ).let { 148 | if (param.genericPackage != null) { 149 | ClassName( 150 | param.genericPackage!!.packagename, 151 | param.genericPackage!!.classname 152 | ).parameterizedBy(it) 153 | } else it 154 | }.copy(nullable = param.nullable) 155 | ).build() 156 | }) 157 | .addParameter( 158 | ParameterSpec.builder( 159 | "callback", 160 | LambdaTypeName.get( 161 | null, 162 | parameters = *arrayOf( 163 | if (isFlow) { 164 | returnType 165 | } else { 166 | SuspendResult::class.asClassName().parameterizedBy( 167 | returnType 168 | ) 169 | } 170 | ), 171 | returnType = Unit::class.asTypeName() 172 | ) 173 | ).build() 174 | ) 175 | .addCode(buildCodeBlock { 176 | 177 | /* 178 | @ExperimentalCoroutinesApi 179 | @NativeFlowFunction 180 | fun subscribeToMowerChanges(test: Int): Flow { 181 | return callbackFlow { 182 | offer("") 183 | } 184 | } 185 | 186 | fun subscribeToMowerChanges(test: Int, callback: (String) -> Unit): Job = GlobalScope.launch { 187 | subscribeToMowerChanges(test).collect { 188 | callback(functionElement) 189 | } 190 | } 191 | */ 192 | 193 | val scopeName = configuration.get( 194 | SCOPENAME, "mainScope" 195 | ) 196 | beginControlFlow("return $scopeName.launch") 197 | val originalCall = 198 | "${functionElement.func.name}(${functionElement.func.getFunctionParameters().joinToString(", ") { param -> param.parameterName }})" 199 | if (isFlow) { 200 | beginControlFlow("${originalCall}.collect") 201 | addStatement("callback(it)") 202 | endControlFlow() 203 | 204 | } else { 205 | addStatement("callback(suspendRunCatching<%T> { $originalCall })", returnType) 206 | } 207 | endControlFlow() 208 | }) 209 | .build() 210 | ) 211 | } 212 | 213 | override fun getSupportedAnnotationTypes(): Set = setOf(nativeSuspendFunction, nativeFlowFunction) 214 | 215 | override fun processingOver() { 216 | log("$TAG***Processor over ***") 217 | 218 | fileBuilder?.build()?.let { 219 | outputFile?.let { file -> 220 | log("$TAG***Processor over, writing to $file ***") 221 | if (!file.exists()) { 222 | file.mkdir() 223 | } 224 | it.writeTo(file) 225 | } 226 | 227 | } 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /mpapt-runtime/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.buildMaven = { p -> repositories { maven { url p } } } 3 | 4 | repositories { 5 | mavenCentral() 6 | } 7 | } 8 | 9 | 10 | plugins { 11 | id 'org.jetbrains.kotlin.jvm' version '1.3.50' 12 | id "maven" 13 | id 'maven-publish' 14 | } 15 | 16 | 17 | apply plugin: "kotlin-kapt" 18 | 19 | allprojects { 20 | 21 | 22 | repositories { 23 | mavenLocal() 24 | mavenCentral() 25 | maven { url "https://maven.google.com" } 26 | maven { url "https://plugins.gradle.org/m2/" } 27 | } 28 | } 29 | 30 | group = "de.jensklingenberg" 31 | archivesBaseName = "mpapt-runtime" 32 | version = "0.8.2" 33 | 34 | install { 35 | repositories.mavenInstaller { 36 | pom.artifactId = archivesBaseName 37 | } 38 | } 39 | 40 | 41 | compileKotlin { 42 | kotlinOptions { 43 | jvmTarget = "1.8" 44 | } 45 | } 46 | 47 | uploadArchives { 48 | repositories { 49 | mavenDeployer { 50 | repository(url: uri("${System.getProperty('user.home')}/.m2/repository")) 51 | } 52 | } 53 | } 54 | 55 | publishing { 56 | publications { 57 | 58 | } 59 | repositories { 60 | maven { 61 | url = uri("${System.getProperty('user.home')}/.m2/repository") 62 | } 63 | } 64 | } 65 | 66 | 67 | dependencies { 68 | compileOnly "org.jetbrains.kotlin:kotlin-stdlib" 69 | compileOnly "org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.50" 70 | compileOnly "com.google.auto.service:auto-service:1.0-rc6" 71 | kapt "com.google.auto.service:auto-service:1.0-rc6" 72 | } 73 | 74 | 75 | build.finalizedBy(install) 76 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/Notes.txt: -------------------------------------------------------------------------------- 1 | Check if class has constructor with a annotation 2 | classDescriptor.constructors.toList().get(0).annotations.hasAnnotation("de.jensklingenberg.ktorfit.Fancy") 3 | 4 | 5 | CollectAdditionalSourcesExtension.registerExtension(project,object :CollectAdditionalSourcesExtension{ 6 | 7 | override fun collectAdditionalSourcesAndUpdateConfiguration(knownSources: Collection, configuration: CompilerConfiguration, project: Project): Collection { 8 | processor.log("collect") 9 | return knownSources 10 | } 11 | }) 12 | 13 | 14 | ShellExtension.registerExtension(project,object :ShellExtension{ 15 | override fun isAccepted(arguments: CommonCompilerArguments): Boolean { 16 | processor.log("ISACCTED") 17 | return false 18 | 19 | } 20 | 21 | override fun run(arguments: CommonCompilerArguments, configuration: CompilerConfiguration, projectEnvironment: JavaCoreProjectEnvironment): ExitCode { 22 | processor.log("run") 23 | 24 | return ExitCode.OK 25 | } 26 | 27 | }) 28 | 29 | 30 | ================================================ 31 | 32 | function.accept(object: DeclarationDescriptorVisitor { 33 | override fun visitPropertySetterDescriptor(p0: PropertySetterDescriptor?, p1: Any?): Any { 34 | return "" 35 | } 36 | 37 | override fun visitConstructorDescriptor(p0: ConstructorDescriptor?, p1: Any?): Any { 38 | return "" 39 | } 40 | 41 | override fun visitReceiverParameterDescriptor(p0: ReceiverParameterDescriptor?, p1: Any?): Any { 42 | return "" 43 | } 44 | 45 | override fun visitPackageViewDescriptor(p0: PackageViewDescriptor?, p1: Any?): Any { 46 | return "" 47 | } 48 | 49 | override fun visitFunctionDescriptor(p0: FunctionDescriptor?, p1: Any?): Any { 50 | return "" 51 | } 52 | 53 | override fun visitModuleDeclaration(p0: ModuleDescriptor?, p1: Any?): Any { 54 | return "" 55 | } 56 | 57 | override fun visitClassDescriptor(p0: ClassDescriptor?, p1: Any?): Any { 58 | return "" 59 | } 60 | 61 | override fun visitPackageFragmentDescriptor(p0: PackageFragmentDescriptor?, p1: Any?): Any { 62 | return "" 63 | } 64 | 65 | override fun visitValueParameterDescriptor(p0: ValueParameterDescriptor?, p1: Any?): Any { 66 | return "" 67 | } 68 | 69 | override fun visitTypeParameterDescriptor(p0: TypeParameterDescriptor?, p1: Any?): Any { 70 | return "" 71 | } 72 | 73 | override fun visitScriptDescriptor(p0: ScriptDescriptor?, p1: Any?): Any { 74 | return "" 75 | } 76 | 77 | override fun visitTypeAliasDescriptor(p0: TypeAliasDescriptor?, p1: Any?): Any { 78 | return "" 79 | } 80 | 81 | override fun visitPropertyGetterDescriptor(p0: PropertyGetterDescriptor?, p1: Any?): Any { 82 | return "" 83 | } 84 | 85 | override fun visitVariableDescriptor(p0: VariableDescriptor?, p1: Any?): Any { 86 | return "" 87 | } 88 | 89 | override fun visitPropertyDescriptor(p0: PropertyDescriptor?, p1: Any?): Any { 90 | return "" 91 | } 92 | 93 | },"") 94 | 95 | 96 | 97 | =========================================== 98 | 99 | private fun checkLocalVariable(declaration: KtPureClassOrObject) { 100 | abstractProcessor.getSupportedAnnotationTypes().forEach { annoation -> 101 | val annotationWithoutPackage = annoation.substringAfterLast(".") 102 | declaration.body?.functions?.forEach { ktfunction -> 103 | 104 | 105 | val findanno: KtProperty? = ktfunction.bodyBlockExpression?.statements?.filterIsInstance()?.firstOrNull { property -> 106 | val che = property.annotationEntries.any() { it.shortName?.identifier.equals(annotationWithoutPackage) ?: false } 107 | 108 | 109 | che 110 | } 111 | 112 | // val getAnno= findanno?.type 113 | 114 | if(findanno!=null){ 115 | val roundEnvironment= RoundEnvironment() 116 | 117 | 118 | roundEnvironment.apply { 119 | elements.add( 120 | Element.LocalVariableElement( 121 | classConstructorDescriptor = findanno, 122 | func = WrappedSimpleFunctionDescriptor(Annotations.EMPTY,ktfunction.toSourceElement()) 123 | // annotation =AnnotationDescriptor 124 | 125 | ) 126 | ) 127 | } 128 | 129 | 130 | 131 | abstractProcessor.process(roundEnvironment) 132 | 133 | //abstractProcessor.log("I FOUND A LOCAL "+findanno?.name) 134 | } 135 | 136 | } 137 | 138 | 139 | } 140 | 141 | } 142 | 143 | 144 | 145 | 146 | ===================================================== 147 | private fun checkLocalVariable(processor: AbstractProcessor, functionDescriptor: FunctionDescriptor) { 148 | 149 | 150 | val ktfunction = functionDescriptor.source 151 | 152 | processor.getSupportedAnnotationTypes().forEach { annoation -> 153 | val annotationWithoutPackage = annoation.substringAfterLast(".") 154 | 155 | 156 | 157 | if (ktfunction.safeAsPsi()?.text?.contains(annotationWithoutPackage) == true) { 158 | 159 | 160 | // processor.log("I FOUND .,,A LOCAL "+ functionDescriptor.name) 161 | } 162 | 163 | } 164 | 165 | 166 | } 167 | =================================== 168 | 169 | class MyDeclarationAttributeAltererExtension(generator: AbstractProcessor) : DeclarationAttributeAltererExtension { 170 | 171 | ================================================ 172 | /** 173 | * /TODO: Find more reliable way 174 | * I know there is a platform property at Descriptors, but it was always null 175 | */ 176 | fun CompilerConfiguration.guessingPlatform(): Platform { 177 | val JS_STRING = "JSCompiler" 178 | val JVM = "JVMCompiler" 179 | val NATIVE = "K2NativeCompilerPerformanceManager" 180 | val METADATA = "MetadataCompiler" 181 | val perf: String = this.get(CLIConfigurationKeys.PERF_MANAGER).toString() ?: "" 182 | 183 | return when { 184 | perf.contains(JS_STRING) -> Platform.JS 185 | perf.contains(JVM) -> Platform.JVM 186 | perf.contains(NATIVE) -> Platform.NATIVE 187 | perf.contains(METADATA) -> Platform.METADATA 188 | else -> Platform.UNKNOWN 189 | } 190 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/AnnotationDescriptorExt.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor 4 | import org.jetbrains.kotlin.descriptors.annotations.Annotations 5 | import org.jetbrains.kotlin.name.FqName 6 | import org.jetbrains.kotlin.name.Name 7 | import org.jetbrains.kotlin.resolve.constants.ConstantValue 8 | import org.jetbrains.kotlin.resolve.constants.KClassValue 9 | import kotlin.reflect.KClass 10 | import kotlin.reflect.KProperty 11 | 12 | fun AnnotationDescriptor.readArgument(key: String): ArrayList { 13 | val keyvalue: ConstantValue<*> = this.allValueArguments[Name.identifier(key)] 14 | ?: throw Exception("The key $key does not exist") 15 | return keyvalue.value as? ArrayList ?: arrayListOf() 16 | } 17 | 18 | fun AnnotationDescriptor?.simpleName(): String = this?.fqName?.shortName()?.asString() ?: "No Name" 19 | fun Annotations.hasAnnotation(fqName: String): Boolean = this.hasAnnotation(FqName(fqName)) 20 | fun Annotations.findAnnotation(fqName: String): AnnotationDescriptor? = this.findAnnotation(FqName(fqName)) 21 | 22 | fun KClass<*>.propertyNames(): List = this.members.filterIsInstance>().map { it.name } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/ClassDescriptorExt.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import org.jetbrains.kotlin.descriptors.* 4 | import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor 5 | import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi 6 | import org.jetbrains.kotlin.name.FqName 7 | import org.jetbrains.kotlin.psi.KtBlockExpression 8 | import org.jetbrains.kotlin.psi.KtProperty 9 | import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 10 | import org.jetbrains.kotlin.resolve.descriptorUtil.module 11 | import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor 12 | import org.jetbrains.kotlin.resolve.source.PsiSourceFile 13 | 14 | 15 | fun ClassDescriptor.hasAnnotation(name: String): Boolean = this.annotations.hasAnnotation(FqName(name)) 16 | fun ClassDescriptor.findAnnotation(name: String): AnnotationDescriptor? = this.annotations.findAnnotation(FqName(name)) 17 | 18 | //TODO:this doesnt work with Native 19 | fun ClassDescriptor.canonicalFilePath() = 20 | (this.source.containingFile as PsiSourceFile).psiFile.virtualFile.canonicalPath 21 | 22 | fun ClassDescriptor.guessingProjectFolder(): String { 23 | //Remove <> from module name 24 | val cleanedModuleName = this.module.simpleName() 25 | val projectPath = this.canonicalFilePath()?.replaceAfter("$cleanedModuleName/", "") 26 | return projectPath ?: "Project folder not found" 27 | } 28 | 29 | fun ClassDescriptor.guessingSourceSetFolder(): String = 30 | canonicalFilePath()?.substringBefore(this.fqNameSafe.asString().replace(".", "/")) ?: "" 31 | 32 | fun ClassDescriptor.guessingBuildFolder(): String = this.guessingProjectFolder() + "build/" 33 | 34 | fun ClassDescriptor.properties(): List = 35 | this.properties(CallableMemberDescriptor.Kind.DECLARATION) 36 | 37 | fun ClassDescriptor.cannonicalFolderPath(): String = canonicalFilePath()?.replaceAfterLast("/", "") ?: "Unkown" 38 | 39 | 40 | fun ClassDescriptor.properties(kind: CallableMemberDescriptor.Kind): List { 41 | return (this as LazyClassDescriptor).declaredCallableMembers.filter { it.kind == kind } 42 | .filterIsInstance() 43 | } 44 | 45 | fun ClassDescriptor.methods(): Collection = methods(CallableMemberDescriptor.Kind.DECLARATION) 46 | 47 | 48 | fun ClassDescriptor.methods(kind: CallableMemberDescriptor.Kind): Collection { 49 | return (this as LazyClassDescriptor) 50 | .declaredCallableMembers 51 | .filter { it.kind.equals(kind) } 52 | .filterIsInstance() 53 | } 54 | 55 | fun ClassConstructorDescriptor.hasAnnotation(name: String): Boolean = this.annotations.hasAnnotation(name) 56 | 57 | private fun KtProperty.hasAnnotation(name: String): Boolean { 58 | return this.annotationEntries.any { name.contains(it.shortName?.identifier ?: "") } 59 | 60 | } 61 | 62 | private fun FunctionDescriptor.ktproperties(): List { 63 | return this.findPsi()?.children?.filterIsInstance()?.flatMap { it.statements.filterIsInstance() } 64 | ?: emptyList() 65 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/ClassParser.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import de.jensklingenberg.mpapt.model.Element 4 | import de.jensklingenberg.mpapt.model.Processor 5 | import de.jensklingenberg.mpapt.model.RoundEnvironment 6 | import org.jetbrains.kotlin.descriptors.* 7 | import org.jetbrains.kotlin.name.FqName 8 | import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 9 | import org.jetbrains.kotlin.resolve.descriptorUtil.module 10 | import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter 11 | import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered 12 | 13 | class ClassParser() { 14 | 15 | 16 | companion object { 17 | 18 | fun parse(descriptor: ClassDescriptor, processor: Processor, roundEnvironment: RoundEnvironment) { 19 | 20 | processor.getSupportedAnnotationTypes().forEach { annotation -> 21 | if (descriptor.hasAnnotation(annotation)) { 22 | roundEnvironment.module = descriptor.module 23 | roundEnvironment.elements.add( 24 | Element.ClassElement( 25 | descriptor.name.asString(), 26 | annotation = descriptor.findAnnotation(annotation), 27 | classDescriptor = descriptor, 28 | pack = descriptor.original.containingDeclaration.fqNameSafe.asString() 29 | ) 30 | ) 31 | processor.process(roundEnvironment) 32 | } 33 | 34 | //parseClassConstructor(descriptor, processor, roundEnvironment, annotation) 35 | 36 | 37 | } 38 | 39 | } 40 | 41 | private fun parseClassConstructor(descriptor: ClassDescriptor, processor: Processor, round: RoundEnvironment, annotation: String) { 42 | try { 43 | descriptor.constructors.forEach { 44 | if (hasAnnnotations(it, annotation)) { 45 | val annotatedConstructors = 46 | descriptor.constructors.filter { constructor -> constructor.hasAnnotation(annotation) } 47 | 48 | annotatedConstructors.forEach { annotatedConstructor -> 49 | 50 | val annotationDesc = annotatedConstructor.annotations.findAnnotation(annotation) 51 | 52 | round.module = descriptor.module 53 | round.elements.add( 54 | Element.ClassConstructorElement( 55 | classConstructorDescriptor = annotatedConstructor, 56 | annotation = annotationDesc 57 | 58 | ) 59 | ) 60 | processor.process(round) 61 | } 62 | 63 | } 64 | } 65 | } catch (e: Exception) { 66 | println(e) 67 | } 68 | 69 | } 70 | 71 | 72 | fun parseMethod( 73 | descriptor: ClassDescriptor, 74 | function: FunctionDescriptor, 75 | processor: Processor, 76 | roundEnvironment: RoundEnvironment 77 | ) { 78 | 79 | processor.getSupportedAnnotationTypes().forEach { annotationNames -> 80 | 81 | checkValueParameter(descriptor, 82 | function, 83 | processor, 84 | roundEnvironment, annotationNames) 85 | 86 | 87 | if (function.annotations.hasAnnotation(FqName(annotationNames))) { 88 | val annotation = function.annotations.findAnnotation(FqName(annotationNames)) 89 | 90 | roundEnvironment.apply { 91 | module = descriptor.module 92 | elements.add( 93 | Element.FunctionElement( 94 | simpleName = function.name.asString(), 95 | annotation = annotation, 96 | descriptor = descriptor, 97 | func = function 98 | ) 99 | ) 100 | } 101 | 102 | processor.process(roundEnvironment) 103 | 104 | } 105 | 106 | } 107 | 108 | 109 | } 110 | 111 | private fun checkValueParameter(descriptor: ClassDescriptor, function: FunctionDescriptor, processor: Processor, roundEnvironment: RoundEnvironment, annotationNames: String) { 112 | function.valueParameters.forEach { parameterDescriptor -> 113 | if (parameterDescriptor.annotations.hasAnnotation(FqName(annotationNames))) { 114 | val annotation = parameterDescriptor.annotations.findAnnotation(FqName(annotationNames)) 115 | 116 | roundEnvironment.apply { 117 | module = descriptor.module 118 | elements.add( 119 | Element.ValueParameterElement( 120 | annotation = annotation 121 | , valueParameterDescriptor = parameterDescriptor 122 | 123 | ) 124 | ) 125 | } 126 | processor.process(roundEnvironment) 127 | 128 | } 129 | } 130 | 131 | } 132 | 133 | 134 | fun parseProperty(propertyDescriptor: PropertyDescriptor, processor: Processor, roundEnvironment: RoundEnvironment) { 135 | 136 | processor.getSupportedAnnotationTypes().forEachIndexed { index, annotationNames -> 137 | 138 | checkPropertyGetter(propertyDescriptor, processor, roundEnvironment, annotationNames) 139 | checkPropertySetter(propertyDescriptor, processor, roundEnvironment, annotationNames) 140 | 141 | if (propertyDescriptor.annotations.hasAnnotation(annotationNames)) { 142 | val annotation = propertyDescriptor.annotations.findAnnotation(annotationNames) 143 | 144 | roundEnvironment.apply { 145 | module = propertyDescriptor.module 146 | elements.add( 147 | Element.PropertyElement( 148 | propertyDescriptor, annotation 149 | ) 150 | ) 151 | } 152 | 153 | processor.process(roundEnvironment) 154 | 155 | } 156 | 157 | } 158 | 159 | 160 | } 161 | 162 | private fun checkPropertySetter(propertyDescriptor: PropertyDescriptor, processor: Processor, roundEnvironment: RoundEnvironment, annotationNames: String) { 163 | propertyDescriptor.setter?.let { setterDesc -> 164 | if (setterDesc.annotations.hasAnnotation(annotationNames)) { 165 | val annotation = setterDesc.annotations.findAnnotation(annotationNames) 166 | 167 | roundEnvironment.apply { 168 | module = propertyDescriptor.module 169 | elements.add( 170 | Element.PropertySetterElement( 171 | setterDesc, annotation 172 | ) 173 | ) 174 | } 175 | 176 | processor.process(roundEnvironment) 177 | } 178 | } 179 | } 180 | 181 | private fun checkPropertyGetter(propertyDescriptor: PropertyDescriptor, processor: Processor, roundEnvironment: RoundEnvironment, annotationNames: String) { 182 | propertyDescriptor.getter?.let { setterDesc -> 183 | if (setterDesc.annotations.hasAnnotation(annotationNames)) { 184 | val annotation = setterDesc.annotations.findAnnotation(annotationNames) 185 | 186 | roundEnvironment.apply { 187 | module = propertyDescriptor.module 188 | elements.add( 189 | Element.PropertyGetterElement( 190 | setterDesc, 191 | annotation 192 | ) 193 | ) 194 | } 195 | 196 | processor.process(roundEnvironment) 197 | } 198 | } 199 | 200 | } 201 | 202 | 203 | private fun hasAnnnotations(it: ClassConstructorDescriptor, annotation: String): Boolean { 204 | /**I dont like this approach*/ 205 | 206 | try { 207 | val test = it.annotations.hasAnnotation(FqName(annotation)) 208 | return test 209 | } catch (any: Exception) { 210 | return false 211 | } 212 | } 213 | 214 | fun checkTypeAlias(it: PackageFragmentDescriptor, annotation: String): Boolean { 215 | /**I dont like this approach*/ 216 | 217 | try { 218 | val test = it.getMemberScope().getDescriptorsFiltered(DescriptorKindFilter.TYPE_ALIASES).isNotEmpty() 219 | return test 220 | } catch (any: Exception) { 221 | return false 222 | } 223 | } 224 | 225 | 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/Ext.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import de.jensklingenberg.mpapt.model.Platform 4 | import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys 5 | import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation 6 | import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity 7 | import org.jetbrains.kotlin.cli.common.messages.MessageCollector 8 | import org.jetbrains.kotlin.config.CompilerConfiguration 9 | import org.jetbrains.kotlin.descriptors.ModuleDescriptor 10 | import org.jetbrains.kotlin.name.Name 11 | import org.jetbrains.kotlin.resolve.constants.KClassValue 12 | 13 | 14 | fun MessageCollector.warn(s: String) { 15 | report( 16 | CompilerMessageSeverity.WARNING, s 17 | ) 18 | } 19 | 20 | 21 | /** 22 | * In the Kotlin Native Compiler the configuration map has an entry with the name "target we compile for" 23 | * the value is one of [de.jensklingenberg.mpapt.utils.KonanTargetValues]. I don't know how to get the value 24 | * out of the configuration map other than parse the "toString()". This function will return an empty value 25 | * when it's used on Kotlin JVM/JS Compiler because the CompilerConfiguration doesn't have that value. 26 | */ 27 | fun CompilerConfiguration.nativeTargetPlatformName(): String { 28 | val targetKeyword = "target we compile for=" 29 | val mapString = this.toString() 30 | return if(!mapString.contains(targetKeyword)){ 31 | "" 32 | }else{ 33 | this.toString().substringAfter(targetKeyword).substringBefore(",") 34 | } 35 | } 36 | 37 | fun MessageCollector.printMessage(diagnosticKind: DiagnosticKind, message: String) { 38 | when (diagnosticKind) { 39 | DiagnosticKind.WARNING -> { 40 | this.report(CompilerMessageSeverity.WARNING, 41 | message, 42 | CompilerMessageLocation.create(null)) 43 | } 44 | DiagnosticKind.ERROR -> { 45 | this.report(CompilerMessageSeverity.ERROR, 46 | message, 47 | CompilerMessageLocation.create(null)) 48 | } 49 | DiagnosticKind.MANDATORY_WARNING -> { 50 | this.report(CompilerMessageSeverity.STRONG_WARNING, 51 | message, 52 | CompilerMessageLocation.create(null)) 53 | } 54 | DiagnosticKind.NOTE -> { 55 | this.report(CompilerMessageSeverity.INFO, 56 | message, 57 | CompilerMessageLocation.create(null)) 58 | } 59 | DiagnosticKind.LOG -> { 60 | this.report(CompilerMessageSeverity.LOGGING, 61 | message, 62 | CompilerMessageLocation.create(null)) 63 | } 64 | else -> { 65 | this.report(CompilerMessageSeverity.WARNING, 66 | message, 67 | CompilerMessageLocation.create(null)) 68 | } 69 | } 70 | 71 | } 72 | 73 | 74 | fun KClassValue.getVariableNames(moduleDescriptor: ModuleDescriptor): List = 75 | this.getArgumentType(moduleDescriptor).memberScope.getVariableNames().toList() 76 | 77 | 78 | enum class DiagnosticKind { 79 | ERROR, 80 | WARNING, 81 | MANDATORY_WARNING, 82 | NOTE, 83 | LOG, 84 | OTHER; 85 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/FunctionDescriptorExt.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import de.jensklingenberg.mpapt.model.FunctionParameter 4 | import org.jetbrains.kotlin.backend.common.descriptors.allParameters 5 | import org.jetbrains.kotlin.com.intellij.psi.PsiElement 6 | import org.jetbrains.kotlin.descriptors.FunctionDescriptor 7 | import org.jetbrains.kotlin.descriptors.SourceElement 8 | import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 9 | import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor 10 | import org.jetbrains.kotlin.resolve.source.KotlinSourceElement 11 | import org.jetbrains.kotlin.resolve.source.getPsi 12 | import de.jensklingenberg.mpapt.model.Package 13 | 14 | 15 | /** 16 | * TODO: i dont know how to get the packageName of a function parameter 17 | */ 18 | fun FunctionDescriptor.getFunctionParameters(): List { 19 | //@de.ktorfit.POST public abstract suspend fun postPictures(helloWorld: sample.model.HelloWorld): kotlin.Unit defined in sample.data.Api[SimpleFunctionDescriptorImpl@470930f5] 20 | 21 | return if (valueParameters.isNotEmpty()) { 22 | this.valueParameters.map { parameter -> 23 | // normal: 24 | //value-parameter id: kotlin.Int defined in de.jensklingenberg.mpapt.CommonAnnotated.firstFunction2[ValueParameterDescriptorImpl@725a91a6] 25 | // Typedefs: 26 | //value-parameter id: de.jensklingenberg.mpapt.Datum /* = kotlin.ranges.CharProgression */ defined in de.jensklingenberg.mpapt.CommonAnnotated.firstFunction2[ValueParameterDescriptorImpl@692444bb 27 | // Arrays: 28 | //value-parameter list: kotlin.collections.List defined in de.jensklingenberg.mpapt.CommonAnnotated.testList[ValueParameterDescriptorImpl@f9c2310] 29 | val fullPackage = parameter.toString().substringAfter(": ") 30 | .substringBefore(" defined") 31 | .substringBefore(" /* =") 32 | val realValue = fullPackage.substringAfter("<").substringBefore(">") 33 | val isGeneric = fullPackage.contains("<") 34 | val genericValue = fullPackage.substringBefore("<") 35 | FunctionParameter( 36 | parameter.name.asString(), 37 | parameter.type.toString().endsWith("?"), 38 | Package( 39 | realValue.split(".").last().replace("?", ""), 40 | realValue.split(".").dropLast(1).joinToString(".") 41 | ), 42 | genericPackage = if (!isGeneric) null else Package( 43 | genericValue.split(".").last().replace("?", ""), 44 | genericValue.split(".").dropLast(1).joinToString(".") 45 | ) 46 | ) 47 | }.toList() 48 | } else { 49 | emptyList() 50 | } 51 | 52 | 53 | } 54 | 55 | /** 56 | * I dont know how to get full package of the return type 57 | */ 58 | fun FunctionDescriptor.getReturnTypeImport(): String = this.toString().substringAfter("): ").substringBefore(" defined") 59 | 60 | fun FunctionDescriptor.simpleName(): String = this.name.asString() 61 | 62 | /** 63 | * getPsi() on Kotlin Native was always crashing 64 | */ 65 | fun SourceElement.safeAsPsi(): PsiElement? { 66 | if (this is KotlinSourceElement) { 67 | return this.psi 68 | } else { 69 | this.getPsi() 70 | } 71 | return null 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/ModuleDescriptorExt.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import org.jetbrains.kotlin.descriptors.ModuleDescriptor 4 | 5 | fun ModuleDescriptor.simpleName() = this.name.asString().replace("<", "").replace(">", "") 6 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/MpAptProject.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import de.jensklingenberg.mpapt.extension.* 4 | import de.jensklingenberg.mpapt.extension.js.JsSyntheticTranslateExtensionExt 5 | import de.jensklingenberg.mpapt.extension.ClassBuilderInterceptorExtensionImpl 6 | import de.jensklingenberg.mpapt.model.AbstractProcessor 7 | import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension 8 | import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension 9 | import org.jetbrains.kotlin.config.CompilerConfiguration 10 | import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor 11 | import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension 12 | import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension 13 | 14 | class MpAptProject(abstractProcessor: AbstractProcessor,configuration: CompilerConfiguration) : SyntheticResolveExtension by SyntheticResolveExtensionImpl(abstractProcessor), 15 | IrGenerationExtension by NativeIrGenerationExtension(abstractProcessor), 16 | JsSyntheticTranslateExtension by JsSyntheticTranslateExtensionExt(abstractProcessor), 17 | ClassBuilderInterceptorExtension by ClassBuilderInterceptorExtensionImpl(abstractProcessor), 18 | StorageComponentContainerContributor by StorageComponentContainerContributorImpl(abstractProcessor) 19 | // CompilerConfigurationExtension by CompilerConfigurationExtensionExt(abstractProcessor), 20 | // ExpressionCodegenExtension by ExpressionCodegenExtensionImpl(abstractProcessor) 21 | // PreprocessedVirtualFileFactoryExtension by MetaPreprocessedVirtualFileFactoryExtension(abstractProcessor) 22 | // AnalysisHandlerExtension by AnalysisHandlerExtensionImpl(abstractProcessor), 23 | { 24 | init { 25 | abstractProcessor.configuration=(configuration) 26 | } 27 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/common/PropertyDescriptorExt.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.common 2 | 3 | import org.jetbrains.kotlin.descriptors.PropertyDescriptor 4 | import org.jetbrains.kotlin.name.FqName 5 | 6 | fun PropertyDescriptor.hasAnnotation(name: String): Boolean = this.annotations.hasAnnotation(FqName(name)) -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/ClassBuilderInterceptorExtensionImpl.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension 2 | 3 | import de.jensklingenberg.mpapt.model.Processor 4 | import org.jetbrains.kotlin.codegen.ClassBuilderFactory 5 | import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension 6 | import org.jetbrains.kotlin.diagnostics.DiagnosticSink 7 | import org.jetbrains.kotlin.resolve.BindingContext 8 | import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin 9 | 10 | 11 | class ClassBuilderInterceptorExtensionImpl(val processor: Processor) : ClassBuilderInterceptorExtension { 12 | 13 | override fun interceptClassBuilderFactory( 14 | interceptedFactory: ClassBuilderFactory, 15 | bindingContext: BindingContext, 16 | diagnostics: DiagnosticSink 17 | ): ClassBuilderFactory = object : ClassBuilderFactory by interceptedFactory { 18 | 19 | override fun newClassBuilder(origin: JvmDeclarationOrigin): DelegatingClassBuilderImpl { 20 | if(processor.isTargetPlatformSupported()){ 21 | processor.processingOver() 22 | } 23 | 24 | return DelegatingClassBuilderImpl(interceptedFactory.newClassBuilder(origin)) 25 | } 26 | } 27 | 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/CompilerConfigurationExtensionExt.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension 2 | 3 | import de.jensklingenberg.mpapt.model.AbstractProcessor 4 | import org.jetbrains.kotlin.config.CompilerConfiguration 5 | import org.jetbrains.kotlin.extensions.CompilerConfigurationExtension 6 | 7 | class CompilerConfigurationExtensionExt(val generator: AbstractProcessor) : CompilerConfigurationExtension { 8 | 9 | 10 | override fun updateConfiguration(configuration: CompilerConfiguration) { 11 | generator.log("updateConfiguration") 12 | //configuration.addKotlinSourceRoot("end",false) 13 | //configuration.addKotlinSourceRoot("/home/jens/Code/2019/MpApt/mpapt/src/main/java/de/jensklingenberg/mpapt/model/End.kt",false) 14 | val it = 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/DelegatingClassBuilderImpl.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension 2 | 3 | import de.jensklingenberg.mpapt.model.AbstractProcessor 4 | import org.jetbrains.kotlin.codegen.ClassBuilder 5 | import org.jetbrains.kotlin.descriptors.* 6 | import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin 7 | import org.jetbrains.org.objectweb.asm.FieldVisitor 8 | import org.jetbrains.org.objectweb.asm.MethodVisitor 9 | 10 | class DelegatingClassBuilderImpl( 11 | val delegateBuilder: ClassBuilder) : org.jetbrains.kotlin.codegen.DelegatingClassBuilder() { 12 | override fun getDelegate() = delegateBuilder 13 | 14 | 15 | override fun newMethod( 16 | origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: Array? 17 | ): MethodVisitor { 18 | // test.log("newMethod: "+name) 19 | // ClassParser.parseMethod(origin.descriptor as ClassDescriptor,) 20 | when (origin.descriptor) { 21 | is ClassDescriptor -> { 22 | val i = 1 23 | 24 | } 25 | is ClassConstructorDescriptor -> { 26 | val i = 1 27 | 28 | } 29 | is PropertyGetterDescriptor -> { 30 | val i = 1 31 | 32 | } 33 | is PropertySetterDescriptor -> { 34 | val i = 1 35 | 36 | } 37 | is SimpleFunctionDescriptor -> { 38 | val i = 1 39 | } 40 | else -> { 41 | 42 | } 43 | 44 | } 45 | val original = super.newMethod(origin, access, name, desc, signature, exceptions) 46 | return original 47 | } 48 | 49 | 50 | override fun newField(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor { 51 | 52 | /** 53 | * Property 54 | */ 55 | when (origin.descriptor) { 56 | is PropertyDescriptor -> { 57 | val i = 1 58 | 59 | } 60 | else -> { 61 | 62 | } 63 | } 64 | 65 | return super.newField(origin, access, name, desc, signature, value) 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/ExpressionCodegenExtensionImpl.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension; 2 | 3 | 4 | import de.jensklingenberg.mpapt.model.AbstractProcessor 5 | import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen 6 | import org.jetbrains.kotlin.codegen.StackValue 7 | import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension 8 | import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall 9 | 10 | class ExpressionCodegenExtensionImpl( 11 | private val abstractProcessor: AbstractProcessor 12 | ) : ExpressionCodegenExtension { 13 | 14 | 15 | override fun applyFunction( 16 | receiver: StackValue, 17 | resolvedCall: ResolvedCall<*>, 18 | c: ExpressionCodegenExtension.Context 19 | ): StackValue? { 20 | abstractProcessor.log("Apply function") 21 | return super.applyFunction(receiver, resolvedCall, c) 22 | } 23 | 24 | 25 | override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) { 26 | abstractProcessor.log("Apply function") 27 | 28 | 29 | } 30 | 31 | override fun applyProperty(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? { 32 | return super.applyProperty(receiver, resolvedCall, c) 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/MetaPreprocessedVirtualFileFactoryExtension.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension 2 | 3 | import de.jensklingenberg.mpapt.model.AbstractProcessor 4 | import org.jetbrains.kotlin.com.intellij.openapi.vfs.VirtualFile 5 | import org.jetbrains.kotlin.com.intellij.testFramework.LightVirtualFile 6 | import org.jetbrains.kotlin.extensions.PreprocessedVirtualFileFactoryExtension 7 | 8 | class MetaPreprocessedVirtualFileFactoryExtension(abstractProcessor: AbstractProcessor) : PreprocessedVirtualFileFactoryExtension { 9 | init { 10 | abstractProcessor.log("MetaPreprocessedVirtualFileFactoryExtension") 11 | } 12 | 13 | override fun createPreprocessedFile(file: VirtualFile?): VirtualFile? = file 14 | 15 | override fun createPreprocessedLightFile(file: LightVirtualFile?): LightVirtualFile? = file 16 | 17 | override fun isPassThrough(): Boolean = true 18 | 19 | } 20 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/NativeIrGenerationExtension.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension 2 | 3 | import de.jensklingenberg.mpapt.model.Processor 4 | import org.jetbrains.kotlin.backend.common.BackendContext 5 | import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension 6 | import org.jetbrains.kotlin.ir.declarations.IrFile 7 | import org.jetbrains.kotlin.resolve.BindingContext 8 | 9 | /** 10 | * This is only used in Native 11 | */ 12 | class NativeIrGenerationExtension(val processor: Processor) : IrGenerationExtension { 13 | 14 | override fun generate(file: IrFile, backendContext: BackendContext, bindingContext: BindingContext) { 15 | if(processor.isTargetPlatformSupported()){ 16 | processor.processingOver() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/StorageComponentContainerContributorImpl.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension 2 | 3 | import de.jensklingenberg.mpapt.model.AbstractProcessor 4 | import org.jetbrains.kotlin.container.StorageComponentContainer 5 | import org.jetbrains.kotlin.descriptors.ModuleDescriptor 6 | import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor 7 | import org.jetbrains.kotlin.platform.TargetPlatform 8 | 9 | class StorageComponentContainerContributorImpl(val processor: AbstractProcessor) : StorageComponentContainerContributor { 10 | 11 | /** 12 | * Here we get the targetplatform of the module 13 | */ 14 | override fun registerModuleComponents(container: StorageComponentContainer, platform: TargetPlatform, moduleDescriptor: ModuleDescriptor) { 15 | processor.activeTargetPlatform = platform 16 | } 17 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/SyntheticResolveExtensionImpl.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension 2 | 3 | import de.jensklingenberg.mpapt.common.ClassParser 4 | import de.jensklingenberg.mpapt.model.Processor 5 | import de.jensklingenberg.mpapt.model.RoundEnvironment 6 | import org.jetbrains.kotlin.descriptors.ClassDescriptor 7 | import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor 8 | import org.jetbrains.kotlin.descriptors.PropertyDescriptor 9 | import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor 10 | import org.jetbrains.kotlin.name.Name 11 | import org.jetbrains.kotlin.resolve.BindingContext 12 | import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension 13 | import org.jetbrains.kotlin.resolve.lazy.LazyClassContext 14 | import org.jetbrains.kotlin.resolve.lazy.declarations.PackageMemberDeclarationProvider 15 | import java.util.* 16 | 17 | internal class SyntheticResolveExtensionImpl(val abstractProcessor: Processor) : SyntheticResolveExtension { 18 | 19 | override fun generateSyntheticClasses(thisDescriptor: PackageFragmentDescriptor, name: Name, ctx: LazyClassContext, declarationProvider: PackageMemberDeclarationProvider, result: MutableSet) { 20 | if (!abstractProcessor.isTargetPlatformSupported()) { 21 | return 22 | } 23 | 24 | val roundEnvironment = RoundEnvironment() 25 | result.forEach { 26 | if (!it.isCompanionObject && name.identifier != "Companion") { 27 | ClassParser.parse(it, abstractProcessor, roundEnvironment) 28 | } 29 | } 30 | 31 | } 32 | 33 | override fun generateSyntheticMethods( 34 | thisDescriptor: ClassDescriptor, 35 | name: Name, 36 | bindingContext: BindingContext, 37 | fromSupertypes: List, 38 | result: MutableCollection 39 | ) { 40 | if (!abstractProcessor.isTargetPlatformSupported()) { 41 | return 42 | } 43 | result.forEach { function -> 44 | ClassParser.parseMethod(thisDescriptor, function, abstractProcessor, RoundEnvironment()) 45 | } 46 | } 47 | 48 | override fun generateSyntheticProperties(thisDescriptor: ClassDescriptor, name: Name, bindingContext: BindingContext, fromSupertypes: ArrayList, result: MutableSet) { 49 | if (!abstractProcessor.isTargetPlatformSupported()) { 50 | return 51 | } 52 | result.forEach { 53 | ClassParser.parseProperty(it, abstractProcessor, RoundEnvironment()) 54 | } 55 | 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/js/JsSyntheticTranslateExtensionExt.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension.js 2 | 3 | import de.jensklingenberg.mpapt.model.AbstractProcessor 4 | import de.jensklingenberg.mpapt.model.Processor 5 | import org.jetbrains.kotlin.descriptors.ClassDescriptor 6 | import org.jetbrains.kotlin.js.translate.context.TranslationContext 7 | import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor 8 | import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension 9 | import org.jetbrains.kotlin.psi.KtPureClassOrObject 10 | 11 | /** 12 | * This class is executed after the [SyntheticResolveExtensionImpl] 13 | */ 14 | internal class JsSyntheticTranslateExtensionExt(val processor: Processor) : JsSyntheticTranslateExtension { 15 | 16 | override fun generateClassSyntheticParts( 17 | declaration: KtPureClassOrObject, 18 | descriptor: ClassDescriptor, 19 | translator: DeclarationBodyVisitor, 20 | context: TranslationContext 21 | ) { 22 | if(processor.isTargetPlatformSupported()){ 23 | processor.processingOver() 24 | } 25 | } 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/extension/unused/AnalysisHandlerExtensionImpl.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.extension.unused 2 | 3 | import de.jensklingenberg.mpapt.model.AbstractProcessor 4 | import org.jetbrains.kotlin.analyzer.AnalysisResult 5 | import org.jetbrains.kotlin.com.intellij.openapi.project.Project 6 | import org.jetbrains.kotlin.container.ComponentProvider 7 | import org.jetbrains.kotlin.context.ProjectContext 8 | import org.jetbrains.kotlin.descriptors.ModuleDescriptor 9 | import org.jetbrains.kotlin.psi.KtFile 10 | import org.jetbrains.kotlin.resolve.BindingTrace 11 | import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension 12 | 13 | 14 | /** 15 | * I think this is only used on JVM 16 | */ 17 | class AnalysisHandlerExtensionImpl(val messageCollector: AbstractProcessor) : AnalysisHandlerExtension { 18 | 19 | override fun doAnalysis( 20 | project: Project, 21 | module: ModuleDescriptor, 22 | projectContext: ProjectContext, 23 | files: Collection, 24 | bindingTrace: BindingTrace, 25 | componentProvider: ComponentProvider 26 | ): AnalysisResult? { 27 | // messageCollector.warn("*** Started analysis") 28 | return super.doAnalysis(project, module, projectContext, files, bindingTrace, componentProvider) 29 | } 30 | 31 | override fun analysisCompleted( 32 | project: Project, 33 | module: ModuleDescriptor, 34 | bindingTrace: BindingTrace, 35 | files: Collection 36 | ): AnalysisResult? { 37 | // messageCollector.warn("*** SOTPPP ANALASyX ") 38 | return super.analysisCompleted(project, module, bindingTrace, files) 39 | } 40 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/AbstractProcessor.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys 4 | import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity 5 | import org.jetbrains.kotlin.cli.common.messages.MessageCollector 6 | import org.jetbrains.kotlin.config.CompilerConfiguration 7 | import org.jetbrains.kotlin.platform.SimplePlatform 8 | import org.jetbrains.kotlin.platform.TargetPlatform 9 | 10 | abstract class AbstractProcessor() : Processor { 11 | var configuration: CompilerConfiguration = CompilerConfiguration() 12 | 13 | private fun messageCollector() = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE) 14 | 15 | var activeTargetPlatform: TargetPlatform = UnknownTarget() 16 | val processingEnv = ProcessingEnvironment(messageCollector()) 17 | 18 | override fun initProcessor() {} 19 | 20 | fun log(message: String) { 21 | messageCollector().report( 22 | CompilerMessageSeverity.WARNING, 23 | "*** AbstractProcessor: $message" 24 | ) 25 | } 26 | 27 | override fun processingOver() {} 28 | 29 | override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latest() 30 | 31 | override fun isTargetPlatformSupported(): Boolean = isTargetPlatformSupported(activeTargetPlatform) 32 | 33 | /** 34 | * This method will check if your processor is enabled for the active target platform. 35 | * By default it's enabled for every platform. You can override it and return true or false for the targets you want to support 36 | */ 37 | open fun isTargetPlatformSupported(platform: TargetPlatform) = true 38 | 39 | 40 | } 41 | 42 | class UnknownTarget : TargetPlatform(setOf(object : SimplePlatform("Unknown") { 43 | override val oldFashionedDescription: String 44 | get() = "Unknown" 45 | 46 | })) -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/Element.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | import org.jetbrains.kotlin.descriptors.* 4 | import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor 5 | import org.jetbrains.kotlin.psi.KtProperty 6 | 7 | sealed class Element constructor( 8 | open val simpleName: String = "", 9 | open val path: String = "", 10 | open val elementKind: ElementKind = ElementKind.OTHER, 11 | open val annotation: AnnotationDescriptor? = null, 12 | open val pack: String = "" 13 | ) { 14 | /** 15 | * Elements annotated with [AnnotationTarget.CLASS] 16 | */ 17 | data class ClassElement( 18 | override val simpleName: String = "", 19 | override val path: String = "", 20 | override val elementKind: ElementKind = ElementKind.CLASS, 21 | override val annotation: AnnotationDescriptor? = null, 22 | override val pack: String = "", 23 | val classDescriptor: ClassDescriptor 24 | ) : Element() 25 | 26 | /** 27 | * Elements annotated with [AnnotationTarget.FUNCTION] 28 | */ 29 | data class FunctionElement( 30 | override val simpleName: String, 31 | override val elementKind: ElementKind = ElementKind.FUNCTION, 32 | override val annotation: AnnotationDescriptor? = null, 33 | val descriptor: ClassDescriptor, 34 | val func: FunctionDescriptor 35 | ) : Element() 36 | 37 | /** 38 | * Elements annotated with [AnnotationTarget.PROPERTY] 39 | */ 40 | data class PropertyElement(val propertyDescriptor: PropertyDescriptor, 41 | override val annotation: AnnotationDescriptor? = null, 42 | override val elementKind: ElementKind = ElementKind.PROPERTY 43 | ) : Element() 44 | 45 | /** 46 | * Elements annotated with [AnnotationTarget.VALUE_PARAMETER] 47 | */ 48 | data class ValueParameterElement(val valueParameterDescriptor: ValueParameterDescriptor, 49 | override val annotation: AnnotationDescriptor? = null, 50 | override val elementKind: ElementKind = ElementKind.VALUE_PARAMETER 51 | ) : Element() 52 | 53 | /** 54 | * Elements annotated with [AnnotationTarget.PROPERTY_GETTER] 55 | */ 56 | data class PropertyGetterElement(val propertyGetterDescriptor: PropertyGetterDescriptor, 57 | override val annotation: AnnotationDescriptor? = null, 58 | override val elementKind: ElementKind = ElementKind.PROPERTY_GETTER 59 | ) : Element() 60 | 61 | /** 62 | * Elements annotated with [AnnotationTarget.PROPERTY_SETTER] 63 | */ 64 | data class PropertySetterElement(val propertySetterDescriptor: PropertySetterDescriptor, 65 | override val annotation: AnnotationDescriptor? = null, 66 | override val elementKind: ElementKind = ElementKind.PROPERTY_SETTER 67 | ) : Element() 68 | 69 | 70 | /** 71 | * Elements annotated with [AnnotationTarget.CONSTRUCTOR] 72 | */ 73 | data class ClassConstructorElement(val classConstructorDescriptor: ClassConstructorDescriptor, 74 | override val annotation: AnnotationDescriptor? = null, 75 | override val elementKind: ElementKind = ElementKind.CONSTRUCTOR 76 | ) : Element() 77 | 78 | 79 | } 80 | 81 | 82 | enum class ElementKind { 83 | /** Class, interface or object, annotation class is also included */ 84 | CLASS, 85 | /** Annotation class only */ 86 | ANNOTATION_CLASS, 87 | /** Generic type parameter (unsupported yet) */ 88 | TYPE_PARAMETER, 89 | /** Property */ 90 | PROPERTY, 91 | /** Field, including property's backing field */ 92 | FIELD, 93 | /** Local variable */ 94 | LOCAL_VARIABLE, 95 | /** Value parameter of a function or a constructor */ 96 | VALUE_PARAMETER, 97 | /** Constructor only (primary or secondary) */ 98 | CONSTRUCTOR, 99 | /** Function (constructors are not included) */ 100 | FUNCTION, 101 | /** Property getter only */ 102 | PROPERTY_GETTER, 103 | /** Property setter only */ 104 | PROPERTY_SETTER, 105 | /** Type usage */ 106 | TYPE, 107 | /** Any expression */ 108 | EXPRESSION, 109 | /** File */ 110 | FILE, 111 | /** Type alias */ 112 | OTHER 113 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/FunctionParameter.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | data class FunctionParameter( 4 | val parameterName: String, 5 | val nullable: Boolean, 6 | val packagee: Package, 7 | val genericPackage: Package? = null 8 | ) 9 | 10 | data class Package(val classname: String, val packagename: String) 11 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/Platform.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | /** 4 | * Targetplatforms 5 | */ 6 | enum class Platform { 7 | ALL, JVM, JS, COMMON, UNKNOWN, NATIVE, METADATA 8 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/ProcessingEnvironment.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | import org.jetbrains.kotlin.cli.common.messages.MessageCollector 4 | import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 5 | 6 | data class ProcessingEnvironment( 7 | open val messager: MessageCollector, 8 | val elementUtils: ElementUtils = ElementUtils() 9 | 10 | ) { 11 | fun elementUtils(): ElementUtils { 12 | return ElementUtils() 13 | } 14 | } 15 | 16 | class ElementUtils() { 17 | fun getPackageOf(sourceClassElement: de.jensklingenberg.mpapt.model.Element): String { 18 | when (sourceClassElement) { 19 | is Element.ClassElement -> { 20 | return sourceClassElement.classDescriptor.original.containingDeclaration.fqNameSafe.asString() 21 | } 22 | } 23 | return "" 24 | 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/Processor.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | interface Processor { 4 | 5 | /** 6 | * The list of Annotations that should be detected by the processor. 7 | * 8 | */ 9 | fun getSupportedAnnotationTypes(): Set 10 | 11 | /** 12 | * TODO: Implement check for source version 13 | */ 14 | fun getSupportedSourceVersion(): SourceVersion 15 | 16 | /** 17 | * This gets triggered when a new module(jvmMain,jsMain,..) is getting parsed by the processor 18 | */ 19 | fun initProcessor() 20 | 21 | /** 22 | * This gets triggered when a new annotation was found 23 | * */ 24 | fun process(roundEnvironment: RoundEnvironment) 25 | 26 | /** 27 | * This get triggered when the last class of a module was parsed. 28 | */ 29 | fun processingOver() 30 | 31 | 32 | fun isTargetPlatformSupported() : Boolean 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/ProcessorProject.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | 4 | class ProcessorProject { 5 | 6 | companion object { 7 | 8 | 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/RoundEnvironment.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | import org.jetbrains.kotlin.descriptors.ModuleDescriptor 4 | 5 | class RoundEnvironment() { 6 | 7 | var elements: MutableList = mutableListOf() 8 | 9 | var module: ModuleDescriptor? = null 10 | 11 | fun getElementsAnnotatedWith(annotationName: String): List = 12 | elements.filter { it.annotation?.fqName?.asString() == annotationName } 13 | 14 | fun getElementsAnnotatedWith(annotationName: List): List = 15 | elements.filter { annotationName.contains(it.annotation?.fqName?.asString()) } 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/model/SourceVersion.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.model 2 | 3 | enum class SourceVersion { 4 | 5 | KOTLIN_1_3, LATEST; 6 | 7 | companion object { 8 | fun latest(): SourceVersion { 9 | return LATEST 10 | } 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/utils/KonanTargetValues.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.utils 2 | 3 | /** 4 | * Got the values from org.jetbrains.kotlin.konan.target.KonanTarget 5 | */ 6 | class KonanTargetValues{ 7 | companion object { 8 | val ANDROID_ARM32 = "android_arm32" 9 | val ANDROID_ARM64 = "android_arm64" 10 | val IOS_ARM32 = "ios_arm32" 11 | val IOS_ARM64 = "ios_arm64" 12 | val IOS_X64 = "ios_x64" 13 | val LINUX_X64 = "linux_x64" 14 | val MINGW_X86 = "mingw_x86" 15 | val MINGW_X64 = "mingw_x64" 16 | val MACOS_X64 = "macos_x64" 17 | val LINUX_ARM32_HFP = "linux_arm32_hfp" 18 | val LINUX_MIPS32 = "linux_mips32" 19 | val LINUX_MIPSEL32 = "linux_mipsel32" 20 | val WASM32 = "wasm32" 21 | } 22 | } -------------------------------------------------------------------------------- /mpapt-runtime/src/main/java/de/jensklingenberg/mpapt/utils/KotlinPlatformValues.kt: -------------------------------------------------------------------------------- 1 | package de.jensklingenberg.mpapt.utils 2 | 3 | class KotlinPlatformValues { 4 | companion object { 5 | const val JS = "JS" 6 | const val JVM = "JVM" 7 | const val NATIVE = "Native" 8 | } 9 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | enableFeaturePreview("GRADLE_METADATA") 2 | 3 | include 'annotations' 4 | //include 'example' 5 | include ':kotlin-plugin' 6 | include ':mpapt-runtime' 7 | --------------------------------------------------------------------------------