├── .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 | [](https://github.com/Foso/MpApt/blob/master/LICENSE)
4 | [](https://github.com/Foso/MpApt/blob/master/LICENSE)
5 | [  ](https://bintray.com/jonasbark/ffuf/nativesuspendfunction-compiler/)
6 | [](http://makeapullrequest.com)
7 |
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 |
--------------------------------------------------------------------------------